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