OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/renderer/media/gpu/rtc_video_decoder.h" | 5 #include "content/renderer/media/gpu/rtc_video_decoder.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 #include "base/numerics/safe_conversions.h" | 13 #include "base/numerics/safe_conversions.h" |
14 #include "base/stl_util.h" | |
15 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
16 #include "base/task_runner_util.h" | 15 #include "base/task_runner_util.h" |
17 #include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h" | 16 #include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h" |
18 #include "gpu/command_buffer/common/mailbox_holder.h" | 17 #include "gpu/command_buffer/common/mailbox_holder.h" |
19 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
20 #include "media/renderers/gpu_video_accelerator_factories.h" | 19 #include "media/renderers/gpu_video_accelerator_factories.h" |
21 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
22 #include "third_party/webrtc/base/bind.h" | 21 #include "third_party/webrtc/base/bind.h" |
23 #include "third_party/webrtc/base/refcount.h" | 22 #include "third_party/webrtc/base/refcount.h" |
24 #include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h" | 23 #include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 weak_factory_(this) { | 83 weak_factory_(this) { |
85 DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread()); | 84 DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread()); |
86 } | 85 } |
87 | 86 |
88 RTCVideoDecoder::~RTCVideoDecoder() { | 87 RTCVideoDecoder::~RTCVideoDecoder() { |
89 DVLOG(2) << "~RTCVideoDecoder"; | 88 DVLOG(2) << "~RTCVideoDecoder"; |
90 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 89 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
91 DestroyVDA(); | 90 DestroyVDA(); |
92 | 91 |
93 // Delete all shared memories. | 92 // Delete all shared memories. |
94 base::STLDeleteElements(&available_shm_segments_); | |
95 base::STLDeleteValues(&bitstream_buffers_in_decoder_); | |
96 base::STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), | |
97 decode_buffers_.end()); | |
98 decode_buffers_.clear(); | |
99 ClearPendingBuffers(); | 93 ClearPendingBuffers(); |
100 } | 94 } |
101 | 95 |
102 // static | 96 // static |
103 std::unique_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( | 97 std::unique_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( |
104 webrtc::VideoCodecType type, | 98 webrtc::VideoCodecType type, |
105 media::GpuVideoAcceleratorFactories* factories) { | 99 media::GpuVideoAcceleratorFactories* factories) { |
106 std::unique_ptr<RTCVideoDecoder> decoder; | 100 std::unique_ptr<RTCVideoDecoder> decoder; |
107 // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5717. | 101 // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5717. |
108 #if defined(OS_WIN) | 102 #if defined(OS_WIN) |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 frame->metadata()->SetBoolean(media::VideoFrameMetadata::ALLOW_OVERLAY, | 480 frame->metadata()->SetBoolean(media::VideoFrameMetadata::ALLOW_OVERLAY, |
487 true); | 481 true); |
488 } | 482 } |
489 return frame; | 483 return frame; |
490 } | 484 } |
491 | 485 |
492 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32_t id) { | 486 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32_t id) { |
493 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; | 487 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; |
494 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 488 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
495 | 489 |
496 std::map<int32_t, base::SharedMemory*>::iterator it = | 490 auto it = bitstream_buffers_in_decoder_.find(id); |
497 bitstream_buffers_in_decoder_.find(id); | |
498 if (it == bitstream_buffers_in_decoder_.end()) { | 491 if (it == bitstream_buffers_in_decoder_.end()) { |
499 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 492 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
500 NOTREACHED() << "Missing bitstream buffer: " << id; | 493 NOTREACHED() << "Missing bitstream buffer: " << id; |
501 return; | 494 return; |
502 } | 495 } |
503 | 496 |
504 { | 497 { |
505 base::AutoLock auto_lock(lock_); | 498 base::AutoLock auto_lock(lock_); |
506 PutSHM_Locked(std::unique_ptr<base::SharedMemory>(it->second)); | 499 PutSHM_Locked(std::move(it->second)); |
507 } | 500 } |
508 bitstream_buffers_in_decoder_.erase(it); | 501 bitstream_buffers_in_decoder_.erase(it); |
509 | 502 |
510 RequestBufferDecode(); | 503 RequestBufferDecode(); |
511 } | 504 } |
512 | 505 |
513 void RTCVideoDecoder::NotifyFlushDone() { | 506 void RTCVideoDecoder::NotifyFlushDone() { |
514 DVLOG(3) << "NotifyFlushDone"; | 507 DVLOG(3) << "NotifyFlushDone"; |
515 NOTREACHED() << "Unexpected flush done notification."; | 508 NOTREACHED() << "Unexpected flush done notification."; |
516 } | 509 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 | 548 |
556 while (CanMoreDecodeWorkBeDone()) { | 549 while (CanMoreDecodeWorkBeDone()) { |
557 // Get a buffer and data from the queue. | 550 // Get a buffer and data from the queue. |
558 std::unique_ptr<base::SharedMemory> shm_buffer; | 551 std::unique_ptr<base::SharedMemory> shm_buffer; |
559 BufferData buffer_data; | 552 BufferData buffer_data; |
560 { | 553 { |
561 base::AutoLock auto_lock(lock_); | 554 base::AutoLock auto_lock(lock_); |
562 // Do not request decode if VDA is resetting. | 555 // Do not request decode if VDA is resetting. |
563 if (decode_buffers_.empty() || state_ == RESETTING) | 556 if (decode_buffers_.empty() || state_ == RESETTING) |
564 return; | 557 return; |
565 shm_buffer.reset(decode_buffers_.front().first); | 558 shm_buffer = std::move(decode_buffers_.front().first); |
566 buffer_data = decode_buffers_.front().second; | 559 buffer_data = decode_buffers_.front().second; |
567 decode_buffers_.pop_front(); | 560 decode_buffers_.pop_front(); |
568 // Drop the buffers before Release is called. | 561 // Drop the buffers before Release is called. |
569 if (!IsBufferAfterReset(buffer_data.bitstream_buffer_id, | 562 if (!IsBufferAfterReset(buffer_data.bitstream_buffer_id, |
570 reset_bitstream_buffer_id_)) { | 563 reset_bitstream_buffer_id_)) { |
571 PutSHM_Locked(std::move(shm_buffer)); | 564 PutSHM_Locked(std::move(shm_buffer)); |
572 continue; | 565 continue; |
573 } | 566 } |
574 } | 567 } |
575 | 568 |
576 // Create a BitstreamBuffer and send to VDA to decode. | 569 // Create a BitstreamBuffer and send to VDA to decode. |
577 media::BitstreamBuffer bitstream_buffer( | 570 media::BitstreamBuffer bitstream_buffer( |
578 buffer_data.bitstream_buffer_id, shm_buffer->handle(), buffer_data.size, | 571 buffer_data.bitstream_buffer_id, shm_buffer->handle(), buffer_data.size, |
579 0, base::TimeDelta::FromInternalValue(buffer_data.timestamp)); | 572 0, base::TimeDelta::FromInternalValue(buffer_data.timestamp)); |
580 const bool inserted = | 573 const bool inserted = bitstream_buffers_in_decoder_ |
581 bitstream_buffers_in_decoder_.insert( | 574 .insert(std::make_pair(bitstream_buffer.id(), |
582 std::make_pair(bitstream_buffer.id(), shm_buffer.release())).second; | 575 std::move(shm_buffer))) |
| 576 .second; |
583 DCHECK(inserted) << "bitstream_buffer_id " << bitstream_buffer.id() | 577 DCHECK(inserted) << "bitstream_buffer_id " << bitstream_buffer.id() |
584 << " existed already in bitstream_buffers_in_decoder_"; | 578 << " existed already in bitstream_buffers_in_decoder_"; |
585 RecordBufferData(buffer_data); | 579 RecordBufferData(buffer_data); |
586 vda_->Decode(bitstream_buffer); | 580 vda_->Decode(bitstream_buffer); |
587 } | 581 } |
588 } | 582 } |
589 | 583 |
590 bool RTCVideoDecoder::CanMoreDecodeWorkBeDone() { | 584 bool RTCVideoDecoder::CanMoreDecodeWorkBeDone() { |
591 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; | 585 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; |
592 } | 586 } |
(...skipping 12 matching lines...) Expand all Loading... |
605 if (id_reset == ID_INVALID) | 599 if (id_reset == ID_INVALID) |
606 return id_buffer == 0; | 600 return id_buffer == 0; |
607 return id_buffer == ((id_reset + 1) & ID_LAST); | 601 return id_buffer == ((id_reset + 1) & ID_LAST); |
608 } | 602 } |
609 | 603 |
610 void RTCVideoDecoder::SaveToDecodeBuffers_Locked( | 604 void RTCVideoDecoder::SaveToDecodeBuffers_Locked( |
611 const webrtc::EncodedImage& input_image, | 605 const webrtc::EncodedImage& input_image, |
612 std::unique_ptr<base::SharedMemory> shm_buffer, | 606 std::unique_ptr<base::SharedMemory> shm_buffer, |
613 const BufferData& buffer_data) { | 607 const BufferData& buffer_data) { |
614 memcpy(shm_buffer->memory(), input_image._buffer, input_image._length); | 608 memcpy(shm_buffer->memory(), input_image._buffer, input_image._length); |
615 std::pair<base::SharedMemory*, BufferData> buffer_pair = | |
616 std::make_pair(shm_buffer.release(), buffer_data); | |
617 | 609 |
618 // Store the buffer and the metadata to the queue. | 610 // Store the buffer and the metadata to the queue. |
619 decode_buffers_.push_back(buffer_pair); | 611 decode_buffers_.emplace_back(std::move(shm_buffer), buffer_data); |
620 } | 612 } |
621 | 613 |
622 bool RTCVideoDecoder::SaveToPendingBuffers_Locked( | 614 bool RTCVideoDecoder::SaveToPendingBuffers_Locked( |
623 const webrtc::EncodedImage& input_image, | 615 const webrtc::EncodedImage& input_image, |
624 const BufferData& buffer_data) { | 616 const BufferData& buffer_data) { |
625 DVLOG(2) << "SaveToPendingBuffers_Locked" | 617 DVLOG(2) << "SaveToPendingBuffers_Locked" |
626 << ". pending_buffers size=" << pending_buffers_.size() | 618 << ". pending_buffers size=" << pending_buffers_.size() |
627 << ". decode_buffers_ size=" << decode_buffers_.size() | 619 << ". decode_buffers_ size=" << decode_buffers_.size() |
628 << ". available_shm size=" << available_shm_segments_.size(); | 620 << ". available_shm size=" << available_shm_segments_.size(); |
629 // Queued too many buffers. Something goes wrong. | 621 // Queued too many buffers. Something goes wrong. |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 void RTCVideoDecoder::DestroyVDA() { | 770 void RTCVideoDecoder::DestroyVDA() { |
779 DVLOG(2) << "DestroyVDA"; | 771 DVLOG(2) << "DestroyVDA"; |
780 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 772 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
781 if (vda_) | 773 if (vda_) |
782 vda_.release()->Destroy(); | 774 vda_.release()->Destroy(); |
783 DestroyTextures(); | 775 DestroyTextures(); |
784 | 776 |
785 base::AutoLock auto_lock(lock_); | 777 base::AutoLock auto_lock(lock_); |
786 | 778 |
787 // Put the buffers back in case we restart the decoder. | 779 // Put the buffers back in case we restart the decoder. |
788 for (const auto& buffer : bitstream_buffers_in_decoder_) | 780 for (auto& buffer : bitstream_buffers_in_decoder_) |
789 PutSHM_Locked(std::unique_ptr<base::SharedMemory>(buffer.second)); | 781 PutSHM_Locked(std::move(buffer.second)); |
790 bitstream_buffers_in_decoder_.clear(); | 782 bitstream_buffers_in_decoder_.clear(); |
791 | 783 |
792 state_ = UNINITIALIZED; | 784 state_ = UNINITIALIZED; |
793 } | 785 } |
794 | 786 |
795 std::unique_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked( | 787 std::unique_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked( |
796 size_t min_size) { | 788 size_t min_size) { |
797 // Reuse a SHM if possible. | 789 // Reuse a SHM if possible. |
798 if (!available_shm_segments_.empty() && | 790 if (!available_shm_segments_.empty() && |
799 available_shm_segments_.back()->mapped_size() >= min_size) { | 791 available_shm_segments_.back()->mapped_size() >= min_size) { |
800 std::unique_ptr<base::SharedMemory> buffer(available_shm_segments_.back()); | 792 std::unique_ptr<base::SharedMemory> buffer = |
| 793 std::move(available_shm_segments_.back()); |
801 available_shm_segments_.pop_back(); | 794 available_shm_segments_.pop_back(); |
802 return buffer; | 795 return buffer; |
803 } | 796 } |
804 | 797 |
805 if (available_shm_segments_.size() != num_shm_buffers_) { | 798 if (available_shm_segments_.size() != num_shm_buffers_) { |
806 // Either available_shm_segments_ is empty (and we already have some SHM | 799 // Either available_shm_segments_ is empty (and we already have some SHM |
807 // buffers allocated), or the size of available segments is not large | 800 // buffers allocated), or the size of available segments is not large |
808 // enough. In the former case we need to wait for buffers to be returned, | 801 // enough. In the former case we need to wait for buffers to be returned, |
809 // in the latter we need to wait for all buffers to be returned to drop | 802 // in the latter we need to wait for all buffers to be returned to drop |
810 // them and reallocate with a new size. | 803 // them and reallocate with a new size. |
811 return NULL; | 804 return NULL; |
812 } | 805 } |
813 | 806 |
814 if (num_shm_buffers_ != 0) { | 807 if (num_shm_buffers_ != 0) { |
815 base::STLDeleteElements(&available_shm_segments_); | 808 available_shm_segments_.clear(); |
816 num_shm_buffers_ = 0; | 809 num_shm_buffers_ = 0; |
817 } | 810 } |
818 | 811 |
819 // Create twice as large buffers as required, to avoid frequent reallocation. | 812 // Create twice as large buffers as required, to avoid frequent reallocation. |
820 factories_->GetTaskRunner()->PostTask( | 813 factories_->GetTaskRunner()->PostTask( |
821 FROM_HERE, | 814 FROM_HERE, |
822 base::Bind(&RTCVideoDecoder::CreateSHM, weak_factory_.GetWeakPtr(), | 815 base::Bind(&RTCVideoDecoder::CreateSHM, weak_factory_.GetWeakPtr(), |
823 kNumSharedMemorySegments, min_size * 2)); | 816 kNumSharedMemorySegments, min_size * 2)); |
824 | 817 |
825 // We'll be called again after the shared memory is created. | 818 // We'll be called again after the shared memory is created. |
826 return NULL; | 819 return NULL; |
827 } | 820 } |
828 | 821 |
829 void RTCVideoDecoder::PutSHM_Locked( | 822 void RTCVideoDecoder::PutSHM_Locked( |
830 std::unique_ptr<base::SharedMemory> shm_buffer) { | 823 std::unique_ptr<base::SharedMemory> shm_buffer) { |
831 lock_.AssertAcquired(); | 824 lock_.AssertAcquired(); |
832 available_shm_segments_.push_back(shm_buffer.release()); | 825 available_shm_segments_.push_back(std::move(shm_buffer)); |
833 } | 826 } |
834 | 827 |
835 void RTCVideoDecoder::CreateSHM(size_t count, size_t size) { | 828 void RTCVideoDecoder::CreateSHM(size_t count, size_t size) { |
836 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 829 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
837 DVLOG(2) << "CreateSHM. count=" << count << ", size=" << size; | 830 DVLOG(2) << "CreateSHM. count=" << count << ", size=" << size; |
838 | 831 |
839 for (size_t i = 0; i < count; i++) { | 832 for (size_t i = 0; i < count; i++) { |
840 std::unique_ptr<base::SharedMemory> shm = | 833 std::unique_ptr<base::SharedMemory> shm = |
841 factories_->CreateSharedMemory(size); | 834 factories_->CreateSharedMemory(size); |
842 if (!shm) { | 835 if (!shm) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 } | 886 } |
894 | 887 |
895 void RTCVideoDecoder::ClearPendingBuffers() { | 888 void RTCVideoDecoder::ClearPendingBuffers() { |
896 // Delete WebRTC input buffers. | 889 // Delete WebRTC input buffers. |
897 for (const auto& pending_buffer : pending_buffers_) | 890 for (const auto& pending_buffer : pending_buffers_) |
898 delete[] pending_buffer.first._buffer; | 891 delete[] pending_buffer.first._buffer; |
899 pending_buffers_.clear(); | 892 pending_buffers_.clear(); |
900 } | 893 } |
901 | 894 |
902 } // namespace content | 895 } // namespace content |
OLD | NEW |