tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

video_decoder_software_fallback_wrapper.cc (9846B)


      1 /*
      2 *  Copyright (c) 2016 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 "api/video_codecs/video_decoder_software_fallback_wrapper.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 #include <memory>
     16 #include <string>
     17 #include <utility>
     18 
     19 #include "api/environment/environment.h"
     20 #include "api/field_trials_view.h"
     21 #include "api/video/encoded_image.h"
     22 #include "api/video/video_codec_type.h"
     23 #include "api/video/video_frame_type.h"
     24 #include "api/video_codecs/video_decoder.h"
     25 #include "modules/video_coding/include/video_error_codes.h"
     26 #include "rtc_base/checks.h"
     27 #include "rtc_base/logging.h"
     28 #include "rtc_base/trace_event.h"
     29 #include "system_wrappers/include/metrics.h"
     30 
     31 namespace webrtc {
     32 
     33 namespace {
     34 
     35 constexpr size_t kMaxConsequtiveHwErrors = 4;
     36 
     37 class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
     38 public:
     39  VideoDecoderSoftwareFallbackWrapper(
     40      const Environment& env,
     41      std::unique_ptr<VideoDecoder> sw_fallback_decoder,
     42      std::unique_ptr<VideoDecoder> hw_decoder);
     43  ~VideoDecoderSoftwareFallbackWrapper() override;
     44 
     45  bool Configure(const Settings& settings) override;
     46 
     47  int32_t Decode(const EncodedImage& input_image,
     48                 int64_t render_time_ms) override;
     49 
     50  int32_t RegisterDecodeCompleteCallback(
     51      DecodedImageCallback* callback) override;
     52 
     53  int32_t Release() override;
     54 
     55  DecoderInfo GetDecoderInfo() const override;
     56  const char* ImplementationName() const override;
     57 
     58 private:
     59  bool InitFallbackDecoder();
     60  void UpdateFallbackDecoderHistograms();
     61 
     62  bool InitHwDecoder();
     63 
     64  VideoDecoder& active_decoder() const;
     65 
     66  // Determines if we are trying to use the HW or SW decoder.
     67  enum class DecoderType {
     68    kNone,
     69    kHardware,
     70    kFallback,
     71  } decoder_type_;
     72  std::unique_ptr<VideoDecoder> hw_decoder_;
     73 
     74  const bool force_sw_decoder_fallback_;
     75  Settings decoder_settings_;
     76  const std::unique_ptr<VideoDecoder> fallback_decoder_;
     77  const std::string fallback_implementation_name_;
     78  DecodedImageCallback* callback_;
     79  int32_t hw_decoded_frames_since_last_fallback_;
     80  size_t hw_consequtive_generic_errors_;
     81 };
     82 
     83 VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
     84    const Environment& env,
     85    std::unique_ptr<VideoDecoder> sw_fallback_decoder,
     86    std::unique_ptr<VideoDecoder> hw_decoder)
     87    : decoder_type_(DecoderType::kNone),
     88      hw_decoder_(std::move(hw_decoder)),
     89      force_sw_decoder_fallback_(
     90          env.field_trials().IsEnabled("WebRTC-Video-ForcedSwDecoderFallback")),
     91      fallback_decoder_(std::move(sw_fallback_decoder)),
     92      fallback_implementation_name_(
     93          fallback_decoder_->GetDecoderInfo().implementation_name +
     94          " (fallback from: " +
     95          hw_decoder_->GetDecoderInfo().implementation_name + ")"),
     96      callback_(nullptr),
     97      hw_decoded_frames_since_last_fallback_(0),
     98      hw_consequtive_generic_errors_(0) {}
     99 VideoDecoderSoftwareFallbackWrapper::~VideoDecoderSoftwareFallbackWrapper() =
    100    default;
    101 
    102 bool VideoDecoderSoftwareFallbackWrapper::Configure(const Settings& settings) {
    103  decoder_settings_ = settings;
    104 
    105  if (force_sw_decoder_fallback_) {
    106    RTC_LOG(LS_INFO) << "Forced software decoder fallback enabled.";
    107    RTC_DCHECK(decoder_type_ == DecoderType::kNone);
    108    return InitFallbackDecoder();
    109  }
    110  if (InitHwDecoder()) {
    111    return true;
    112  }
    113 
    114  RTC_DCHECK(decoder_type_ == DecoderType::kNone);
    115  return InitFallbackDecoder();
    116 }
    117 
    118 bool VideoDecoderSoftwareFallbackWrapper::InitHwDecoder() {
    119  RTC_DCHECK(decoder_type_ == DecoderType::kNone);
    120  if (!hw_decoder_->Configure(decoder_settings_)) {
    121    return false;
    122  }
    123 
    124  decoder_type_ = DecoderType::kHardware;
    125  if (callback_)
    126    hw_decoder_->RegisterDecodeCompleteCallback(callback_);
    127  return true;
    128 }
    129 
    130 bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() {
    131  RTC_DCHECK(decoder_type_ == DecoderType::kNone ||
    132             decoder_type_ == DecoderType::kHardware);
    133  RTC_LOG(LS_WARNING) << "Decoder falling back to software decoding.";
    134  if (!fallback_decoder_->Configure(decoder_settings_)) {
    135    RTC_LOG(LS_ERROR) << "Failed to initialize software-decoder fallback.";
    136    return false;
    137  }
    138 
    139  UpdateFallbackDecoderHistograms();
    140 
    141  if (decoder_type_ == DecoderType::kHardware) {
    142    hw_decoder_->Release();
    143  }
    144  decoder_type_ = DecoderType::kFallback;
    145 
    146  if (callback_)
    147    fallback_decoder_->RegisterDecodeCompleteCallback(callback_);
    148  return true;
    149 }
    150 
    151 void VideoDecoderSoftwareFallbackWrapper::UpdateFallbackDecoderHistograms() {
    152  const std::string kFallbackHistogramsUmaPrefix =
    153      "WebRTC.Video.HardwareDecodedFramesBetweenSoftwareFallbacks.";
    154  // Each histogram needs its own code path for this to work otherwise the
    155  // histogram names will be mixed up by the optimization that takes place.
    156  switch (decoder_settings_.codec_type()) {
    157    case kVideoCodecGeneric:
    158      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Generic",
    159                                  hw_decoded_frames_since_last_fallback_);
    160      break;
    161    case kVideoCodecVP8:
    162      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Vp8",
    163                                  hw_decoded_frames_since_last_fallback_);
    164      break;
    165    case kVideoCodecVP9:
    166      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Vp9",
    167                                  hw_decoded_frames_since_last_fallback_);
    168      break;
    169    case kVideoCodecAV1:
    170      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Av1",
    171                                  hw_decoded_frames_since_last_fallback_);
    172      break;
    173    case kVideoCodecH264:
    174      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H264",
    175                                  hw_decoded_frames_since_last_fallback_);
    176      break;
    177    case kVideoCodecH265:
    178      RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H265",
    179                                  hw_decoded_frames_since_last_fallback_);
    180      break;
    181  }
    182 }
    183 
    184 int32_t VideoDecoderSoftwareFallbackWrapper::Decode(
    185    const EncodedImage& input_image,
    186    int64_t render_time_ms) {
    187  TRACE_EVENT0("webrtc", "VideoDecoderSoftwareFallbackWrapper::Decode");
    188  switch (decoder_type_) {
    189    case DecoderType::kNone:
    190      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    191    case DecoderType::kHardware: {
    192      int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
    193      ret = hw_decoder_->Decode(input_image, render_time_ms);
    194      if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) {
    195        if (ret != WEBRTC_VIDEO_CODEC_ERROR) {
    196          ++hw_decoded_frames_since_last_fallback_;
    197          hw_consequtive_generic_errors_ = 0;
    198          return ret;
    199        }
    200        if (input_image._frameType == VideoFrameType::kVideoFrameKey) {
    201          // Only count errors on key-frames, since generic errors can happen
    202          // with hw decoder due to many arbitrary reasons.
    203          // However, requesting a key-frame is supposed to fix the issue.
    204          ++hw_consequtive_generic_errors_;
    205        }
    206        if (hw_consequtive_generic_errors_ < kMaxConsequtiveHwErrors) {
    207          return ret;
    208        }
    209      }
    210 
    211      // HW decoder returned WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE or
    212      // too many generic errors on key-frames encountered.
    213      if (!InitFallbackDecoder()) {
    214        return ret;
    215      }
    216 
    217      // Fallback decoder initialized, fall-through.
    218      [[fallthrough]];
    219    }
    220    case DecoderType::kFallback:
    221      return fallback_decoder_->Decode(input_image, render_time_ms);
    222    default:
    223      RTC_DCHECK_NOTREACHED();
    224      return WEBRTC_VIDEO_CODEC_ERROR;
    225  }
    226 }
    227 
    228 int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback(
    229    DecodedImageCallback* callback) {
    230  callback_ = callback;
    231  return active_decoder().RegisterDecodeCompleteCallback(callback);
    232 }
    233 
    234 int32_t VideoDecoderSoftwareFallbackWrapper::Release() {
    235  int32_t status;
    236  switch (decoder_type_) {
    237    case DecoderType::kHardware:
    238      status = hw_decoder_->Release();
    239      break;
    240    case DecoderType::kFallback:
    241      RTC_LOG(LS_INFO) << "Releasing software fallback decoder.";
    242      status = fallback_decoder_->Release();
    243      break;
    244    case DecoderType::kNone:
    245      status = WEBRTC_VIDEO_CODEC_OK;
    246      break;
    247    default:
    248      RTC_DCHECK_NOTREACHED();
    249      status = WEBRTC_VIDEO_CODEC_ERROR;
    250  }
    251 
    252  decoder_type_ = DecoderType::kNone;
    253  return status;
    254 }
    255 
    256 VideoDecoder::DecoderInfo VideoDecoderSoftwareFallbackWrapper::GetDecoderInfo()
    257    const {
    258  DecoderInfo info = active_decoder().GetDecoderInfo();
    259  if (decoder_type_ == DecoderType::kFallback) {
    260    // Cached "A (fallback from B)" string.
    261    info.implementation_name = fallback_implementation_name_;
    262  }
    263  return info;
    264 }
    265 
    266 const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const {
    267  if (decoder_type_ == DecoderType::kFallback) {
    268    // Cached "A (fallback from B)" string.
    269    return fallback_implementation_name_.c_str();
    270  } else {
    271    return hw_decoder_->ImplementationName();
    272  }
    273 }
    274 
    275 VideoDecoder& VideoDecoderSoftwareFallbackWrapper::active_decoder() const {
    276  return decoder_type_ == DecoderType::kFallback ? *fallback_decoder_
    277                                                 : *hw_decoder_;
    278 }
    279 
    280 }  // namespace
    281 
    282 std::unique_ptr<VideoDecoder> CreateVideoDecoderSoftwareFallbackWrapper(
    283    const Environment& env,
    284    std::unique_ptr<VideoDecoder> sw_fallback_decoder,
    285    std::unique_ptr<VideoDecoder> hw_decoder) {
    286  return std::make_unique<VideoDecoderSoftwareFallbackWrapper>(
    287      env, std::move(sw_fallback_decoder), std::move(hw_decoder));
    288 }
    289 
    290 }  // namespace webrtc