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

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: Handle the offset with a helper class Created 4 years, 12 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 <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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698