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