| 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> |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 | 143 |
| 144 if (!CreateInputBuffers() || !CreateOutputBuffers()) | 144 if (!CreateInputBuffers() || !CreateOutputBuffers()) |
| 145 return false; | 145 return false; |
| 146 | 146 |
| 147 if (!device_thread_.Start()) { | 147 if (!device_thread_.Start()) { |
| 148 LOG(ERROR) << "Initialize(): encoder thread failed to start"; | 148 LOG(ERROR) << "Initialize(): encoder thread failed to start"; |
| 149 return false; | 149 return false; |
| 150 } | 150 } |
| 151 | 151 |
| 152 // StartDevicePoll will NotifyError on failure, so IgnoreResult is fine here. | 152 // StartDevicePoll will NotifyError on failure, so IgnoreResult is fine here. |
| 153 device_thread_.message_loop()->PostTask( | 153 device_thread_.task_runner()->PostTask( |
| 154 FROM_HERE, | 154 FROM_HERE, |
| 155 base::Bind(base::IgnoreResult(&V4L2ImageProcessor::StartDevicePoll), | 155 base::Bind(base::IgnoreResult(&V4L2ImageProcessor::StartDevicePoll), |
| 156 base::Unretained(this))); | 156 base::Unretained(this))); |
| 157 | 157 |
| 158 DVLOG(1) << "V4L2ImageProcessor initialized for " | 158 DVLOG(1) << "V4L2ImageProcessor initialized for " |
| 159 << " input_format:" << VideoPixelFormatToString(input_format) | 159 << " input_format:" << VideoPixelFormatToString(input_format) |
| 160 << ", output_format:" << VideoPixelFormatToString(output_format) | 160 << ", output_format:" << VideoPixelFormatToString(output_format) |
| 161 << ", input_visible_size: " << input_visible_size.ToString() | 161 << ", input_visible_size: " << input_visible_size.ToString() |
| 162 << ", input_allocated_size: " << input_allocated_size_.ToString() | 162 << ", input_allocated_size: " << input_allocated_size_.ToString() |
| 163 << ", input_planes_count: " << input_planes_count_ | 163 << ", input_planes_count: " << input_planes_count_ |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 void V4L2ImageProcessor::Process(const scoped_refptr<VideoFrame>& frame, | 221 void V4L2ImageProcessor::Process(const scoped_refptr<VideoFrame>& frame, |
| 222 int output_buffer_index, | 222 int output_buffer_index, |
| 223 const FrameReadyCB& cb) { | 223 const FrameReadyCB& cb) { |
| 224 DVLOG(3) << __func__ << ": ts=" << frame->timestamp().InMilliseconds(); | 224 DVLOG(3) << __func__ << ": ts=" << frame->timestamp().InMilliseconds(); |
| 225 | 225 |
| 226 std::unique_ptr<JobRecord> job_record(new JobRecord()); | 226 std::unique_ptr<JobRecord> job_record(new JobRecord()); |
| 227 job_record->frame = frame; | 227 job_record->frame = frame; |
| 228 job_record->output_buffer_index = output_buffer_index; | 228 job_record->output_buffer_index = output_buffer_index; |
| 229 job_record->ready_cb = cb; | 229 job_record->ready_cb = cb; |
| 230 | 230 |
| 231 device_thread_.message_loop()->PostTask( | 231 device_thread_.task_runner()->PostTask( |
| 232 FROM_HERE, base::Bind(&V4L2ImageProcessor::ProcessTask, | 232 FROM_HERE, base::Bind(&V4L2ImageProcessor::ProcessTask, |
| 233 base::Unretained(this), base::Passed(&job_record))); | 233 base::Unretained(this), base::Passed(&job_record))); |
| 234 } | 234 } |
| 235 | 235 |
| 236 void V4L2ImageProcessor::ProcessTask(std::unique_ptr<JobRecord> job_record) { | 236 void V4L2ImageProcessor::ProcessTask(std::unique_ptr<JobRecord> job_record) { |
| 237 int index = job_record->output_buffer_index; | 237 int index = job_record->output_buffer_index; |
| 238 DVLOG(3) << __func__ << ": Reusing output buffer, index=" << index; | 238 DVLOG(3) << __func__ << ": Reusing output buffer, index=" << index; |
| 239 DCHECK(device_thread_.task_runner()->BelongsToCurrentThread()); | 239 DCHECK(device_thread_.task_runner()->BelongsToCurrentThread()); |
| 240 | 240 |
| 241 EnqueueOutput(index); | 241 EnqueueOutput(index); |
| 242 input_queue_.push(make_linked_ptr(job_record.release())); | 242 input_queue_.push(make_linked_ptr(job_record.release())); |
| 243 EnqueueInput(); | 243 EnqueueInput(); |
| 244 } | 244 } |
| 245 | 245 |
| 246 void V4L2ImageProcessor::Destroy() { | 246 void V4L2ImageProcessor::Destroy() { |
| 247 DVLOG(3) << __func__; | 247 DVLOG(3) << __func__; |
| 248 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 248 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 249 | 249 |
| 250 weak_this_factory_.InvalidateWeakPtrs(); | 250 weak_this_factory_.InvalidateWeakPtrs(); |
| 251 | 251 |
| 252 // If the device thread is running, destroy using posted task. | 252 // If the device thread is running, destroy using posted task. |
| 253 if (device_thread_.IsRunning()) { | 253 if (device_thread_.IsRunning()) { |
| 254 device_thread_.message_loop()->PostTask( | 254 device_thread_.task_runner()->PostTask( |
| 255 FROM_HERE, | 255 FROM_HERE, |
| 256 base::Bind(&V4L2ImageProcessor::DestroyTask, base::Unretained(this))); | 256 base::Bind(&V4L2ImageProcessor::DestroyTask, base::Unretained(this))); |
| 257 // Wait for tasks to finish/early-exit. | 257 // Wait for tasks to finish/early-exit. |
| 258 device_thread_.Stop(); | 258 device_thread_.Stop(); |
| 259 } else { | 259 } else { |
| 260 // Otherwise DestroyTask() is not needed. | 260 // Otherwise DestroyTask() is not needed. |
| 261 DCHECK(!device_poll_thread_.IsRunning()); | 261 DCHECK(!device_poll_thread_.IsRunning()); |
| 262 } | 262 } |
| 263 | 263 |
| 264 delete this; | 264 delete this; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 DCHECK(device_poll_thread_.task_runner()->BelongsToCurrentThread()); | 422 DCHECK(device_poll_thread_.task_runner()->BelongsToCurrentThread()); |
| 423 | 423 |
| 424 bool event_pending; | 424 bool event_pending; |
| 425 if (!device_->Poll(poll_device, &event_pending)) { | 425 if (!device_->Poll(poll_device, &event_pending)) { |
| 426 NotifyError(); | 426 NotifyError(); |
| 427 return; | 427 return; |
| 428 } | 428 } |
| 429 | 429 |
| 430 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 430 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
| 431 // touch encoder state from this thread. | 431 // touch encoder state from this thread. |
| 432 device_thread_.message_loop()->PostTask( | 432 device_thread_.task_runner()->PostTask( |
| 433 FROM_HERE, base::Bind(&V4L2ImageProcessor::ServiceDeviceTask, | 433 FROM_HERE, base::Bind(&V4L2ImageProcessor::ServiceDeviceTask, |
| 434 base::Unretained(this))); | 434 base::Unretained(this))); |
| 435 } | 435 } |
| 436 | 436 |
| 437 void V4L2ImageProcessor::ServiceDeviceTask() { | 437 void V4L2ImageProcessor::ServiceDeviceTask() { |
| 438 DCHECK(device_thread_.task_runner()->BelongsToCurrentThread()); | 438 DCHECK(device_thread_.task_runner()->BelongsToCurrentThread()); |
| 439 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), | 439 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), |
| 440 // so either: | 440 // so either: |
| 441 // * device_poll_thread_ is running normally | 441 // * device_poll_thread_ is running normally |
| 442 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, | 442 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, |
| 443 // in which case we should early-out. | 443 // in which case we should early-out. |
| 444 if (!device_poll_thread_.message_loop()) | 444 if (!device_poll_thread_.message_loop()) |
| 445 return; | 445 return; |
| 446 | 446 |
| 447 Dequeue(); | 447 Dequeue(); |
| 448 EnqueueInput(); | 448 EnqueueInput(); |
| 449 | 449 |
| 450 if (!device_->ClearDevicePollInterrupt()) | 450 if (!device_->ClearDevicePollInterrupt()) |
| 451 return; | 451 return; |
| 452 | 452 |
| 453 bool poll_device = | 453 bool poll_device = |
| 454 (input_buffer_queued_count_ > 0 || output_buffer_queued_count_ > 0); | 454 (input_buffer_queued_count_ > 0 || output_buffer_queued_count_ > 0); |
| 455 | 455 |
| 456 device_poll_thread_.message_loop()->PostTask( | 456 device_poll_thread_.task_runner()->PostTask( |
| 457 FROM_HERE, base::Bind(&V4L2ImageProcessor::DevicePollTask, | 457 FROM_HERE, base::Bind(&V4L2ImageProcessor::DevicePollTask, |
| 458 base::Unretained(this), poll_device)); | 458 base::Unretained(this), poll_device)); |
| 459 | 459 |
| 460 DVLOG(2) << __func__ << ": buffer counts: INPUT[" << input_queue_.size() | 460 DVLOG(2) << __func__ << ": buffer counts: INPUT[" << input_queue_.size() |
| 461 << "] => DEVICE[" << free_input_buffers_.size() << "+" | 461 << "] => DEVICE[" << free_input_buffers_.size() << "+" |
| 462 << input_buffer_queued_count_ << "/" << input_buffer_map_.size() | 462 << input_buffer_queued_count_ << "/" << input_buffer_map_.size() |
| 463 << "->" << output_buffer_map_.size() - output_buffer_queued_count_ | 463 << "->" << output_buffer_map_.size() - output_buffer_queued_count_ |
| 464 << "+" << output_buffer_queued_count_ << "/" | 464 << "+" << output_buffer_queued_count_ << "/" |
| 465 << output_buffer_map_.size() << "]"; | 465 << output_buffer_map_.size() << "]"; |
| 466 } | 466 } |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 DCHECK(!device_poll_thread_.IsRunning()); | 649 DCHECK(!device_poll_thread_.IsRunning()); |
| 650 | 650 |
| 651 // Start up the device poll thread and schedule its first DevicePollTask(). | 651 // Start up the device poll thread and schedule its first DevicePollTask(). |
| 652 if (!device_poll_thread_.Start()) { | 652 if (!device_poll_thread_.Start()) { |
| 653 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 653 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
| 654 NotifyError(); | 654 NotifyError(); |
| 655 return false; | 655 return false; |
| 656 } | 656 } |
| 657 // Enqueue a poll task with no devices to poll on - will wait only for the | 657 // Enqueue a poll task with no devices to poll on - will wait only for the |
| 658 // poll interrupt | 658 // poll interrupt |
| 659 device_poll_thread_.message_loop()->PostTask( | 659 device_poll_thread_.task_runner()->PostTask( |
| 660 FROM_HERE, base::Bind(&V4L2ImageProcessor::DevicePollTask, | 660 FROM_HERE, base::Bind(&V4L2ImageProcessor::DevicePollTask, |
| 661 base::Unretained(this), false)); | 661 base::Unretained(this), false)); |
| 662 | 662 |
| 663 return true; | 663 return true; |
| 664 } | 664 } |
| 665 | 665 |
| 666 bool V4L2ImageProcessor::StopDevicePoll() { | 666 bool V4L2ImageProcessor::StopDevicePoll() { |
| 667 DVLOG(3) << __func__ << ": stopping device poll"; | 667 DVLOG(3) << __func__ << ": stopping device poll"; |
| 668 if (device_thread_.IsRunning()) | 668 if (device_thread_.IsRunning()) |
| 669 DCHECK(device_thread_.task_runner()->BelongsToCurrentThread()); | 669 DCHECK(device_thread_.task_runner()->BelongsToCurrentThread()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 return true; | 712 return true; |
| 713 } | 713 } |
| 714 | 714 |
| 715 void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb, | 715 void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb, |
| 716 int output_buffer_index) { | 716 int output_buffer_index) { |
| 717 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 717 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 718 cb.Run(output_buffer_index); | 718 cb.Run(output_buffer_index); |
| 719 } | 719 } |
| 720 | 720 |
| 721 } // namespace media | 721 } // namespace media |
| OLD | NEW |