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 <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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |