blob: 36208ab23afc377290c8a2bf6bcf4024f4399ded [file] [log] [blame]
// 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.
#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 <optional>
#include <string>
#include <vector>
#include "base/functional/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/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,
std::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,
std::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.
std::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_