OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <dlfcn.h> | 5 #include <dlfcn.h> |
6 #include <errno.h> | 6 #include <errno.h> |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <libdrm/drm_fourcc.h> | 8 #include <libdrm/drm_fourcc.h> |
9 #include <linux/videodev2.h> | 9 #include <linux/videodev2.h> |
10 #include <poll.h> | 10 #include <poll.h> |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 return false; | 260 return false; |
261 } | 261 } |
262 | 262 |
263 if (!CreateInputBuffers()) | 263 if (!CreateInputBuffers()) |
264 return false; | 264 return false; |
265 | 265 |
266 // Output format has to be setup before streaming starts. | 266 // Output format has to be setup before streaming starts. |
267 struct v4l2_format format; | 267 struct v4l2_format format; |
268 memset(&format, 0, sizeof(format)); | 268 memset(&format, 0, sizeof(format)); |
269 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 269 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
270 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; | 270 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; |
Pawel Osciak
2014/03/25 08:21:08
I think we discussed before that this should be fi
| |
271 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 271 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
272 | 272 |
273 memset(¤t_format_, 0, sizeof(current_format_)); | |
274 | |
273 // Subscribe to the resolution change event. | 275 // Subscribe to the resolution change event. |
274 struct v4l2_event_subscription sub; | 276 struct v4l2_event_subscription sub; |
275 memset(&sub, 0, sizeof(sub)); | 277 memset(&sub, 0, sizeof(sub)); |
276 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; | 278 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; |
277 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); | 279 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); |
278 | 280 |
279 // Initialize format-specific bits. | 281 // Initialize format-specific bits. |
280 if (video_profile_ >= media::H264PROFILE_MIN && | 282 if (video_profile_ >= media::H264PROFILE_MIN && |
281 video_profile_ <= media::H264PROFILE_MAX) { | 283 video_profile_ <= media::H264PROFILE_MAX) { |
282 decoder_h264_parser_.reset(new media::H264Parser()); | 284 decoder_h264_parser_.reset(new media::H264Parser()); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 355 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
354 DCHECK_EQ(output_record.picture_id, -1); | 356 DCHECK_EQ(output_record.picture_id, -1); |
355 DCHECK_EQ(output_record.cleared, false); | 357 DCHECK_EQ(output_record.cleared, false); |
356 | 358 |
357 attrs[7] = output_record.fds[0]; | 359 attrs[7] = output_record.fds[0]; |
358 attrs[9] = 0; | 360 attrs[9] = 0; |
359 attrs[11] = frame_buffer_size_.width(); | 361 attrs[11] = frame_buffer_size_.width(); |
360 attrs[13] = output_record.fds[1]; | 362 attrs[13] = output_record.fds[1]; |
361 attrs[15] = 0; | 363 attrs[15] = 0; |
362 attrs[17] = frame_buffer_size_.width(); | 364 attrs[17] = frame_buffer_size_.width(); |
363 | 365 EGLImageKHR egl_image = device_->CreateEGLImage( |
364 EGLImageKHR egl_image = eglCreateImageKHR( | 366 egl_display_, attrs, buffers[i].texture_id(), i); |
365 egl_display_, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); | |
366 if (egl_image == EGL_NO_IMAGE_KHR) { | 367 if (egl_image == EGL_NO_IMAGE_KHR) { |
367 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; | 368 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
368 // Ownership of EGLImages allocated in previous iterations of this loop | 369 // Ownership of EGLImages allocated in previous iterations of this loop |
369 // has been transferred to output_buffer_map_. After we error-out here | 370 // has been transferred to output_buffer_map_. After we error-out here |
370 // the destructor will handle their cleanup. | 371 // the destructor will handle their cleanup. |
371 NOTIFY_ERROR(PLATFORM_FAILURE); | 372 NOTIFY_ERROR(PLATFORM_FAILURE); |
372 return; | 373 return; |
373 } | 374 } |
374 | 375 |
375 glBindTexture(GL_TEXTURE_EXTERNAL_OES, buffers[i].texture_id()); | |
376 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); | |
377 | |
378 output_record.egl_image = egl_image; | 376 output_record.egl_image = egl_image; |
379 output_record.picture_id = buffers[i].id(); | 377 output_record.picture_id = buffers[i].id(); |
380 free_output_buffers_.push(i); | 378 free_output_buffers_.push(i); |
381 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i | 379 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i |
382 << "]: picture_id=" << output_record.picture_id; | 380 << "]: picture_id=" << output_record.picture_id; |
383 } | 381 } |
384 | 382 |
385 pictures_assigned_.Signal(); | 383 pictures_assigned_.Signal(); |
386 } | 384 } |
387 | 385 |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
737 | 735 |
738 if (again) { | 736 if (again) { |
739 // Need more stream to decode format, return true and schedule next buffer. | 737 // Need more stream to decode format, return true and schedule next buffer. |
740 *endpos = size; | 738 *endpos = size; |
741 return true; | 739 return true; |
742 } | 740 } |
743 | 741 |
744 // Run this initialization only on first startup. | 742 // Run this initialization only on first startup. |
745 if (decoder_state_ == kInitialized) { | 743 if (decoder_state_ == kInitialized) { |
746 DVLOG(3) << "DecodeBufferInitial(): running initialization"; | 744 DVLOG(3) << "DecodeBufferInitial(): running initialization"; |
745 current_format_ = format; | |
Pawel Osciak
2014/03/25 08:21:08
Please move this to the CreateBuffersForFormat cal
| |
747 // Success! Setup our parameters. | 746 // Success! Setup our parameters. |
748 if (!CreateBuffersForFormat(format)) | 747 if (!CreateBuffersForFormat(format)) |
749 return false; | 748 return false; |
750 | 749 |
751 // We expect to process the initial buffer once during stream init to | 750 // We expect to process the initial buffer once during stream init to |
752 // configure stream parameters, but will not consume the steam data on that | 751 // configure stream parameters, but will not consume the steam data on that |
753 // iteration. Subsequent iterations (including after reset) do not require | 752 // iteration. Subsequent iterations (including after reset) do not require |
754 // the stream init step. | 753 // the stream init step. |
755 *endpos = 0; | 754 *endpos = 0; |
756 } else { | 755 } else { |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
998 DCHECK_NE(decoder_state_, kUninitialized); | 997 DCHECK_NE(decoder_state_, kUninitialized); |
999 DVLOG(3) << "DequeueEvents()"; | 998 DVLOG(3) << "DequeueEvents()"; |
1000 | 999 |
1001 struct v4l2_event ev; | 1000 struct v4l2_event ev; |
1002 memset(&ev, 0, sizeof(ev)); | 1001 memset(&ev, 0, sizeof(ev)); |
1003 | 1002 |
1004 while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { | 1003 while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { |
1005 if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { | 1004 if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { |
1006 DVLOG(3) << "DequeueEvents(): got resolution change event."; | 1005 DVLOG(3) << "DequeueEvents(): got resolution change event."; |
1007 DCHECK(!resolution_change_pending_); | 1006 DCHECK(!resolution_change_pending_); |
1008 resolution_change_pending_ = true; | 1007 // Check if we already have current_format_ set or this is an event |
Pawel Osciak
2014/03/25 08:21:08
s/or this/or if this/
shivdasp
2014/03/25 10:36:40
Done.
| |
1008 // to trigger decoder initialization. | |
1009 if ((current_format_.fmt.pix_mp.width == 0) || | |
Pawel Osciak
2014/03/25 08:21:08
Since you are using the format only for size, I th
shivdasp
2014/03/25 10:36:40
Done.
| |
1010 (current_format_.fmt.pix_mp.height == 0)) { | |
1011 DVLOG(3) << "DequeueEvents(): Decoder init through resolution change "; | |
1012 resolution_change_pending_ = true; | |
1013 } else if (IsResolutionChangeNecessary()) { | |
Pawel Osciak
2014/03/25 08:21:08
Also, IsResolutionChangeNecessary() should handle
| |
1014 DVLOG(3) << "DequeueEvents(): Resolution change event detected "; | |
1015 resolution_change_pending_ = true; | |
1016 } | |
1009 } else { | 1017 } else { |
1010 DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type | 1018 DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type |
1011 << ") we haven't subscribed to."; | 1019 << ") we haven't subscribed to."; |
1012 } | 1020 } |
1013 } | 1021 } |
1014 } | 1022 } |
1015 | 1023 |
1016 void V4L2VideoDecodeAccelerator::Dequeue() { | 1024 void V4L2VideoDecodeAccelerator::Dequeue() { |
1017 DVLOG(3) << "Dequeue()"; | 1025 DVLOG(3) << "Dequeue()"; |
1018 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1026 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
(...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1529 } | 1537 } |
1530 | 1538 |
1531 struct v4l2_format format; | 1539 struct v4l2_format format; |
1532 bool again; | 1540 bool again; |
1533 bool ret = GetFormatInfo(&format, &again); | 1541 bool ret = GetFormatInfo(&format, &again); |
1534 if (!ret || again) { | 1542 if (!ret || again) { |
1535 DVLOG(3) << "Couldn't get format information after resolution change"; | 1543 DVLOG(3) << "Couldn't get format information after resolution change"; |
1536 NOTIFY_ERROR(PLATFORM_FAILURE); | 1544 NOTIFY_ERROR(PLATFORM_FAILURE); |
1537 return; | 1545 return; |
1538 } | 1546 } |
1539 | 1547 // Store this new format. |
1548 current_format_ = format; | |
1540 if (!CreateBuffersForFormat(format)) { | 1549 if (!CreateBuffersForFormat(format)) { |
1541 DVLOG(3) << "Couldn't reallocate buffers after resolution change"; | 1550 DVLOG(3) << "Couldn't reallocate buffers after resolution change"; |
1542 NOTIFY_ERROR(PLATFORM_FAILURE); | 1551 NOTIFY_ERROR(PLATFORM_FAILURE); |
1543 return; | 1552 return; |
1544 } | 1553 } |
1545 | 1554 |
1546 decoder_state_ = kDecoding; | 1555 decoder_state_ = kDecoding; |
1547 | 1556 |
1548 if (resolution_change_reset_pending_) { | 1557 if (resolution_change_reset_pending_) { |
1549 resolution_change_reset_pending_ = false; | 1558 resolution_change_reset_pending_ = false; |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1752 | 1761 |
1753 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " | 1762 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " |
1754 << "buffer_count=" << output_buffer_map_.size() | 1763 << "buffer_count=" << output_buffer_map_.size() |
1755 << ", width=" << frame_buffer_size_.width() | 1764 << ", width=" << frame_buffer_size_.width() |
1756 << ", height=" << frame_buffer_size_.height(); | 1765 << ", height=" << frame_buffer_size_.height(); |
1757 child_message_loop_proxy_->PostTask(FROM_HERE, | 1766 child_message_loop_proxy_->PostTask(FROM_HERE, |
1758 base::Bind(&Client::ProvidePictureBuffers, | 1767 base::Bind(&Client::ProvidePictureBuffers, |
1759 client_, | 1768 client_, |
1760 output_buffer_map_.size(), | 1769 output_buffer_map_.size(), |
1761 frame_buffer_size_, | 1770 frame_buffer_size_, |
1762 GL_TEXTURE_EXTERNAL_OES)); | 1771 device_->GetTextureTarget())); |
1763 | 1772 |
1764 // Wait for the client to call AssignPictureBuffers() on the Child thread. | 1773 // Wait for the client to call AssignPictureBuffers() on the Child thread. |
1765 // We do this, because if we continue decoding without finishing buffer | 1774 // We do this, because if we continue decoding without finishing buffer |
1766 // allocation, we may end up Resetting before AssignPictureBuffers arrives, | 1775 // allocation, we may end up Resetting before AssignPictureBuffers arrives, |
1767 // resulting in unnecessary complications and subtle bugs. | 1776 // resulting in unnecessary complications and subtle bugs. |
1768 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) | 1777 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) |
1769 // in a sequence, and Decode(Input1) results in us getting here and exiting | 1778 // in a sequence, and Decode(Input1) results in us getting here and exiting |
1770 // without waiting, we might end up running Reset{,Done}Task() before | 1779 // without waiting, we might end up running Reset{,Done}Task() before |
1771 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers | 1780 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers |
1772 // to the free_output_buffers_ map twice. If we somehow marked buffers as | 1781 // to the free_output_buffers_ map twice. If we somehow marked buffers as |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1919 } | 1928 } |
1920 | 1929 |
1921 void V4L2VideoDecodeAccelerator::PictureCleared() { | 1930 void V4L2VideoDecodeAccelerator::PictureCleared() { |
1922 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 1931 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
1923 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1932 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1924 DCHECK_GT(picture_clearing_count_, 0); | 1933 DCHECK_GT(picture_clearing_count_, 0); |
1925 picture_clearing_count_--; | 1934 picture_clearing_count_--; |
1926 SendPictureReady(); | 1935 SendPictureReady(); |
1927 } | 1936 } |
1928 | 1937 |
1938 bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() { | |
1939 DVLOG(3) << "IsResolutionChangeNecessary() "; | |
1940 struct v4l2_control ctrl; | |
1941 memset(&ctrl, 0, sizeof(ctrl)); | |
1942 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; | |
1943 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); | |
1944 if (ctrl.value != output_dpb_size_) | |
1945 return true; | |
1946 struct v4l2_format format; | |
1947 bool again = false; | |
1948 bool ret = GetFormatInfo(&format, &again); | |
1949 if (!ret || again) { | |
1950 DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed"; | |
1951 NOTIFY_ERROR(PLATFORM_FAILURE); | |
Pawel Osciak
2014/03/25 08:21:08
This means we will send NOTIFY_ERROR twice in case
shivdasp
2014/03/25 10:36:40
Since GetFormatInfo() does NOTIFY_ERROR already I
| |
1952 return false; | |
1953 } | |
1954 if ((format.fmt.pix_mp.width != current_format_.fmt.pix_mp.width) || | |
1955 (format.fmt.pix_mp.height != current_format_.fmt.pix_mp.height)) { | |
1956 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; | |
1957 current_format_ = format; | |
Pawel Osciak
2014/03/25 08:21:08
If you are doing this here, then there is no need
| |
1958 return true; | |
1959 } else { | |
1960 DVLOG(3) << "IsResolutionChangeNecessary(): Dropping resolution change"; | |
Pawel Osciak
2014/03/25 08:21:08
No need for the else clause, just move it out plea
shivdasp
2014/03/25 10:36:40
Done.
| |
1961 } | |
1962 return false; | |
1963 } | |
1964 | |
1929 } // namespace content | 1965 } // namespace content |
OLD | NEW |