1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/decoder_selector.h"
10 #include "base/feature_list.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram_functions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/task/sequenced_task_runner.h"
18 #include "base/trace_event/trace_event.h"
19 #include "build/build_config.h"
20 #include "build/chromeos_buildflags.h"
21 #include "media/base/audio_decoder.h"
22 #include "media/base/cdm_context.h"
23 #include "media/base/demuxer_stream.h"
24 #include "media/base/media_log.h"
25 #include "media/base/media_switches.h"
26 #include "media/base/video_decoder.h"
27 #include "media/filters/decoder_stream_traits.h"
28 #include "media/filters/decrypting_demuxer_stream.h"
34 const char kSelectDecoderTrace[] = "DecoderSelector::SelectDecoder";
36 bool SkipDecoderForRTC(const AudioDecoderConfig& /*config*/,
37 const AudioDecoder& /*decoder*/) {
41 bool SkipDecoderForRTC(const VideoDecoderConfig& config,
42 const VideoDecoder& decoder) {
43 // Skip non-platform decoders for rtc based on the feature flag.
44 return config.is_rtc() && !decoder.IsPlatformDecoder() &&
45 !base::FeatureList::IsEnabled(kExposeSwDecodersToWebRTC);
48 template <typename ConfigT, typename DecoderT>
49 DecoderPriority NormalDecoderPriority(const ConfigT& config,
50 const DecoderT& decoder) {
51 if (SkipDecoderForRTC(config, decoder))
52 return DecoderPriority::kSkipped;
54 return DecoderPriority::kNormal;
57 DecoderPriority ResolutionBasedDecoderPriority(const VideoDecoderConfig& config,
58 const VideoDecoder& decoder) {
59 #if BUILDFLAG(IS_ANDROID)
60 constexpr auto kSoftwareDecoderHeightCutoff = 360;
61 #elif BUILDFLAG(IS_CHROMEOS_ASH)
62 constexpr auto kSoftwareDecoderHeightCutoff = 360;
64 constexpr auto kSoftwareDecoderHeightCutoff = 720;
67 if (SkipDecoderForRTC(config, decoder))
68 return DecoderPriority::kSkipped;
70 // We only do a height check to err on the side of prioritizing platform
72 const auto at_or_above_software_cutoff =
73 config.visible_rect().height() >= kSoftwareDecoderHeightCutoff;
75 // Platform decoders are deprioritized below the cutoff, and non-platform
76 // decoders are deprioritized above it.
77 return at_or_above_software_cutoff == decoder.IsPlatformDecoder()
78 ? DecoderPriority::kNormal
79 : DecoderPriority::kDeprioritized;
82 DecoderPriority PreferNonPlatformDecoders(const VideoDecoderConfig& config,
83 const VideoDecoder& decoder) {
84 // Prefer software decoders over hardware decoders. This is useful to force
85 // software fallback for WebRTC, but still use hardware if there's no software
86 // implementation to choose.
87 return decoder.IsPlatformDecoder() ? DecoderPriority::kDeprioritized
88 : DecoderPriority::kNormal;
91 DecoderPriority UnifiedDecoderPriority(const VideoDecoderConfig& config,
92 const VideoDecoder& decoder) {
93 if (config.is_rtc() ||
94 base::FeatureList::IsEnabled(kResolutionBasedDecoderPriority)) {
95 return ResolutionBasedDecoderPriority(config, decoder);
97 return NormalDecoderPriority(config, decoder);
101 template <typename ConfigT, typename DecoderT>
102 DecoderPriority SkipNonPlatformDecoders(const ConfigT& config,
103 const DecoderT& decoder) {
104 if (SkipDecoderForRTC(config, decoder))
105 return DecoderPriority::kSkipped;
107 return decoder.IsPlatformDecoder() ? DecoderPriority::kNormal
108 : DecoderPriority::kSkipped;
111 void SetDefaultDecoderPriorityCB(
112 VideoDecoderSelector::DecoderPriorityCB* out,
113 const DecoderStreamTraits<DemuxerStream::VIDEO>* traits) {
114 if (base::FeatureList::IsEnabled(kForceHardwareVideoDecoders)) {
115 *out = base::BindRepeating(
116 SkipNonPlatformDecoders<VideoDecoderConfig, VideoDecoder>);
117 } else if (traits->GetPreferNonPlatformDecoders()) {
118 *out = base::BindRepeating(PreferNonPlatformDecoders);
120 *out = base::BindRepeating(UnifiedDecoderPriority);
124 void SetDefaultDecoderPriorityCB(
125 AudioDecoderSelector::DecoderPriorityCB* out,
126 const DecoderStreamTraits<DemuxerStream::AUDIO>*) {
127 if (base::FeatureList::IsEnabled(kForceHardwareAudioDecoders)) {
128 *out = base::BindRepeating(
129 SkipNonPlatformDecoders<AudioDecoderConfig, AudioDecoder>);
131 // Platform audio decoders are not currently prioritized or deprioritized
132 *out = base::BindRepeating(
133 NormalDecoderPriority<AudioDecoderConfig, AudioDecoder>);
139 template <DemuxerStream::Type StreamType>
140 DecoderSelector<StreamType>::DecoderSelector(
141 scoped_refptr<base::SequencedTaskRunner> task_runner,
142 CreateDecodersCB create_decoders_cb,
144 : task_runner_(std::move(task_runner)),
145 create_decoders_cb_(std::move(create_decoders_cb)),
146 media_log_(media_log) {
147 DETACH_FROM_SEQUENCE(sequence_checker_);
150 template <DemuxerStream::Type StreamType>
151 DecoderSelector<StreamType>::~DecoderSelector() {
152 DVLOG(2) << __func__;
153 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
154 if (select_decoder_cb_)
155 ReturnSelectionError(DecoderStatus::Codes::kFailed);
158 template <DemuxerStream::Type StreamType>
159 void DecoderSelector<StreamType>::Initialize(StreamTraits* traits,
160 DemuxerStream* stream,
161 CdmContext* cdm_context,
162 WaitingCB waiting_cb) {
163 DVLOG(2) << __func__;
169 cdm_context_ = cdm_context;
170 waiting_cb_ = std::move(waiting_cb);
171 // Only set this here if nobody has overridden it for tests.
172 if (!decoder_priority_cb_)
173 SetDefaultDecoderPriorityCB(&decoder_priority_cb_, traits_);
176 template <DemuxerStream::Type StreamType>
177 void DecoderSelector<StreamType>::SelectDecoderInternal(
178 SelectDecoderCB select_decoder_cb,
179 typename Decoder::OutputCB output_cb,
180 bool needs_new_decoders) {
181 DVLOG(2) << __func__;
182 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
183 DCHECK(select_decoder_cb);
184 DCHECK(!select_decoder_cb_);
185 select_decoder_cb_ = std::move(select_decoder_cb);
186 output_cb_ = std::move(output_cb);
187 config_ = traits_->GetDecoderConfig(stream_);
189 TRACE_EVENT_ASYNC_BEGIN2("media", kSelectDecoderTrace, this, "type",
190 DemuxerStream::GetTypeName(StreamType), "config",
191 config_.AsHumanReadableString());
193 if (!config_.IsValidConfig()) {
194 DLOG(ERROR) << "Invalid stream config";
195 ReturnSelectionError(DecoderStatus::Codes::kUnsupportedConfig);
199 if (needs_new_decoders) {
200 decode_failure_reinit_cause_ = absl::nullopt;
204 GetAndInitializeNextDecoder();
207 template <DemuxerStream::Type StreamType>
208 void DecoderSelector<StreamType>::BeginDecoderSelection(
209 SelectDecoderCB select_decoder_cb,
210 typename Decoder::OutputCB output_cb) {
211 SelectDecoderInternal(std::move(select_decoder_cb), std::move(output_cb),
212 /*needs_new_decoders = */ true);
215 template <DemuxerStream::Type StreamType>
216 void DecoderSelector<StreamType>::ResumeDecoderSelection(
217 SelectDecoderCB select_decoder_cb,
218 typename Decoder::OutputCB output_cb,
219 DecoderStatus&& reinit_cause) {
220 DVLOG(2) << __func__;
221 if (!decode_failure_reinit_cause_.has_value())
222 decode_failure_reinit_cause_ = std::move(reinit_cause);
223 SelectDecoderInternal(std::move(select_decoder_cb), std::move(output_cb),
224 /*needs_new_decoders = */ false);
227 template <DemuxerStream::Type StreamType>
228 void DecoderSelector<StreamType>::FinalizeDecoderSelection() {
229 DVLOG(2) << __func__;
230 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
231 DCHECK(!select_decoder_cb_);
233 // Discard any remaining decoder instances, they won't be used.
237 template <DemuxerStream::Type StreamType>
238 void DecoderSelector<StreamType>::PrependDecoder(
239 std::unique_ptr<Decoder> decoder) {
240 DVLOG(2) << __func__;
241 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
243 // Decoders inserted directly should be given priority over those returned by
244 // |create_decoders_cb_|.
245 decoders_.insert(decoders_.begin(), std::move(decoder));
246 FilterAndSortAvailableDecoders();
249 template <DemuxerStream::Type StreamType>
250 void DecoderSelector<StreamType>::OverrideDecoderPriorityCBForTesting(
251 DecoderPriorityCB decoder_priority_cb) {
252 decoder_priority_cb_ = std::move(decoder_priority_cb);
255 template <DemuxerStream::Type StreamType>
256 void DecoderSelector<StreamType>::CreateDecoders() {
257 // Post-insert decoders returned by `create_decoders_cb_`, so that
258 // any decoders added via `PrependDecoder()` are not overwritten and retain
259 // priority (even if they are ultimately de-ranked by
260 // `FilterAndSortAvailableDecoders()`)
261 auto new_decoders = create_decoders_cb_.Run();
262 std::move(new_decoders.begin(), new_decoders.end(),
263 std::inserter(decoders_, decoders_.end()));
264 FilterAndSortAvailableDecoders();
267 template <DemuxerStream::Type StreamType>
268 void DecoderSelector<StreamType>::GetAndInitializeNextDecoder() {
269 DVLOG(2) << __func__;
270 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
273 if (decoders_.empty()) {
274 // Decoder selection failed. If the stream is encrypted, try again using
275 // DecryptingDemuxerStream.
276 if (config_.is_encrypted() && cdm_context_) {
277 InitializeDecryptingDemuxerStream();
281 if (decode_failure_reinit_cause_.has_value()) {
282 ReturnSelectionError(std::move(*decode_failure_reinit_cause_));
284 ReturnSelectionError(DecoderStatus::Codes::kUnsupportedConfig);
289 // Initialize the first decoder on the list.
290 decoder_ = std::move(decoders_.front());
291 decoders_.erase(decoders_.begin());
292 TRACE_EVENT_ASYNC_STEP_INTO0("media", kSelectDecoderTrace, this,
293 GetDecoderName(decoder_->GetDecoderType()));
295 DVLOG(2) << __func__ << ": initializing " << decoder_->GetDecoderType();
296 const bool is_live = stream_->liveness() == StreamLiveness::kLive;
297 traits_->InitializeDecoder(
298 decoder_.get(), config_, is_live, cdm_context_,
299 base::BindOnce(&DecoderSelector<StreamType>::OnDecoderInitializeDone,
300 weak_this_factory_.GetWeakPtr()),
301 output_cb_, waiting_cb_);
304 template <DemuxerStream::Type StreamType>
305 void DecoderSelector<StreamType>::OnDecoderInitializeDone(
306 DecoderStatus status) {
308 DVLOG(2) << __func__ << ": " << decoder_->GetDecoderType()
309 << " success=" << static_cast<int>(status.code());
310 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
312 if (!status.is_ok()) {
313 // Note: Don't track this decode status, as it is the result of decoder
314 // selection (initialization) failure.
315 MEDIA_LOG(INFO, media_log_)
316 << "Cannot select " << decoder_->GetDecoderType() << " for "
317 << DemuxerStream::GetTypeName(StreamType) << " decoding";
319 // Try the next decoder on the list.
321 GetAndInitializeNextDecoder();
325 RunSelectDecoderCB(std::move(decoder_));
328 template <DemuxerStream::Type StreamType>
329 void DecoderSelector<StreamType>::ReturnSelectionError(DecoderStatus error) {
330 DVLOG(1) << __func__ << ": No decoder selected";
331 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
332 DCHECK(!error.is_ok());
334 decrypting_demuxer_stream_.reset();
336 RunSelectDecoderCB(std::move(error));
339 template <DemuxerStream::Type StreamType>
340 void DecoderSelector<StreamType>::InitializeDecryptingDemuxerStream() {
341 DCHECK(decoders_.empty());
342 DCHECK(config_.is_encrypted());
343 DCHECK(cdm_context_);
344 TRACE_EVENT_ASYNC_STEP_INTO0("media", kSelectDecoderTrace, this,
345 "DecryptingDemuxerStream");
347 decrypting_demuxer_stream_ = std::make_unique<DecryptingDemuxerStream>(
348 task_runner_, media_log_, waiting_cb_);
350 decrypting_demuxer_stream_->Initialize(
351 stream_, cdm_context_,
353 &DecoderSelector<StreamType>::OnDecryptingDemuxerStreamInitializeDone,
354 weak_this_factory_.GetWeakPtr()));
357 template <DemuxerStream::Type StreamType>
358 void DecoderSelector<StreamType>::OnDecryptingDemuxerStreamInitializeDone(
359 PipelineStatus status) {
360 DVLOG(2) << __func__ << ": status=" << status;
361 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
363 if (status != PIPELINE_OK) {
364 // Since we already tried every potential decoder without DDS, give up.
365 ReturnSelectionError(
366 {DecoderStatus::Codes::kUnsupportedEncryptionMode, std::move(status)});
370 // Once DDS is enabled, there is no going back.
371 // TODO(sandersd): Support transitions from encrypted to unencrypted.
372 stream_ = decrypting_demuxer_stream_.get();
373 cdm_context_ = nullptr;
375 // We'll use the decrypted config from now on.
376 config_ = traits_->GetDecoderConfig(stream_);
377 DCHECK(!config_.is_encrypted());
379 // Try decoder selection again now that DDS is being used.
381 GetAndInitializeNextDecoder();
384 template <DemuxerStream::Type StreamType>
385 void DecoderSelector<StreamType>::RunSelectDecoderCB(
386 DecoderOrError decoder_or_error) {
387 DCHECK(select_decoder_cb_);
388 TRACE_EVENT_ASYNC_END2(
389 "media", kSelectDecoderTrace, this, "type",
390 DemuxerStream::GetTypeName(StreamType), "decoder",
393 decoder_or_error.has_value()
394 ? GetDecoderName(decoder_or_error->GetDecoderType()).c_str()
396 decrypting_demuxer_stream_ ? "encrypted" : "unencrypted"));
398 task_runner_->PostTask(
400 base::BindOnce(std::move(select_decoder_cb_), std::move(decoder_or_error),
401 std::move(decrypting_demuxer_stream_)));
404 template <DemuxerStream::Type StreamType>
405 void DecoderSelector<StreamType>::FilterAndSortAvailableDecoders() {
406 std::vector<std::unique_ptr<Decoder>> decoders = std::move(decoders_);
407 std::vector<std::unique_ptr<Decoder>> deprioritized_decoders;
408 DCHECK(decoder_priority_cb_);
410 for (auto& decoder : decoders) {
411 // Skip the decoder if this decoder doesn't support encryption for a
413 if (config_.is_encrypted() && !decoder->SupportsDecryption())
416 // Run the predicate on this decoder.
417 switch (decoder_priority_cb_.Run(config_, *decoder)) {
418 case DecoderPriority::kSkipped:
420 case DecoderPriority::kNormal:
421 decoders_.push_back(std::move(decoder));
423 case DecoderPriority::kDeprioritized:
424 deprioritized_decoders.push_back(std::move(decoder));
429 // Post-insert deprioritized decoders
430 std::move(deprioritized_decoders.begin(), deprioritized_decoders.end(),
431 std::inserter(decoders_, decoders_.end()));
434 // These forward declarations tell the compiler that we will use
435 // DecoderSelector with these arguments, allowing us to keep these definitions
436 // in our .cc without causing linker errors. This also means if anyone tries to
437 // instantiate a DecoderSelector with anything but these two specializations
438 // they'll most likely get linker errors.
439 template class DecoderSelector<DemuxerStream::AUDIO>;
440 template class DecoderSelector<DemuxerStream::VIDEO>;