blob: 33ec0556c819040017c70d07ee25e5b3b1e9b625 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// 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/bind.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/single_thread_task_runner.h"
#include "media/base/channel_layout.h"
#include "media/base/demuxer_stream.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(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();
return true;
}
private:
static const media::DemuxerStream::Type stream_type = StreamType;
media::AudioDecoderConfig audio_decoder_config_;
media::VideoDecoderConfig video_decoder_config_;
};
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;
}
template <media::DemuxerStream::Type StreamType>
DecoderSelector<StreamType>::DecoderSelector(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
CreateDecodersCB create_decoders_cb,
typename Decoder::OutputCB output_cb)
: impl_(std::move(task_runner),
std::move(create_decoders_cb),
&null_media_log_),
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,
SelectDecoderCB select_decoder_cb) {
// |impl_| will internally use this the |config| from our NullDemuxerStream.
demuxer_stream_->Configure(config);
// Destroying |impl_| will cancel pending operations, so it's safe to use
// Unretained() with |select_decoder_cb|.
impl_.SelectDecoder(
WTF::Bind(&DecoderSelector<StreamType>::OnDecoderSelected,
WTF::Unretained(this), 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);
}
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,
std::unique_ptr<Decoder> decoder,
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();
std::move(select_decoder_cb).Run(std::move(decoder));
}
template class MODULES_EXPORT DecoderSelector<media::DemuxerStream::VIDEO>;
template class MODULES_EXPORT DecoderSelector<media::DemuxerStream::AUDIO>;
} // namespace blink