Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: content/common/gpu/media/v4l2_video_decode_accelerator.cc

Issue 1541353002: Add offset support to BitstreamBuffer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address review comments and rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 scoped_ptr<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 scoped_ptr<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(std::move(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 361 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 void V4L2VideoDecodeAccelerator::DecodeTask( 471 void V4L2VideoDecodeAccelerator::DecodeTask(
476 const media::BitstreamBuffer& bitstream_buffer) { 472 const media::BitstreamBuffer& bitstream_buffer) {
477 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); 473 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id();
478 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 474 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
479 DCHECK_NE(decoder_state_, kUninitialized); 475 DCHECK_NE(decoder_state_, kUninitialized);
480 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", 476 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id",
481 bitstream_buffer.id()); 477 bitstream_buffer.id());
482 478
483 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( 479 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef(
484 io_client_, io_task_runner_, 480 io_client_, io_task_runner_,
485 new base::SharedMemory(bitstream_buffer.handle(), true), 481 scoped_ptr<SharedMemoryRegion>(
486 bitstream_buffer.size(), bitstream_buffer.id())); 482 new SharedMemoryRegion(bitstream_buffer, true)),
487 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { 483 bitstream_buffer.id()));
484 if (!bitstream_record->shm->Map()) {
488 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; 485 LOG(ERROR) << "Decode(): could not map bitstream_buffer";
489 NOTIFY_ERROR(UNREADABLE_INPUT); 486 NOTIFY_ERROR(UNREADABLE_INPUT);
490 return; 487 return;
491 } 488 }
492 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); 489 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory();
493 490
494 if (decoder_state_ == kResetting || decoder_flushing_) { 491 if (decoder_state_ == kResetting || decoder_flushing_) {
495 // 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
496 // the BitstreamBuffers that come after the Reset() or Flush() call. When 493 // the BitstreamBuffers that come after the Reset() or Flush() call. When
497 // 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
536 } 533 }
537 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); 534 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front();
538 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { 535 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) {
539 // We're asked to delay decoding on this and subsequent buffers. 536 // We're asked to delay decoding on this and subsequent buffers.
540 return; 537 return;
541 } 538 }
542 539
543 // Setup to use the next buffer. 540 // Setup to use the next buffer.
544 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); 541 decoder_current_bitstream_buffer_.reset(buffer_ref.release());
545 decoder_input_queue_.pop(); 542 decoder_input_queue_.pop();
546 DVLOG(3) << "DecodeBufferTask(): reading input_id=" 543 const auto& shm = decoder_current_bitstream_buffer_->shm;
547 << decoder_current_bitstream_buffer_->input_id 544 if (shm) {
548 << ", addr=" << (decoder_current_bitstream_buffer_->shm ? 545 DVLOG(3) << "DecodeBufferTask(): reading input_id="
549 decoder_current_bitstream_buffer_->shm->memory() : 546 << decoder_current_bitstream_buffer_->input_id
550 NULL) 547 << ", addr=" << shm->memory() << ", size=" << shm->size();
551 << ", size=" << decoder_current_bitstream_buffer_->size; 548 } else {
549 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId);
550 DVLOG(3) << "DecodeBufferTask(): reading input_id=kFlushBufferId";
551 }
552 } 552 }
553 bool schedule_task = false; 553 bool schedule_task = false;
554 const size_t size = decoder_current_bitstream_buffer_->size;
555 size_t decoded_size = 0; 554 size_t decoded_size = 0;
556 if (size == 0) { 555 const auto& shm = decoder_current_bitstream_buffer_->shm;
557 const int32_t input_id = decoder_current_bitstream_buffer_->input_id; 556 if (!shm) {
558 if (input_id >= 0) { 557 // This is a dummy buffer, queued to flush the pipe. Flush.
559 // This is a buffer queued from the client that has zero size. Skip. 558 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId);
559 // Enqueue a buffer guaranteed to be empty. To do that, we flush the
560 // current input, enqueue no data to the next frame, then flush that down.
561 schedule_task = true;
562 if (decoder_current_input_buffer_ != -1 &&
563 input_buffer_map_[decoder_current_input_buffer_].input_id !=
564 kFlushBufferId)
565 schedule_task = FlushInputFrame();
566
567 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) {
568 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer";
569 decoder_partial_frame_pending_ = false;
560 schedule_task = true; 570 schedule_task = true;
561 } else { 571 } else {
562 // This is a buffer of zero size, queued to flush the pipe. Flush. 572 // If we failed to enqueue the empty buffer (due to pipeline
563 DCHECK_EQ(decoder_current_bitstream_buffer_->shm.get(), 573 // backpressure), don't advance the bitstream buffer queue, and don't
564 static_cast<base::SharedMemory*>(NULL)); 574 // schedule the next task. This bitstream buffer queue entry will get
565 // Enqueue a buffer guaranteed to be empty. To do that, we flush the 575 // reprocessed when the pipeline frees up.
566 // current input, enqueue no data to the next frame, then flush that down. 576 schedule_task = false;
567 schedule_task = true;
568 if (decoder_current_input_buffer_ != -1 &&
569 input_buffer_map_[decoder_current_input_buffer_].input_id !=
570 kFlushBufferId)
571 schedule_task = FlushInputFrame();
572
573 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) {
574 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer";
575 decoder_partial_frame_pending_ = false;
576 schedule_task = true;
577 } else {
578 // If we failed to enqueue the empty buffer (due to pipeline
579 // backpressure), don't advance the bitstream buffer queue, and don't
580 // schedule the next task. This bitstream buffer queue entry will get
581 // reprocessed when the pipeline frees up.
582 schedule_task = false;
583 }
584 } 577 }
578 } else if (shm->size() == 0) {
579 // This is a buffer queued from the client that has zero size. Skip.
580 schedule_task = true;
585 } else { 581 } else {
586 // This is a buffer queued from the client, with actual contents. Decode. 582 // This is a buffer queued from the client, with actual contents. Decode.
587 const uint8_t* const data = 583 const uint8_t* const data =
588 reinterpret_cast<const uint8_t*>( 584 reinterpret_cast<const uint8_t*>(shm->memory()) +
589 decoder_current_bitstream_buffer_->shm->memory()) +
590 decoder_current_bitstream_buffer_->bytes_used; 585 decoder_current_bitstream_buffer_->bytes_used;
591 const size_t data_size = 586 const size_t data_size =
592 decoder_current_bitstream_buffer_->size - 587 shm->size() - decoder_current_bitstream_buffer_->bytes_used;
593 decoder_current_bitstream_buffer_->bytes_used;
594 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { 588 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) {
595 NOTIFY_ERROR(UNREADABLE_INPUT); 589 NOTIFY_ERROR(UNREADABLE_INPUT);
596 return; 590 return;
597 } 591 }
598 // AdvanceFrameFragment should not return a size larger than the buffer 592 // AdvanceFrameFragment should not return a size larger than the buffer
599 // size, even on invalid data. 593 // size, even on invalid data.
600 CHECK_LE(decoded_size, data_size); 594 CHECK_LE(decoded_size, data_size);
601 595
602 switch (decoder_state_) { 596 switch (decoder_state_) {
603 case kInitialized: 597 case kInitialized:
604 case kAfterReset: 598 case kAfterReset:
605 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); 599 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size);
606 break; 600 break;
607 case kDecoding: 601 case kDecoding:
608 schedule_task = DecodeBufferContinue(data, decoded_size); 602 schedule_task = DecodeBufferContinue(data, decoded_size);
609 break; 603 break;
610 default: 604 default:
611 NOTIFY_ERROR(ILLEGAL_STATE); 605 NOTIFY_ERROR(ILLEGAL_STATE);
612 return; 606 return;
613 } 607 }
614 } 608 }
615 if (decoder_state_ == kError) { 609 if (decoder_state_ == kError) {
616 // Failed during decode. 610 // Failed during decode.
617 return; 611 return;
618 } 612 }
619 613
620 if (schedule_task) { 614 if (schedule_task) {
621 decoder_current_bitstream_buffer_->bytes_used += decoded_size; 615 decoder_current_bitstream_buffer_->bytes_used += decoded_size;
622 if (decoder_current_bitstream_buffer_->bytes_used == 616 if ((shm ? shm->size() : 0) ==
623 decoder_current_bitstream_buffer_->size) { 617 decoder_current_bitstream_buffer_->bytes_used) {
624 // Our current bitstream buffer is done; return it. 618 // Our current bitstream buffer is done; return it.
625 int32_t input_id = decoder_current_bitstream_buffer_->input_id; 619 int32_t input_id = decoder_current_bitstream_buffer_->input_id;
626 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; 620 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id;
627 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). 621 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer().
628 decoder_current_bitstream_buffer_.reset(); 622 decoder_current_bitstream_buffer_.reset();
629 } 623 }
630 ScheduleDecodeBufferTaskIfNeeded(); 624 ScheduleDecodeBufferTaskIfNeeded();
631 } 625 }
632 } 626 }
633 627
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after
1269 DVLOG(2) << "FlushTask(): early out: kError state"; 1263 DVLOG(2) << "FlushTask(): early out: kError state";
1270 return; 1264 return;
1271 } 1265 }
1272 1266
1273 // We don't support stacked flushing. 1267 // We don't support stacked flushing.
1274 DCHECK(!decoder_flushing_); 1268 DCHECK(!decoder_flushing_);
1275 1269
1276 // Queue up an empty buffer -- this triggers the flush. 1270 // Queue up an empty buffer -- this triggers the flush.
1277 decoder_input_queue_.push( 1271 decoder_input_queue_.push(
1278 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( 1272 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef(
1279 io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); 1273 io_client_, io_task_runner_, nullptr, kFlushBufferId)));
1280 decoder_flushing_ = true; 1274 decoder_flushing_ = true;
1281 SendPictureReady(); // Send all pending PictureReady. 1275 SendPictureReady(); // Send all pending PictureReady.
1282 1276
1283 ScheduleDecodeBufferTaskIfNeeded(); 1277 ScheduleDecodeBufferTaskIfNeeded();
1284 } 1278 }
1285 1279
1286 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { 1280 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() {
1287 if (!decoder_flushing_) 1281 if (!decoder_flushing_)
1288 return; 1282 return;
1289 1283
(...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after
2033 2027
2034 void V4L2VideoDecodeAccelerator::PictureCleared() { 2028 void V4L2VideoDecodeAccelerator::PictureCleared() {
2035 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; 2029 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_;
2036 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 2030 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
2037 DCHECK_GT(picture_clearing_count_, 0); 2031 DCHECK_GT(picture_clearing_count_, 0);
2038 picture_clearing_count_--; 2032 picture_clearing_count_--;
2039 SendPictureReady(); 2033 SendPictureReady();
2040 } 2034 }
2041 2035
2042 } // namespace content 2036 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698