| 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 19 matching lines...) Expand all Loading... |
| 53 if (device_->Ioctl(type, arg) != 0) \ | 53 if (device_->Ioctl(type, arg) != 0) \ |
| 54 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ | 54 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ |
| 55 } while (0) | 55 } while (0) |
| 56 | 56 |
| 57 namespace content { | 57 namespace content { |
| 58 | 58 |
| 59 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { | 59 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { |
| 60 BitstreamBufferRef( | 60 BitstreamBufferRef( |
| 61 base::WeakPtr<Client>& client, | 61 base::WeakPtr<Client>& client, |
| 62 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 62 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 63 base::SharedMemory* shm, | 63 SharedMemoryRegion* shm, |
| 64 size_t size, | |
| 65 int32_t input_id); | 64 int32_t input_id); |
| 66 ~BitstreamBufferRef(); | 65 ~BitstreamBufferRef(); |
| 67 const base::WeakPtr<Client> client; | 66 const base::WeakPtr<Client> client; |
| 68 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; | 67 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; |
| 69 const scoped_ptr<base::SharedMemory> shm; | 68 const scoped_ptr<SharedMemoryRegion> shm; |
| 70 const size_t size; | |
| 71 size_t bytes_used; | 69 size_t bytes_used; |
| 72 const int32_t input_id; | 70 const int32_t input_id; |
| 73 }; | 71 }; |
| 74 | 72 |
| 75 struct V4L2VideoDecodeAccelerator::EGLSyncKHRRef { | 73 struct V4L2VideoDecodeAccelerator::EGLSyncKHRRef { |
| 76 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); | 74 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); |
| 77 ~EGLSyncKHRRef(); | 75 ~EGLSyncKHRRef(); |
| 78 EGLDisplay const egl_display; | 76 EGLDisplay const egl_display; |
| 79 EGLSyncKHR egl_sync; | 77 EGLSyncKHR egl_sync; |
| 80 }; | 78 }; |
| 81 | 79 |
| 82 struct V4L2VideoDecodeAccelerator::PictureRecord { | 80 struct V4L2VideoDecodeAccelerator::PictureRecord { |
| 83 PictureRecord(bool cleared, const media::Picture& picture); | 81 PictureRecord(bool cleared, const media::Picture& picture); |
| 84 ~PictureRecord(); | 82 ~PictureRecord(); |
| 85 bool cleared; // Whether the texture is cleared and safe to render from. | 83 bool cleared; // Whether the texture is cleared and safe to render from. |
| 86 media::Picture picture; // The decoded picture. | 84 media::Picture picture; // The decoded picture. |
| 87 }; | 85 }; |
| 88 | 86 |
| 89 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( | 87 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( |
| 90 base::WeakPtr<Client>& client, | 88 base::WeakPtr<Client>& client, |
| 91 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 89 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 92 base::SharedMemory* shm, | 90 SharedMemoryRegion* shm, |
| 93 size_t size, | |
| 94 int32_t input_id) | 91 int32_t input_id) |
| 95 : client(client), | 92 : client(client), |
| 96 client_task_runner(client_task_runner), | 93 client_task_runner(client_task_runner), |
| 97 shm(shm), | 94 shm(shm), |
| 98 size(size), | |
| 99 bytes_used(0), | 95 bytes_used(0), |
| 100 input_id(input_id) {} | 96 input_id(input_id) {} |
| 101 | 97 |
| 102 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { | 98 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { |
| 103 if (input_id >= 0) { | 99 if (input_id >= 0) { |
| 104 client_task_runner->PostTask( | 100 client_task_runner->PostTask( |
| 105 FROM_HERE, | 101 FROM_HERE, |
| 106 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); | 102 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); |
| 107 } | 103 } |
| 108 } | 104 } |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 void V4L2VideoDecodeAccelerator::DecodeTask( | 480 void V4L2VideoDecodeAccelerator::DecodeTask( |
| 485 const media::BitstreamBuffer& bitstream_buffer) { | 481 const media::BitstreamBuffer& bitstream_buffer) { |
| 486 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); | 482 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); |
| 487 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 483 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 488 DCHECK_NE(decoder_state_, kUninitialized); | 484 DCHECK_NE(decoder_state_, kUninitialized); |
| 489 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", | 485 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", |
| 490 bitstream_buffer.id()); | 486 bitstream_buffer.id()); |
| 491 | 487 |
| 492 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( | 488 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( |
| 493 io_client_, io_task_runner_, | 489 io_client_, io_task_runner_, |
| 494 new base::SharedMemory(bitstream_buffer.handle(), true), | 490 new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); |
| 495 bitstream_buffer.size(), bitstream_buffer.id())); | 491 if (!bitstream_record->shm->Map()) { |
| 496 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { | |
| 497 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; | 492 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; |
| 498 NOTIFY_ERROR(UNREADABLE_INPUT); | 493 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 499 return; | 494 return; |
| 500 } | 495 } |
| 501 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); | 496 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); |
| 502 | 497 |
| 503 if (decoder_state_ == kResetting || decoder_flushing_) { | 498 if (decoder_state_ == kResetting || decoder_flushing_) { |
| 504 // In the case that we're resetting or flushing, we need to delay decoding | 499 // In the case that we're resetting or flushing, we need to delay decoding |
| 505 // the BitstreamBuffers that come after the Reset() or Flush() call. When | 500 // the BitstreamBuffers that come after the Reset() or Flush() call. When |
| 506 // we're here, we know that this DecodeTask() was scheduled by a Decode() | 501 // 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... |
| 545 } | 540 } |
| 546 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); | 541 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); |
| 547 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { | 542 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { |
| 548 // We're asked to delay decoding on this and subsequent buffers. | 543 // We're asked to delay decoding on this and subsequent buffers. |
| 549 return; | 544 return; |
| 550 } | 545 } |
| 551 | 546 |
| 552 // Setup to use the next buffer. | 547 // Setup to use the next buffer. |
| 553 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); | 548 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); |
| 554 decoder_input_queue_.pop(); | 549 decoder_input_queue_.pop(); |
| 555 DVLOG(3) << "DecodeBufferTask(): reading input_id=" | 550 const auto& shm = decoder_current_bitstream_buffer_->shm; |
| 556 << decoder_current_bitstream_buffer_->input_id | 551 if (shm) { |
| 557 << ", addr=" << (decoder_current_bitstream_buffer_->shm ? | 552 DVLOG(3) << "DecodeBufferTask(): reading input_id=" |
| 558 decoder_current_bitstream_buffer_->shm->memory() : | 553 << decoder_current_bitstream_buffer_->input_id |
| 559 NULL) | 554 << ", addr=" << shm->memory() << ", size=" << shm->size(); |
| 560 << ", size=" << decoder_current_bitstream_buffer_->size; | 555 } else { |
| 556 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); |
| 557 DVLOG(3) << "DecodeBufferTask(): reading input_id=kFlushBufferId"; |
| 558 } |
| 561 } | 559 } |
| 562 bool schedule_task = false; | 560 bool schedule_task = false; |
| 563 const size_t size = decoder_current_bitstream_buffer_->size; | |
| 564 size_t decoded_size = 0; | 561 size_t decoded_size = 0; |
| 565 if (size == 0) { | 562 const auto& shm = decoder_current_bitstream_buffer_->shm; |
| 566 const int32_t input_id = decoder_current_bitstream_buffer_->input_id; | 563 if (!shm) { |
| 567 if (input_id >= 0) { | 564 // This is a dummy buffer, queued to flush the pipe. Flush. |
| 568 // This is a buffer queued from the client that has zero size. Skip. | 565 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); |
| 566 // Enqueue a buffer guaranteed to be empty. To do that, we flush the |
| 567 // current input, enqueue no data to the next frame, then flush that down. |
| 568 schedule_task = true; |
| 569 if (decoder_current_input_buffer_ != -1 && |
| 570 input_buffer_map_[decoder_current_input_buffer_].input_id != |
| 571 kFlushBufferId) |
| 572 schedule_task = FlushInputFrame(); |
| 573 |
| 574 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { |
| 575 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; |
| 576 decoder_partial_frame_pending_ = false; |
| 569 schedule_task = true; | 577 schedule_task = true; |
| 570 } else { | 578 } else { |
| 571 // This is a buffer of zero size, queued to flush the pipe. Flush. | 579 // If we failed to enqueue the empty buffer (due to pipeline |
| 572 DCHECK_EQ(decoder_current_bitstream_buffer_->shm.get(), | 580 // backpressure), don't advance the bitstream buffer queue, and don't |
| 573 static_cast<base::SharedMemory*>(NULL)); | 581 // schedule the next task. This bitstream buffer queue entry will get |
| 574 // Enqueue a buffer guaranteed to be empty. To do that, we flush the | 582 // reprocessed when the pipeline frees up. |
| 575 // current input, enqueue no data to the next frame, then flush that down. | 583 schedule_task = false; |
| 576 schedule_task = true; | |
| 577 if (decoder_current_input_buffer_ != -1 && | |
| 578 input_buffer_map_[decoder_current_input_buffer_].input_id != | |
| 579 kFlushBufferId) | |
| 580 schedule_task = FlushInputFrame(); | |
| 581 | |
| 582 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { | |
| 583 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; | |
| 584 decoder_partial_frame_pending_ = false; | |
| 585 schedule_task = true; | |
| 586 } else { | |
| 587 // If we failed to enqueue the empty buffer (due to pipeline | |
| 588 // backpressure), don't advance the bitstream buffer queue, and don't | |
| 589 // schedule the next task. This bitstream buffer queue entry will get | |
| 590 // reprocessed when the pipeline frees up. | |
| 591 schedule_task = false; | |
| 592 } | |
| 593 } | 584 } |
| 585 } else if (shm->size() == 0) { |
| 586 // This is a buffer queued from the client that has zero size. Skip. |
| 587 schedule_task = true; |
| 594 } else { | 588 } else { |
| 595 // This is a buffer queued from the client, with actual contents. Decode. | 589 // This is a buffer queued from the client, with actual contents. Decode. |
| 596 const uint8_t* const data = | 590 const uint8_t* const data = |
| 597 reinterpret_cast<const uint8_t*>( | 591 reinterpret_cast<const uint8_t*>(shm->memory()) + |
| 598 decoder_current_bitstream_buffer_->shm->memory()) + | |
| 599 decoder_current_bitstream_buffer_->bytes_used; | 592 decoder_current_bitstream_buffer_->bytes_used; |
| 600 const size_t data_size = | 593 const size_t data_size = |
| 601 decoder_current_bitstream_buffer_->size - | 594 shm->size() - decoder_current_bitstream_buffer_->bytes_used; |
| 602 decoder_current_bitstream_buffer_->bytes_used; | |
| 603 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { | 595 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { |
| 604 NOTIFY_ERROR(UNREADABLE_INPUT); | 596 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 605 return; | 597 return; |
| 606 } | 598 } |
| 607 // AdvanceFrameFragment should not return a size larger than the buffer | 599 // AdvanceFrameFragment should not return a size larger than the buffer |
| 608 // size, even on invalid data. | 600 // size, even on invalid data. |
| 609 CHECK_LE(decoded_size, data_size); | 601 CHECK_LE(decoded_size, data_size); |
| 610 | 602 |
| 611 switch (decoder_state_) { | 603 switch (decoder_state_) { |
| 612 case kInitialized: | 604 case kInitialized: |
| 613 case kAfterReset: | 605 case kAfterReset: |
| 614 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); | 606 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); |
| 615 break; | 607 break; |
| 616 case kDecoding: | 608 case kDecoding: |
| 617 schedule_task = DecodeBufferContinue(data, decoded_size); | 609 schedule_task = DecodeBufferContinue(data, decoded_size); |
| 618 break; | 610 break; |
| 619 default: | 611 default: |
| 620 NOTIFY_ERROR(ILLEGAL_STATE); | 612 NOTIFY_ERROR(ILLEGAL_STATE); |
| 621 return; | 613 return; |
| 622 } | 614 } |
| 623 } | 615 } |
| 624 if (decoder_state_ == kError) { | 616 if (decoder_state_ == kError) { |
| 625 // Failed during decode. | 617 // Failed during decode. |
| 626 return; | 618 return; |
| 627 } | 619 } |
| 628 | 620 |
| 629 if (schedule_task) { | 621 if (schedule_task) { |
| 630 decoder_current_bitstream_buffer_->bytes_used += decoded_size; | 622 decoder_current_bitstream_buffer_->bytes_used += decoded_size; |
| 631 if (decoder_current_bitstream_buffer_->bytes_used == | 623 if ((shm ? shm->size() : 0) == |
| 632 decoder_current_bitstream_buffer_->size) { | 624 decoder_current_bitstream_buffer_->bytes_used) { |
| 633 // Our current bitstream buffer is done; return it. | 625 // Our current bitstream buffer is done; return it. |
| 634 int32_t input_id = decoder_current_bitstream_buffer_->input_id; | 626 int32_t input_id = decoder_current_bitstream_buffer_->input_id; |
| 635 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; | 627 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; |
| 636 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). | 628 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). |
| 637 decoder_current_bitstream_buffer_.reset(); | 629 decoder_current_bitstream_buffer_.reset(); |
| 638 } | 630 } |
| 639 ScheduleDecodeBufferTaskIfNeeded(); | 631 ScheduleDecodeBufferTaskIfNeeded(); |
| 640 } | 632 } |
| 641 } | 633 } |
| 642 | 634 |
| (...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 DVLOG(2) << "FlushTask(): early out: kError state"; | 1277 DVLOG(2) << "FlushTask(): early out: kError state"; |
| 1286 return; | 1278 return; |
| 1287 } | 1279 } |
| 1288 | 1280 |
| 1289 // We don't support stacked flushing. | 1281 // We don't support stacked flushing. |
| 1290 DCHECK(!decoder_flushing_); | 1282 DCHECK(!decoder_flushing_); |
| 1291 | 1283 |
| 1292 // Queue up an empty buffer -- this triggers the flush. | 1284 // Queue up an empty buffer -- this triggers the flush. |
| 1293 decoder_input_queue_.push( | 1285 decoder_input_queue_.push( |
| 1294 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( | 1286 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( |
| 1295 io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); | 1287 io_client_, io_task_runner_, nullptr, kFlushBufferId))); |
| 1296 decoder_flushing_ = true; | 1288 decoder_flushing_ = true; |
| 1297 SendPictureReady(); // Send all pending PictureReady. | 1289 SendPictureReady(); // Send all pending PictureReady. |
| 1298 | 1290 |
| 1299 ScheduleDecodeBufferTaskIfNeeded(); | 1291 ScheduleDecodeBufferTaskIfNeeded(); |
| 1300 } | 1292 } |
| 1301 | 1293 |
| 1302 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { | 1294 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
| 1303 if (!decoder_flushing_) | 1295 if (!decoder_flushing_) |
| 1304 return; | 1296 return; |
| 1305 | 1297 |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2049 | 2041 |
| 2050 void V4L2VideoDecodeAccelerator::PictureCleared() { | 2042 void V4L2VideoDecodeAccelerator::PictureCleared() { |
| 2051 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 2043 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
| 2052 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 2044 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 2053 DCHECK_GT(picture_clearing_count_, 0); | 2045 DCHECK_GT(picture_clearing_count_, 0); |
| 2054 picture_clearing_count_--; | 2046 picture_clearing_count_--; |
| 2055 SendPictureReady(); | 2047 SendPictureReady(); |
| 2056 } | 2048 } |
| 2057 | 2049 |
| 2058 } // namespace content | 2050 } // namespace content |
| OLD | NEW |