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

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 dcheng's comments 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 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 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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698