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 kNumVDAErrorsHandled = 5; | |
|
mcasas
2016/03/28 18:15:20
micro-pedantic-nit:
s/kNumVDAErrorsHandled/kNumVDA
emircan
2016/03/29 01:50:50
kNumVDAResetsBeforeSWFallback?
| |
| 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. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 | 154 |
| 154 base::AutoLock auto_lock(lock_); | 155 base::AutoLock auto_lock(lock_); |
| 155 | 156 |
| 156 if (state_ == UNINITIALIZED || !decode_complete_callback_) { | 157 if (state_ == UNINITIALIZED || !decode_complete_callback_) { |
| 157 LOG(ERROR) << "The decoder has not initialized."; | 158 LOG(ERROR) << "The decoder has not initialized."; |
| 158 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 159 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 159 } | 160 } |
| 160 | 161 |
| 161 if (state_ == DECODE_ERROR) { | 162 if (state_ == DECODE_ERROR) { |
| 162 LOG(ERROR) << "Decoding error occurred."; | 163 LOG(ERROR) << "Decoding error occurred."; |
| 164 // Try reseting the session |kNumVDAErrorsHandled| times. | |
| 165 if (num_vda_errors_ > kNumVDAErrorsHandled) { | |
| 166 DVLOG(1) << num_vda_errors_ | |
|
mcasas
2016/03/28 18:15:20
nit: s/DVLOG(1)/DLOG(ERROR)/
emircan
2016/03/29 01:50:50
Done.
| |
| 167 << " errors reported by VDA, falling back to software decode"; | |
| 168 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | |
| 169 } | |
| 170 state_ = RESETTING; | |
| 171 factories_->GetTaskRunner()->PostTask( | |
| 172 FROM_HERE, base::Bind(&RTCVideoDecoder::ResetInternal, | |
| 173 weak_factory_.GetWeakPtr())); | |
| 163 return WEBRTC_VIDEO_CODEC_ERROR; | 174 return WEBRTC_VIDEO_CODEC_ERROR; |
| 164 } | 175 } |
| 165 | 176 |
| 166 if (missingFrames || !inputImage._completeFrame) { | 177 if (missingFrames || !inputImage._completeFrame) { |
| 167 DLOG(ERROR) << "Missing or incomplete frames."; | 178 DLOG(ERROR) << "Missing or incomplete frames."; |
| 168 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. | 179 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. |
| 169 // Return an error to request a key frame. | 180 // Return an error to request a key frame. |
| 170 return WEBRTC_VIDEO_CODEC_ERROR; | 181 return WEBRTC_VIDEO_CODEC_ERROR; |
| 171 } | 182 } |
| 172 | 183 |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 return; | 480 return; |
| 470 | 481 |
| 471 LOG(ERROR) << "VDA Error:" << error; | 482 LOG(ERROR) << "VDA Error:" << error; |
| 472 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", | 483 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", |
| 473 error, | 484 error, |
| 474 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); | 485 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); |
| 475 DestroyVDA(); | 486 DestroyVDA(); |
| 476 | 487 |
| 477 base::AutoLock auto_lock(lock_); | 488 base::AutoLock auto_lock(lock_); |
| 478 state_ = DECODE_ERROR; | 489 state_ = DECODE_ERROR; |
| 490 num_vda_errors_++; | |
|
mcasas
2016/03/28 18:15:20
nit: prefer pre-increment.
I know, I know, we coul
emircan
2016/03/29 01:50:50
Done.
| |
| 479 } | 491 } |
| 480 | 492 |
| 481 void RTCVideoDecoder::RequestBufferDecode() { | 493 void RTCVideoDecoder::RequestBufferDecode() { |
| 482 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 494 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 483 if (!vda_) | 495 if (!vda_) |
| 484 return; | 496 return; |
| 485 | 497 |
| 486 MovePendingBuffersToDecodeBuffers(); | 498 MovePendingBuffersToDecodeBuffers(); |
| 487 | 499 |
| 488 while (CanMoreDecodeWorkBeDone()) { | 500 while (CanMoreDecodeWorkBeDone()) { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 GetSHM_Locked(input_image._length); | 610 GetSHM_Locked(input_image._length); |
| 599 if (!shm_buffer) | 611 if (!shm_buffer) |
| 600 return; | 612 return; |
| 601 SaveToDecodeBuffers_Locked(input_image, std::move(shm_buffer), buffer_data); | 613 SaveToDecodeBuffers_Locked(input_image, std::move(shm_buffer), buffer_data); |
| 602 delete[] input_image._buffer; | 614 delete[] input_image._buffer; |
| 603 pending_buffers_.pop_front(); | 615 pending_buffers_.pop_front(); |
| 604 } | 616 } |
| 605 } | 617 } |
| 606 | 618 |
| 607 void RTCVideoDecoder::ResetInternal() { | 619 void RTCVideoDecoder::ResetInternal() { |
| 620 DVLOG(2) << __FUNCTION__; | |
| 608 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 621 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 609 DVLOG(2) << "ResetInternal"; | 622 |
| 610 if (vda_) | 623 if (vda_) { |
| 611 vda_->Reset(); | 624 vda_->Reset(); |
| 625 } else { | |
| 626 CreateVDA(vda_codec_profile_, nullptr); | |
| 627 } | |
|
mcasas
2016/03/28 18:15:20
No {} for one-liners as I replied to pbos@
(this i
emircan
2016/03/29 01:50:50
Done.
| |
| 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 |