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 <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 Loading... | |
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, |
dcheng
2016/03/01 01:48:43
scoped_ptr<SharedMemoryRegion> to have the compile
Owen Lin
2016/03/02 02:50:53
Done.
| |
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 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); |
486 bitstream_buffer.size(), bitstream_buffer.id())); | 482 if (!bitstream_record->shm->Map()) { |
487 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { | |
488 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; | 483 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; |
489 NOTIFY_ERROR(UNREADABLE_INPUT); | 484 NOTIFY_ERROR(UNREADABLE_INPUT); |
490 return; | 485 return; |
491 } | 486 } |
492 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); | 487 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); |
493 | 488 |
494 if (decoder_state_ == kResetting || decoder_flushing_) { | 489 if (decoder_state_ == kResetting || decoder_flushing_) { |
495 // In the case that we're resetting or flushing, we need to delay decoding | 490 // 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 | 491 // 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() | 492 // 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... | |
536 } | 531 } |
537 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); | 532 linked_ptr<BitstreamBufferRef>& buffer_ref = decoder_input_queue_.front(); |
538 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { | 533 if (decoder_delay_bitstream_buffer_id_ == buffer_ref->input_id) { |
539 // We're asked to delay decoding on this and subsequent buffers. | 534 // We're asked to delay decoding on this and subsequent buffers. |
540 return; | 535 return; |
541 } | 536 } |
542 | 537 |
543 // Setup to use the next buffer. | 538 // Setup to use the next buffer. |
544 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); | 539 decoder_current_bitstream_buffer_.reset(buffer_ref.release()); |
545 decoder_input_queue_.pop(); | 540 decoder_input_queue_.pop(); |
546 DVLOG(3) << "DecodeBufferTask(): reading input_id=" | 541 const auto& shm = decoder_current_bitstream_buffer_->shm; |
547 << decoder_current_bitstream_buffer_->input_id | 542 if (shm) { |
548 << ", addr=" << (decoder_current_bitstream_buffer_->shm ? | 543 DVLOG(3) << "DecodeBufferTask(): reading input_id=" |
549 decoder_current_bitstream_buffer_->shm->memory() : | 544 << decoder_current_bitstream_buffer_->input_id |
550 NULL) | 545 << ", addr=" << shm->memory() << ", size=" << shm->size(); |
551 << ", size=" << decoder_current_bitstream_buffer_->size; | 546 } else { |
547 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); | |
548 DVLOG(3) << "DecodeBufferTask(): reading input_id=kFlushBufferId"; | |
549 } | |
552 } | 550 } |
553 bool schedule_task = false; | 551 bool schedule_task = false; |
554 const size_t size = decoder_current_bitstream_buffer_->size; | |
555 size_t decoded_size = 0; | 552 size_t decoded_size = 0; |
556 if (size == 0) { | 553 const auto& shm = decoder_current_bitstream_buffer_->shm; |
557 const int32_t input_id = decoder_current_bitstream_buffer_->input_id; | 554 if (!shm) { |
558 if (input_id >= 0) { | 555 // 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. | 556 DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId); |
557 // Enqueue a buffer guaranteed to be empty. To do that, we flush the | |
558 // current input, enqueue no data to the next frame, then flush that down. | |
559 schedule_task = true; | |
560 if (decoder_current_input_buffer_ != -1 && | |
561 input_buffer_map_[decoder_current_input_buffer_].input_id != | |
562 kFlushBufferId) | |
563 schedule_task = FlushInputFrame(); | |
564 | |
565 if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) { | |
566 DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer"; | |
567 decoder_partial_frame_pending_ = false; | |
560 schedule_task = true; | 568 schedule_task = true; |
561 } else { | 569 } else { |
562 // This is a buffer of zero size, queued to flush the pipe. Flush. | 570 // If we failed to enqueue the empty buffer (due to pipeline |
563 DCHECK_EQ(decoder_current_bitstream_buffer_->shm.get(), | 571 // backpressure), don't advance the bitstream buffer queue, and don't |
564 static_cast<base::SharedMemory*>(NULL)); | 572 // 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 | 573 // reprocessed when the pipeline frees up. |
566 // current input, enqueue no data to the next frame, then flush that down. | 574 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 } | 575 } |
576 } else if (shm->size() == 0) { | |
577 // This is a buffer queued from the client that has zero size. Skip. | |
578 schedule_task = true; | |
585 } else { | 579 } else { |
586 // This is a buffer queued from the client, with actual contents. Decode. | 580 // This is a buffer queued from the client, with actual contents. Decode. |
587 const uint8_t* const data = | 581 const uint8_t* const data = |
588 reinterpret_cast<const uint8_t*>( | 582 reinterpret_cast<const uint8_t*>(shm->memory()) + |
589 decoder_current_bitstream_buffer_->shm->memory()) + | |
590 decoder_current_bitstream_buffer_->bytes_used; | 583 decoder_current_bitstream_buffer_->bytes_used; |
591 const size_t data_size = | 584 const size_t data_size = |
592 decoder_current_bitstream_buffer_->size - | 585 shm->size() - decoder_current_bitstream_buffer_->bytes_used; |
593 decoder_current_bitstream_buffer_->bytes_used; | |
594 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { | 586 if (!AdvanceFrameFragment(data, data_size, &decoded_size)) { |
595 NOTIFY_ERROR(UNREADABLE_INPUT); | 587 NOTIFY_ERROR(UNREADABLE_INPUT); |
596 return; | 588 return; |
597 } | 589 } |
598 // AdvanceFrameFragment should not return a size larger than the buffer | 590 // AdvanceFrameFragment should not return a size larger than the buffer |
599 // size, even on invalid data. | 591 // size, even on invalid data. |
600 CHECK_LE(decoded_size, data_size); | 592 CHECK_LE(decoded_size, data_size); |
601 | 593 |
602 switch (decoder_state_) { | 594 switch (decoder_state_) { |
603 case kInitialized: | 595 case kInitialized: |
604 case kAfterReset: | 596 case kAfterReset: |
605 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); | 597 schedule_task = DecodeBufferInitial(data, decoded_size, &decoded_size); |
606 break; | 598 break; |
607 case kDecoding: | 599 case kDecoding: |
608 schedule_task = DecodeBufferContinue(data, decoded_size); | 600 schedule_task = DecodeBufferContinue(data, decoded_size); |
609 break; | 601 break; |
610 default: | 602 default: |
611 NOTIFY_ERROR(ILLEGAL_STATE); | 603 NOTIFY_ERROR(ILLEGAL_STATE); |
612 return; | 604 return; |
613 } | 605 } |
614 } | 606 } |
615 if (decoder_state_ == kError) { | 607 if (decoder_state_ == kError) { |
616 // Failed during decode. | 608 // Failed during decode. |
617 return; | 609 return; |
618 } | 610 } |
619 | 611 |
620 if (schedule_task) { | 612 if (schedule_task) { |
621 decoder_current_bitstream_buffer_->bytes_used += decoded_size; | 613 decoder_current_bitstream_buffer_->bytes_used += decoded_size; |
622 if (decoder_current_bitstream_buffer_->bytes_used == | 614 if ((shm ? shm->size() : 0) == |
623 decoder_current_bitstream_buffer_->size) { | 615 decoder_current_bitstream_buffer_->bytes_used) { |
624 // Our current bitstream buffer is done; return it. | 616 // Our current bitstream buffer is done; return it. |
625 int32_t input_id = decoder_current_bitstream_buffer_->input_id; | 617 int32_t input_id = decoder_current_bitstream_buffer_->input_id; |
626 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; | 618 DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id; |
627 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). | 619 // BitstreamBufferRef destructor calls NotifyEndOfBitstreamBuffer(). |
628 decoder_current_bitstream_buffer_.reset(); | 620 decoder_current_bitstream_buffer_.reset(); |
629 } | 621 } |
630 ScheduleDecodeBufferTaskIfNeeded(); | 622 ScheduleDecodeBufferTaskIfNeeded(); |
631 } | 623 } |
632 } | 624 } |
633 | 625 |
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1269 DVLOG(2) << "FlushTask(): early out: kError state"; | 1261 DVLOG(2) << "FlushTask(): early out: kError state"; |
1270 return; | 1262 return; |
1271 } | 1263 } |
1272 | 1264 |
1273 // We don't support stacked flushing. | 1265 // We don't support stacked flushing. |
1274 DCHECK(!decoder_flushing_); | 1266 DCHECK(!decoder_flushing_); |
1275 | 1267 |
1276 // Queue up an empty buffer -- this triggers the flush. | 1268 // Queue up an empty buffer -- this triggers the flush. |
1277 decoder_input_queue_.push( | 1269 decoder_input_queue_.push( |
1278 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( | 1270 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( |
1279 io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); | 1271 io_client_, io_task_runner_, nullptr, kFlushBufferId))); |
1280 decoder_flushing_ = true; | 1272 decoder_flushing_ = true; |
1281 SendPictureReady(); // Send all pending PictureReady. | 1273 SendPictureReady(); // Send all pending PictureReady. |
1282 | 1274 |
1283 ScheduleDecodeBufferTaskIfNeeded(); | 1275 ScheduleDecodeBufferTaskIfNeeded(); |
1284 } | 1276 } |
1285 | 1277 |
1286 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { | 1278 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
1287 if (!decoder_flushing_) | 1279 if (!decoder_flushing_) |
1288 return; | 1280 return; |
1289 | 1281 |
(...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2033 | 2025 |
2034 void V4L2VideoDecodeAccelerator::PictureCleared() { | 2026 void V4L2VideoDecodeAccelerator::PictureCleared() { |
2035 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 2027 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
2036 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 2028 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
2037 DCHECK_GT(picture_clearing_count_, 0); | 2029 DCHECK_GT(picture_clearing_count_, 0); |
2038 picture_clearing_count_--; | 2030 picture_clearing_count_--; |
2039 SendPictureReady(); | 2031 SendPictureReady(); |
2040 } | 2032 } |
2041 | 2033 |
2042 } // namespace content | 2034 } // namespace content |
OLD | NEW |