| /* |
| * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/media/engine/videodecodersoftwarefallbackwrapper.h" |
| |
| #include <string> |
| |
| #include "webrtc/media/engine/internaldecoderfactory.h" |
| #include "webrtc/modules/video_coding/include/video_error_codes.h" |
| #include "webrtc/rtc_base/checks.h" |
| #include "webrtc/rtc_base/logging.h" |
| #include "webrtc/rtc_base/trace_event.h" |
| |
| namespace webrtc { |
| |
| VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper( |
| VideoCodecType codec_type, |
| std::unique_ptr<VideoDecoder> decoder) |
| : codec_type_(codec_type), |
| decoder_(std::move(decoder)), |
| decoder_initialized_(false), |
| callback_(nullptr) {} |
| |
| int32_t VideoDecoderSoftwareFallbackWrapper::InitDecode( |
| const VideoCodec* codec_settings, |
| int32_t number_of_cores) { |
| RTC_DCHECK(!fallback_decoder_) << "Fallback decoder should never be " |
| "initialized here, it should've been " |
| "released."; |
| codec_settings_ = *codec_settings; |
| number_of_cores_ = number_of_cores; |
| int32_t ret = decoder_->InitDecode(codec_settings, number_of_cores); |
| if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) { |
| decoder_initialized_ = (ret == WEBRTC_VIDEO_CODEC_OK); |
| return ret; |
| } |
| decoder_initialized_ = false; |
| |
| // Try to initialize fallback decoder. |
| if (InitFallbackDecoder()) |
| return WEBRTC_VIDEO_CODEC_OK; |
| return ret; |
| } |
| |
| bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() { |
| RTC_CHECK(codec_type_ != kVideoCodecUnknown) |
| << "Decoder requesting fallback to codec not supported in software."; |
| LOG(LS_WARNING) << "Decoder falling back to software decoding."; |
| cricket::InternalDecoderFactory internal_decoder_factory; |
| fallback_decoder_.reset( |
| internal_decoder_factory.CreateVideoDecoder(codec_type_)); |
| if (fallback_decoder_->InitDecode(&codec_settings_, number_of_cores_) != |
| WEBRTC_VIDEO_CODEC_OK) { |
| LOG(LS_ERROR) << "Failed to initialize software-decoder fallback."; |
| fallback_decoder_.reset(); |
| return false; |
| } |
| if (callback_) |
| fallback_decoder_->RegisterDecodeCompleteCallback(callback_); |
| fallback_implementation_name_ = |
| std::string(fallback_decoder_->ImplementationName()) + |
| " (fallback from: " + decoder_->ImplementationName() + ")"; |
| return true; |
| } |
| |
| int32_t VideoDecoderSoftwareFallbackWrapper::Decode( |
| const EncodedImage& input_image, |
| bool missing_frames, |
| const RTPFragmentationHeader* fragmentation, |
| const CodecSpecificInfo* codec_specific_info, |
| int64_t render_time_ms) { |
| TRACE_EVENT0("webrtc", "VideoDecoderSoftwareFallbackWrapper::Decode"); |
| // Try initializing and decoding with the provided decoder on every keyframe |
| // or when there's no fallback decoder. This is the normal case. |
| if (!fallback_decoder_ || input_image._frameType == kVideoFrameKey) { |
| int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
| // Try reinitializing the decoder if it had failed before. |
| if (!decoder_initialized_) { |
| decoder_initialized_ = |
| decoder_->InitDecode(&codec_settings_, number_of_cores_) == |
| WEBRTC_VIDEO_CODEC_OK; |
| } |
| if (decoder_initialized_) { |
| ret = decoder_->Decode(input_image, missing_frames, fragmentation, |
| codec_specific_info, render_time_ms); |
| } |
| if (ret == WEBRTC_VIDEO_CODEC_OK) { |
| if (fallback_decoder_) { |
| // Decode OK -> stop using fallback decoder. |
| LOG(LS_WARNING) |
| << "Decode OK, no longer using the software fallback decoder."; |
| fallback_decoder_->Release(); |
| fallback_decoder_.reset(); |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| } |
| if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) |
| return ret; |
| if (!fallback_decoder_) { |
| // Try to initialize fallback decoder. |
| if (!InitFallbackDecoder()) |
| return ret; |
| } |
| } |
| return fallback_decoder_->Decode(input_image, missing_frames, fragmentation, |
| codec_specific_info, render_time_ms); |
| } |
| |
| int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback( |
| DecodedImageCallback* callback) { |
| callback_ = callback; |
| int32_t ret = decoder_->RegisterDecodeCompleteCallback(callback); |
| if (fallback_decoder_) |
| return fallback_decoder_->RegisterDecodeCompleteCallback(callback); |
| return ret; |
| } |
| |
| int32_t VideoDecoderSoftwareFallbackWrapper::Release() { |
| if (fallback_decoder_) { |
| LOG(LS_INFO) << "Releasing software fallback decoder."; |
| fallback_decoder_->Release(); |
| fallback_decoder_.reset(); |
| } |
| decoder_initialized_ = false; |
| return decoder_->Release(); |
| } |
| |
| bool VideoDecoderSoftwareFallbackWrapper::PrefersLateDecoding() const { |
| if (fallback_decoder_) |
| return fallback_decoder_->PrefersLateDecoding(); |
| return decoder_->PrefersLateDecoding(); |
| } |
| |
| const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const { |
| if (fallback_decoder_) |
| return fallback_implementation_name_.c_str(); |
| return decoder_->ImplementationName(); |
| } |
| |
| } // namespace webrtc |