| 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 <errno.h> | 5 #include <errno.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <linux/videodev2.h> | 7 #include <linux/videodev2.h> |
| 8 #include <poll.h> | 8 #include <poll.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| 11 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
| 12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
| 16 #include "base/callback.h" | 16 #include "base/callback.h" |
| 17 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
| 18 #include "base/thread_task_runner_handle.h" | 18 #include "base/thread_task_runner_handle.h" |
| 19 #include "content/common/gpu/media/v4l2_image_processor.h" | 19 #include "media/gpu/v4l2_image_processor.h" |
| 20 | 20 |
| 21 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ | 21 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ |
| 22 do { \ | 22 do { \ |
| 23 if (device_->Ioctl(type, arg) != 0) { \ | 23 if (device_->Ioctl(type, arg) != 0) { \ |
| 24 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_str; \ | 24 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_str; \ |
| 25 return value; \ | 25 return value; \ |
| 26 } \ | 26 } \ |
| 27 } while (0) | 27 } while (0) |
| 28 | 28 |
| 29 #define IOCTL_OR_ERROR_RETURN(type, arg) \ | 29 #define IOCTL_OR_ERROR_RETURN(type, arg) \ |
| 30 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type) | 30 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type) |
| 31 | 31 |
| 32 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \ | 32 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \ |
| 33 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type) | 33 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type) |
| 34 | 34 |
| 35 #define IOCTL_OR_LOG_ERROR(type, arg) \ | 35 #define IOCTL_OR_LOG_ERROR(type, arg) \ |
| 36 do { \ | 36 do { \ |
| 37 if (device_->Ioctl(type, arg) != 0) \ | 37 if (device_->Ioctl(type, arg) != 0) \ |
| 38 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ | 38 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ |
| 39 } while (0) | 39 } while (0) |
| 40 | 40 |
| 41 namespace content { | 41 namespace media { |
| 42 | 42 |
| 43 V4L2ImageProcessor::InputRecord::InputRecord() : at_device(false) { | 43 V4L2ImageProcessor::InputRecord::InputRecord() : at_device(false) {} |
| 44 } | |
| 45 | 44 |
| 46 V4L2ImageProcessor::InputRecord::~InputRecord() { | 45 V4L2ImageProcessor::InputRecord::~InputRecord() {} |
| 47 } | |
| 48 | 46 |
| 49 V4L2ImageProcessor::OutputRecord::OutputRecord() : at_device(false) {} | 47 V4L2ImageProcessor::OutputRecord::OutputRecord() : at_device(false) {} |
| 50 | 48 |
| 51 V4L2ImageProcessor::OutputRecord::~OutputRecord() { | 49 V4L2ImageProcessor::OutputRecord::~OutputRecord() {} |
| 52 } | |
| 53 | 50 |
| 54 V4L2ImageProcessor::JobRecord::JobRecord() : output_buffer_index(-1) {} | 51 V4L2ImageProcessor::JobRecord::JobRecord() : output_buffer_index(-1) {} |
| 55 | 52 |
| 56 V4L2ImageProcessor::JobRecord::~JobRecord() { | 53 V4L2ImageProcessor::JobRecord::~JobRecord() {} |
| 57 } | |
| 58 | 54 |
| 59 V4L2ImageProcessor::V4L2ImageProcessor(const scoped_refptr<V4L2Device>& device) | 55 V4L2ImageProcessor::V4L2ImageProcessor(const scoped_refptr<V4L2Device>& device) |
| 60 : input_format_(media::PIXEL_FORMAT_UNKNOWN), | 56 : input_format_(media::PIXEL_FORMAT_UNKNOWN), |
| 61 output_format_(media::PIXEL_FORMAT_UNKNOWN), | 57 output_format_(media::PIXEL_FORMAT_UNKNOWN), |
| 62 input_memory_type_(V4L2_MEMORY_USERPTR), | 58 input_memory_type_(V4L2_MEMORY_USERPTR), |
| 63 input_format_fourcc_(0), | 59 input_format_fourcc_(0), |
| 64 output_format_fourcc_(0), | 60 output_format_fourcc_(0), |
| 65 input_planes_count_(0), | 61 input_planes_count_(0), |
| 66 output_planes_count_(0), | 62 output_planes_count_(0), |
| 67 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 63 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 output_visible_size_ = output_visible_size; | 129 output_visible_size_ = output_visible_size; |
| 134 output_allocated_size_ = output_allocated_size; | 130 output_allocated_size_ = output_allocated_size; |
| 135 | 131 |
| 136 // Capabilities check. | 132 // Capabilities check. |
| 137 struct v4l2_capability caps; | 133 struct v4l2_capability caps; |
| 138 memset(&caps, 0, sizeof(caps)); | 134 memset(&caps, 0, sizeof(caps)); |
| 139 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 135 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
| 140 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 136 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
| 141 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 137 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
| 142 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " | 138 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " |
| 143 "caps check failed: 0x" << std::hex << caps.capabilities; | 139 "caps check failed: 0x" |
| 140 << std::hex << caps.capabilities; |
| 144 return false; | 141 return false; |
| 145 } | 142 } |
| 146 | 143 |
| 147 if (!CreateInputBuffers() || !CreateOutputBuffers()) | 144 if (!CreateInputBuffers() || !CreateOutputBuffers()) |
| 148 return false; | 145 return false; |
| 149 | 146 |
| 150 if (!device_thread_.Start()) { | 147 if (!device_thread_.Start()) { |
| 151 LOG(ERROR) << "Initialize(): encoder thread failed to start"; | 148 LOG(ERROR) << "Initialize(): encoder thread failed to start"; |
| 152 return false; | 149 return false; |
| 153 } | 150 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 int output_buffer_index, | 223 int output_buffer_index, |
| 227 const FrameReadyCB& cb) { | 224 const FrameReadyCB& cb) { |
| 228 DVLOG(3) << __func__ << ": ts=" << frame->timestamp().InMilliseconds(); | 225 DVLOG(3) << __func__ << ": ts=" << frame->timestamp().InMilliseconds(); |
| 229 | 226 |
| 230 std::unique_ptr<JobRecord> job_record(new JobRecord()); | 227 std::unique_ptr<JobRecord> job_record(new JobRecord()); |
| 231 job_record->frame = frame; | 228 job_record->frame = frame; |
| 232 job_record->output_buffer_index = output_buffer_index; | 229 job_record->output_buffer_index = output_buffer_index; |
| 233 job_record->ready_cb = cb; | 230 job_record->ready_cb = cb; |
| 234 | 231 |
| 235 device_thread_.message_loop()->PostTask( | 232 device_thread_.message_loop()->PostTask( |
| 236 FROM_HERE, | 233 FROM_HERE, base::Bind(&V4L2ImageProcessor::ProcessTask, |
| 237 base::Bind(&V4L2ImageProcessor::ProcessTask, | 234 base::Unretained(this), base::Passed(&job_record))); |
| 238 base::Unretained(this), | |
| 239 base::Passed(&job_record))); | |
| 240 } | 235 } |
| 241 | 236 |
| 242 void V4L2ImageProcessor::ProcessTask(std::unique_ptr<JobRecord> job_record) { | 237 void V4L2ImageProcessor::ProcessTask(std::unique_ptr<JobRecord> job_record) { |
| 243 int index = job_record->output_buffer_index; | 238 int index = job_record->output_buffer_index; |
| 244 DVLOG(3) << __func__ << ": Reusing output buffer, index=" << index; | 239 DVLOG(3) << __func__ << ": Reusing output buffer, index=" << index; |
| 245 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 240 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
| 246 | 241 |
| 247 EnqueueOutput(index); | 242 EnqueueOutput(index); |
| 248 input_queue_.push(make_linked_ptr(job_record.release())); | 243 input_queue_.push(make_linked_ptr(job_record.release())); |
| 249 EnqueueInput(); | 244 EnqueueInput(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 memset(&format, 0, sizeof(format)); | 302 memset(&format, 0, sizeof(format)); |
| 308 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 303 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 309 format.fmt.pix_mp.width = input_allocated_size_.width(); | 304 format.fmt.pix_mp.width = input_allocated_size_.width(); |
| 310 format.fmt.pix_mp.height = input_allocated_size_.height(); | 305 format.fmt.pix_mp.height = input_allocated_size_.height(); |
| 311 format.fmt.pix_mp.pixelformat = input_format_fourcc_; | 306 format.fmt.pix_mp.pixelformat = input_format_fourcc_; |
| 312 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 307 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
| 313 | 308 |
| 314 input_planes_count_ = format.fmt.pix_mp.num_planes; | 309 input_planes_count_ = format.fmt.pix_mp.num_planes; |
| 315 DCHECK_LE(input_planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES)); | 310 DCHECK_LE(input_planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES)); |
| 316 input_allocated_size_ = V4L2Device::CodedSizeFromV4L2Format(format); | 311 input_allocated_size_ = V4L2Device::CodedSizeFromV4L2Format(format); |
| 317 DCHECK(gfx::Rect(input_allocated_size_).Contains( | 312 DCHECK(gfx::Rect(input_allocated_size_) |
| 318 gfx::Rect(input_visible_size_))); | 313 .Contains(gfx::Rect(input_visible_size_))); |
| 319 | 314 |
| 320 struct v4l2_crop crop; | 315 struct v4l2_crop crop; |
| 321 memset(&crop, 0, sizeof(crop)); | 316 memset(&crop, 0, sizeof(crop)); |
| 322 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 317 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 323 crop.c.left = 0; | 318 crop.c.left = 0; |
| 324 crop.c.top = 0; | 319 crop.c.top = 0; |
| 325 crop.c.width = base::checked_cast<__u32>(input_visible_size_.width()); | 320 crop.c.width = base::checked_cast<__u32>(input_visible_size_.width()); |
| 326 crop.c.height = base::checked_cast<__u32>(input_visible_size_.height()); | 321 crop.c.height = base::checked_cast<__u32>(input_visible_size_.height()); |
| 327 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); | 322 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); |
| 328 | 323 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 357 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 352 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 358 format.fmt.pix_mp.width = output_allocated_size_.width(); | 353 format.fmt.pix_mp.width = output_allocated_size_.width(); |
| 359 format.fmt.pix_mp.height = output_allocated_size_.height(); | 354 format.fmt.pix_mp.height = output_allocated_size_.height(); |
| 360 format.fmt.pix_mp.pixelformat = output_format_fourcc_; | 355 format.fmt.pix_mp.pixelformat = output_format_fourcc_; |
| 361 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 356 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
| 362 | 357 |
| 363 output_planes_count_ = format.fmt.pix_mp.num_planes; | 358 output_planes_count_ = format.fmt.pix_mp.num_planes; |
| 364 DCHECK_LE(output_planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES)); | 359 DCHECK_LE(output_planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES)); |
| 365 gfx::Size adjusted_allocated_size = | 360 gfx::Size adjusted_allocated_size = |
| 366 V4L2Device::CodedSizeFromV4L2Format(format); | 361 V4L2Device::CodedSizeFromV4L2Format(format); |
| 367 DCHECK(gfx::Rect(adjusted_allocated_size).Contains( | 362 DCHECK(gfx::Rect(adjusted_allocated_size) |
| 368 gfx::Rect(output_allocated_size_))); | 363 .Contains(gfx::Rect(output_allocated_size_))); |
| 369 output_allocated_size_ = adjusted_allocated_size; | 364 output_allocated_size_ = adjusted_allocated_size; |
| 370 | 365 |
| 371 struct v4l2_crop crop; | 366 struct v4l2_crop crop; |
| 372 memset(&crop, 0, sizeof(crop)); | 367 memset(&crop, 0, sizeof(crop)); |
| 373 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 368 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 374 crop.c.left = 0; | 369 crop.c.left = 0; |
| 375 crop.c.top = 0; | 370 crop.c.top = 0; |
| 376 crop.c.width = base::checked_cast<__u32>(output_visible_size_.width()); | 371 crop.c.width = base::checked_cast<__u32>(output_visible_size_.width()); |
| 377 crop.c.height = base::checked_cast<__u32>(output_visible_size_.height()); | 372 crop.c.height = base::checked_cast<__u32>(output_visible_size_.height()); |
| 378 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); | 373 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 | 424 |
| 430 bool event_pending; | 425 bool event_pending; |
| 431 if (!device_->Poll(poll_device, &event_pending)) { | 426 if (!device_->Poll(poll_device, &event_pending)) { |
| 432 NotifyError(); | 427 NotifyError(); |
| 433 return; | 428 return; |
| 434 } | 429 } |
| 435 | 430 |
| 436 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 431 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
| 437 // touch encoder state from this thread. | 432 // touch encoder state from this thread. |
| 438 device_thread_.message_loop()->PostTask( | 433 device_thread_.message_loop()->PostTask( |
| 439 FROM_HERE, | 434 FROM_HERE, base::Bind(&V4L2ImageProcessor::ServiceDeviceTask, |
| 440 base::Bind(&V4L2ImageProcessor::ServiceDeviceTask, | 435 base::Unretained(this))); |
| 441 base::Unretained(this))); | |
| 442 } | 436 } |
| 443 | 437 |
| 444 void V4L2ImageProcessor::ServiceDeviceTask() { | 438 void V4L2ImageProcessor::ServiceDeviceTask() { |
| 445 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 439 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
| 446 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), | 440 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), |
| 447 // so either: | 441 // so either: |
| 448 // * device_poll_thread_ is running normally | 442 // * device_poll_thread_ is running normally |
| 449 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, | 443 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, |
| 450 // in which case we should early-out. | 444 // in which case we should early-out. |
| 451 if (!device_poll_thread_.message_loop()) | 445 if (!device_poll_thread_.message_loop()) |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 struct v4l2_buffer qbuf; | 594 struct v4l2_buffer qbuf; |
| 601 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; | 595 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; |
| 602 memset(&qbuf, 0, sizeof(qbuf)); | 596 memset(&qbuf, 0, sizeof(qbuf)); |
| 603 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 597 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
| 604 qbuf.index = index; | 598 qbuf.index = index; |
| 605 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 599 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 606 qbuf.memory = input_memory_type_; | 600 qbuf.memory = input_memory_type_; |
| 607 qbuf.m.planes = qbuf_planes; | 601 qbuf.m.planes = qbuf_planes; |
| 608 qbuf.length = input_planes_count_; | 602 qbuf.length = input_planes_count_; |
| 609 for (size_t i = 0; i < input_planes_count_; ++i) { | 603 for (size_t i = 0; i < input_planes_count_; ++i) { |
| 610 qbuf.m.planes[i].bytesused = media::VideoFrame::PlaneSize( | 604 qbuf.m.planes[i].bytesused = |
| 611 input_record.frame->format(), i, input_allocated_size_).GetArea(); | 605 media::VideoFrame::PlaneSize(input_record.frame->format(), i, |
| 606 input_allocated_size_) |
| 607 .GetArea(); |
| 612 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused; | 608 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused; |
| 613 if (input_memory_type_ == V4L2_MEMORY_USERPTR) { | 609 if (input_memory_type_ == V4L2_MEMORY_USERPTR) { |
| 614 qbuf.m.planes[i].m.userptr = | 610 qbuf.m.planes[i].m.userptr = |
| 615 reinterpret_cast<unsigned long>(input_record.frame->data(i)); | 611 reinterpret_cast<unsigned long>(input_record.frame->data(i)); |
| 616 } else { | 612 } else { |
| 617 qbuf.m.planes[i].m.fd = input_record.frame->dmabuf_fd(i); | 613 qbuf.m.planes[i].m.fd = input_record.frame->dmabuf_fd(i); |
| 618 } | 614 } |
| 619 } | 615 } |
| 620 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 616 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
| 621 input_record.at_device = true; | 617 input_record.at_device = true; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 | 653 |
| 658 // Start up the device poll thread and schedule its first DevicePollTask(). | 654 // Start up the device poll thread and schedule its first DevicePollTask(). |
| 659 if (!device_poll_thread_.Start()) { | 655 if (!device_poll_thread_.Start()) { |
| 660 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 656 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
| 661 NotifyError(); | 657 NotifyError(); |
| 662 return false; | 658 return false; |
| 663 } | 659 } |
| 664 // Enqueue a poll task with no devices to poll on - will wait only for the | 660 // Enqueue a poll task with no devices to poll on - will wait only for the |
| 665 // poll interrupt | 661 // poll interrupt |
| 666 device_poll_thread_.message_loop()->PostTask( | 662 device_poll_thread_.message_loop()->PostTask( |
| 667 FROM_HERE, | 663 FROM_HERE, base::Bind(&V4L2ImageProcessor::DevicePollTask, |
| 668 base::Bind( | 664 base::Unretained(this), false)); |
| 669 &V4L2ImageProcessor::DevicePollTask, base::Unretained(this), false)); | |
| 670 | 665 |
| 671 return true; | 666 return true; |
| 672 } | 667 } |
| 673 | 668 |
| 674 bool V4L2ImageProcessor::StopDevicePoll() { | 669 bool V4L2ImageProcessor::StopDevicePoll() { |
| 675 DVLOG(3) << __func__ << ": stopping device poll"; | 670 DVLOG(3) << __func__ << ": stopping device poll"; |
| 676 if (device_thread_.IsRunning()) | 671 if (device_thread_.IsRunning()) |
| 677 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 672 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
| 678 | 673 |
| 679 // Signal the DevicePollTask() to stop, and stop the device poll thread. | 674 // Signal the DevicePollTask() to stop, and stop the device poll thread. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 | 714 |
| 720 return true; | 715 return true; |
| 721 } | 716 } |
| 722 | 717 |
| 723 void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb, | 718 void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb, |
| 724 int output_buffer_index) { | 719 int output_buffer_index) { |
| 725 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 720 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 726 cb.Run(output_buffer_index); | 721 cb.Run(output_buffer_index); |
| 727 } | 722 } |
| 728 | 723 |
| 729 } // namespace content | 724 } // namespace media |
| OLD | NEW |