avcodec: add D3D12VA hardware HEVC encoder

This implementation is based on D3D12 Video Encoding Spec:
https://microsoft.github.io/DirectX-Specs/d3d/D3D12VideoEncoding.html

Sample command line for transcoding:
ffmpeg.exe -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.mp4
-c:v hevc_d3d12va output.mp4

Signed-off-by: Tong Wu <tong1.wu@intel.com>
This commit is contained in:
Tong Wu 2023-08-22 13:26:36 +08:00 committed by Lynne
parent d822146f4f
commit ba0c14e6bf
6 changed files with 2910 additions and 1 deletions

6
configure vendored
View File

@ -2547,6 +2547,7 @@ CONFIG_EXTRA="
cbs_mpeg2
cbs_vp8
cbs_vp9
d3d12va_encode
deflate_wrapper
dirac_parse
dnn
@ -3283,6 +3284,7 @@ wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel"
# hardware-accelerated codecs
d3d12va_encode_deps="d3d12va ID3D12VideoEncoder d3d12_encoder_feature"
mediafoundation_deps="mftransform_h MFCreateAlignedMemoryBuffer"
omx_deps="libdl pthreads"
omx_rpi_select="omx"
@ -3350,6 +3352,7 @@ h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m"
hevc_amf_encoder_deps="amf"
hevc_cuvid_decoder_deps="cuvid"
hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf"
hevc_d3d12va_encoder_select="cbs_h265 d3d12va_encode"
hevc_mediacodec_decoder_deps="mediacodec"
hevc_mediacodec_decoder_select="hevc_mp4toannexb_bsf hevc_parser"
hevc_mediacodec_encoder_deps="mediacodec"
@ -6692,6 +6695,9 @@ check_type "windows.h d3d11.h" "ID3D11VideoDecoder"
check_type "windows.h d3d11.h" "ID3D11VideoContext"
check_type "windows.h d3d12.h" "ID3D12Device"
check_type "windows.h d3d12video.h" "ID3D12VideoDecoder"
check_type "windows.h d3d12video.h" "ID3D12VideoEncoder"
test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_VIDEO feature = D3D12_FEATURE_VIDEO_ENCODER_CODEC" && \
test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS req" && enable d3d12_encoder_feature
check_type "windows.h" "DPI_AWARENESS_CONTEXT" -D_WIN32_WINNT=0x0A00
check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602
check_func_headers mfapi.h MFCreateAlignedMemoryBuffer -lmfplat

View File

@ -87,6 +87,7 @@ OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o
OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o
OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o
OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o
OBJS-$(CONFIG_D3D12VA_ENCODE) += d3d12va_encode.o hw_base_encode.o
OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o
OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o dovi_rpudec.o
OBJS-$(CONFIG_DOVI_RPUENC) += dovi_rpu.o dovi_rpuenc.o
@ -433,6 +434,8 @@ OBJS-$(CONFIG_HDR_ENCODER) += hdrenc.o
OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o
OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o
OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o
OBJS-$(CONFIG_HEVC_D3D12VA_ENCODER) += d3d12va_encode_hevc.o h265_profile_level.o \
h2645data.o
OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o
OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o
@ -1262,7 +1265,7 @@ SKIPHEADERS += %_tablegen.h \
SKIPHEADERS-$(CONFIG_AMF) += amfenc.h
SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h
SKIPHEADERS-$(CONFIG_D3D12VA) += d3d12va_decode.h
SKIPHEADERS-$(CONFIG_D3D12VA) += d3d12va_decode.h d3d12va_encode.h
SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h
SKIPHEADERS-$(CONFIG_JNI) += ffjni.h
SKIPHEADERS-$(CONFIG_LCMS2) += fflcms2.h

View File

@ -849,6 +849,7 @@ extern const FFCodec ff_h264_vaapi_encoder;
extern const FFCodec ff_h264_videotoolbox_encoder;
extern const FFCodec ff_hevc_amf_encoder;
extern const FFCodec ff_hevc_cuvid_decoder;
extern const FFCodec ff_hevc_d3d12va_encoder;
extern const FFCodec ff_hevc_mediacodec_decoder;
extern const FFCodec ff_hevc_mediacodec_encoder;
extern const FFCodec ff_hevc_mf_encoder;

