Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: media/gpu/v4l2_image_processor.cc

Issue 1882373004: Migrate content/common/gpu/media code to media/gpu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix several more bot-identified build issues Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698