|  | // 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; | 
|  | } | 
|  |  | 
|  | void set_low_delay(bool low_delay) { low_delay_ = low_delay; } | 
|  | media::DemuxerStream::Liveness liveness() const override { | 
|  | return low_delay_ ? media::DemuxerStream::LIVENESS_LIVE | 
|  | : media::DemuxerStream::LIVENESS_UNKNOWN; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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_), | 
|  | 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 null decoder if selection is | 
|  | // in progress when it is destructed. | 
|  | impl_.SelectDecoder( | 
|  | WTF::Bind(&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); | 
|  | } | 
|  |  | 
|  | 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 |