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

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 comment and fix one flush issue Created 4 years, 11 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 19 matching lines...) Expand all
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698