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 <fcntl.h> | 5 #include <fcntl.h> |
6 #include <linux/videodev2.h> | 6 #include <linux/videodev2.h> |
7 #include <poll.h> | 7 #include <poll.h> |
8 #include <sys/eventfd.h> | 8 #include <sys/eventfd.h> |
9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
14 #include "base/callback.h" | 14 #include "base/callback.h" |
| 15 #include "base/message_loop/message_loop_proxy.h" |
15 #include "base/numerics/safe_conversions.h" | 16 #include "base/numerics/safe_conversions.h" |
16 #include "content/common/gpu/media/v4l2_image_processor.h" | 17 #include "content/common/gpu/media/v4l2_image_processor.h" |
17 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
18 | 19 |
19 #define NOTIFY_ERROR() \ | 20 #define NOTIFY_ERROR() \ |
20 do { \ | 21 do { \ |
21 LOG(ERROR) << "calling NotifyError()"; \ | 22 LOG(ERROR) << "calling NotifyError()"; \ |
22 NotifyError(); \ | 23 NotifyError(); \ |
23 } while (0) | 24 } while (0) |
24 | 25 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 V4L2ImageProcessor::JobRecord::~JobRecord() { | 64 V4L2ImageProcessor::JobRecord::~JobRecord() { |
64 } | 65 } |
65 | 66 |
66 V4L2ImageProcessor::V4L2ImageProcessor(const scoped_refptr<V4L2Device>& device) | 67 V4L2ImageProcessor::V4L2ImageProcessor(const scoped_refptr<V4L2Device>& device) |
67 : input_format_(media::VideoFrame::UNKNOWN), | 68 : input_format_(media::VideoFrame::UNKNOWN), |
68 output_format_(media::VideoFrame::UNKNOWN), | 69 output_format_(media::VideoFrame::UNKNOWN), |
69 input_format_fourcc_(0), | 70 input_format_fourcc_(0), |
70 output_format_fourcc_(0), | 71 output_format_fourcc_(0), |
71 input_planes_count_(0), | 72 input_planes_count_(0), |
72 output_planes_count_(0), | 73 output_planes_count_(0), |
73 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 74 child_message_loop_proxy_(base::MessageLoopProxy::current()), |
74 device_(device), | 75 device_(device), |
75 device_thread_("V4L2ImageProcessorThread"), | 76 device_thread_("V4L2ImageProcessorThread"), |
76 device_poll_thread_("V4L2ImageProcessorDevicePollThread"), | 77 device_poll_thread_("V4L2ImageProcessorDevicePollThread"), |
77 input_streamon_(false), | 78 input_streamon_(false), |
78 input_buffer_queued_count_(0), | 79 input_buffer_queued_count_(0), |
79 output_streamon_(false), | 80 output_streamon_(false), |
80 output_buffer_queued_count_(0), | 81 output_buffer_queued_count_(0), |
81 device_weak_factory_(this) { | 82 device_weak_factory_(this) { |
82 } | 83 } |
83 | 84 |
84 V4L2ImageProcessor::~V4L2ImageProcessor() { | 85 V4L2ImageProcessor::~V4L2ImageProcessor() { |
85 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 86 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
86 DCHECK(!device_thread_.IsRunning()); | 87 DCHECK(!device_thread_.IsRunning()); |
87 DCHECK(!device_poll_thread_.IsRunning()); | 88 DCHECK(!device_poll_thread_.IsRunning()); |
88 | 89 |
89 DestroyInputBuffers(); | 90 DestroyInputBuffers(); |
90 DestroyOutputBuffers(); | 91 DestroyOutputBuffers(); |
91 } | 92 } |
92 | 93 |
93 void V4L2ImageProcessor::NotifyError() { | 94 void V4L2ImageProcessor::NotifyError() { |
94 if (!child_task_runner_->BelongsToCurrentThread()) | 95 if (!child_message_loop_proxy_->BelongsToCurrentThread()) |
95 child_task_runner_->PostTask(FROM_HERE, error_cb_); | 96 child_message_loop_proxy_->PostTask(FROM_HERE, error_cb_); |
96 else | 97 else |
97 error_cb_.Run(); | 98 error_cb_.Run(); |
98 } | 99 } |
99 | 100 |
100 bool V4L2ImageProcessor::Initialize(media::VideoFrame::Format input_format, | 101 bool V4L2ImageProcessor::Initialize(media::VideoFrame::Format input_format, |
101 media::VideoFrame::Format output_format, | 102 media::VideoFrame::Format output_format, |
102 gfx::Size input_visible_size, | 103 gfx::Size input_visible_size, |
103 gfx::Size output_visible_size, | 104 gfx::Size output_visible_size, |
104 gfx::Size output_allocated_size, | 105 gfx::Size output_allocated_size, |
105 const base::Closure& error_cb) { | 106 const base::Closure& error_cb) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 | 188 |
188 void V4L2ImageProcessor::ProcessTask(scoped_ptr<JobRecord> job_record) { | 189 void V4L2ImageProcessor::ProcessTask(scoped_ptr<JobRecord> job_record) { |
189 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 190 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
190 | 191 |
191 input_queue_.push(make_linked_ptr(job_record.release())); | 192 input_queue_.push(make_linked_ptr(job_record.release())); |
192 Enqueue(); | 193 Enqueue(); |
193 } | 194 } |
194 | 195 |
195 void V4L2ImageProcessor::Destroy() { | 196 void V4L2ImageProcessor::Destroy() { |
196 DVLOG(3) << __func__; | 197 DVLOG(3) << __func__; |
197 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 198 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
198 | 199 |
199 // If the device thread is running, destroy using posted task. | 200 // If the device thread is running, destroy using posted task. |
200 if (device_thread_.IsRunning()) { | 201 if (device_thread_.IsRunning()) { |
201 device_thread_.message_loop()->PostTask( | 202 device_thread_.message_loop()->PostTask( |
202 FROM_HERE, | 203 FROM_HERE, |
203 base::Bind(&V4L2ImageProcessor::DestroyTask, base::Unretained(this))); | 204 base::Bind(&V4L2ImageProcessor::DestroyTask, base::Unretained(this))); |
204 // Wait for tasks to finish/early-exit. | 205 // Wait for tasks to finish/early-exit. |
205 device_thread_.Stop(); | 206 device_thread_.Stop(); |
206 } else { | 207 } else { |
207 // Otherwise DestroyTask() is not needed. | 208 // Otherwise DestroyTask() is not needed. |
208 DCHECK(!device_poll_thread_.IsRunning()); | 209 DCHECK(!device_poll_thread_.IsRunning()); |
209 DCHECK(!device_weak_factory_.HasWeakPtrs()); | 210 DCHECK(!device_weak_factory_.HasWeakPtrs()); |
210 } | 211 } |
211 | 212 |
212 delete this; | 213 delete this; |
213 } | 214 } |
214 | 215 |
215 void V4L2ImageProcessor::DestroyTask() { | 216 void V4L2ImageProcessor::DestroyTask() { |
216 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 217 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
217 | 218 |
218 device_weak_factory_.InvalidateWeakPtrs(); | 219 device_weak_factory_.InvalidateWeakPtrs(); |
219 | 220 |
220 // Stop streaming and the device_poll_thread_. | 221 // Stop streaming and the device_poll_thread_. |
221 StopDevicePoll(); | 222 StopDevicePoll(); |
222 } | 223 } |
223 | 224 |
224 bool V4L2ImageProcessor::CreateInputBuffers() { | 225 bool V4L2ImageProcessor::CreateInputBuffers() { |
225 DVLOG(3) << __func__; | 226 DVLOG(3) << __func__; |
226 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 227 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
227 DCHECK(!input_streamon_); | 228 DCHECK(!input_streamon_); |
228 | 229 |
229 struct v4l2_control control; | 230 struct v4l2_control control; |
230 memset(&control, 0, sizeof(control)); | 231 memset(&control, 0, sizeof(control)); |
231 control.id = V4L2_CID_ROTATE; | 232 control.id = V4L2_CID_ROTATE; |
232 control.value = 0; | 233 control.value = 0; |
233 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CTRL, &control); | 234 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CTRL, &control); |
234 | 235 |
235 memset(&control, 0, sizeof(control)); | 236 memset(&control, 0, sizeof(control)); |
236 control.id = V4L2_CID_HFLIP; | 237 control.id = V4L2_CID_HFLIP; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 input_buffer_map_.resize(reqbufs.count); | 288 input_buffer_map_.resize(reqbufs.count); |
288 | 289 |
289 for (size_t i = 0; i < input_buffer_map_.size(); ++i) | 290 for (size_t i = 0; i < input_buffer_map_.size(); ++i) |
290 free_input_buffers_.push_back(i); | 291 free_input_buffers_.push_back(i); |
291 | 292 |
292 return true; | 293 return true; |
293 } | 294 } |
294 | 295 |
295 bool V4L2ImageProcessor::CreateOutputBuffers() { | 296 bool V4L2ImageProcessor::CreateOutputBuffers() { |
296 DVLOG(3) << __func__; | 297 DVLOG(3) << __func__; |
297 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 298 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
298 DCHECK(!output_streamon_); | 299 DCHECK(!output_streamon_); |
299 | 300 |
300 struct v4l2_format format; | 301 struct v4l2_format format; |
301 memset(&format, 0, sizeof(format)); | 302 memset(&format, 0, sizeof(format)); |
302 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 303 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
303 format.fmt.pix_mp.width = output_allocated_size_.width(); | 304 format.fmt.pix_mp.width = output_allocated_size_.width(); |
304 format.fmt.pix_mp.height = output_allocated_size_.height(); | 305 format.fmt.pix_mp.height = output_allocated_size_.height(); |
305 format.fmt.pix_mp.pixelformat = output_format_fourcc_; | 306 format.fmt.pix_mp.pixelformat = output_format_fourcc_; |
306 format.fmt.pix_mp.num_planes = output_planes_count_; | 307 format.fmt.pix_mp.num_planes = output_planes_count_; |
307 for (size_t i = 0; i < output_planes_count_; ++i) { | 308 for (size_t i = 0; i < output_planes_count_; ++i) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_EXPBUF, &expbuf); | 351 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_EXPBUF, &expbuf); |
351 output_record.fds[j] = expbuf.fd; | 352 output_record.fds[j] = expbuf.fd; |
352 } | 353 } |
353 free_output_buffers_.push_back(i); | 354 free_output_buffers_.push_back(i); |
354 } | 355 } |
355 | 356 |
356 return true; | 357 return true; |
357 } | 358 } |
358 | 359 |
359 void V4L2ImageProcessor::DestroyInputBuffers() { | 360 void V4L2ImageProcessor::DestroyInputBuffers() { |
360 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 361 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
361 DCHECK(!input_streamon_); | 362 DCHECK(!input_streamon_); |
362 | 363 |
363 struct v4l2_requestbuffers reqbufs; | 364 struct v4l2_requestbuffers reqbufs; |
364 memset(&reqbufs, 0, sizeof(reqbufs)); | 365 memset(&reqbufs, 0, sizeof(reqbufs)); |
365 reqbufs.count = 0; | 366 reqbufs.count = 0; |
366 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 367 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
367 reqbufs.memory = V4L2_MEMORY_USERPTR; | 368 reqbufs.memory = V4L2_MEMORY_USERPTR; |
368 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 369 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
369 | 370 |
370 input_buffer_map_.clear(); | 371 input_buffer_map_.clear(); |
371 free_input_buffers_.clear(); | 372 free_input_buffers_.clear(); |
372 } | 373 } |
373 | 374 |
374 void V4L2ImageProcessor::DestroyOutputBuffers() { | 375 void V4L2ImageProcessor::DestroyOutputBuffers() { |
375 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 376 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
376 DCHECK(!output_streamon_); | 377 DCHECK(!output_streamon_); |
377 | 378 |
378 for (size_t buf = 0; buf < output_buffer_map_.size(); ++buf) { | 379 for (size_t buf = 0; buf < output_buffer_map_.size(); ++buf) { |
379 OutputRecord& output_record = output_buffer_map_[buf]; | 380 OutputRecord& output_record = output_buffer_map_[buf]; |
380 for (size_t plane = 0; plane < output_record.fds.size(); ++plane) | 381 for (size_t plane = 0; plane < output_record.fds.size(); ++plane) |
381 close(output_record.fds[plane]); | 382 close(output_record.fds[plane]); |
382 output_record.fds.clear(); | 383 output_record.fds.clear(); |
383 } | 384 } |
384 | 385 |
385 struct v4l2_requestbuffers reqbufs; | 386 struct v4l2_requestbuffers reqbufs; |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 output_record.fds, | 563 output_record.fds, |
563 job_record->frame->timestamp(), | 564 job_record->frame->timestamp(), |
564 media::BindToCurrentLoop( | 565 media::BindToCurrentLoop( |
565 base::Bind(&V4L2ImageProcessor::ReuseOutputBuffer, | 566 base::Bind(&V4L2ImageProcessor::ReuseOutputBuffer, |
566 device_weak_factory_.GetWeakPtr(), | 567 device_weak_factory_.GetWeakPtr(), |
567 dqbuf.index))); | 568 dqbuf.index))); |
568 | 569 |
569 DVLOG(3) << "Processing finished, returning frame, ts=" | 570 DVLOG(3) << "Processing finished, returning frame, ts=" |
570 << output_frame->timestamp().InMilliseconds(); | 571 << output_frame->timestamp().InMilliseconds(); |
571 | 572 |
572 child_task_runner_->PostTask( | 573 child_message_loop_proxy_->PostTask( |
573 FROM_HERE, base::Bind(job_record->ready_cb, output_frame)); | 574 FROM_HERE, base::Bind(job_record->ready_cb, output_frame)); |
574 } | 575 } |
575 } | 576 } |
576 | 577 |
577 void V4L2ImageProcessor::ReuseOutputBuffer(int index) { | 578 void V4L2ImageProcessor::ReuseOutputBuffer(int index) { |
578 DVLOG(3) << "Reusing output buffer, index=" << index; | 579 DVLOG(3) << "Reusing output buffer, index=" << index; |
579 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); | 580 DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current()); |
580 | 581 |
581 OutputRecord& output_record = output_buffer_map_[index]; | 582 OutputRecord& output_record = output_buffer_map_[index]; |
582 DCHECK(output_record.at_client); | 583 DCHECK(output_record.at_client); |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 output_record.at_device = false; | 719 output_record.at_device = false; |
719 if (!output_record.at_client) | 720 if (!output_record.at_client) |
720 free_output_buffers_.push_back(i); | 721 free_output_buffers_.push_back(i); |
721 } | 722 } |
722 output_buffer_queued_count_ = 0; | 723 output_buffer_queued_count_ = 0; |
723 | 724 |
724 return true; | 725 return true; |
725 } | 726 } |
726 | 727 |
727 } // namespace content | 728 } // namespace content |
OLD | NEW |