| 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 |