| // 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 |