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