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