1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webcodecs/decoder_selector.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "media/base/channel_layout.h"
#include "media/base/demuxer_stream.h"
#include "media/base/sample_format.h"
#include "media/filters/decrypting_demuxer_stream.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
// Demuxing isn't part of WebCodecs. This shim allows us to reuse decoder
// selection logic from <video>.
// TODO(chcunningham): Maybe refactor DecoderSelector to separate dependency on
// media::DemuxerStream. DecoderSelection doesn't conceptually require a
// Demuxer. The tough part is re-working Decryptingmedia::DemuxerStream.
template <media::DemuxerStream::Type StreamType>
class NullDemuxerStream : public media::DemuxerStream {
public:
using DecoderConfigType =
typename media::DecoderStreamTraits<StreamType>::DecoderConfigType;
~NullDemuxerStream() override = default;
void Read(uint32_t count, ReadCB read_cb) override { NOTREACHED(); }
void Configure(DecoderConfigType config);
media::AudioDecoderConfig audio_decoder_config() override {
DCHECK_EQ(type(), media::DemuxerStream::AUDIO);
return audio_decoder_config_;
}
media::VideoDecoderConfig video_decoder_config() override {
DCHECK_EQ(type(), media::DemuxerStream::VIDEO);
return video_decoder_config_;
}
Type type() const override { return stream_type; }
bool SupportsConfigChanges() override { NOTREACHED(); }
void set_low_delay(bool low_delay) { low_delay_ = low_delay; }
media::StreamLiveness liveness() const override {
return low_delay_ ? media::StreamLiveness::kLive
: media::StreamLiveness::kUnknown;
}
private:
static const media::DemuxerStream::Type stream_type = StreamType;
media::AudioDecoderConfig audio_decoder_config_;
media::VideoDecoderConfig video_decoder_config_;
bool low_delay_ = false;
};
template <>
void NullDemuxerStream<media::DemuxerStream::AUDIO>::Configure(
DecoderConfigType config) {
audio_decoder_config_ = config;
}
template <>
void NullDemuxerStream<media::DemuxerStream::VIDEO>::Configure(
DecoderConfigType config) {
video_decoder_config_ = config;
}
// TODO(crbug.com/368085608): Flip `enable_priority_based_selection` to true.
template <media::DemuxerStream::Type StreamType>
DecoderSelector<StreamType>::DecoderSelector(
scoped_refptr<base::SequencedTaskRunner> task_runner,
CreateDecodersCB create_decoders_cb,
typename Decoder::OutputCB output_cb)
: impl_(std::move(task_runner),
std::move(create_decoders_cb),
&null_media_log_,
/*enable_priority_based_selection=*/false),
demuxer_stream_(new NullDemuxerStream<StreamType>()),
stream_traits_(CreateStreamTraits()),
output_cb_(output_cb) {
impl_.Initialize(stream_traits_.get(), demuxer_stream_.get(),
nullptr /*CdmContext*/, media::WaitingCB());
}
template <media::DemuxerStream::Type StreamType>
DecoderSelector<StreamType>::~DecoderSelector() = default;
template <media::DemuxerStream::Type StreamType>
void DecoderSelector<StreamType>::SelectDecoder(
const DecoderConfig& config,
bool low_delay,
SelectDecoderCB select_decoder_cb) {
// |impl_| will internally use this the |config| from our NullDemuxerStream.
demuxer_stream_->Configure(config);
demuxer_stream_->set_low_delay(low_delay);
// media::DecoderSelector will call back with a DecoderStatus if selection is
// in progress when it is destructed.
impl_.BeginDecoderSelection(
WTF::BindOnce(&DecoderSelector<StreamType>::OnDecoderSelected,
weak_factory_.GetWeakPtr(), std::move(select_decoder_cb)),
output_cb_);
}
template <>
std::unique_ptr<WebCodecsAudioDecoderSelector::StreamTraits>
DecoderSelector<media::DemuxerStream::AUDIO>::CreateStreamTraits() {
// TODO(chcunningham): Consider plumbing real hw channel layout.
return std::make_unique<DecoderSelector::StreamTraits>(
&null_media_log_, media::CHANNEL_LAYOUT_NONE,
media::kUnknownSampleFormat);
}
template <>
std::unique_ptr<WebCodecsVideoDecoderSelector::StreamTraits>
DecoderSelector<media::DemuxerStream::VIDEO>::CreateStreamTraits() {
return std::make_unique<DecoderSelector::StreamTraits>(&null_media_log_);
}
template <media::DemuxerStream::Type StreamType>
void DecoderSelector<StreamType>::OnDecoderSelected(
SelectDecoderCB select_decoder_cb,
DecoderOrError decoder_or_error,
std::unique_ptr<media::DecryptingDemuxerStream> decrypting_demuxer_stream) {
DCHECK(!decrypting_demuxer_stream);
// We immediately finalize decoder selection.
// TODO(chcunningham): Rework this to do finalize after first frame
// successfully decoded. This updates to match latest plans for spec
// (configure() no longer takes a promise).
impl_.FinalizeDecoderSelection();
if (!decoder_or_error.has_value()) {
std::move(select_decoder_cb).Run(nullptr);
} else {
std::move(select_decoder_cb).Run(std::move(decoder_or_error).value());
}
}
template class MODULES_EXPORT DecoderSelector<media::DemuxerStream::VIDEO>;
template class MODULES_EXPORT DecoderSelector<media::DemuxerStream::AUDIO>;
} // namespace blink
|