Chromium Code Reviews| 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/rtc_video_decoder.h" | 5 #include "content/renderer/media/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" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "third_party/skia/include/core/SkBitmap.h" | 21 #include "third_party/skia/include/core/SkBitmap.h" |
| 22 #include "third_party/webrtc/base/bind.h" | 22 #include "third_party/webrtc/base/bind.h" |
| 23 #include "third_party/webrtc/base/refcount.h" | 23 #include "third_party/webrtc/base/refcount.h" |
| 24 #include "third_party/webrtc/video_frame.h" | 24 #include "third_party/webrtc/video_frame.h" |
| 25 | 25 |
| 26 namespace content { | 26 namespace content { |
| 27 | 27 |
| 28 const int32_t RTCVideoDecoder::ID_LAST = 0x3FFFFFFF; | 28 const int32_t RTCVideoDecoder::ID_LAST = 0x3FFFFFFF; |
| 29 const int32_t RTCVideoDecoder::ID_HALF = 0x20000000; | 29 const int32_t RTCVideoDecoder::ID_HALF = 0x20000000; |
| 30 const int32_t RTCVideoDecoder::ID_INVALID = -1; | 30 const int32_t RTCVideoDecoder::ID_INVALID = -1; |
| 31 const uint32_t kNumVDAResetsBeforeSWFallback = 5; | |
| 31 | 32 |
| 32 // Maximum number of concurrent VDA::Decode() operations RVD will maintain. | 33 // Maximum number of concurrent VDA::Decode() operations RVD will maintain. |
| 33 // Higher values allow better pipelining in the GPU, but also require more | 34 // Higher values allow better pipelining in the GPU, but also require more |
| 34 // resources. | 35 // resources. |
| 35 static const size_t kMaxInFlightDecodes = 8; | 36 static const size_t kMaxInFlightDecodes = 8; |
| 36 | 37 |
| 37 // Number of allocated shared memory segments. | 38 // Number of allocated shared memory segments. |
| 38 static const size_t kNumSharedMemorySegments = 16; | 39 static const size_t kNumSharedMemorySegments = 16; |
| 39 | 40 |
| 40 // Maximum number of pending WebRTC buffers that are waiting for shared memory. | 41 // Maximum number of pending WebRTC buffers that are waiting for shared memory. |
| 41 static const size_t kMaxNumOfPendingBuffers = 8; | 42 static const size_t kMaxNumOfPendingBuffers = 8; |
| 42 | 43 |
| 43 RTCVideoDecoder::BufferData::BufferData(int32_t bitstream_buffer_id, | 44 RTCVideoDecoder::BufferData::BufferData(int32_t bitstream_buffer_id, |
| 44 uint32_t timestamp, | 45 uint32_t timestamp, |
| 45 size_t size, | 46 size_t size, |
| 46 const gfx::Rect& visible_rect) | 47 const gfx::Rect& visible_rect) |
| 47 : bitstream_buffer_id(bitstream_buffer_id), | 48 : bitstream_buffer_id(bitstream_buffer_id), |
| 48 timestamp(timestamp), | 49 timestamp(timestamp), |
| 49 size(size), | 50 size(size), |
| 50 visible_rect(visible_rect) {} | 51 visible_rect(visible_rect) {} |
| 51 | 52 |
| 52 RTCVideoDecoder::BufferData::BufferData() {} | 53 RTCVideoDecoder::BufferData::BufferData() {} |
| 53 | 54 |
| 54 RTCVideoDecoder::BufferData::~BufferData() {} | 55 RTCVideoDecoder::BufferData::~BufferData() {} |
| 55 | 56 |
| 56 RTCVideoDecoder::RTCVideoDecoder(webrtc::VideoCodecType type, | 57 RTCVideoDecoder::RTCVideoDecoder(webrtc::VideoCodecType type, |
| 57 media::GpuVideoAcceleratorFactories* factories) | 58 media::GpuVideoAcceleratorFactories* factories) |
| 58 : video_codec_type_(type), | 59 : num_vda_errors_(0), |
| 60 video_codec_type_(type), | |
| 59 factories_(factories), | 61 factories_(factories), |
| 60 decoder_texture_target_(0), | 62 decoder_texture_target_(0), |
| 61 next_picture_buffer_id_(0), | 63 next_picture_buffer_id_(0), |
| 62 state_(UNINITIALIZED), | 64 state_(UNINITIALIZED), |
| 63 decode_complete_callback_(nullptr), | 65 decode_complete_callback_(nullptr), |
| 64 num_shm_buffers_(0), | 66 num_shm_buffers_(0), |
| 65 next_bitstream_buffer_id_(0), | 67 next_bitstream_buffer_id_(0), |
| 66 reset_bitstream_buffer_id_(ID_INVALID), | 68 reset_bitstream_buffer_id_(ID_INVALID), |
| 67 weak_factory_(this) { | 69 weak_factory_(this) { |
| 68 DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread()); | 70 DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread()); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 | 155 |
| 154 base::AutoLock auto_lock(lock_); | 156 base::AutoLock auto_lock(lock_); |
| 155 | 157 |
| 156 if (state_ == UNINITIALIZED || !decode_complete_callback_) { | 158 if (state_ == UNINITIALIZED || !decode_complete_callback_) { |
| 157 LOG(ERROR) << "The decoder has not initialized."; | 159 LOG(ERROR) << "The decoder has not initialized."; |
| 158 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 160 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 159 } | 161 } |
| 160 | 162 |
| 161 if (state_ == DECODE_ERROR) { | 163 if (state_ == DECODE_ERROR) { |
| 162 LOG(ERROR) << "Decoding error occurred."; | 164 LOG(ERROR) << "Decoding error occurred."; |
| 165 // Try reseting the session |kNumVDAErrorsHandled| times. | |
| 166 if (num_vda_errors_ > kNumVDAResetsBeforeSWFallback) { | |
| 167 DLOG(ERROR) << num_vda_errors_ | |
| 168 << " errors reported by VDA, falling back to software decode"; | |
| 169 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | |
|
hbos_chromium
2016/03/29 12:28:19
What if there is no SW decoder available? Would it
emircan
2016/03/29 19:37:55
That logic is handled in the WebRTC side: https://
hbos_chromium
2016/03/30 16:43:39
Yeah, makes sense. Let's not assume HW errors occu
| |
| 170 } | |
| 171 state_ = RESETTING; | |
| 172 factories_->GetTaskRunner()->PostTask( | |
| 173 FROM_HERE, base::Bind(&RTCVideoDecoder::ResetInternal, | |
| 174 weak_factory_.GetWeakPtr())); | |
| 163 return WEBRTC_VIDEO_CODEC_ERROR; | 175 return WEBRTC_VIDEO_CODEC_ERROR; |
| 164 } | 176 } |
| 165 | 177 |
| 166 if (missingFrames || !inputImage._completeFrame) { | 178 if (missingFrames || !inputImage._completeFrame) { |
| 167 DLOG(ERROR) << "Missing or incomplete frames."; | 179 DLOG(ERROR) << "Missing or incomplete frames."; |
| 168 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. | 180 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. |
| 169 // Return an error to request a key frame. | 181 // Return an error to request a key frame. |
| 170 return WEBRTC_VIDEO_CODEC_ERROR; | 182 return WEBRTC_VIDEO_CODEC_ERROR; |
| 171 } | 183 } |
| 172 | 184 |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 return; | 481 return; |
| 470 | 482 |
| 471 LOG(ERROR) << "VDA Error:" << error; | 483 LOG(ERROR) << "VDA Error:" << error; |
| 472 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", | 484 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", |
| 473 error, | 485 error, |
| 474 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); | 486 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); |
| 475 DestroyVDA(); | 487 DestroyVDA(); |
| 476 | 488 |
| 477 base::AutoLock auto_lock(lock_); | 489 base::AutoLock auto_lock(lock_); |
| 478 state_ = DECODE_ERROR; | 490 state_ = DECODE_ERROR; |
| 491 ++num_vda_errors_; | |
| 479 } | 492 } |
| 480 | 493 |
| 481 void RTCVideoDecoder::RequestBufferDecode() { | 494 void RTCVideoDecoder::RequestBufferDecode() { |
| 482 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 495 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 483 if (!vda_) | 496 if (!vda_) |
| 484 return; | 497 return; |
| 485 | 498 |
| 486 MovePendingBuffersToDecodeBuffers(); | 499 MovePendingBuffersToDecodeBuffers(); |
| 487 | 500 |
| 488 while (CanMoreDecodeWorkBeDone()) { | 501 while (CanMoreDecodeWorkBeDone()) { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 GetSHM_Locked(input_image._length); | 611 GetSHM_Locked(input_image._length); |
| 599 if (!shm_buffer) | 612 if (!shm_buffer) |
| 600 return; | 613 return; |
| 601 SaveToDecodeBuffers_Locked(input_image, std::move(shm_buffer), buffer_data); | 614 SaveToDecodeBuffers_Locked(input_image, std::move(shm_buffer), buffer_data); |
| 602 delete[] input_image._buffer; | 615 delete[] input_image._buffer; |
| 603 pending_buffers_.pop_front(); | 616 pending_buffers_.pop_front(); |
| 604 } | 617 } |
| 605 } | 618 } |
| 606 | 619 |
| 607 void RTCVideoDecoder::ResetInternal() { | 620 void RTCVideoDecoder::ResetInternal() { |
| 621 DVLOG(2) << __FUNCTION__; | |
| 608 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 622 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 609 DVLOG(2) << "ResetInternal"; | 623 |
| 610 if (vda_) | 624 if (vda_) |
| 611 vda_->Reset(); | 625 vda_->Reset(); |
| 626 else | |
| 627 CreateVDA(vda_codec_profile_, nullptr); | |
| 612 } | 628 } |
| 613 | 629 |
| 614 // static | 630 // static |
| 615 void RTCVideoDecoder::ReleaseMailbox( | 631 void RTCVideoDecoder::ReleaseMailbox( |
| 616 base::WeakPtr<RTCVideoDecoder> decoder, | 632 base::WeakPtr<RTCVideoDecoder> decoder, |
| 617 media::GpuVideoAcceleratorFactories* factories, | 633 media::GpuVideoAcceleratorFactories* factories, |
| 618 int64_t picture_buffer_id, | 634 int64_t picture_buffer_id, |
| 619 uint32_t texture_id, | 635 uint32_t texture_id, |
| 620 const gpu::SyncToken& release_sync_token) { | 636 const gpu::SyncToken& release_sync_token) { |
| 621 DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread()); | 637 DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 673 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 689 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 674 | 690 |
| 675 if (!IsProfileSupported(profile)) { | 691 if (!IsProfileSupported(profile)) { |
| 676 DVLOG(1) << "Unsupported profile " << profile; | 692 DVLOG(1) << "Unsupported profile " << profile; |
| 677 } else { | 693 } else { |
| 678 vda_ = factories_->CreateVideoDecodeAccelerator(); | 694 vda_ = factories_->CreateVideoDecodeAccelerator(); |
| 679 | 695 |
| 680 media::VideoDecodeAccelerator::Config config(profile); | 696 media::VideoDecodeAccelerator::Config config(profile); |
| 681 if (vda_ && !vda_->Initialize(config, this)) | 697 if (vda_ && !vda_->Initialize(config, this)) |
| 682 vda_.release()->Destroy(); | 698 vda_.release()->Destroy(); |
| 699 vda_codec_profile_ = profile; | |
| 683 } | 700 } |
| 684 | 701 |
| 685 waiter->Signal(); | 702 if (waiter) |
| 703 waiter->Signal(); | |
| 686 } | 704 } |
| 687 | 705 |
| 688 void RTCVideoDecoder::DestroyTextures() { | 706 void RTCVideoDecoder::DestroyTextures() { |
| 689 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 707 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 690 | 708 |
| 691 // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since | 709 // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since |
| 692 // their textures may still be in use by the user of this RTCVideoDecoder. | 710 // their textures may still be in use by the user of this RTCVideoDecoder. |
| 693 for (const auto& picture_buffer_at_display : picture_buffers_at_display_) | 711 for (const auto& picture_buffer_at_display : picture_buffers_at_display_) |
| 694 assigned_picture_buffers_.erase(picture_buffer_at_display.first); | 712 assigned_picture_buffers_.erase(picture_buffer_at_display.first); |
| 695 | 713 |
| 696 for (const auto& assigned_picture_buffer : assigned_picture_buffers_) | 714 for (const auto& assigned_picture_buffer : assigned_picture_buffers_) |
| 697 factories_->DeleteTexture(assigned_picture_buffer.second.texture_id()); | 715 factories_->DeleteTexture(assigned_picture_buffer.second.texture_id()); |
| 698 | 716 |
| 699 assigned_picture_buffers_.clear(); | 717 assigned_picture_buffers_.clear(); |
| 700 } | 718 } |
| 701 | 719 |
| 702 void RTCVideoDecoder::DestroyVDA() { | 720 void RTCVideoDecoder::DestroyVDA() { |
| 703 DVLOG(2) << "DestroyVDA"; | 721 DVLOG(2) << "DestroyVDA"; |
| 704 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 722 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 705 if (vda_) | 723 if (vda_) |
| 706 vda_.release()->Destroy(); | 724 vda_.release()->Destroy(); |
| 707 DestroyTextures(); | 725 DestroyTextures(); |
| 726 | |
| 708 base::AutoLock auto_lock(lock_); | 727 base::AutoLock auto_lock(lock_); |
| 728 | |
| 729 // Put the buffers back in case we restart the decoder. | |
| 730 for (const auto& buffer : bitstream_buffers_in_decoder_) | |
| 731 PutSHM_Locked(scoped_ptr<base::SharedMemory>(buffer.second)); | |
| 732 bitstream_buffers_in_decoder_.clear(); | |
| 733 | |
| 709 state_ = UNINITIALIZED; | 734 state_ = UNINITIALIZED; |
| 710 } | 735 } |
| 711 | 736 |
| 712 scoped_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked(size_t min_size) { | 737 scoped_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked(size_t min_size) { |
| 713 // Reuse a SHM if possible. | 738 // Reuse a SHM if possible. |
| 714 if (!available_shm_segments_.empty() && | 739 if (!available_shm_segments_.empty() && |
| 715 available_shm_segments_.back()->mapped_size() >= min_size) { | 740 available_shm_segments_.back()->mapped_size() >= min_size) { |
| 716 scoped_ptr<base::SharedMemory> buffer(available_shm_segments_.back()); | 741 scoped_ptr<base::SharedMemory> buffer(available_shm_segments_.back()); |
| 717 available_shm_segments_.pop_back(); | 742 available_shm_segments_.pop_back(); |
| 718 return buffer; | 743 return buffer; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 807 } | 832 } |
| 808 | 833 |
| 809 void RTCVideoDecoder::ClearPendingBuffers() { | 834 void RTCVideoDecoder::ClearPendingBuffers() { |
| 810 // Delete WebRTC input buffers. | 835 // Delete WebRTC input buffers. |
| 811 for (const auto& pending_buffer : pending_buffers_) | 836 for (const auto& pending_buffer : pending_buffers_) |
| 812 delete[] pending_buffer.first._buffer; | 837 delete[] pending_buffer.first._buffer; |
| 813 pending_buffers_.clear(); | 838 pending_buffers_.clear(); |
| 814 } | 839 } |
| 815 | 840 |
| 816 } // namespace content | 841 } // namespace content |
| OLD | NEW |