1/*
2 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/video_decoder.h"
12
13#include "webrtc/base/checks.h"
14#include "webrtc/base/logging.h"
15#include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
16#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
17#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
18
19namespace webrtc {
20VideoDecoder* VideoDecoder::Create(VideoDecoder::DecoderType codec_type) {
21  switch (codec_type) {
22    case kH264:
23      RTC_DCHECK(H264Decoder::IsSupported());
24      return H264Decoder::Create();
25    case kVp8:
26      return VP8Decoder::Create();
27    case kVp9:
28      return VP9Decoder::Create();
29    case kUnsupportedCodec:
30      RTC_NOTREACHED();
31      return nullptr;
32  }
33  RTC_NOTREACHED();
34  return nullptr;
35}
36
37VideoDecoder::DecoderType CodecTypeToDecoderType(VideoCodecType codec_type) {
38  switch (codec_type) {
39    case kVideoCodecH264:
40      return VideoDecoder::kH264;
41    case kVideoCodecVP8:
42      return VideoDecoder::kVp8;
43    case kVideoCodecVP9:
44      return VideoDecoder::kVp9;
45    default:
46      return VideoDecoder::kUnsupportedCodec;
47  }
48}
49
50VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
51    VideoCodecType codec_type,
52    VideoDecoder* decoder)
53    : decoder_type_(CodecTypeToDecoderType(codec_type)),
54      decoder_(decoder),
55      callback_(nullptr) {
56}
57
58int32_t VideoDecoderSoftwareFallbackWrapper::InitDecode(
59    const VideoCodec* codec_settings,
60    int32_t number_of_cores) {
61  codec_settings_ = *codec_settings;
62  number_of_cores_ = number_of_cores;
63  return decoder_->InitDecode(codec_settings, number_of_cores);
64}
65
66bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() {
67  RTC_CHECK(decoder_type_ != kUnsupportedCodec)
68      << "Decoder requesting fallback to codec not supported in software.";
69  LOG(LS_WARNING) << "Decoder falling back to software decoding.";
70  fallback_decoder_.reset(VideoDecoder::Create(decoder_type_));
71  if (fallback_decoder_->InitDecode(&codec_settings_, number_of_cores_) !=
72      WEBRTC_VIDEO_CODEC_OK) {
73    LOG(LS_ERROR) << "Failed to initialize software-decoder fallback.";
74    fallback_decoder_.reset();
75    return false;
76  }
77  if (callback_ != nullptr)
78    fallback_decoder_->RegisterDecodeCompleteCallback(callback_);
79  fallback_implementation_name_ =
80      std::string(fallback_decoder_->ImplementationName()) +
81      " (fallback from: " + decoder_->ImplementationName() + ")";
82  return true;
83}
84
85int32_t VideoDecoderSoftwareFallbackWrapper::Decode(
86    const EncodedImage& input_image,
87    bool missing_frames,
88    const RTPFragmentationHeader* fragmentation,
89    const CodecSpecificInfo* codec_specific_info,
90    int64_t render_time_ms) {
91  // Try decoding with the provided decoder on every keyframe or when there's no
92  // fallback decoder. This is the normal case.
93  if (!fallback_decoder_ || input_image._frameType == kVideoFrameKey) {
94    int32_t ret = decoder_->Decode(input_image, missing_frames, fragmentation,
95                                   codec_specific_info, render_time_ms);
96    if (ret == WEBRTC_VIDEO_CODEC_OK) {
97      if (fallback_decoder_) {
98        // Decode OK -> stop using fallback decoder.
99        fallback_decoder_->Release();
100        fallback_decoder_.reset();
101        return WEBRTC_VIDEO_CODEC_OK;
102      }
103    }
104    if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE)
105      return ret;
106    if (!fallback_decoder_) {
107      // Try to initialize fallback decoder.
108      if (!InitFallbackDecoder())
109        return ret;
110    }
111  }
112  return fallback_decoder_->Decode(input_image, missing_frames, fragmentation,
113                                   codec_specific_info, render_time_ms);
114}
115
116int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback(
117    DecodedImageCallback* callback) {
118  callback_ = callback;
119  int32_t ret = decoder_->RegisterDecodeCompleteCallback(callback);
120  if (fallback_decoder_)
121    return fallback_decoder_->RegisterDecodeCompleteCallback(callback);
122  return ret;
123}
124
125int32_t VideoDecoderSoftwareFallbackWrapper::Release() {
126  if (fallback_decoder_)
127    fallback_decoder_->Release();
128  return decoder_->Release();
129}
130
131int32_t VideoDecoderSoftwareFallbackWrapper::Reset() {
132  if (fallback_decoder_)
133    fallback_decoder_->Reset();
134  return decoder_->Reset();
135}
136
137bool VideoDecoderSoftwareFallbackWrapper::PrefersLateDecoding() const {
138  if (fallback_decoder_)
139    return fallback_decoder_->PrefersLateDecoding();
140  return decoder_->PrefersLateDecoding();
141}
142
143const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const {
144  if (fallback_decoder_)
145    return fallback_implementation_name_.c_str();
146  return decoder_->ImplementationName();
147}
148
149}  // namespace webrtc
150