| // 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. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_DECODER_BROKER_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_DECODER_BROKER_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "media/base/decoder_status.h" |
| #include "media/base/video_decoder.h" |
| #include "media/base/video_frame.h" |
| #include "media/video/gpu_video_accelerator_factories.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/blink/renderer/core/execution_context/execution_context.h" |
| #include "third_party/blink/renderer/modules/modules_export.h" |
| #include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h" |
| #include "third_party/blink/renderer/platform/wtf/hash_map.h" |
| |
| namespace base { |
| class SequencedTaskRunner; |
| } // namespace base |
| |
| namespace blink { |
| |
| // Implementation detail of VideoDecoderBroker. Helps safely perform decoder |
| // tasks on the media thread. |
| class MediaVideoTaskWrapper; |
| |
| // Client interface for MediaVideoTaskWrapper. Implementation detail of |
| // VideoDecoderBroker, but we need to define it here to implement it below. |
| // |
| // This avoids having pass-through callbacks from main->media task sequence, |
| // which is unsafe because the public callers of broker APIs may be broken if |
| // their callback is destructed on another thread. |
| // |
| // An int "cb_id" is used for those that are traditionally OnceCallbacks to |
| // lookup the correct public callback. |
| class CrossThreadVideoDecoderClient { |
| public: |
| struct DecoderDetails { |
| media::VideoDecoderType decoder_id; |
| bool is_platform_decoder; |
| bool needs_bitstream_conversion; |
| int max_decode_requests; |
| }; |
| |
| virtual void OnInitialize(media::DecoderStatus status, |
| absl::optional<DecoderDetails> details) = 0; |
| |
| virtual void OnDecodeDone(int cb_id, media::DecoderStatus status) = 0; |
| |
| virtual void OnDecodeOutput(scoped_refptr<media::VideoFrame> frame, |
| bool can_read_without_stalling) = 0; |
| |
| virtual void OnReset(int cb_id) = 0; |
| }; |
| |
| // This class brokers the connection between WebCodecs and an underlying |
| // media::VideoDecoder. It abstracts away details of construction and selection |
| // of the media/ decoder. It also handles thread-hopping as required by |
| // underlying APIS. |
| // |
| // A new underlying decoder is selected anytime Initialize() is called. |
| // TODO(chcunningham): Elide re-selection if the config has not significantly |
| // changed. |
| // |
| // All API calls and callbacks must occur on the main thread. |
| class MODULES_EXPORT VideoDecoderBroker : public media::VideoDecoder, |
| public CrossThreadVideoDecoderClient { |
| public: |
| // |gpu_factories| may be null when GPU accelerated decoding is not available. |
| explicit VideoDecoderBroker( |
| ExecutionContext& execution_context, |
| media::GpuVideoAcceleratorFactories* gpu_factories, |
| media::MediaLog* media_log); |
| ~VideoDecoderBroker() override; |
| |
| // Disallow copy and assign. |
| VideoDecoderBroker(const VideoDecoderBroker&) = delete; |
| VideoDecoderBroker& operator=(const VideoDecoderBroker&) = delete; |
| |
| // VideoDecoder implementation. |
| media::VideoDecoderType GetDecoderType() const override; |
| bool IsPlatformDecoder() const override; |
| void Initialize(const media::VideoDecoderConfig& config, |
| bool low_delay, |
| media::CdmContext* cdm_context, |
| InitCB init_cb, |
| const OutputCB& output_cb, |
| const media::WaitingCB& waiting_cb) override; |
| void Decode(scoped_refptr<media::DecoderBuffer> buffer, |
| DecodeCB decode_cb) override; |
| void Reset(base::OnceClosure reset_cb) override; |
| bool NeedsBitstreamConversion() const override; |
| bool CanReadWithoutStalling() const override; |
| int GetMaxDecodeRequests() const override; |
| |
| void SetHardwarePreference(HardwarePreference hardware_preference); |
| |
| private: |
| // Creates a new (incremented) callback ID from |last_callback_id_| for |
| // mapping in |pending_decode_cb_map_|. |
| int CreateCallbackId(); |
| |
| // MediaVideoTaskWrapper::CrossThreadVideoDecoderClient |
| void OnInitialize(media::DecoderStatus status, |
| absl::optional<DecoderDetails> details) override; |
| void OnDecodeDone(int cb_id, media::DecoderStatus status) override; |
| void OnDecodeOutput(scoped_refptr<media::VideoFrame> frame, |
| bool can_read_without_stalling) override; |
| void OnReset(int cb_id) override; |
| |
| // When media::GpuVideoAcceleratorFactories is provided, its API requires |
| // that we use its TaskRunner (the media thread). When not provided, this task |
| // runner will still be used to reduce contention on the main thread. |
| // TODO(chcunningham): Try to eliminate the Post(). Most of the |
| // underlying::VideoDecoders already offload their work, so this just adds |
| // overhead. |
| scoped_refptr<base::SequencedTaskRunner> media_task_runner_; |
| |
| // Owner of state and methods to be used on media_task_runner_; |
| std::unique_ptr<MediaVideoTaskWrapper> media_tasks_; |
| |
| // Wrapper state for GetDecoderType(), IsPlatformDecoder() and others. |
| absl::optional<DecoderDetails> decoder_details_; |
| |
| // Set to match the underlying decoder's answer at every OnDecodeOutput(). |
| bool can_read_without_stalling_ = true; |
| |
| // Holds the last key for callbacks in the map below. Incremented for each |
| // usage via CreateCallbackId(). |
| uint32_t last_callback_id_ = 0; |
| |
| // Maps a callback ID to pending Decode(). See CrossThreadVideoDecoderClient. |
| HashMap<int, DecodeCB> pending_decode_cb_map_; |
| |
| // Maps a callback ID to pending Reset(). See CrossThreadVideoDecoderClient. |
| HashMap<int, base::OnceClosure> pending_reset_cb_map_; |
| |
| // Pending InitCB saved from the last call to Initialize(); |
| InitCB init_cb_; |
| |
| // OutputCB saved from last call to Initialize(). |
| OutputCB output_cb_; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| base::WeakPtrFactory<VideoDecoderBroker> weak_factory_{this}; |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_DECODER_BROKER_H_ |