Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(999)

Side by Side Diff: content/renderer/media/rtc_video_decoder.cc

Issue 1817573004: Handle HW decode failures in RTCVideoDecoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/renderer/media/rtc_video_decoder.h ('k') | content/renderer/media/rtc_video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698