| 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/system_wrappers/include/ref_count.h" | 23 #include "third_party/webrtc/system_wrappers/include/ref_count.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; |
| 170 } |
| 171 base::AutoUnlock auto_unlock(lock_); |
| 172 Release(); |
| 163 return WEBRTC_VIDEO_CODEC_ERROR; | 173 return WEBRTC_VIDEO_CODEC_ERROR; |
| 164 } | 174 } |
| 165 | 175 |
| 166 if (missingFrames || !inputImage._completeFrame) { | 176 if (missingFrames || !inputImage._completeFrame) { |
| 167 DLOG(ERROR) << "Missing or incomplete frames."; | 177 DLOG(ERROR) << "Missing or incomplete frames."; |
| 168 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. | 178 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. |
| 169 // Return an error to request a key frame. | 179 // Return an error to request a key frame. |
| 170 return WEBRTC_VIDEO_CODEC_ERROR; | 180 return WEBRTC_VIDEO_CODEC_ERROR; |
| 171 } | 181 } |
| 172 | 182 |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 return; | 479 return; |
| 470 | 480 |
| 471 LOG(ERROR) << "VDA Error:" << error; | 481 LOG(ERROR) << "VDA Error:" << error; |
| 472 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", | 482 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", |
| 473 error, | 483 error, |
| 474 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); | 484 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); |
| 475 DestroyVDA(); | 485 DestroyVDA(); |
| 476 | 486 |
| 477 base::AutoLock auto_lock(lock_); | 487 base::AutoLock auto_lock(lock_); |
| 478 state_ = DECODE_ERROR; | 488 state_ = DECODE_ERROR; |
| 489 ++num_vda_errors_; |
| 479 } | 490 } |
| 480 | 491 |
| 481 void RTCVideoDecoder::RequestBufferDecode() { | 492 void RTCVideoDecoder::RequestBufferDecode() { |
| 482 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 493 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 483 if (!vda_) | 494 if (!vda_) |
| 484 return; | 495 return; |
| 485 | 496 |
| 486 MovePendingBuffersToDecodeBuffers(); | 497 MovePendingBuffersToDecodeBuffers(); |
| 487 | 498 |
| 488 while (CanMoreDecodeWorkBeDone()) { | 499 while (CanMoreDecodeWorkBeDone()) { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 GetSHM_Locked(input_image._length); | 609 GetSHM_Locked(input_image._length); |
| 599 if (!shm_buffer) | 610 if (!shm_buffer) |
| 600 return; | 611 return; |
| 601 SaveToDecodeBuffers_Locked(input_image, std::move(shm_buffer), buffer_data); | 612 SaveToDecodeBuffers_Locked(input_image, std::move(shm_buffer), buffer_data); |
| 602 delete[] input_image._buffer; | 613 delete[] input_image._buffer; |
| 603 pending_buffers_.pop_front(); | 614 pending_buffers_.pop_front(); |
| 604 } | 615 } |
| 605 } | 616 } |
| 606 | 617 |
| 607 void RTCVideoDecoder::ResetInternal() { | 618 void RTCVideoDecoder::ResetInternal() { |
| 619 DVLOG(2) << __FUNCTION__; |
| 608 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 620 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 609 DVLOG(2) << "ResetInternal"; | 621 |
| 610 if (vda_) | 622 if (vda_) { |
| 611 vda_->Reset(); | 623 vda_->Reset(); |
| 624 } else { |
| 625 CreateVDA(vda_codec_profile_, nullptr); |
| 626 if (vda_) |
| 627 state_ = INITIALIZED; |
| 628 } |
| 612 } | 629 } |
| 613 | 630 |
| 614 // static | 631 // static |
| 615 void RTCVideoDecoder::ReleaseMailbox( | 632 void RTCVideoDecoder::ReleaseMailbox( |
| 616 base::WeakPtr<RTCVideoDecoder> decoder, | 633 base::WeakPtr<RTCVideoDecoder> decoder, |
| 617 media::GpuVideoAcceleratorFactories* factories, | 634 media::GpuVideoAcceleratorFactories* factories, |
| 618 int64_t picture_buffer_id, | 635 int64_t picture_buffer_id, |
| 619 uint32_t texture_id, | 636 uint32_t texture_id, |
| 620 const gpu::SyncToken& release_sync_token) { | 637 const gpu::SyncToken& release_sync_token) { |
| 621 DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread()); | 638 DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 690 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 674 | 691 |
| 675 if (!IsProfileSupported(profile)) { | 692 if (!IsProfileSupported(profile)) { |
| 676 DVLOG(1) << "Unsupported profile " << profile; | 693 DVLOG(1) << "Unsupported profile " << profile; |
| 677 } else { | 694 } else { |
| 678 vda_ = factories_->CreateVideoDecodeAccelerator(); | 695 vda_ = factories_->CreateVideoDecodeAccelerator(); |
| 679 | 696 |
| 680 media::VideoDecodeAccelerator::Config config(profile); | 697 media::VideoDecodeAccelerator::Config config(profile); |
| 681 if (vda_ && !vda_->Initialize(config, this)) | 698 if (vda_ && !vda_->Initialize(config, this)) |
| 682 vda_.release()->Destroy(); | 699 vda_.release()->Destroy(); |
| 700 vda_codec_profile_ = profile; |
| 683 } | 701 } |
| 684 | 702 |
| 685 waiter->Signal(); | 703 if (waiter) |
| 704 waiter->Signal(); |
| 686 } | 705 } |
| 687 | 706 |
| 688 void RTCVideoDecoder::DestroyTextures() { | 707 void RTCVideoDecoder::DestroyTextures() { |
| 689 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 708 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 690 | 709 |
| 691 // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since | 710 // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since |
| 692 // their textures may still be in use by the user of this RTCVideoDecoder. | 711 // 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_) | 712 for (const auto& picture_buffer_at_display : picture_buffers_at_display_) |
| 694 assigned_picture_buffers_.erase(picture_buffer_at_display.first); | 713 assigned_picture_buffers_.erase(picture_buffer_at_display.first); |
| 695 | 714 |
| 696 for (const auto& assigned_picture_buffer : assigned_picture_buffers_) | 715 for (const auto& assigned_picture_buffer : assigned_picture_buffers_) |
| 697 factories_->DeleteTexture(assigned_picture_buffer.second.texture_id()); | 716 factories_->DeleteTexture(assigned_picture_buffer.second.texture_id()); |
| 698 | 717 |
| 699 assigned_picture_buffers_.clear(); | 718 assigned_picture_buffers_.clear(); |
| 700 } | 719 } |
| 701 | 720 |
| 702 void RTCVideoDecoder::DestroyVDA() { | 721 void RTCVideoDecoder::DestroyVDA() { |
| 703 DVLOG(2) << "DestroyVDA"; | 722 DVLOG(2) << "DestroyVDA"; |
| 704 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 723 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 705 if (vda_) | 724 if (vda_) |
| 706 vda_.release()->Destroy(); | 725 vda_.release()->Destroy(); |
| 707 DestroyTextures(); | 726 DestroyTextures(); |
| 727 |
| 708 base::AutoLock auto_lock(lock_); | 728 base::AutoLock auto_lock(lock_); |
| 729 |
| 730 // Put the buffers back in case we restart the decoder. |
| 731 for (const auto& buffer : bitstream_buffers_in_decoder_) |
| 732 PutSHM_Locked(scoped_ptr<base::SharedMemory>(buffer.second)); |
| 733 bitstream_buffers_in_decoder_.clear(); |
| 734 |
| 709 state_ = UNINITIALIZED; | 735 state_ = UNINITIALIZED; |
| 710 } | 736 } |
| 711 | 737 |
| 712 scoped_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked(size_t min_size) { | 738 scoped_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked(size_t min_size) { |
| 713 // Reuse a SHM if possible. | 739 // Reuse a SHM if possible. |
| 714 if (!available_shm_segments_.empty() && | 740 if (!available_shm_segments_.empty() && |
| 715 available_shm_segments_.back()->mapped_size() >= min_size) { | 741 available_shm_segments_.back()->mapped_size() >= min_size) { |
| 716 scoped_ptr<base::SharedMemory> buffer(available_shm_segments_.back()); | 742 scoped_ptr<base::SharedMemory> buffer(available_shm_segments_.back()); |
| 717 available_shm_segments_.pop_back(); | 743 available_shm_segments_.pop_back(); |
| 718 return buffer; | 744 return buffer; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 } | 833 } |
| 808 | 834 |
| 809 void RTCVideoDecoder::ClearPendingBuffers() { | 835 void RTCVideoDecoder::ClearPendingBuffers() { |
| 810 // Delete WebRTC input buffers. | 836 // Delete WebRTC input buffers. |
| 811 for (const auto& pending_buffer : pending_buffers_) | 837 for (const auto& pending_buffer : pending_buffers_) |
| 812 delete[] pending_buffer.first._buffer; | 838 delete[] pending_buffer.first._buffer; |
| 813 pending_buffers_.clear(); | 839 pending_buffers_.clear(); |
| 814 } | 840 } |
| 815 | 841 |
| 816 } // namespace content | 842 } // namespace content |
| OLD | NEW |