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 "content/common/gpu/media/v4l2_image_processor.h" | |
19 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.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_format_fourcc_(0), | 58 input_format_fourcc_(0), |
63 output_format_fourcc_(0), | 59 output_format_fourcc_(0), |
64 input_planes_count_(0), | 60 input_planes_count_(0), |
65 output_planes_count_(0), | 61 output_planes_count_(0), |
66 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 62 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
67 device_(device), | 63 device_(device), |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 output_planes_count_ = media::VideoFrame::NumPlanes(output_format); | 132 output_planes_count_ = media::VideoFrame::NumPlanes(output_format); |
137 DCHECK_LE(output_planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES)); | 133 DCHECK_LE(output_planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES)); |
138 | 134 |
139 // Capabilities check. | 135 // Capabilities check. |
140 struct v4l2_capability caps; | 136 struct v4l2_capability caps; |
141 memset(&caps, 0, sizeof(caps)); | 137 memset(&caps, 0, sizeof(caps)); |
142 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 138 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
143 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 139 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
144 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 140 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
145 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " | 141 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " |
146 "caps check failed: 0x" << std::hex << caps.capabilities; | 142 "caps check failed: 0x" |
| 143 << std::hex << caps.capabilities; |
147 return false; | 144 return false; |
148 } | 145 } |
149 | 146 |
150 if (!CreateInputBuffers() || !CreateOutputBuffers()) | 147 if (!CreateInputBuffers() || !CreateOutputBuffers()) |
151 return false; | 148 return false; |
152 | 149 |
153 if (!device_thread_.Start()) { | 150 if (!device_thread_.Start()) { |
154 LOG(ERROR) << "Initialize(): encoder thread failed to start"; | 151 LOG(ERROR) << "Initialize(): encoder thread failed to start"; |
155 return false; | 152 return false; |
156 } | 153 } |
(...skipping 29 matching lines...) Expand all Loading... |
186 int output_buffer_index, | 183 int output_buffer_index, |
187 const FrameReadyCB& cb) { | 184 const FrameReadyCB& cb) { |
188 DVLOG(3) << __func__ << ": ts=" << frame->timestamp().InMilliseconds(); | 185 DVLOG(3) << __func__ << ": ts=" << frame->timestamp().InMilliseconds(); |
189 | 186 |
190 std::unique_ptr<JobRecord> job_record(new JobRecord()); | 187 std::unique_ptr<JobRecord> job_record(new JobRecord()); |
191 job_record->frame = frame; | 188 job_record->frame = frame; |
192 job_record->output_buffer_index = output_buffer_index; | 189 job_record->output_buffer_index = output_buffer_index; |
193 job_record->ready_cb = cb; | 190 job_record->ready_cb = cb; |
194 | 191 |
195 device_thread_.message_loop()->PostTask( | 192 device_thread_.message_loop()->PostTask( |
196 FROM_HERE, | 193 FROM_HERE, base::Bind(&V4L2ImageProcessor::ProcessTask, |
197 base::Bind(&V4L2ImageProcessor::ProcessTask, | 194 base::Unretained(this), base::Passed(&job_record))); |
198 base::Unretained(this), | |
199 base::Passed(&job_record))); | |
200 } | 195 } |
201 | 196 |
202 void V4L2ImageProcessor::ProcessTask(std::unique_ptr<JobRecord> job_record) { | 197 void V4L2ImageProcessor::ProcessTask(std::unique_ptr<JobRecord> job_record) { |
203 int index = job_record->output_buffer_index; | 198 int index = job_record->output_buffer_index; |
204 DVLOG(3) << __func__ << ": Reusing output buffer, index=" << index; | 199 DVLOG(3) << __func__ << ": Reusing output buffer, index=" << index; |
205 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 200 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
206 | 201 |
207 EnqueueOutput(index); | 202 EnqueueOutput(index); |
208 input_queue_.push(make_linked_ptr(job_record.release())); | 203 input_queue_.push(make_linked_ptr(job_record.release())); |
209 EnqueueInput(); | 204 EnqueueInput(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 for (size_t i = 0; i < input_planes_count_; ++i) { | 268 for (size_t i = 0; i < input_planes_count_; ++i) { |
274 format.fmt.pix_mp.plane_fmt[i].sizeimage = | 269 format.fmt.pix_mp.plane_fmt[i].sizeimage = |
275 media::VideoFrame::PlaneSize(input_format_, i, input_allocated_size_) | 270 media::VideoFrame::PlaneSize(input_format_, i, input_allocated_size_) |
276 .GetArea(); | 271 .GetArea(); |
277 format.fmt.pix_mp.plane_fmt[i].bytesperline = | 272 format.fmt.pix_mp.plane_fmt[i].bytesperline = |
278 base::checked_cast<__u32>(input_allocated_size_.width()); | 273 base::checked_cast<__u32>(input_allocated_size_.width()); |
279 } | 274 } |
280 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 275 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
281 | 276 |
282 input_allocated_size_ = V4L2Device::CodedSizeFromV4L2Format(format); | 277 input_allocated_size_ = V4L2Device::CodedSizeFromV4L2Format(format); |
283 DCHECK(gfx::Rect(input_allocated_size_).Contains( | 278 DCHECK(gfx::Rect(input_allocated_size_) |
284 gfx::Rect(input_visible_size_))); | 279 .Contains(gfx::Rect(input_visible_size_))); |
285 | 280 |
286 struct v4l2_crop crop; | 281 struct v4l2_crop crop; |
287 memset(&crop, 0, sizeof(crop)); | 282 memset(&crop, 0, sizeof(crop)); |
288 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 283 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
289 crop.c.left = 0; | 284 crop.c.left = 0; |
290 crop.c.top = 0; | 285 crop.c.top = 0; |
291 crop.c.width = base::checked_cast<__u32>(input_visible_size_.width()); | 286 crop.c.width = base::checked_cast<__u32>(input_visible_size_.width()); |
292 crop.c.height = base::checked_cast<__u32>(input_visible_size_.height()); | 287 crop.c.height = base::checked_cast<__u32>(input_visible_size_.height()); |
293 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); | 288 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); |
294 | 289 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 format.fmt.pix_mp.plane_fmt[i].sizeimage = | 324 format.fmt.pix_mp.plane_fmt[i].sizeimage = |
330 media::VideoFrame::PlaneSize(output_format_, i, output_allocated_size_) | 325 media::VideoFrame::PlaneSize(output_format_, i, output_allocated_size_) |
331 .GetArea(); | 326 .GetArea(); |
332 format.fmt.pix_mp.plane_fmt[i].bytesperline = | 327 format.fmt.pix_mp.plane_fmt[i].bytesperline = |
333 base::checked_cast<__u32>(output_allocated_size_.width()); | 328 base::checked_cast<__u32>(output_allocated_size_.width()); |
334 } | 329 } |
335 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 330 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
336 | 331 |
337 gfx::Size adjusted_allocated_size = | 332 gfx::Size adjusted_allocated_size = |
338 V4L2Device::CodedSizeFromV4L2Format(format); | 333 V4L2Device::CodedSizeFromV4L2Format(format); |
339 DCHECK(gfx::Rect(adjusted_allocated_size).Contains( | 334 DCHECK(gfx::Rect(adjusted_allocated_size) |
340 gfx::Rect(output_allocated_size_))); | 335 .Contains(gfx::Rect(output_allocated_size_))); |
341 output_allocated_size_ = adjusted_allocated_size; | 336 output_allocated_size_ = adjusted_allocated_size; |
342 | 337 |
343 struct v4l2_crop crop; | 338 struct v4l2_crop crop; |
344 memset(&crop, 0, sizeof(crop)); | 339 memset(&crop, 0, sizeof(crop)); |
345 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 340 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
346 crop.c.left = 0; | 341 crop.c.left = 0; |
347 crop.c.top = 0; | 342 crop.c.top = 0; |
348 crop.c.width = base::checked_cast<__u32>(output_visible_size_.width()); | 343 crop.c.width = base::checked_cast<__u32>(output_visible_size_.width()); |
349 crop.c.height = base::checked_cast<__u32>(output_visible_size_.height()); | 344 crop.c.height = base::checked_cast<__u32>(output_visible_size_.height()); |
350 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); | 345 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 | 396 |
402 bool event_pending; | 397 bool event_pending; |
403 if (!device_->Poll(poll_device, &event_pending)) { | 398 if (!device_->Poll(poll_device, &event_pending)) { |
404 NotifyError(); | 399 NotifyError(); |
405 return; | 400 return; |
406 } | 401 } |
407 | 402 |
408 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 403 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
409 // touch encoder state from this thread. | 404 // touch encoder state from this thread. |
410 device_thread_.message_loop()->PostTask( | 405 device_thread_.message_loop()->PostTask( |
411 FROM_HERE, | 406 FROM_HERE, base::Bind(&V4L2ImageProcessor::ServiceDeviceTask, |
412 base::Bind(&V4L2ImageProcessor::ServiceDeviceTask, | 407 base::Unretained(this))); |
413 base::Unretained(this))); | |
414 } | 408 } |
415 | 409 |
416 void V4L2ImageProcessor::ServiceDeviceTask() { | 410 void V4L2ImageProcessor::ServiceDeviceTask() { |
417 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 411 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
418 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), | 412 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), |
419 // so either: | 413 // so either: |
420 // * device_poll_thread_ is running normally | 414 // * device_poll_thread_ is running normally |
421 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, | 415 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, |
422 // in which case we should early-out. | 416 // in which case we should early-out. |
423 if (!device_poll_thread_.message_loop()) | 417 if (!device_poll_thread_.message_loop()) |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 struct v4l2_buffer qbuf; | 566 struct v4l2_buffer qbuf; |
573 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; | 567 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; |
574 memset(&qbuf, 0, sizeof(qbuf)); | 568 memset(&qbuf, 0, sizeof(qbuf)); |
575 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 569 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
576 qbuf.index = index; | 570 qbuf.index = index; |
577 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 571 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
578 qbuf.memory = V4L2_MEMORY_USERPTR; | 572 qbuf.memory = V4L2_MEMORY_USERPTR; |
579 qbuf.m.planes = qbuf_planes; | 573 qbuf.m.planes = qbuf_planes; |
580 qbuf.length = input_planes_count_; | 574 qbuf.length = input_planes_count_; |
581 for (size_t i = 0; i < input_planes_count_; ++i) { | 575 for (size_t i = 0; i < input_planes_count_; ++i) { |
582 qbuf.m.planes[i].bytesused = media::VideoFrame::PlaneSize( | 576 qbuf.m.planes[i].bytesused = |
583 input_record.frame->format(), i, input_allocated_size_).GetArea(); | 577 media::VideoFrame::PlaneSize(input_record.frame->format(), i, |
| 578 input_allocated_size_) |
| 579 .GetArea(); |
584 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused; | 580 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused; |
585 qbuf.m.planes[i].m.userptr = | 581 qbuf.m.planes[i].m.userptr = |
586 reinterpret_cast<unsigned long>(input_record.frame->data(i)); | 582 reinterpret_cast<unsigned long>(input_record.frame->data(i)); |
587 } | 583 } |
588 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 584 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
589 input_record.at_device = true; | 585 input_record.at_device = true; |
590 running_jobs_.push(job_record); | 586 running_jobs_.push(job_record); |
591 free_input_buffers_.pop_back(); | 587 free_input_buffers_.pop_back(); |
592 input_buffer_queued_count_++; | 588 input_buffer_queued_count_++; |
593 | 589 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 | 621 |
626 // Start up the device poll thread and schedule its first DevicePollTask(). | 622 // Start up the device poll thread and schedule its first DevicePollTask(). |
627 if (!device_poll_thread_.Start()) { | 623 if (!device_poll_thread_.Start()) { |
628 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 624 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
629 NotifyError(); | 625 NotifyError(); |
630 return false; | 626 return false; |
631 } | 627 } |
632 // Enqueue a poll task with no devices to poll on - will wait only for the | 628 // Enqueue a poll task with no devices to poll on - will wait only for the |
633 // poll interrupt | 629 // poll interrupt |
634 device_poll_thread_.message_loop()->PostTask( | 630 device_poll_thread_.message_loop()->PostTask( |
635 FROM_HERE, | 631 FROM_HERE, base::Bind(&V4L2ImageProcessor::DevicePollTask, |
636 base::Bind( | 632 base::Unretained(this), false)); |
637 &V4L2ImageProcessor::DevicePollTask, base::Unretained(this), false)); | |
638 | 633 |
639 return true; | 634 return true; |
640 } | 635 } |
641 | 636 |
642 bool V4L2ImageProcessor::StopDevicePoll() { | 637 bool V4L2ImageProcessor::StopDevicePoll() { |
643 DVLOG(3) << __func__ << ": stopping device poll"; | 638 DVLOG(3) << __func__ << ": stopping device poll"; |
644 if (device_thread_.IsRunning()) | 639 if (device_thread_.IsRunning()) |
645 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 640 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
646 | 641 |
647 // Signal the DevicePollTask() to stop, and stop the device poll thread. | 642 // Signal the DevicePollTask() to stop, and stop the device poll thread. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 | 682 |
688 return true; | 683 return true; |
689 } | 684 } |
690 | 685 |
691 void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb, | 686 void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb, |
692 int output_buffer_index) { | 687 int output_buffer_index) { |
693 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 688 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
694 cb.Run(output_buffer_index); | 689 cb.Run(output_buffer_index); |
695 } | 690 } |
696 | 691 |
697 } // namespace content | 692 } // namespace media |
OLD | NEW |