1558
libavcodec/d3d12va_encode.c Normal file

File diff suppressed because it is too large Load Diff

334
libavcodec/d3d12va_encode.h Normal file
View File

@ -0,0 +1,334 @@
/*
* Direct3D 12 HW acceleration video encoder
*
* Copyright (c) 2024 Intel Corporation
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_D3D12VA_ENCODE_H
#define AVCODEC_D3D12VA_ENCODE_H
#include "libavutil/fifo.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_d3d12va_internal.h"
#include "libavutil/hwcontext_d3d12va.h"
#include "avcodec.h"
#include "internal.h"
#include "hwconfig.h"
#include "hw_base_encode.h"
struct D3D12VAEncodeType;
extern const AVCodecHWConfigInternal *const ff_d3d12va_encode_hw_configs[];
#define MAX_PARAM_BUFFER_SIZE 4096
#define D3D12VA_VIDEO_ENC_ASYNC_DEPTH 8
typedef struct D3D12VAEncodePicture {
FFHWBaseEncodePicture base;
int header_size;
AVD3D12VAFrame *input_surface;
AVD3D12VAFrame *recon_surface;
AVBufferRef *output_buffer_ref;
ID3D12Resource *output_buffer;
ID3D12Resource *encoded_metadata;
ID3D12Resource *resolved_metadata;
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA pic_ctl;
int fence_value;
} D3D12VAEncodePicture;
typedef struct D3D12VAEncodeProfile {
/**
* lavc profile value (AV_PROFILE_*).
*/
int av_profile;
/**
* Supported bit depth.
*/
int depth;
/**
* Number of components.
*/
int nb_components;
/**
* Chroma subsampling in width dimension.
*/
int log2_chroma_w;
/**
* Chroma subsampling in height dimension.
*/
int log2_chroma_h;
/**
* D3D12 profile value.
*/
D3D12_VIDEO_ENCODER_PROFILE_DESC d3d12_profile;
} D3D12VAEncodeProfile;
enum {
RC_MODE_AUTO,
RC_MODE_CQP,
RC_MODE_CBR,
RC_MODE_VBR,
RC_MODE_QVBR,
RC_MODE_MAX = RC_MODE_QVBR,
};
typedef struct D3D12VAEncodeRCMode {
/**
* Mode from above enum (RC_MODE_*).
*/
int mode;
/**
* Name.
*
*/
const char *name;
/**
* Uses bitrate parameters.
*
*/
int bitrate;
/**
* Supports maxrate distinct from bitrate.
*
*/
int maxrate;
/**
* Uses quality value.
*
*/
int quality;
/**
* Supports HRD/VBV parameters.
*
*/
int hrd;
/**
* D3D12 mode value.
*/
D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_mode;
} D3D12VAEncodeRCMode;
typedef struct D3D12VAEncodeContext {
FFHWBaseEncodeContext base;
/**
* Codec-specific hooks.
*/
const struct D3D12VAEncodeType *codec;
/**
* Explicitly set RC mode (otherwise attempt to pick from
* available modes).
*/
int explicit_rc_mode;
/**
* Explicitly-set QP, for use with the "qp" options.
* (Forces CQP mode when set, overriding everything else.)
*/
int explicit_qp;
/**
* RC quality level - meaning depends on codec and RC mode.
* In CQP mode this sets the fixed quantiser value.
*/
int rc_quality;
/**
* Chosen encoding profile details.
*/
const D3D12VAEncodeProfile *profile;
AVD3D12VADeviceContext *hwctx;
/**
* ID3D12Device3 interface.
*/
ID3D12Device3 *device3;
/**
* ID3D12VideoDevice3 interface.
*/
ID3D12VideoDevice3 *video_device3;
/**
* Pool of (reusable) bitstream output buffers.
*/
AVBufferPool *output_buffer_pool;
/**
* D3D12 video encoder.
*/
AVBufferRef *encoder_ref;
ID3D12VideoEncoder *encoder;
/**
* D3D12 video encoder heap.
*/
ID3D12VideoEncoderHeap *encoder_heap;
/**
* A cached queue for reusing the D3D12 command allocators.
*
* @see https://learn.microsoft.com/en-us/windows/win32/direct3d12/recording-command-lists-and-bundles#id3d12commandallocator
*/
AVFifo *allocator_queue;
/**
* D3D12 command queue.
*/
ID3D12CommandQueue *command_queue;
/**
* D3D12 video encode command list.
*/
ID3D12VideoEncodeCommandList2 *command_list;
/**
* The sync context used to sync command queue.
*/
AVD3D12VASyncContext sync_ctx;
/**
* The bi_not_empty feature.
*/
int bi_not_empty;
/**
* D3D12_FEATURE structures.
*/
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS req;
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS res_limits;
/**
* D3D12_VIDEO_ENCODER structures.
*/
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC resolution;
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codec_conf;
D3D12_VIDEO_ENCODER_RATE_CONTROL rc;
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE gop;
D3D12_VIDEO_ENCODER_LEVEL_SETTING level;
} D3D12VAEncodeContext;
typedef struct D3D12VAEncodeType {
/**
* List of supported profiles.
*/
const D3D12VAEncodeProfile *profiles;
/**
* D3D12 codec name.
*/
D3D12_VIDEO_ENCODER_CODEC d3d12_codec;
/**
* Codec feature flags.
*/
int flags;
/**
* Default quality for this codec - used as quantiser or RC quality
* factor depending on RC mode.
*/
int default_quality;
/**
* Query codec configuration and determine encode parameters like
* block sizes for surface alignment and slices. If not set, assume
* that all blocks are 16x16 and that surfaces should be aligned to match
* this.
*/
int (*get_encoder_caps)(AVCodecContext *avctx);
/**
* Perform any extra codec-specific configuration.
*/
int (*configure)(AVCodecContext *avctx);
/**
* Set codec-specific level setting.
*/
int (*set_level)(AVCodecContext *avctx);
/**
* The size of any private data structure associated with each
* picture (can be zero if not required).
*/
size_t picture_priv_data_size;
/**
* Fill the corresponding parameters.
*/
int (*init_sequence_params)(AVCodecContext *avctx);
int (*init_picture_params)(AVCodecContext *avctx,
D3D12VAEncodePicture *pic);
void (*free_picture_params)(D3D12VAEncodePicture *pic);
/**
* Write the packed header data to the provided buffer.
*/
int (*write_sequence_header)(AVCodecContext *avctx,
char *data, size_t *data_len);
} D3D12VAEncodeType;
int ff_d3d12va_encode_init(AVCodecContext *avctx);
int ff_d3d12va_encode_close(AVCodecContext *avctx);
#define D3D12VA_ENCODE_RC_MODE(name, desc) \
{ #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \
0, 0, FLAGS, .unit = "rc_mode" }
#define D3D12VA_ENCODE_RC_OPTIONS \
{ "rc_mode",\
"Set rate control mode", \
OFFSET(common.explicit_rc_mode), AV_OPT_TYPE_INT, \
{ .i64 = RC_MODE_AUTO }, RC_MODE_AUTO, RC_MODE_MAX, FLAGS, .unit = "rc_mode" }, \
{ "auto", "Choose mode automatically based on other parameters", \
0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_AUTO }, 0, 0, FLAGS, .unit = "rc_mode" }, \
D3D12VA_ENCODE_RC_MODE(CQP, "Constant-quality"), \
D3D12VA_ENCODE_RC_MODE(CBR, "Constant-bitrate"), \
D3D12VA_ENCODE_RC_MODE(VBR, "Variable-bitrate"), \
D3D12VA_ENCODE_RC_MODE(QVBR, "Quality-defined variable-bitrate")
#endif /* AVCODEC_D3D12VA_ENCODE_H */

File diff suppressed because it is too large Load Diff