blob: cf6f823b92ad92358e1329c40e28269b34d55a3e [file] [log] [blame]
magjedf6acc2a2016-11-22 09:43:031/*
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
Anders Carlssondd3e0ab2018-06-12 09:15:5611#include "api/video_codecs/video_decoder_software_fallback_wrapper.h"
magjedf6acc2a2016-11-22 09:43:0312
Yves Gerey3e707812018-11-28 15:47:4913#include <stdint.h>
Jonas Olssona4d87372019-07-05 17:08:3314
Mirko Bonadei317a1f02019-09-17 15:06:1815#include <memory>
magjedf6acc2a2016-11-22 09:43:0316#include <string>
Steve Antone78bcb92017-10-31 16:53:0817#include <utility>
magjedf6acc2a2016-11-22 09:43:0318
Yves Gerey3e707812018-11-28 15:47:4919#include "api/video/encoded_image.h"
Danil Chapovalov7fa3f402021-08-12 09:04:4520#include "api/video_codecs/video_decoder.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3121#include "modules/video_coding/include/video_error_codes.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/logging.h"
24#include "rtc_base/trace_event.h"
Åsa Perssona8cb3662019-02-07 14:31:1825#include "system_wrappers/include/field_trial.h"
Johannes Kron57033032020-03-17 09:01:4326#include "system_wrappers/include/metrics.h"
magjedf6acc2a2016-11-22 09:43:0327
28namespace webrtc {
29
Anders Carlssondd3e0ab2018-06-12 09:15:5630namespace {
31
Ilya Nikolaevskiy35fc1532020-05-15 12:25:5932constexpr size_t kMaxConsequtiveHwErrors = 4;
33
Anders Carlssondd3e0ab2018-06-12 09:15:5634class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
35 public:
36 VideoDecoderSoftwareFallbackWrapper(
37 std::unique_ptr<VideoDecoder> sw_fallback_decoder,
38 std::unique_ptr<VideoDecoder> hw_decoder);
39 ~VideoDecoderSoftwareFallbackWrapper() override;
40
Danil Chapovalov7fa3f402021-08-12 09:04:4541 bool Configure(const Settings& settings) override;
Anders Carlssondd3e0ab2018-06-12 09:15:5642
43 int32_t Decode(const EncodedImage& input_image,
44 bool missing_frames,
Anders Carlssondd3e0ab2018-06-12 09:15:5645 int64_t render_time_ms) override;
46
47 int32_t RegisterDecodeCompleteCallback(
48 DecodedImageCallback* callback) override;
49
50 int32_t Release() override;
Anders Carlssondd3e0ab2018-06-12 09:15:5651
Erik Språngc12f6252021-01-13 20:49:5952 DecoderInfo GetDecoderInfo() const override;
Anders Carlssondd3e0ab2018-06-12 09:15:5653 const char* ImplementationName() const override;
54
55 private:
56 bool InitFallbackDecoder();
Johannes Kron57033032020-03-17 09:01:4357 void UpdateFallbackDecoderHistograms();
58
Danil Chapovalov7fa3f402021-08-12 09:04:4559 bool InitHwDecoder();
Anders Carlssondd3e0ab2018-06-12 09:15:5660
61 VideoDecoder& active_decoder() const;
62
63 // Determines if we are trying to use the HW or SW decoder.
64 enum class DecoderType {
65 kNone,
66 kHardware,
67 kFallback,
68 } decoder_type_;
69 std::unique_ptr<VideoDecoder> hw_decoder_;
70
Danil Chapovalov7fa3f402021-08-12 09:04:4571 Settings decoder_settings_;
Anders Carlssondd3e0ab2018-06-12 09:15:5672 const std::unique_ptr<VideoDecoder> fallback_decoder_;
73 const std::string fallback_implementation_name_;
74 DecodedImageCallback* callback_;
Johannes Kron57033032020-03-17 09:01:4375 int32_t hw_decoded_frames_since_last_fallback_;
Ilya Nikolaevskiy35fc1532020-05-15 12:25:5976 size_t hw_consequtive_generic_errors_;
Anders Carlssondd3e0ab2018-06-12 09:15:5677};
78
magjedf6acc2a2016-11-22 09:43:0379VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
Magnus Jedvert7501b1c2017-11-09 12:43:4280 std::unique_ptr<VideoDecoder> sw_fallback_decoder,
81 std::unique_ptr<VideoDecoder> hw_decoder)
Sami Kalliomäki99f52f82018-02-23 08:05:4982 : decoder_type_(DecoderType::kNone),
Magnus Jedvert7501b1c2017-11-09 12:43:4283 hw_decoder_(std::move(hw_decoder)),
Magnus Jedvert7501b1c2017-11-09 12:43:4284 fallback_decoder_(std::move(sw_fallback_decoder)),
85 fallback_implementation_name_(
Johannes Kron96dbc602022-04-04 12:16:3886 fallback_decoder_->GetDecoderInfo().implementation_name +
87 " (fallback from: " +
88 hw_decoder_->GetDecoderInfo().implementation_name + ")"),
Johannes Kron57033032020-03-17 09:01:4389 callback_(nullptr),
Ilya Nikolaevskiy35fc1532020-05-15 12:25:5990 hw_decoded_frames_since_last_fallback_(0),
91 hw_consequtive_generic_errors_(0) {}
Paulina Hensmana680a6a2018-04-05 09:42:2492VideoDecoderSoftwareFallbackWrapper::~VideoDecoderSoftwareFallbackWrapper() =
93 default;
magjedf6acc2a2016-11-22 09:43:0394
Danil Chapovalov7fa3f402021-08-12 09:04:4595bool VideoDecoderSoftwareFallbackWrapper::Configure(const Settings& settings) {
96 decoder_settings_ = settings;
Peter Boströmf812e452017-02-13 22:11:0897
Åsa Perssona8cb3662019-02-07 14:31:1898 if (webrtc::field_trial::IsEnabled("WebRTC-Video-ForcedSwDecoderFallback")) {
99 RTC_LOG(LS_INFO) << "Forced software decoder fallback enabled.";
100 RTC_DCHECK(decoder_type_ == DecoderType::kNone);
Danil Chapovalov7fa3f402021-08-12 09:04:45101 return InitFallbackDecoder();
Åsa Perssona8cb3662019-02-07 14:31:18102 }
Danil Chapovalov7fa3f402021-08-12 09:04:45103 if (InitHwDecoder()) {
104 return true;
Sami Kalliomäki99f52f82018-02-23 08:05:49105 }
Magnus Jedvert7501b1c2017-11-09 12:43:42106
Sami Kalliomäki99f52f82018-02-23 08:05:49107 RTC_DCHECK(decoder_type_ == DecoderType::kNone);
Danil Chapovalov7fa3f402021-08-12 09:04:45108 return InitFallbackDecoder();
Sami Kalliomäki99f52f82018-02-23 08:05:49109}
110
Danil Chapovalov7fa3f402021-08-12 09:04:45111bool VideoDecoderSoftwareFallbackWrapper::InitHwDecoder() {
Sami Kalliomäki99f52f82018-02-23 08:05:49112 RTC_DCHECK(decoder_type_ == DecoderType::kNone);
Danil Chapovalov7fa3f402021-08-12 09:04:45113 if (!hw_decoder_->Configure(decoder_settings_)) {
114 return false;
Sami Kalliomäki99f52f82018-02-23 08:05:49115 }
116
117 decoder_type_ = DecoderType::kHardware;
118 if (callback_)
119 hw_decoder_->RegisterDecodeCompleteCallback(callback_);
Danil Chapovalov7fa3f402021-08-12 09:04:45120 return true;
magjedf6acc2a2016-11-22 09:43:03121}
122
123bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() {
Sami Kalliomäki99f52f82018-02-23 08:05:49124 RTC_DCHECK(decoder_type_ == DecoderType::kNone ||
125 decoder_type_ == DecoderType::kHardware);
Mirko Bonadei675513b2017-11-09 10:09:25126 RTC_LOG(LS_WARNING) << "Decoder falling back to software decoding.";
Danil Chapovalov7fa3f402021-08-12 09:04:45127 if (!fallback_decoder_->Configure(decoder_settings_)) {
Mirko Bonadei675513b2017-11-09 10:09:25128 RTC_LOG(LS_ERROR) << "Failed to initialize software-decoder fallback.";
magjedf6acc2a2016-11-22 09:43:03129 return false;
130 }
Sami Kalliomäki99f52f82018-02-23 08:05:49131
Johannes Kron57033032020-03-17 09:01:43132 UpdateFallbackDecoderHistograms();
133
Sami Kalliomäki99f52f82018-02-23 08:05:49134 if (decoder_type_ == DecoderType::kHardware) {
135 hw_decoder_->Release();
136 }
137 decoder_type_ = DecoderType::kFallback;
138
magjedf6acc2a2016-11-22 09:43:03139 if (callback_)
140 fallback_decoder_->RegisterDecodeCompleteCallback(callback_);
magjedf6acc2a2016-11-22 09:43:03141 return true;
142}
143
Johannes Kron57033032020-03-17 09:01:43144void VideoDecoderSoftwareFallbackWrapper::UpdateFallbackDecoderHistograms() {
145 const std::string kFallbackHistogramsUmaPrefix =
146 "WebRTC.Video.HardwareDecodedFramesBetweenSoftwareFallbacks.";
147 // Each histogram needs its own code path for this to work otherwise the
148 // histogram names will be mixed up by the optimization that takes place.
Danil Chapovalov7fa3f402021-08-12 09:04:45149 switch (decoder_settings_.codec_type()) {
Johannes Kron57033032020-03-17 09:01:43150 case kVideoCodecGeneric:
151 RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Generic",
152 hw_decoded_frames_since_last_fallback_);
153 break;
154 case kVideoCodecVP8:
155 RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Vp8",
156 hw_decoded_frames_since_last_fallback_);
157 break;
158 case kVideoCodecVP9:
159 RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Vp9",
160 hw_decoded_frames_since_last_fallback_);
161 break;
162 case kVideoCodecAV1:
163 RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Av1",
164 hw_decoded_frames_since_last_fallback_);
165 break;
166 case kVideoCodecH264:
167 RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H264",
168 hw_decoded_frames_since_last_fallback_);
169 break;
170 case kVideoCodecMultiplex:
171 RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Multiplex",
172 hw_decoded_frames_since_last_fallback_);
173 break;
174 }
175}
176
magjedf6acc2a2016-11-22 09:43:03177int32_t VideoDecoderSoftwareFallbackWrapper::Decode(
178 const EncodedImage& input_image,
179 bool missing_frames,
magjedf6acc2a2016-11-22 09:43:03180 int64_t render_time_ms) {
Sami Kalliomäki99f52f82018-02-23 08:05:49181 TRACE_EVENT0("webrtc", "VideoDecoderSoftwareFallbackWrapper::Decode");
182 switch (decoder_type_) {
183 case DecoderType::kNone:
184 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
185 case DecoderType::kHardware: {
186 int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
Niels Möller7aacdd92019-03-25 08:11:40187 ret = hw_decoder_->Decode(input_image, missing_frames, render_time_ms);
Sami Kalliomäki99f52f82018-02-23 08:05:49188 if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) {
Ilya Nikolaevskiy35fc1532020-05-15 12:25:59189 if (ret != WEBRTC_VIDEO_CODEC_ERROR) {
Johannes Kron57033032020-03-17 09:01:43190 ++hw_decoded_frames_since_last_fallback_;
Ilya Nikolaevskiy35fc1532020-05-15 12:25:59191 hw_consequtive_generic_errors_ = 0;
192 return ret;
Johannes Kron57033032020-03-17 09:01:43193 }
Ilya Nikolaevskiy35fc1532020-05-15 12:25:59194 if (input_image._frameType == VideoFrameType::kVideoFrameKey) {
195 // Only count errors on key-frames, since generic errors can happen
196 // with hw decoder due to many arbitrary reasons.
197 // However, requesting a key-frame is supposed to fix the issue.
198 ++hw_consequtive_generic_errors_;
199 }
200 if (hw_consequtive_generic_errors_ < kMaxConsequtiveHwErrors) {
201 return ret;
202 }
Sami Kalliomäki99f52f82018-02-23 08:05:49203 }
204
205 // HW decoder returned WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE or
Ilya Nikolaevskiy35fc1532020-05-15 12:25:59206 // too many generic errors on key-frames encountered.
Sami Kalliomäki99f52f82018-02-23 08:05:49207 if (!InitFallbackDecoder()) {
208 return ret;
209 }
210
211 // Fallback decoder initialized, fall-through.
Danil Chapovalov46cc32d2022-01-17 13:41:13212 [[fallthrough]];
magjedf6acc2a2016-11-22 09:43:03213 }
Sami Kalliomäki99f52f82018-02-23 08:05:49214 case DecoderType::kFallback:
215 return fallback_decoder_->Decode(input_image, missing_frames,
Niels Möller7aacdd92019-03-25 08:11:40216 render_time_ms);
Sami Kalliomäki99f52f82018-02-23 08:05:49217 default:
Artem Titovd3251962021-11-15 15:57:07218 RTC_DCHECK_NOTREACHED();
Sami Kalliomäki99f52f82018-02-23 08:05:49219 return WEBRTC_VIDEO_CODEC_ERROR;
magjedf6acc2a2016-11-22 09:43:03220 }
magjedf6acc2a2016-11-22 09:43:03221}
222
223int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback(
224 DecodedImageCallback* callback) {
225 callback_ = callback;
Sami Kalliomäki99f52f82018-02-23 08:05:49226 return active_decoder().RegisterDecodeCompleteCallback(callback);
magjedf6acc2a2016-11-22 09:43:03227}
228
229int32_t VideoDecoderSoftwareFallbackWrapper::Release() {
Sami Kalliomäki99f52f82018-02-23 08:05:49230 int32_t status;
231 switch (decoder_type_) {
232 case DecoderType::kHardware:
233 status = hw_decoder_->Release();
234 break;
235 case DecoderType::kFallback:
236 RTC_LOG(LS_INFO) << "Releasing software fallback decoder.";
237 status = fallback_decoder_->Release();
238 break;
239 case DecoderType::kNone:
240 status = WEBRTC_VIDEO_CODEC_OK;
241 break;
242 default:
Artem Titovd3251962021-11-15 15:57:07243 RTC_DCHECK_NOTREACHED();
Sami Kalliomäki99f52f82018-02-23 08:05:49244 status = WEBRTC_VIDEO_CODEC_ERROR;
Peter Boströmf812e452017-02-13 22:11:08245 }
Sami Kalliomäki99f52f82018-02-23 08:05:49246
247 decoder_type_ = DecoderType::kNone;
248 return status;
magjedf6acc2a2016-11-22 09:43:03249}
250
Erik Språngc12f6252021-01-13 20:49:59251VideoDecoder::DecoderInfo VideoDecoderSoftwareFallbackWrapper::GetDecoderInfo()
252 const {
253 DecoderInfo info = active_decoder().GetDecoderInfo();
254 if (decoder_type_ == DecoderType::kFallback) {
255 // Cached "A (fallback from B)" string.
256 info.implementation_name = fallback_implementation_name_;
257 }
258 return info;
259}
260
magjedf6acc2a2016-11-22 09:43:03261const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const {
Erik Språngc12f6252021-01-13 20:49:59262 if (decoder_type_ == DecoderType::kFallback) {
263 // Cached "A (fallback from B)" string.
264 return fallback_implementation_name_.c_str();
265 } else {
266 return hw_decoder_->ImplementationName();
267 }
Sami Kalliomäki99f52f82018-02-23 08:05:49268}
269
270VideoDecoder& VideoDecoderSoftwareFallbackWrapper::active_decoder() const {
271 return decoder_type_ == DecoderType::kFallback ? *fallback_decoder_
272 : *hw_decoder_;
magjedf6acc2a2016-11-22 09:43:03273}
274
Anders Carlssondd3e0ab2018-06-12 09:15:56275} // namespace
276
277std::unique_ptr<VideoDecoder> CreateVideoDecoderSoftwareFallbackWrapper(
278 std::unique_ptr<VideoDecoder> sw_fallback_decoder,
279 std::unique_ptr<VideoDecoder> hw_decoder) {
Mirko Bonadei317a1f02019-09-17 15:06:18280 return std::make_unique<VideoDecoderSoftwareFallbackWrapper>(
Anders Carlssondd3e0ab2018-06-12 09:15:56281 std::move(sw_fallback_decoder), std::move(hw_decoder));
282}
283
magjedf6acc2a2016-11-22 09:43:03284} // namespace webrtc