#ifndef MEDIA_GPU_WINDOWS_D3D12_VIDEO_ENCODE_DELEGATE_H_
#define MEDIA_GPU_WINDOWS_D3D12_VIDEO_ENCODE_DELEGATE_H_
#include "third_party/microsoft_dxheaders/src/include/directx/d3d12.h"
#include <wrl.h>
#include "base/functional/callback.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/encoder_status.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/svc_layers.h"
#include "media/gpu/windows/d3d12_video_encoder_wrapper.h"
#include "media/gpu/windows/d3d12_video_helpers.h"
#include "media/gpu/windows/d3d12_video_processor_wrapper.h"
#include "media/video/video_encode_accelerator.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
namespace media {
class MEDIA_GPU_EXPORT D3D12VideoEncodeDelegate {
public:
static constexpr size_t kAV1DPBMaxSize = 8;
struct EncodeResult {
int32_t bitstream_buffer_id;
BitstreamBufferMetadata metadata;
};
static VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles(
ID3D12VideoDevice3* video_device,
const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
const std::vector<D3D12_VIDEO_ENCODER_CODEC>& codecs);
explicit D3D12VideoEncodeDelegate(
Microsoft::WRL::ComPtr<ID3D12VideoDevice3> video_device);
virtual ~D3D12VideoEncodeDelegate();
virtual EncoderStatus Initialize(VideoEncodeAccelerator::Config config);
virtual size_t GetMaxNumOfRefFrames() const = 0;
virtual size_t GetMaxNumOfManualRefBuffers() const = 0;
virtual bool SupportsRateControlReconfiguration() const = 0;
virtual bool ReportsAverageQp() const;
virtual bool UpdateRateControl(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate);
virtual EncoderStatus::Or<EncodeResult> Encode(
Microsoft::WRL::ComPtr<ID3D12Resource> input_frame,
UINT input_frame_subresource,
const gfx::ColorSpace& input_frame_color_space,
const BitstreamBuffer& bitstream_buffer,
const VideoEncoder::EncodeOptions& options);
virtual EncoderStatus EncodeImpl(
ID3D12Resource* input_frame,
UINT input_frame_subresource,
const VideoEncoder::EncodeOptions& options,
const gfx::ColorSpace& input_color_space) = 0;
uint8_t GetNumTemporalLayers() const;
void SetFactoriesForTesting(
base::RepeatingCallback<decltype(CreateD3D12VideoEncoderWrapper)>
video_encoder_wrapper_factory,
base::RepeatingCallback<
decltype(std::make_unique<D3D12VideoProcessorWrapper,
Microsoft::WRL::ComPtr<ID3D12VideoDevice>>)>
video_processor_wrapper_factory) {
video_encoder_wrapper_factory_ = std::move(video_encoder_wrapper_factory);
video_processor_wrapper_factory_ =
std::move(video_processor_wrapper_factory);
}
D3D12VideoEncoderWrapper* GetVideoEncoderWrapperForTesting() {
return video_encoder_wrapper_.get();
}
D3D12VideoProcessorWrapper* GetVideoProcessorWrapperForTesting() {
return video_processor_wrapper_.get();
}
DXGI_FORMAT GetFormatForTesting() const { return input_format_; }
protected:
class D3D12VideoEncoderRateControl {
public:
enum class FrameType { kIntra, kInterPrev, kInterBiDirectional };
D3D12VideoEncoderRateControl();
D3D12VideoEncoderRateControl(const D3D12VideoEncoderRateControl& other);
D3D12VideoEncoderRateControl& operator=(
const D3D12VideoEncoderRateControl& other);
static D3D12VideoEncoderRateControl CreateCqp(uint32_t i_frame_qp,
uint32_t p_frame_qp,
uint32_t b_frame_qp);
static D3D12VideoEncoderRateControl Create(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate,
ID3D12VideoDevice3* video_device,
VideoCodecProfile output_profile);
D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE GetMode() const;
void SetCQP(FrameType frame_type, uint32_t qp);
const D3D12_VIDEO_ENCODER_RATE_CONTROL& GetD3D12VideoEncoderRateControl()
const {
return rate_control_;
}
bool operator==(const D3D12VideoEncoderRateControl& other) const;
private:
D3D12_VIDEO_ENCODER_RATE_CONTROL rate_control_{};
union {
D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP cqp;
D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR cbr;
D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR vbr;
} params_{};
};
virtual EncoderStatus InitializeVideoEncoder(
const VideoEncodeAccelerator::Config& config) = 0;
virtual EncoderStatus::Or<size_t> GetEncodedBitstreamWrittenBytesCount(
const ScopedD3D12ResourceMap& metadata);
virtual EncoderStatus::Or<size_t> ReadbackBitstream(
base::span<uint8_t> bitstream_buffer);
Microsoft::WRL::ComPtr<ID3D12Device> device_;
Microsoft::WRL::ComPtr<ID3D12VideoDevice3> video_device_;
VideoBitrateAllocation bitrate_allocation_{Bitrate::Mode::kConstant};
uint32_t framerate_ = 30;
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC input_size_{};
DXGI_FORMAT input_format_ = DXGI_FORMAT_UNKNOWN;
D3D12VideoEncoderRateControl rate_control_;
VideoCodecProfile output_profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
base::RepeatingCallback<decltype(CreateD3D12VideoEncoderWrapper)>
video_encoder_wrapper_factory_ =
base::BindRepeating(&CreateD3D12VideoEncoderWrapper);
std::unique_ptr<D3D12VideoEncoderWrapper> video_encoder_wrapper_;
std::optional<SVCLayers> svc_layers_;
BitstreamBufferMetadata metadata_;
private:
base::RepeatingCallback<
decltype(std::make_unique<D3D12VideoProcessorWrapper,
Microsoft::WRL::ComPtr<ID3D12VideoDevice>>)>
video_processor_wrapper_factory_ = base::BindRepeating(
&std::make_unique<D3D12VideoProcessorWrapper,
Microsoft::WRL::ComPtr<ID3D12VideoDevice>>);
std::unique_ptr<D3D12VideoProcessorWrapper> video_processor_wrapper_;
Microsoft::WRL::ComPtr<ID3D12Resource> processed_input_frame_;
};
struct D3D12PictureBuffer {
raw_ptr<ID3D12Resource> resource_ = nullptr;
UINT subresource_ = 0;
};
template <size_t maxDpbSize>
class D3D12VideoEncodeDecodedPictureBuffers {
public:
D3D12VideoEncodeDecodedPictureBuffers();
virtual ~D3D12VideoEncodeDecodedPictureBuffers();
size_t size() const { return size_; }
bool InitializeTextureResources(ID3D12Device* device,
gfx::Size texture_size,
DXGI_FORMAT format,
size_t max_num_ref_frames,
bool use_texture_array = false);
D3D12PictureBuffer GetCurrentFrame() const;
void InsertCurrentFrame(size_t position);
void ReplaceWithCurrentFrame(size_t position);
void EraseFrame(size_t position);
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES ToD3D12VideoEncodeReferenceFrames();
private:
size_t size_ = 0;
absl::InlinedVector<Microsoft::WRL::ComPtr<ID3D12Resource>, maxDpbSize + 1>
resources_;
absl::InlinedVector<ID3D12Resource*, maxDpbSize + 1> raw_resources_;
absl::InlinedVector<UINT, maxDpbSize + 1> subresources_;
};
}
#endif