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 "media/gpu/v4l2_video_encode_accelerator.h" | 5 #include "media/gpu/v4l2_video_encode_accelerator.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
9 #include <poll.h> | 9 #include <poll.h> |
10 #include <string.h> | 10 #include <string.h> |
11 #include <sys/eventfd.h> | 11 #include <sys/eventfd.h> |
12 #include <sys/ioctl.h> | 12 #include <sys/ioctl.h> |
13 #include <sys/mman.h> | 13 #include <sys/mman.h> |
14 | 14 |
15 #include <utility> | 15 #include <utility> |
16 | 16 |
17 #include "base/callback.h" | 17 #include "base/callback.h" |
18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
19 #include "base/macros.h" | 19 #include "base/macros.h" |
20 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
| 21 #include "base/single_thread_task_runner.h" |
21 #include "base/threading/thread_task_runner_handle.h" | 22 #include "base/threading/thread_task_runner_handle.h" |
22 #include "base/trace_event/trace_event.h" | 23 #include "base/trace_event/trace_event.h" |
23 #include "media/base/bind_to_current_loop.h" | 24 #include "media/base/bind_to_current_loop.h" |
24 #include "media/base/bitstream_buffer.h" | 25 #include "media/base/bitstream_buffer.h" |
25 #include "media/gpu/shared_memory_region.h" | 26 #include "media/gpu/shared_memory_region.h" |
26 | 27 |
27 #define NOTIFY_ERROR(x) \ | 28 #define NOTIFY_ERROR(x) \ |
28 do { \ | 29 do { \ |
29 LOG(ERROR) << "Setting error state:" << x; \ | 30 LOG(ERROR) << "Setting error state:" << x; \ |
30 SetErrorState(x); \ | 31 SetErrorState(x); \ |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed, | 236 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed, |
236 base::Unretained(this), force_keyframe, | 237 base::Unretained(this), force_keyframe, |
237 frame->timestamp())); | 238 frame->timestamp())); |
238 } else { | 239 } else { |
239 ImageProcessorInputRecord record; | 240 ImageProcessorInputRecord record; |
240 record.frame = frame; | 241 record.frame = frame; |
241 record.force_keyframe = force_keyframe; | 242 record.force_keyframe = force_keyframe; |
242 image_processor_input_queue_.push(record); | 243 image_processor_input_queue_.push(record); |
243 } | 244 } |
244 } else { | 245 } else { |
245 encoder_thread_.message_loop()->PostTask( | 246 encoder_thread_.task_runner()->PostTask( |
246 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask, | 247 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask, |
247 base::Unretained(this), frame, force_keyframe)); | 248 base::Unretained(this), frame, force_keyframe)); |
248 } | 249 } |
249 } | 250 } |
250 | 251 |
251 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer( | 252 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer( |
252 const BitstreamBuffer& buffer) { | 253 const BitstreamBuffer& buffer) { |
253 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id(); | 254 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id(); |
254 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 255 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
255 | 256 |
256 if (buffer.size() < output_buffer_byte_size_) { | 257 if (buffer.size() < output_buffer_byte_size_) { |
257 NOTIFY_ERROR(kInvalidArgumentError); | 258 NOTIFY_ERROR(kInvalidArgumentError); |
258 return; | 259 return; |
259 } | 260 } |
260 | 261 |
261 std::unique_ptr<SharedMemoryRegion> shm( | 262 std::unique_ptr<SharedMemoryRegion> shm( |
262 new SharedMemoryRegion(buffer, false)); | 263 new SharedMemoryRegion(buffer, false)); |
263 if (!shm->Map()) { | 264 if (!shm->Map()) { |
264 NOTIFY_ERROR(kPlatformFailureError); | 265 NOTIFY_ERROR(kPlatformFailureError); |
265 return; | 266 return; |
266 } | 267 } |
267 | 268 |
268 std::unique_ptr<BitstreamBufferRef> buffer_ref( | 269 std::unique_ptr<BitstreamBufferRef> buffer_ref( |
269 new BitstreamBufferRef(buffer.id(), std::move(shm))); | 270 new BitstreamBufferRef(buffer.id(), std::move(shm))); |
270 encoder_thread_.message_loop()->PostTask( | 271 encoder_thread_.task_runner()->PostTask( |
271 FROM_HERE, | 272 FROM_HERE, |
272 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask, | 273 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask, |
273 base::Unretained(this), base::Passed(&buffer_ref))); | 274 base::Unretained(this), base::Passed(&buffer_ref))); |
274 } | 275 } |
275 | 276 |
276 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange( | 277 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange( |
277 uint32_t bitrate, | 278 uint32_t bitrate, |
278 uint32_t framerate) { | 279 uint32_t framerate) { |
279 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate | 280 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate |
280 << ", framerate=" << framerate; | 281 << ", framerate=" << framerate; |
281 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 282 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
282 | 283 |
283 encoder_thread_.message_loop()->PostTask( | 284 encoder_thread_.task_runner()->PostTask( |
284 FROM_HERE, | 285 FROM_HERE, |
285 base::Bind( | 286 base::Bind( |
286 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask, | 287 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask, |
287 base::Unretained(this), bitrate, framerate)); | 288 base::Unretained(this), bitrate, framerate)); |
288 } | 289 } |
289 | 290 |
290 void V4L2VideoEncodeAccelerator::Destroy() { | 291 void V4L2VideoEncodeAccelerator::Destroy() { |
291 DVLOG(3) << "Destroy()"; | 292 DVLOG(3) << "Destroy()"; |
292 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 293 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
293 | 294 |
294 // We're destroying; cancel all callbacks. | 295 // We're destroying; cancel all callbacks. |
295 client_ptr_factory_.reset(); | 296 client_ptr_factory_.reset(); |
296 weak_this_ptr_factory_.InvalidateWeakPtrs(); | 297 weak_this_ptr_factory_.InvalidateWeakPtrs(); |
297 | 298 |
298 if (image_processor_.get()) | 299 if (image_processor_.get()) |
299 image_processor_.release()->Destroy(); | 300 image_processor_.release()->Destroy(); |
300 | 301 |
301 // If the encoder thread is running, destroy using posted task. | 302 // If the encoder thread is running, destroy using posted task. |
302 if (encoder_thread_.IsRunning()) { | 303 if (encoder_thread_.IsRunning()) { |
303 encoder_thread_.message_loop()->PostTask( | 304 encoder_thread_.task_runner()->PostTask( |
304 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask, | 305 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask, |
305 base::Unretained(this))); | 306 base::Unretained(this))); |
306 // DestroyTask() will put the encoder into kError state and cause all tasks | 307 // DestroyTask() will put the encoder into kError state and cause all tasks |
307 // to no-op. | 308 // to no-op. |
308 encoder_thread_.Stop(); | 309 encoder_thread_.Stop(); |
309 } else { | 310 } else { |
310 // Otherwise, call the destroy task directly. | 311 // Otherwise, call the destroy task directly. |
311 DestroyTask(); | 312 DestroyTask(); |
312 } | 313 } |
313 | 314 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 device_input_format_, image_processor_->output_allocated_size(), | 377 device_input_format_, image_processor_->output_allocated_size(), |
377 gfx::Rect(visible_size_), visible_size_, fds, timestamp); | 378 gfx::Rect(visible_size_), visible_size_, fds, timestamp); |
378 if (!output_frame) { | 379 if (!output_frame) { |
379 NOTIFY_ERROR(kPlatformFailureError); | 380 NOTIFY_ERROR(kPlatformFailureError); |
380 return; | 381 return; |
381 } | 382 } |
382 output_frame->AddDestructionObserver(BindToCurrentLoop( | 383 output_frame->AddDestructionObserver(BindToCurrentLoop( |
383 base::Bind(&V4L2VideoEncodeAccelerator::ReuseImageProcessorOutputBuffer, | 384 base::Bind(&V4L2VideoEncodeAccelerator::ReuseImageProcessorOutputBuffer, |
384 weak_this_, output_buffer_index))); | 385 weak_this_, output_buffer_index))); |
385 | 386 |
386 encoder_thread_.message_loop()->PostTask( | 387 encoder_thread_.task_runner()->PostTask( |
387 FROM_HERE, | 388 FROM_HERE, |
388 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask, | 389 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask, |
389 base::Unretained(this), output_frame, force_keyframe)); | 390 base::Unretained(this), output_frame, force_keyframe)); |
390 } | 391 } |
391 | 392 |
392 void V4L2VideoEncodeAccelerator::ReuseImageProcessorOutputBuffer( | 393 void V4L2VideoEncodeAccelerator::ReuseImageProcessorOutputBuffer( |
393 int output_buffer_index) { | 394 int output_buffer_index) { |
394 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 395 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
395 DVLOG(3) << __func__ << ": output_buffer_index=" << output_buffer_index; | 396 DVLOG(3) << __func__ << ": output_buffer_index=" << output_buffer_index; |
396 free_image_processor_output_buffers_.push_back(output_buffer_index); | 397 free_image_processor_output_buffers_.push_back(output_buffer_index); |
397 if (!image_processor_input_queue_.empty()) { | 398 if (!image_processor_input_queue_.empty()) { |
398 ImageProcessorInputRecord record = image_processor_input_queue_.front(); | 399 ImageProcessorInputRecord record = image_processor_input_queue_.front(); |
399 image_processor_input_queue_.pop(); | 400 image_processor_input_queue_.pop(); |
400 Encode(record.frame, record.force_keyframe); | 401 Encode(record.frame, record.force_keyframe); |
401 } | 402 } |
402 } | 403 } |
403 | 404 |
404 void V4L2VideoEncodeAccelerator::EncodeTask( | 405 void V4L2VideoEncodeAccelerator::EncodeTask( |
405 const scoped_refptr<VideoFrame>& frame, | 406 const scoped_refptr<VideoFrame>& frame, |
406 bool force_keyframe) { | 407 bool force_keyframe) { |
407 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe; | 408 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe; |
408 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 409 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
409 DCHECK_NE(encoder_state_, kUninitialized); | 410 DCHECK_NE(encoder_state_, kUninitialized); |
410 | 411 |
411 if (encoder_state_ == kError) { | 412 if (encoder_state_ == kError) { |
412 DVLOG(2) << "EncodeTask(): early out: kError state"; | 413 DVLOG(2) << "EncodeTask(): early out: kError state"; |
413 return; | 414 return; |
414 } | 415 } |
415 | 416 |
416 encoder_input_queue_.push(frame); | 417 encoder_input_queue_.push(frame); |
417 Enqueue(); | 418 Enqueue(); |
418 | 419 |
(...skipping 22 matching lines...) Expand all Loading... |
441 NOTIFY_ERROR(kPlatformFailureError); | 442 NOTIFY_ERROR(kPlatformFailureError); |
442 return; | 443 return; |
443 } | 444 } |
444 } | 445 } |
445 } | 446 } |
446 } | 447 } |
447 | 448 |
448 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask( | 449 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask( |
449 std::unique_ptr<BitstreamBufferRef> buffer_ref) { | 450 std::unique_ptr<BitstreamBufferRef> buffer_ref) { |
450 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id; | 451 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id; |
451 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 452 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
452 | 453 |
453 encoder_output_queue_.push_back( | 454 encoder_output_queue_.push_back( |
454 linked_ptr<BitstreamBufferRef>(buffer_ref.release())); | 455 linked_ptr<BitstreamBufferRef>(buffer_ref.release())); |
455 Enqueue(); | 456 Enqueue(); |
456 | 457 |
457 if (encoder_state_ == kInitialized) { | 458 if (encoder_state_ == kInitialized) { |
458 // Finish setting up our OUTPUT queue. See: Initialize(). | 459 // Finish setting up our OUTPUT queue. See: Initialize(). |
459 // VIDIOC_REQBUFS on OUTPUT queue. | 460 // VIDIOC_REQBUFS on OUTPUT queue. |
460 if (!CreateInputBuffers()) | 461 if (!CreateInputBuffers()) |
461 return; | 462 return; |
(...skipping 10 matching lines...) Expand all Loading... |
472 | 473 |
473 // Stop streaming and the device_poll_thread_. | 474 // Stop streaming and the device_poll_thread_. |
474 StopDevicePoll(); | 475 StopDevicePoll(); |
475 | 476 |
476 // Set our state to kError, and early-out all tasks. | 477 // Set our state to kError, and early-out all tasks. |
477 encoder_state_ = kError; | 478 encoder_state_ = kError; |
478 } | 479 } |
479 | 480 |
480 void V4L2VideoEncodeAccelerator::ServiceDeviceTask() { | 481 void V4L2VideoEncodeAccelerator::ServiceDeviceTask() { |
481 DVLOG(3) << "ServiceDeviceTask()"; | 482 DVLOG(3) << "ServiceDeviceTask()"; |
482 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 483 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
483 DCHECK_NE(encoder_state_, kUninitialized); | 484 DCHECK_NE(encoder_state_, kUninitialized); |
484 DCHECK_NE(encoder_state_, kInitialized); | 485 DCHECK_NE(encoder_state_, kInitialized); |
485 | 486 |
486 if (encoder_state_ == kError) { | 487 if (encoder_state_ == kError) { |
487 DVLOG(2) << "ServiceDeviceTask(): early out: kError state"; | 488 DVLOG(2) << "ServiceDeviceTask(): early out: kError state"; |
488 return; | 489 return; |
489 } | 490 } |
490 | 491 |
491 Dequeue(); | 492 Dequeue(); |
492 Enqueue(); | 493 Enqueue(); |
493 | 494 |
494 // Clear the interrupt fd. | 495 // Clear the interrupt fd. |
495 if (!device_->ClearDevicePollInterrupt()) | 496 if (!device_->ClearDevicePollInterrupt()) |
496 return; | 497 return; |
497 | 498 |
498 // Device can be polled as soon as either input or output buffers are queued. | 499 // Device can be polled as soon as either input or output buffers are queued. |
499 bool poll_device = | 500 bool poll_device = |
500 (input_buffer_queued_count_ + output_buffer_queued_count_ > 0); | 501 (input_buffer_queued_count_ + output_buffer_queued_count_ > 0); |
501 | 502 |
502 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), | 503 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), |
503 // so either: | 504 // so either: |
504 // * device_poll_thread_ is running normally | 505 // * device_poll_thread_ is running normally |
505 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, | 506 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, |
506 // in which case we're in kError state, and we should have early-outed | 507 // in which case we're in kError state, and we should have early-outed |
507 // already. | 508 // already. |
508 DCHECK(device_poll_thread_.message_loop()); | 509 DCHECK(device_poll_thread_.message_loop()); |
509 // Queue the DevicePollTask() now. | 510 // Queue the DevicePollTask() now. |
510 device_poll_thread_.message_loop()->PostTask( | 511 device_poll_thread_.task_runner()->PostTask( |
511 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, | 512 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, |
512 base::Unretained(this), poll_device)); | 513 base::Unretained(this), poll_device)); |
513 | 514 |
514 DVLOG(2) << __func__ << ": buffer counts: ENC[" | 515 DVLOG(2) << __func__ << ": buffer counts: ENC[" |
515 << encoder_input_queue_.size() << "] => DEVICE[" | 516 << encoder_input_queue_.size() << "] => DEVICE[" |
516 << free_input_buffers_.size() << "+" | 517 << free_input_buffers_.size() << "+" |
517 << input_buffer_queued_count_ << "/" | 518 << input_buffer_queued_count_ << "/" |
518 << input_buffer_map_.size() << "->" | 519 << input_buffer_map_.size() << "->" |
519 << free_output_buffers_.size() << "+" | 520 << free_output_buffers_.size() << "+" |
520 << output_buffer_queued_count_ << "/" | 521 << output_buffer_queued_count_ << "/" |
521 << output_buffer_map_.size() << "] => OUT[" | 522 << output_buffer_map_.size() << "] => OUT[" |
522 << encoder_output_queue_.size() << "]"; | 523 << encoder_output_queue_.size() << "]"; |
523 } | 524 } |
524 | 525 |
525 void V4L2VideoEncodeAccelerator::Enqueue() { | 526 void V4L2VideoEncodeAccelerator::Enqueue() { |
526 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 527 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
527 | 528 |
528 DVLOG(3) << "Enqueue() " | 529 DVLOG(3) << "Enqueue() " |
529 << "free_input_buffers: " << free_input_buffers_.size() | 530 << "free_input_buffers: " << free_input_buffers_.size() |
530 << "input_queue: " << encoder_input_queue_.size(); | 531 << "input_queue: " << encoder_input_queue_.size(); |
531 | 532 |
532 // Enqueue all the inputs we can. | 533 // Enqueue all the inputs we can. |
533 const int old_inputs_queued = input_buffer_queued_count_; | 534 const int old_inputs_queued = input_buffer_queued_count_; |
534 // while (!ready_input_buffers_.empty()) { | 535 // while (!ready_input_buffers_.empty()) { |
535 while (!encoder_input_queue_.empty() && !free_input_buffers_.empty()) { | 536 while (!encoder_input_queue_.empty() && !free_input_buffers_.empty()) { |
536 if (!EnqueueInputRecord()) | 537 if (!EnqueueInputRecord()) |
(...skipping 27 matching lines...) Expand all Loading... |
564 if (!output_streamon_) { | 565 if (!output_streamon_) { |
565 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 566 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
566 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type); | 567 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type); |
567 output_streamon_ = true; | 568 output_streamon_ = true; |
568 } | 569 } |
569 } | 570 } |
570 } | 571 } |
571 | 572 |
572 void V4L2VideoEncodeAccelerator::Dequeue() { | 573 void V4L2VideoEncodeAccelerator::Dequeue() { |
573 DVLOG(3) << "Dequeue()"; | 574 DVLOG(3) << "Dequeue()"; |
574 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 575 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
575 | 576 |
576 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free | 577 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free |
577 // list. | 578 // list. |
578 struct v4l2_buffer dqbuf; | 579 struct v4l2_buffer dqbuf; |
579 struct v4l2_plane planes[VIDEO_MAX_PLANES]; | 580 struct v4l2_plane planes[VIDEO_MAX_PLANES]; |
580 while (input_buffer_queued_count_ > 0) { | 581 while (input_buffer_queued_count_ > 0) { |
581 DVLOG(4) << "inputs queued: " << input_buffer_queued_count_; | 582 DVLOG(4) << "inputs queued: " << input_buffer_queued_count_; |
582 DCHECK(input_streamon_); | 583 DCHECK(input_streamon_); |
583 memset(&dqbuf, 0, sizeof(dqbuf)); | 584 memset(&dqbuf, 0, sizeof(dqbuf)); |
584 memset(&planes, 0, sizeof(planes)); | 585 memset(&planes, 0, sizeof(planes)); |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 output_record.at_device = true; | 760 output_record.at_device = true; |
760 output_record.buffer_ref = output_buffer; | 761 output_record.buffer_ref = output_buffer; |
761 encoder_output_queue_.pop_back(); | 762 encoder_output_queue_.pop_back(); |
762 free_output_buffers_.pop_back(); | 763 free_output_buffers_.pop_back(); |
763 output_buffer_queued_count_++; | 764 output_buffer_queued_count_++; |
764 return true; | 765 return true; |
765 } | 766 } |
766 | 767 |
767 bool V4L2VideoEncodeAccelerator::StartDevicePoll() { | 768 bool V4L2VideoEncodeAccelerator::StartDevicePoll() { |
768 DVLOG(3) << "StartDevicePoll()"; | 769 DVLOG(3) << "StartDevicePoll()"; |
769 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 770 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
770 DCHECK(!device_poll_thread_.IsRunning()); | 771 DCHECK(!device_poll_thread_.IsRunning()); |
771 | 772 |
772 // Start up the device poll thread and schedule its first DevicePollTask(). | 773 // Start up the device poll thread and schedule its first DevicePollTask(). |
773 if (!device_poll_thread_.Start()) { | 774 if (!device_poll_thread_.Start()) { |
774 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 775 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
775 NOTIFY_ERROR(kPlatformFailureError); | 776 NOTIFY_ERROR(kPlatformFailureError); |
776 return false; | 777 return false; |
777 } | 778 } |
778 // Enqueue a poll task with no devices to poll on -- it will wait only on the | 779 // Enqueue a poll task with no devices to poll on -- it will wait only on the |
779 // interrupt fd. | 780 // interrupt fd. |
780 device_poll_thread_.message_loop()->PostTask( | 781 device_poll_thread_.task_runner()->PostTask( |
781 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, | 782 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, |
782 base::Unretained(this), false)); | 783 base::Unretained(this), false)); |
783 | 784 |
784 return true; | 785 return true; |
785 } | 786 } |
786 | 787 |
787 bool V4L2VideoEncodeAccelerator::StopDevicePoll() { | 788 bool V4L2VideoEncodeAccelerator::StopDevicePoll() { |
788 DVLOG(3) << "StopDevicePoll()"; | 789 DVLOG(3) << "StopDevicePoll()"; |
789 | 790 |
790 // Signal the DevicePollTask() to stop, and stop the device poll thread. | 791 // Signal the DevicePollTask() to stop, and stop the device poll thread. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
829 output_buffer_queued_count_ = 0; | 830 output_buffer_queued_count_ = 0; |
830 | 831 |
831 encoder_output_queue_.clear(); | 832 encoder_output_queue_.clear(); |
832 | 833 |
833 DVLOG(3) << "StopDevicePoll(): device poll stopped"; | 834 DVLOG(3) << "StopDevicePoll(): device poll stopped"; |
834 return true; | 835 return true; |
835 } | 836 } |
836 | 837 |
837 void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device) { | 838 void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device) { |
838 DVLOG(3) << "DevicePollTask()"; | 839 DVLOG(3) << "DevicePollTask()"; |
839 DCHECK_EQ(device_poll_thread_.message_loop(), base::MessageLoop::current()); | 840 DCHECK(device_poll_thread_.task_runner()->BelongsToCurrentThread()); |
840 | 841 |
841 bool event_pending; | 842 bool event_pending; |
842 if (!device_->Poll(poll_device, &event_pending)) { | 843 if (!device_->Poll(poll_device, &event_pending)) { |
843 NOTIFY_ERROR(kPlatformFailureError); | 844 NOTIFY_ERROR(kPlatformFailureError); |
844 return; | 845 return; |
845 } | 846 } |
846 | 847 |
847 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 848 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
848 // touch encoder state from this thread. | 849 // touch encoder state from this thread. |
849 encoder_thread_.message_loop()->PostTask( | 850 encoder_thread_.task_runner()->PostTask( |
850 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask, | 851 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask, |
851 base::Unretained(this))); | 852 base::Unretained(this))); |
852 } | 853 } |
853 | 854 |
854 void V4L2VideoEncodeAccelerator::NotifyError(Error error) { | 855 void V4L2VideoEncodeAccelerator::NotifyError(Error error) { |
855 DVLOG(1) << "NotifyError(): error=" << error; | 856 DVLOG(1) << "NotifyError(): error=" << error; |
856 | 857 |
857 if (!child_task_runner_->BelongsToCurrentThread()) { | 858 if (!child_task_runner_->BelongsToCurrentThread()) { |
858 child_task_runner_->PostTask( | 859 child_task_runner_->PostTask( |
859 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::NotifyError, | 860 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::NotifyError, |
860 weak_this_, error)); | 861 weak_this_, error)); |
861 return; | 862 return; |
862 } | 863 } |
863 | 864 |
864 if (client_) { | 865 if (client_) { |
865 client_->NotifyError(error); | 866 client_->NotifyError(error); |
866 client_ptr_factory_.reset(); | 867 client_ptr_factory_.reset(); |
867 } | 868 } |
868 } | 869 } |
869 | 870 |
870 void V4L2VideoEncodeAccelerator::SetErrorState(Error error) { | 871 void V4L2VideoEncodeAccelerator::SetErrorState(Error error) { |
871 // We can touch encoder_state_ only if this is the encoder thread or the | 872 // We can touch encoder_state_ only if this is the encoder thread or the |
872 // encoder thread isn't running. | 873 // encoder thread isn't running. |
873 if (encoder_thread_.message_loop() != NULL && | 874 scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
874 encoder_thread_.message_loop() != base::MessageLoop::current()) { | 875 encoder_thread_.task_runner(); |
875 encoder_thread_.message_loop()->PostTask( | 876 if (task_runner && !task_runner->BelongsToCurrentThread()) { |
876 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::SetErrorState, | 877 task_runner->PostTask(FROM_HERE, |
877 base::Unretained(this), error)); | 878 base::Bind(&V4L2VideoEncodeAccelerator::SetErrorState, |
| 879 base::Unretained(this), error)); |
878 return; | 880 return; |
879 } | 881 } |
880 | 882 |
881 // Post NotifyError only if we are already initialized, as the API does | 883 // Post NotifyError only if we are already initialized, as the API does |
882 // not allow doing so before that. | 884 // not allow doing so before that. |
883 if (encoder_state_ != kError && encoder_state_ != kUninitialized) | 885 if (encoder_state_ != kError && encoder_state_ != kUninitialized) |
884 NotifyError(error); | 886 NotifyError(error); |
885 | 887 |
886 encoder_state_ = kError; | 888 encoder_state_ = kError; |
887 } | 889 } |
888 | 890 |
889 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 891 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
890 uint32_t bitrate, | 892 uint32_t bitrate, |
891 uint32_t framerate) { | 893 uint32_t framerate) { |
892 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate | 894 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate |
893 << ", framerate=" << framerate; | 895 << ", framerate=" << framerate; |
894 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 896 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
895 | 897 |
896 if (bitrate < 1) | 898 if (bitrate < 1) |
897 bitrate = 1; | 899 bitrate = 1; |
898 if (framerate < 1) | 900 if (framerate < 1) |
899 framerate = 1; | 901 framerate = 1; |
900 | 902 |
901 std::vector<struct v4l2_ext_control> ctrls; | 903 std::vector<struct v4l2_ext_control> ctrls; |
902 struct v4l2_ext_control ctrl; | 904 struct v4l2_ext_control ctrl; |
903 memset(&ctrl, 0, sizeof(ctrl)); | 905 memset(&ctrl, 0, sizeof(ctrl)); |
904 ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE; | 906 ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE; |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 // Ignore return value as these controls are optional. | 1141 // Ignore return value as these controls are optional. |
1140 SetExtCtrls(ctrls); | 1142 SetExtCtrls(ctrls); |
1141 | 1143 |
1142 return true; | 1144 return true; |
1143 } | 1145 } |
1144 | 1146 |
1145 bool V4L2VideoEncodeAccelerator::CreateInputBuffers() { | 1147 bool V4L2VideoEncodeAccelerator::CreateInputBuffers() { |
1146 DVLOG(3) << "CreateInputBuffers()"; | 1148 DVLOG(3) << "CreateInputBuffers()"; |
1147 // This function runs on encoder_thread_ after output buffers have been | 1149 // This function runs on encoder_thread_ after output buffers have been |
1148 // provided by the client. | 1150 // provided by the client. |
1149 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 1151 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); |
1150 DCHECK(!input_streamon_); | 1152 DCHECK(!input_streamon_); |
1151 | 1153 |
1152 struct v4l2_requestbuffers reqbufs; | 1154 struct v4l2_requestbuffers reqbufs; |
1153 memset(&reqbufs, 0, sizeof(reqbufs)); | 1155 memset(&reqbufs, 0, sizeof(reqbufs)); |
1154 // Driver will modify to the appropriate number of buffers. | 1156 // Driver will modify to the appropriate number of buffers. |
1155 reqbufs.count = 1; | 1157 reqbufs.count = 1; |
1156 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1158 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
1157 // TODO(posciak): Once we start doing zero-copy, we should decide based on | 1159 // TODO(posciak): Once we start doing zero-copy, we should decide based on |
1158 // the current pipeline setup which memory type to use. This should probably | 1160 // the current pipeline setup which memory type to use. This should probably |
1159 // be decided based on an argument to Initialize(). | 1161 // be decided based on an argument to Initialize(). |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1247 reqbufs.count = 0; | 1249 reqbufs.count = 0; |
1248 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1250 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1249 reqbufs.memory = V4L2_MEMORY_MMAP; | 1251 reqbufs.memory = V4L2_MEMORY_MMAP; |
1250 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 1252 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
1251 | 1253 |
1252 output_buffer_map_.clear(); | 1254 output_buffer_map_.clear(); |
1253 free_output_buffers_.clear(); | 1255 free_output_buffers_.clear(); |
1254 } | 1256 } |
1255 | 1257 |
1256 } // namespace media | 1258 } // namespace media |
OLD | NEW |