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 |