Chromium Code Reviews| 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 <dlfcn.h> | 5 #include <dlfcn.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 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 <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| 11 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
| 12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 16 #include "base/memory/shared_memory.h" | |
| 17 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 18 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
| 19 #include "base/thread_task_runner_handle.h" | 18 #include "base/thread_task_runner_handle.h" |
| 20 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
| 20 #include "content/common/gpu/media/shared_memory_region.h" | |
| 21 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" | 21 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" |
| 22 #include "media/base/media_switches.h" | 22 #include "media/base/media_switches.h" |
| 23 #include "media/filters/h264_parser.h" | 23 #include "media/filters/h264_parser.h" |
| 24 #include "ui/gfx/geometry/rect.h" | 24 #include "ui/gfx/geometry/rect.h" |
| 25 #include "ui/gl/scoped_binders.h" | 25 #include "ui/gl/scoped_binders.h" |
| 26 | 26 |
| 27 #define NOTIFY_ERROR(x) \ | 27 #define NOTIFY_ERROR(x) \ |
| 28 do { \ | 28 do { \ |
| 29 LOG(ERROR) << "Setting error state:" << x; \ | 29 LOG(ERROR) << "Setting error state:" << x; \ |
| 30 SetErrorState(x); \ | 30 SetErrorState(x); \ |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 50 if (device_->Ioctl(type, arg) != 0) \ | 50 if (device_->Ioctl(type, arg) != 0) \ |
| 51 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ | 51 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ |
| 52 } while (0) | 52 } while (0) |
| 53 | 53 |
| 54 namespace content { | 54 namespace content { |
| 55 | 55 |
| 56 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { | 56 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { |
| 57 BitstreamBufferRef( | 57 BitstreamBufferRef( |
| 58 base::WeakPtr<Client>& client, | 58 base::WeakPtr<Client>& client, |
| 59 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 59 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 60 base::SharedMemory* shm, | 60 SharedMemoryRegion* shm, |
| 61 size_t size, | |
| 62 int32 input_id); | 61 int32 input_id); |
| 63 ~BitstreamBufferRef(); | 62 ~BitstreamBufferRef(); |
| 64 const base::WeakPtr<Client> client; | 63 const base::WeakPtr<Client> client; |
| 65 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; | 64 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; |
| 66 const scoped_ptr<base::SharedMemory> shm; | 65 const scoped_ptr<SharedMemoryRegion> shm; |
| 67 const size_t size; | |
| 68 size_t bytes_used; | 66 size_t bytes_used; |
| 69 const int32 input_id; | 67 const int32 input_id; |
| 70 }; | 68 }; |
| 71 | 69 |
| 72 struct V4L2VideoDecodeAccelerator::EGLSyncKHRRef { | 70 struct V4L2VideoDecodeAccelerator::EGLSyncKHRRef { |
| 73 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); | 71 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); |
| 74 ~EGLSyncKHRRef(); | 72 ~EGLSyncKHRRef(); |
| 75 EGLDisplay const egl_display; | 73 EGLDisplay const egl_display; |
| 76 EGLSyncKHR egl_sync; | 74 EGLSyncKHR egl_sync; |
| 77 }; | 75 }; |
| 78 | 76 |
| 79 struct V4L2VideoDecodeAccelerator::PictureRecord { | 77 struct V4L2VideoDecodeAccelerator::PictureRecord { |
| 80 PictureRecord(bool cleared, const media::Picture& picture); | 78 PictureRecord(bool cleared, const media::Picture& picture); |
| 81 ~PictureRecord(); | 79 ~PictureRecord(); |
| 82 bool cleared; // Whether the texture is cleared and safe to render from. | 80 bool cleared; // Whether the texture is cleared and safe to render from. |
| 83 media::Picture picture; // The decoded picture. | 81 media::Picture picture; // The decoded picture. |
| 84 }; | 82 }; |
| 85 | 83 |
| 86 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( | 84 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( |
| 87 base::WeakPtr<Client>& client, | 85 base::WeakPtr<Client>& client, |
| 88 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 86 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 89 base::SharedMemory* shm, | 87 SharedMemoryRegion* shm, |
| 90 size_t size, | |
| 91 int32 input_id) | 88 int32 input_id) |
| 92 : client(client), | 89 : client(client), |
| 93 client_task_runner(client_task_runner), | 90 client_task_runner(client_task_runner), |
| 94 shm(shm), | 91 shm(shm), |
| 95 size(size), | |
| 96 bytes_used(0), | 92 bytes_used(0), |
| 97 input_id(input_id) { | 93 input_id(input_id) {} |
| 98 } | |
| 99 | 94 |
| 100 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { | 95 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { |
| 101 if (input_id >= 0) { | 96 if (input_id >= 0) { |
| 102 client_task_runner->PostTask( | 97 client_task_runner->PostTask( |
| 103 FROM_HERE, | 98 FROM_HERE, |
| 104 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); | 99 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); |
| 105 } | 100 } |
| 106 } | 101 } |
| 107 | 102 |
| 108 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef( | 103 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef( |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 void V4L2VideoDecodeAccelerator::DecodeTask( | 473 void V4L2VideoDecodeAccelerator::DecodeTask( |
| 479 const media::BitstreamBuffer& bitstream_buffer) { | 474 const media::BitstreamBuffer& bitstream_buffer) { |
| 480 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); | 475 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); |
| 481 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 476 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 482 DCHECK_NE(decoder_state_, kUninitialized); | 477 DCHECK_NE(decoder_state_, kUninitialized); |
| 483 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", | 478 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", |
| 484 bitstream_buffer.id()); | 479 bitstream_buffer.id()); |
| 485 | 480 |
| 486 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( | 481 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( |
| 487 io_client_, io_task_runner_, | 482 io_client_, io_task_runner_, |
| 488 new base::SharedMemory(bitstream_buffer.handle(), true), | 483 new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); |
| 489 bitstream_buffer.size(), bitstream_buffer.id())); | 484 if (!bitstream_record->shm->Map()) { |
| 490 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { | |
| 491 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; | 485 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; |
| 492 NOTIFY_ERROR(UNREADABLE_INPUT); | 486 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 493 return; | 487 return; |
| 494 } | 488 } |
| 495 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); | 489 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); |
| 496 | 490 |
| 497 if (decoder_state_ == kResetting || decoder_flushing_) { | 491 if (decoder_state_ == kResetting || decoder_flushing_) { |
| 498 // In the case that we're resetting or flushing, we need to delay decoding | 492 // In the case that we're resetting or flushing, we need to delay decoding |
| 499 // the BitstreamBuffers that come after the Reset() or Flush() call. When | 493 // the BitstreamBuffers that come after the Reset() or Flush() call. When |
| 500 // we're here, we know that this DecodeTask() was scheduled by a Decode() | 494 // we're here, we know that this DecodeTask() was scheduled by a Decode() |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 } | 533 } |
| 540 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); | 534 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); |
| 541 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { | 535 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { |
| 542 // We're asked to delay decoding on this and subsequent buffers. | 536 // We're asked to delay decoding on this and subsequent buffers. |
| 543 return; | 537 return; |
| 544 } | 538 } |
| 545 | 539 |
| 546 // Setup to use the next buffer. | 540 // Setup to use the next buffer. |
| 547 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); | 541 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); |
| 548 decoder_input_queue_.pop(); | 542 decoder_input_queue_.pop(); |
| 549 DVLOG(3) << "DecodeBufferTask(): reading input_id=" | 543 if (decoder_current_bitstream_buffer_->shm == NULL) { |
|
Pawel Osciak
2015/12/31 02:05:54
s/ == NULL//
Also, perhaps we could
const auto s
Owen Lin
2016/01/04 08:54:17
Done.
| |
| 550 << decoder_current_bitstream_buffer_->input_id | 544 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); |
| 551 << ", addr=" << (decoder_current_bitstream_buffer_->shm ? | 545 DVLOG(3) << "DecodeBufferTask(): reading input_id=kFlushBufferId"; |
| 552 decoder_current_bitstream_buffer_->shm->memory() : | 546 } else { |
| 553 NULL) | 547 DVLOG(3) << "DecodeBufferTask(): reading input_id=" |
| 554 << ", size=" << decoder_current_bitstream_buffer_->size; | 548 << decoder_current_bitstream_buffer_->input_id |
| 549 << ", addr=" << decoder_current_bitstream_buffer_->shm->memory() | |
| 550 << ", size=" << decoder_current_bitstream_buffer_->shm->size(); | |
| 551 } | |
| 555 } | 552 } |
| 556 bool schedule_task = false; | 553 bool schedule_task = false; |
| 557 const size_t size = decoder_current_bitstream_buffer_->size; | |
| 558 size_t decoded_size = 0; | 554 size_t decoded_size = 0; |
| 559 if (size == 0) { | 555 if (decoder_current_bitstream_buffer_->shm == NULL) { |
|
Pawel Osciak
2015/12/31 02:05:54
s/ == NULL//
Owen Lin
2016/01/04 08:54:17
Done.
| |
| 560 const int32 input_id = decoder_current_bitstream_buffer_->input_id; | 556 // This is a buffer of zero size, queued to flush the pipe. Flush. |
|
Pawel Osciak
2015/12/31 02:05:54
s/buffer of zero size,/dummy buffer,/
Owen Lin
2016/01/04 08:54:17
Done.
| |
| 561 if (input_id >= 0) { | 557 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); |
| 562 // This is a buffer queued from the client that has zero size. Skip. | 558 // Enqueue a buffer guaranteed to be empty. To do that, we flush the |
| 559 // current input, enqueue no data to the next frame, then flush that down. | |
| 560 schedule_task = true; | |
| 561 if (decoder_current_input_buffer_ != -1 && | |
| 562 input_buffer_map_[decoder_current_input_buffer_].input_id != | |
| 563 kFlushBufferId) | |
| 564 schedule_task = FlushInputFrame(); | |
| 565 | |
| 566 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { | |
| 567 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; | |
| 568 decoder_partial_frame_pending_ = false; | |
| 563 schedule_task = true; | 569 schedule_task = true; |
| 564 } else { | 570 } else { |
| 565 // This is a buffer of zero size, queued to flush the pipe. Flush. | 571 // If we failed to enqueue the empty buffer (due to pipeline |
| 566 DCHECK_EQ(decoder_current_bitstream_buffer_->shm.get(), | 572 // backpressure), don't advance the bitstream buffer queue, and don't |
| 567 static_cast<base::SharedMemory*>(NULL)); | 573 // schedule the next task. This bitstream buffer queue entry will get |
| 568 // Enqueue a buffer guaranteed to be empty. To do that, we flush the | 574 // reprocessed when the pipeline frees up. |
| 569 // current input, enqueue no data to the next frame, then flush that down. | 575 schedule_task = false; |
| 570 schedule_task = true; | |
| 571 if (decoder_current_input_buffer_ != -1 && | |
| 572 input_buffer_map_[decoder_current_input_buffer_].input_id != | |
| 573 kFlushBufferId) | |
| 574 schedule_task = FlushInputFrame(); | |
| 575 | |
| 576 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { | |
| 577 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; | |
| 578 decoder_partial_frame_pending_ = false; | |
| 579 schedule_task = true; | |
| 580 } else { | |
| 581 // If we failed to enqueue the empty buffer (due to pipeline | |
| 582 // backpressure), don't advance the bitstream buffer queue, and don't | |
| 583 // schedule the next task. This bitstream buffer queue entry will get | |
| 584 // reprocessed when the pipeline frees up. | |
| 585 schedule_task = false; | |
| 586 } | |
| 587 } | 576 } |
| 577 } else if (decoder_current_bitstream_buffer_->shm->size() == 0) { | |
| 578 // This is a buffer queued from the client that has zero size. Skip. | |
| 579 schedule_task = true; | |
| 588 } else { | 580 } else { |
| 589 // This is a buffer queued from the client, with actual contents. Decode. | 581 // This is a buffer queued from the client, with actual contents. Decode. |
| 590 const uint8* const data = | 582 const uint8* const data = |
| 591 reinterpret_cast<const uint8*>( | 583 reinterpret_cast<const uint8*>( |
| 592 decoder_current_bitstream_buffer_->shm->memory()) + | 584 decoder_current_bitstream_buffer_->shm->memory()) + |
| 593 decoder_current_bitstream_buffer_->bytes_used; | 585 decoder_current_bitstream_buffer_->bytes_used; |
| 594 const size_t data_size = | 586 const size_t data_size = decoder_current_bitstream_buffer_->shm->size() - |
| 595 decoder_current_bitstream_buffer_->size - | 587 decoder_current_bitstream_buffer_->bytes_used; |
| 596 decoder_current_bitstream_buffer_->bytes_used; | |
| 597 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { | 588 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { |
| 598 NOTIFY_ERROR(UNREADABLE_INPUT); | 589 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 599 return; | 590 return; |
| 600 } | 591 } |
| 601 // AdvanceFrameFragment should not return a size larger than the buffer | 592 // AdvanceFrameFragment should not return a size larger than the buffer |
| 602 // size, even on invalid data. | 593 // size, even on invalid data. |
| 603 CHECK_LE(decoded_size, data_size); | 594 CHECK_LE(decoded_size, data_size); |
| 604 | 595 |
| 605 switch (decoder_state_) { | 596 switch (decoder_state_) { |
| 606 case kInitialized: | 597 case kInitialized: |
| 607 case kAfterReset: | 598 case kAfterReset: |
| 608 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); | 599 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); |
| 609 break; | 600 break; |
| 610 case kDecoding: | 601 case kDecoding: |
| 611 schedule_task = DecodeBufferContinue(data, decoded_size); | 602 schedule_task = DecodeBufferContinue(data, decoded_size); |
| 612 break; | 603 break; |
| 613 default: | 604 default: |
| 614 NOTIFY_ERROR(ILLEGAL_STATE); | 605 NOTIFY_ERROR(ILLEGAL_STATE); |
| 615 return; | 606 return; |
| 616 } | 607 } |
| 617 } | 608 } |
| 618 if (decoder_state_ == kError) { | 609 if (decoder_state_ == kError) { |
| 619 // Failed during decode. | 610 // Failed during decode. |
| 620 return; | 611 return; |
| 621 } | 612 } |
| 622 | 613 |
| 623 if (schedule_task) { | 614 if (schedule_task) { |
| 624 decoder_current_bitstream_buffer_->bytes_used += decoded_size; | 615 decoder_current_bitstream_buffer_->bytes_used += decoded_size; |
| 625 if (decoder_current_bitstream_buffer_->bytes_used == | 616 if (decoder_current_bitstream_buffer_->bytes_used == |
| 626 decoder_current_bitstream_buffer_->size) { | 617 decoder_current_bitstream_buffer_->shm->size()) { |
| 627 // Our current bitstream buffer is done; return it. | 618 // Our current bitstream buffer is done; return it. |
| 628 int32 input_id = decoder_current_bitstream_buffer_->input_id; | 619 int32 input_id = decoder_current_bitstream_buffer_->input_id; |
| 629 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; | 620 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; |
| 630 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). | 621 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). |
| 631 decoder_current_bitstream_buffer_.reset(); | 622 decoder_current_bitstream_buffer_.reset(); |
| 632 } | 623 } |
| 633 ScheduleDecodeBufferTaskIfNeeded(); | 624 ScheduleDecodeBufferTaskIfNeeded(); |
| 634 } | 625 } |
| 635 } | 626 } |
| 636 | 627 |
| (...skipping 643 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1280 DVLOG(2) << "FlushTask(): early out: kError state"; | 1271 DVLOG(2) << "FlushTask(): early out: kError state"; |
| 1281 return; | 1272 return; |
| 1282 } | 1273 } |
| 1283 | 1274 |
| 1284 // We don't support stacked flushing. | 1275 // We don't support stacked flushing. |
| 1285 DCHECK(!decoder_flushing_); | 1276 DCHECK(!decoder_flushing_); |
| 1286 | 1277 |
| 1287 // Queue up an empty buffer -- this triggers the flush. | 1278 // Queue up an empty buffer -- this triggers the flush. |
| 1288 decoder_input_queue_.push( | 1279 decoder_input_queue_.push( |
| 1289 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( | 1280 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( |
| 1290 io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); | 1281 io_client_, io_task_runner_, NULL, kFlushBufferId))); |
|
Pawel Osciak
2015/12/31 02:05:54
nullptr
Owen Lin
2016/01/04 08:54:17
Done.
| |
| 1291 decoder_flushing_ = true; | 1282 decoder_flushing_ = true; |
| 1292 SendPictureReady(); // Send all pending PictureReady. | 1283 SendPictureReady(); // Send all pending PictureReady. |
| 1293 | 1284 |
| 1294 ScheduleDecodeBufferTaskIfNeeded(); | 1285 ScheduleDecodeBufferTaskIfNeeded(); |
| 1295 } | 1286 } |
| 1296 | 1287 |
| 1297 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { | 1288 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
| 1298 if (!decoder_flushing_) | 1289 if (!decoder_flushing_) |
| 1299 return; | 1290 return; |
| 1300 | 1291 |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2044 | 2035 |
| 2045 void V4L2VideoDecodeAccelerator::PictureCleared() { | 2036 void V4L2VideoDecodeAccelerator::PictureCleared() { |
| 2046 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 2037 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
| 2047 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 2038 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 2048 DCHECK_GT(picture_clearing_count_, 0); | 2039 DCHECK_GT(picture_clearing_count_, 0); |
| 2049 picture_clearing_count_--; | 2040 picture_clearing_count_--; |
| 2050 SendPictureReady(); | 2041 SendPictureReady(); |
| 2051 } | 2042 } |
| 2052 | 2043 |
| 2053 } // namespace content | 2044 } // namespace content |
| OLD | NEW |