The branch, master has been updated
via 92f2f9ea5c49e94814693861a7e9e47c993fca2e (commit)
from 81362b319ea7244d8d17110adfa59f10c7e78268 (commit)
- Log -----------------------------------------------------------------
commit 92f2f9ea5c49e94814693861a7e9e47c993fca2e
Author: Araz Iusubov <[email protected]>
AuthorDate: Mon Nov 10 17:23:25 2025 +0100
Commit: Tong Wu <[email protected]>
CommitDate: Wed Nov 26 09:58:44 2025 +0000
avcodec/d3d12va_encode: D3D12 AV1 encoding support
Implement AV1 hardware encoding
using Direct3D 12 Video API (D3D12VA).
diff --git a/Changelog b/Changelog
index b4c23ac1ee..4648899ca3 100644
--- a/Changelog
+++ b/Changelog
@@ -10,6 +10,7 @@ version <next>:
- D3D12 H.264 encoder
- drawvg filter via libcairo
- ffmpeg CLI tiled HEIF support
+- D3D12 AV1 encoder
version 8.0:
diff --git a/configure b/configure
index 99734e9d03..7ef50095a3 100755
--- a/configure
+++ b/configure
@@ -3444,6 +3444,8 @@ amrwb_mediacodec_decoder_select="amr_parser"
av1_amf_encoder_deps="amf"
av1_amf_decoder_deps="amf"
av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS"
+av1_d3d12va_encoder_deps="d3d12va d3d12va_av1_headers"
+av1_d3d12va_encoder_select="cbs_av1 d3d12va_encode"
av1_mediacodec_decoder_deps="mediacodec"
av1_mediacodec_encoder_deps="mediacodec"
av1_mediacodec_encoder_select="extract_extradata_bsf"
@@ -6958,6 +6960,7 @@ 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
+test_code cc "windows.h d3d12video.h" "D3D12_VIDEO_ENCODER_CODEC c =
D3D12_VIDEO_ENCODER_CODEC_AV1; (void)c;" && enable d3d12va_av1_headers
check_type "windows.h" "DPI_AWARENESS_CONTEXT" -D_WIN32_WINNT=0x0A00
check_type "windows.h security.h schnlsp.h" SecPkgContext_KeyingMaterialInfo
-DSECURITY_WIN32
check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 0cd2408865..fba9f0aff0 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -274,6 +274,7 @@ OBJS-$(CONFIG_AURA_DECODER) += cyuv.o
OBJS-$(CONFIG_AURA2_DECODER) += aura.o
OBJS-$(CONFIG_AV1_DECODER) += av1dec.o av1_parse.o
OBJS-$(CONFIG_AV1_CUVID_DECODER) += cuviddec.o
+OBJS-$(CONFIG_AV1_D3D12VA_ENCODER) += d3d12va_encode_av1.o av1_levels.o
OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_AV1_MEDIACODEC_ENCODER) += mediacodecenc.o
OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 251ffae390..cce23d1541 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -855,6 +855,7 @@ extern const FFCodec ff_libaom_av1_decoder;
/* hwaccel hooks only, so prefer external decoders */
extern const FFCodec ff_av1_decoder;
extern const FFCodec ff_av1_cuvid_decoder;
+extern const FFCodec ff_av1_d3d12va_encoder;
extern const FFCodec ff_av1_mediacodec_decoder;
extern const FFCodec ff_av1_mediacodec_encoder;
extern const FFCodec ff_av1_nvenc_encoder;
diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c
index aa8a5982be..d28447c3c9 100644
--- a/libavcodec/d3d12va_encode.c
+++ b/libavcodec/d3d12va_encode.c
@@ -29,6 +29,7 @@
#include "libavutil/hwcontext_d3d12va_internal.h"
#include "libavutil/hwcontext_d3d12va.h"
+#include "config_components.h"
#include "avcodec.h"
#include "d3d12va_encode.h"
#include "encode.h"
@@ -144,6 +145,12 @@ static int
d3d12va_encode_create_metadata_buffers(AVCodecContext *avctx,
{
D3D12VAEncodeContext *ctx = avctx->priv_data;
int width = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) +
sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA);
+#if CONFIG_AV1_D3D12VA_ENCODER
+ if (ctx->codec->d3d12_codec == D3D12_VIDEO_ENCODER_CODEC_AV1) {
+ width +=
sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES)
+ + sizeof(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES);
+ }
+#endif
D3D12_HEAP_PROPERTIES encoded_meta_props = { .Type =
D3D12_HEAP_TYPE_DEFAULT }, resolved_meta_props;
D3D12_HEAP_TYPE resolved_heap_type = D3D12_HEAP_TYPE_READBACK;
HRESULT hr;
@@ -211,7 +218,7 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
.RateControl = ctx->rc,
.PictureTargetResolution = ctx->resolution,
.SelectedLayoutMode =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
- .FrameSubregionsLayoutData = { 0 },
+ .FrameSubregionsLayoutData = ctx->subregions_layout,
.CodecGopSequence = ctx->gop,
},
.pInputFrame = pic->input_surface->texture,
@@ -732,16 +739,21 @@ end:
static int d3d12va_encode_output(AVCodecContext *avctx,
FFHWBaseEncodePicture *base_pic, AVPacket
*pkt)
{
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
- D3D12VAEncodePicture *pic = base_pic->priv;
- AVPacket *pkt_ptr = pkt;
- int err;
+ D3D12VAEncodePicture *pic = base_pic->priv;
+ AVPacket *pkt_ptr = pkt;
+ int err = 0;
err = d3d12va_encode_wait(avctx, base_pic);
if (err < 0)
return err;
- err = d3d12va_encode_get_coded_data(avctx, pic, pkt);
+ if (ctx->codec->get_coded_data)
+ err = ctx->codec->get_coded_data(avctx, pic, pkt);
+ else
+ err = d3d12va_encode_get_coded_data(avctx, pic, pkt);
+
if (err < 0)
return err;
@@ -1129,6 +1141,9 @@ static int
d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
union {
D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264;
D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc;
+#if CONFIG_AV1_D3D12VA_ENCODER
+ D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT av1;
+#endif
} codec_support;
support.NodeIndex = 0;
@@ -1146,6 +1161,13 @@ static int
d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
support.PictureSupport.pHEVCSupport = &codec_support.hevc;
break;
+#if CONFIG_AV1_D3D12VA_ENCODER
+ case D3D12_VIDEO_ENCODER_CODEC_AV1:
+ memset(&codec_support.av1, 0, sizeof(codec_support.av1));
+ support.PictureSupport.DataSize = sizeof(codec_support.av1);
+ support.PictureSupport.pAV1Support = &codec_support.av1;
+ break;
+#endif
default:
av_assert0(0);
}
@@ -1171,6 +1193,13 @@ static int
d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
ref_l1 =
support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB;
break;
+#if CONFIG_AV1_D3D12VA_ENCODER
+ case D3D12_VIDEO_ENCODER_CODEC_AV1:
+ ref_l0 =
support.PictureSupport.pAV1Support->MaxUniqueReferencesPerFrame;
+ // AV1 doesn't use traditional L1 references like H.264/HEVC
+ ref_l1 = 0;
+ break;
+#endif
default:
av_assert0(0);
}
@@ -1521,6 +1550,12 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
if (err < 0)
goto fail;
+ if (ctx->codec->set_tile) {
+ err = ctx->codec->set_tile(avctx);
+ if (err < 0)
+ goto fail;
+ }
+
err = d3d12va_encode_init_rate_control(avctx);
if (err < 0)
goto fail;
diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h
index 5bd1eedb7f..b7cfea0582 100644
--- a/libavcodec/d3d12va_encode.h
+++ b/libavcodec/d3d12va_encode.h
@@ -264,6 +264,8 @@ typedef struct D3D12VAEncodeContext {
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE gop;
D3D12_VIDEO_ENCODER_LEVEL_SETTING level;
+
+ D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA
subregions_layout;
} D3D12VAEncodeContext;
typedef struct D3D12VAEncodeType {
@@ -306,6 +308,11 @@ typedef struct D3D12VAEncodeType {
*/
int (*set_level)(AVCodecContext *avctx);
+ /**
+ * Set codec-specific tile setting.
+ */
+ int (*set_tile)(AVCodecContext *avctx);
+
/**
* The size of any private data structure associated with each
* picture (can be zero if not required).
@@ -327,6 +334,12 @@ typedef struct D3D12VAEncodeType {
*/
int (*write_sequence_header)(AVCodecContext *avctx,
char *data, size_t *data_len);
+
+ /**
+ * Fill the coded data into AVPacket
+ */
+ int (*get_coded_data)(AVCodecContext *avctx,
+ D3D12VAEncodePicture *pic, AVPacket *pkt);
} D3D12VAEncodeType;
int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt);
diff --git a/libavcodec/d3d12va_encode_av1.c b/libavcodec/d3d12va_encode_av1.c
new file mode 100644
index 0000000000..e7a115a2ee
--- /dev/null
+++ b/libavcodec/d3d12va_encode_av1.c
@@ -0,0 +1,1182 @@
+/*
+ * 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
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/common.h"
+#include "libavutil/mem.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/hwcontext_d3d12va_internal.h"
+
+#include "config_components.h"
+#include "avcodec.h"
+#include "cbs.h"
+#include "cbs_av1.h"
+#include "av1_levels.h"
+#include "codec_internal.h"
+#include "d3d12va_encode.h"
+#include "encode.h"
+#include "hw_base_encode.h"
+
+#include <d3d12.h>
+#include <d3d12video.h>
+
+#ifndef D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX
+#define D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX ( 0xff )
+#endif
+
+typedef struct D3D12VAHWBaseEncodeAV1 {
+ AV1RawOBU raw_sequence_header;
+ AV1RawOBU raw_frame_header;
+ AV1RawOBU raw_tile_group;
+} D3D12VAHWBaseEncodeAV1;
+
+typedef struct D3D12VAHWBaseEncodeAV1Opts {
+ int tier; // 0: Main tier, 1: High tier
+ int level; // AV1 level (2.0-7.3 map to 0-23)
+
+ int enable_cdef; // Constrained Directional Enhancement Filter
+ int enable_restoration; // loop restoration
+ int enable_superres; // super-resolution
+ int enable_ref_frame_mvs;
+
+ int enable_jnt_comp;
+ int enable_128x128_superblock;
+
+ int enable_warped_motion;
+ int enable_intra_edge_filter;
+ int enable_interintra_compound;
+ int enable_masked_compound;
+ int enable_filter_intra;
+
+ int enable_loop_filter;
+ int enable_loop_filter_delta;
+ int enable_dual_filter;
+
+ int enable_palette;
+ int enable_intra_block_copy;
+} D3D12VAHWBaseEncodeAV1Opts;
+
+typedef struct D3D12VAEncodeAV1Picture {
+ uint8_t temporal_id;
+ uint8_t spatial_id;
+ uint8_t show_frame;
+ uint8_t frame_type;
+ uint16_t last_idr_frame;
+ uint8_t slot;
+} D3D12VAEncodeAV1Picture;
+
+typedef struct D3D12VAEncodeAV1Context {
+ D3D12VAEncodeContext common;
+ // User options.
+ int qp;
+ int profile;
+ int level;
+ int tier;
+
+ uint8_t q_idx_idr;
+ uint8_t q_idx_p;
+
+ // Writer structures.
+ D3D12VAHWBaseEncodeAV1 units;
+ D3D12VAHWBaseEncodeAV1Opts unit_opts;
+
+ CodedBitstreamContext *cbc;
+ CodedBitstreamFragment current_obu;
+ D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAGS post_encode_values_flag;
+ AVFifo *picture_header_list;
+} D3D12VAEncodeAV1Context;
+
+typedef struct D3D12VAEncodeAV1Level {
+ uint8_t level;
+ D3D12_VIDEO_ENCODER_AV1_LEVELS d3d12_level;
+} D3D12VAEncodeAV1Level;
+
+
+static const D3D12VAEncodeAV1Level av1_levels[] = {
+ { 0, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_0 },
+ { 1, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_1 },
+ { 2, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_2 },
+ { 3, D3D12_VIDEO_ENCODER_AV1_LEVELS_2_3 },
+ { 4, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_0 },
+ { 5, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_1 },
+ { 6, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_2 },
+ { 7, D3D12_VIDEO_ENCODER_AV1_LEVELS_3_3 },
+ { 8, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_0 },
+ { 9, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_1 },
+ { 10, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_2 },
+ { 11, D3D12_VIDEO_ENCODER_AV1_LEVELS_4_3 },
+ { 12, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_0 },
+ { 13, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_1 },
+ { 14, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2 },
+ { 15, D3D12_VIDEO_ENCODER_AV1_LEVELS_5_3 },
+ { 16, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_0 },
+ { 17, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_1 },
+ { 18, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_2 },
+ { 19, D3D12_VIDEO_ENCODER_AV1_LEVELS_6_3 },
+ { 20, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_0 },
+ { 21, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_1 },
+ { 22, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_2 },
+ { 23, D3D12_VIDEO_ENCODER_AV1_LEVELS_7_3 },
+};
+
+static const D3D12_VIDEO_ENCODER_AV1_PROFILE profile_main =
D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN;
+static const D3D12_VIDEO_ENCODER_AV1_PROFILE profile_high =
D3D12_VIDEO_ENCODER_AV1_PROFILE_HIGH;
+static const D3D12_VIDEO_ENCODER_AV1_PROFILE profile_professional =
D3D12_VIDEO_ENCODER_AV1_PROFILE_PROFESSIONAL;
+
+#define D3D_PROFILE_DESC(name) \
+ { sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE), { .pAV1Profile =
(D3D12_VIDEO_ENCODER_AV1_PROFILE *)&profile_ ## name } }
+static const D3D12VAEncodeProfile d3d12va_encode_av1_profiles[] = {
+ { AV_PROFILE_AV1_MAIN, 8, 3, 1, 1, D3D_PROFILE_DESC(main)
},
+ { AV_PROFILE_AV1_MAIN, 10, 3, 1, 1, D3D_PROFILE_DESC(main)
},
+ { AV_PROFILE_AV1_HIGH, 10, 3, 1, 1, D3D_PROFILE_DESC(high)
},
+ { AV_PROFILE_AV1_PROFESSIONAL, 8, 3, 1, 1, D3D_PROFILE_DESC(professional)
},
+ { AV_PROFILE_AV1_PROFESSIONAL, 10, 3, 1, 1, D3D_PROFILE_DESC(professional)
},
+ { AV_PROFILE_AV1_PROFESSIONAL, 12, 3, 1, 1, D3D_PROFILE_DESC(professional)
},
+ { AV_PROFILE_UNKNOWN },
+};
+
+static int d3d12va_encode_av1_write_obu(AVCodecContext *avctx,
+ char *data, size_t *data_len,
+ CodedBitstreamFragment *obu)
+{
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ int err = 0;
+
+ err = ff_cbs_write_fragment_data(priv->cbc, obu);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to write packed OBU data.\n");
+ return err;
+ }
+
+ memcpy(data, obu->data, obu->data_size);
+ *data_len = (8 * obu->data_size) - obu->data_bit_padding;
+
+ return 0;
+}
+
+static int d3d12va_encode_av1_add_obu(AVCodecContext* avctx,
+ CodedBitstreamFragment* au,
+ CodedBitstreamUnitType obu_type,
+ void* obu_unit)
+{
+ int err = 0;
+
+ err = ff_cbs_insert_unit_content(au, -1, obu_type, obu_unit, NULL);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: "
+ "type = %d.\n", obu_type);
+ return err;
+ }
+ return 0;
+}
+
+static int d3d12va_encode_av1_write_sequence_header(AVCodecContext *avctx,
+ char *data, size_t
*data_len)
+{
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ CodedBitstreamFragment *obu = &priv->current_obu;
+ int err = 0;
+
+ priv->units.raw_sequence_header.header.obu_type = AV1_OBU_SEQUENCE_HEADER;
+ err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_SEQUENCE_HEADER,
&priv->units.raw_sequence_header);
+ if (err < 0)
+ goto fail;
+
+ err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu);
+
+fail:
+ ff_cbs_fragment_reset(obu);
+ return err;
+}
+
+static int
d3d12va_encode_av1_update_current_frame_picture_header(AVCodecContext *avctx,
+
D3D12VAEncodePicture *pic,
+ AV1RawOBU
*frameheader_obu)
+{
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ AV1RawFrameHeader *fh = &frameheader_obu->obu.frame_header;
+ uint8_t *data = NULL;
+ HRESULT hr = S_OK;
+ int err = 0;
+ D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES *post_encode_values = NULL;
+
+ // Update the frame header according to the picture post_encode_values
+ hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data);
+ if (FAILED(hr)) {
+ err = AVERROR_UNKNOWN;
+ return err;
+ }
+ post_encode_values = (D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES*) (data +
+ sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) +
+ sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA) +
+
sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES));
+
+ if (priv->post_encode_values_flag &
D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION) {
+ fh->base_q_idx = post_encode_values->Quantization.BaseQIndex;
+ fh->delta_q_y_dc = post_encode_values->Quantization.YDCDeltaQ;
+ fh->delta_q_u_dc = post_encode_values->Quantization.UDCDeltaQ;
+ fh->delta_q_u_ac = post_encode_values->Quantization.UACDeltaQ;
+ fh->delta_q_v_dc = post_encode_values->Quantization.VDCDeltaQ;
+ fh->delta_q_v_ac = post_encode_values->Quantization.VACDeltaQ;
+ fh->using_qmatrix = post_encode_values->Quantization.UsingQMatrix;
+ fh->qm_y = post_encode_values->Quantization.QMY;
+ fh->qm_u = post_encode_values->Quantization.QMU;
+ fh->qm_v = post_encode_values->Quantization.QMV;
+ }
+
+ if (priv->post_encode_values_flag &
D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER) {
+ fh->loop_filter_level[0] =
post_encode_values->LoopFilter.LoopFilterLevel[0];
+ fh->loop_filter_level[1] =
post_encode_values->LoopFilter.LoopFilterLevel[1];
+ fh->loop_filter_level[2] =
post_encode_values->LoopFilter.LoopFilterLevelU;
+ fh->loop_filter_level[3] =
post_encode_values->LoopFilter.LoopFilterLevelV;
+ fh->loop_filter_sharpness =
post_encode_values->LoopFilter.LoopFilterSharpnessLevel;
+ fh->loop_filter_delta_enabled =
post_encode_values->LoopFilter.LoopFilterDeltaEnabled;
+ if (fh->loop_filter_delta_enabled) {
+ for (int i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) {
+ fh->loop_filter_ref_deltas[i] =
post_encode_values->LoopFilter.RefDeltas[i];
+ fh->update_ref_delta[i] =
post_encode_values->LoopFilter.RefDeltas[i];
+ }
+ for (int i = 0; i < 2; i++) {
+ fh->loop_filter_mode_deltas[i] =
post_encode_values->LoopFilter.ModeDeltas[i];
+ fh->update_mode_delta[i] =
post_encode_values->LoopFilter.ModeDeltas[i];
+ }
+ }
+ }
+ if (priv->post_encode_values_flag &
D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CDEF_DATA) {
+ fh->cdef_damping_minus_3 = post_encode_values->CDEF.CdefDampingMinus3;
+ fh->cdef_bits = post_encode_values->CDEF.CdefBits;
+ for (int i = 0; i < 8; i++) {
+ fh->cdef_y_pri_strength[i] =
post_encode_values->CDEF.CdefYPriStrength[i];
+ fh->cdef_y_sec_strength[i] =
post_encode_values->CDEF.CdefYSecStrength[i];
+ fh->cdef_uv_pri_strength[i] =
post_encode_values->CDEF.CdefUVPriStrength[i];
+ fh->cdef_uv_sec_strength[i] =
post_encode_values->CDEF.CdefUVSecStrength[i];
+ }
+ }
+ if (priv->post_encode_values_flag &
D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION_DELTA) {
+ fh->delta_q_present =
post_encode_values->QuantizationDelta.DeltaQPresent;
+ fh->delta_q_res = post_encode_values->QuantizationDelta.DeltaQRes;
+ }
+
+ if (priv->post_encode_values_flag &
D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_REFERENCE_INDICES) {
+ for (int i = 0; i < AV1_REFS_PER_FRAME; i++) {
+ fh->ref_frame_idx[i] = post_encode_values->ReferenceIndices[i];
+ }
+ }
+
+ ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL);
+ return 0;
+}
+
+static int d3d12va_encode_av1_write_picture_header(AVCodecContext *avctx,
+ D3D12VAEncodePicture *pic,
+ char *data, size_t
*data_len)
+{
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ CodedBitstreamFragment *obu = &priv->current_obu;
+ AV1RawOBU *frameheader_obu = av_mallocz(sizeof(AV1RawOBU));
+ int err = 0;
+
+ av_fifo_read(priv->picture_header_list, frameheader_obu, 1);
+ err = d3d12va_encode_av1_update_current_frame_picture_header(avctx,
pic,frameheader_obu);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to update current frame picture
header: %d.\n", err);
+ return err;
+ }
+
+ // Add the frame header OBU
+ frameheader_obu->header.obu_has_size_field = 1;
+
+ err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER,
frameheader_obu);
+ if (err < 0)
+ goto fail;
+ err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu);
+
+fail:
+ ff_cbs_fragment_reset(obu);
+ av_freep(&frameheader_obu);
+ return err;
+}
+
+static int d3d12va_encode_av1_write_tile_group(AVCodecContext *avctx,
+ uint8_t* tile_group,
+ uint32_t tile_group_size,
+ char *data, size_t *data_len)
+{
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ CodedBitstreamFragment *obu = &priv->current_obu;
+ AV1RawOBU *tile_group_obu = &priv->units.raw_tile_group;
+ AV1RawTileGroup *tg = &tile_group_obu->obu.tile_group;
+ int err = 0;
+
+ tg->tile_data.data = tile_group;
+ tg->tile_data.data_ref = NULL;
+ tg->tile_data.data_size = tile_group_size;
+ tile_group_obu->header.obu_has_size_field = 1;
+ tile_group_obu->header.obu_type = AV1_OBU_TILE_GROUP;
+
+ err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_TILE_GROUP,
tile_group_obu);
+ if (err < 0)
+ goto fail;
+ err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu);
+
+fail:
+ ff_cbs_fragment_reset(obu);
+ return err;
+}
+
+static int d3d12va_encode_av1_get_buffer_size(AVCodecContext *avctx,
+ D3D12VAEncodePicture *pic,
size_t *size)
+{
+ D3D12VAEncodeContext *ctx =
avctx->priv_data;
+ D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta = NULL;
+ D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *subregion_meta = NULL;
+ uint8_t *data = NULL;
+ HRESULT hr = S_OK;
+ int err = 0;
+
+ hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data);
+ if (FAILED(hr)) {
+ err = AVERROR_UNKNOWN;
+ return err;
+ }
+
+ subregion_meta = (D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA*)(data +
sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA));
+ if (subregion_meta->bSize == 0) {
+ av_log(avctx, AV_LOG_ERROR, "No subregion metadata found\n");
+ err = AVERROR(EINVAL);
+ return err;
+ }
+ *size = subregion_meta->bSize;
+
+ ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL);
+
+ return 0;
+}
+
+static int d3d12va_encode_av1_get_coded_data(AVCodecContext *avctx,
+ D3D12VAEncodePicture *pic,
AVPacket *pkt)
+{
+ int err = 0;
+ uint8_t *ptr = NULL;
+ uint8_t *mapped_data = NULL;
+ size_t total_size = 0;
+ HRESULT hr = S_OK;
+ size_t av1_pic_hd_size = 0;
+ int tile_group_extra_size = 0;
+ size_t bit_len = 0;
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+
+ char pic_hd_data[MAX_PARAM_BUFFER_SIZE] = { 0 };
+
+ err = d3d12va_encode_av1_get_buffer_size(avctx, pic, &total_size);
+ if (err < 0)
+ goto end;
+
+ // Update the picture header and calculate the picture header size
+ memset(pic_hd_data, 0, sizeof(pic_hd_data));
+ err = d3d12va_encode_av1_write_picture_header(avctx, pic, pic_hd_data,
&av1_pic_hd_size);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to write picture header: %d.\n",
err);
+ return err;
+ }
+ av1_pic_hd_size /= 8;
+ av_log(avctx, AV_LOG_DEBUG, "AV1 picture header size: %zu bytes.\n",
av1_pic_hd_size);
+
+
+ tile_group_extra_size = (av_log2(total_size) + 7) / 7 + 1; // 1 byte for
obu header, rest for tile group LEB128 size
+ av_log(avctx, AV_LOG_DEBUG, "Tile group extra size: %d bytes.\n",
tile_group_extra_size);
+
+ total_size += (pic->header_size + tile_group_extra_size + av1_pic_hd_size);
+ av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"SIZE_SPECIFIER"\n",
total_size);
+
+ hr = ID3D12Resource_Map(pic->output_buffer, 0, NULL, (void
**)&mapped_data);
+ if (FAILED(hr)) {
+ err = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
+ if (err < 0)
+ goto end;
+ ptr = pkt->data;
+
+ memcpy(ptr, mapped_data, pic->header_size);
+
+ ptr += pic->header_size;
+ mapped_data += pic->aligned_header_size;
+ total_size -= pic->header_size;
+
+ memcpy(ptr, pic_hd_data, av1_pic_hd_size);
+ ptr += av1_pic_hd_size;
+ total_size -= av1_pic_hd_size;
+ av_log(avctx, AV_LOG_DEBUG, "AV1 total_size after write picture header:
%d.\n", total_size);
+
+ total_size -= tile_group_extra_size;
+ err = d3d12va_encode_av1_write_tile_group(avctx, mapped_data, total_size,
ptr, &bit_len);
+ if (err < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to write tile group: %d.\n", err);
+ goto end;
+ }
+ assert((total_size + tile_group_extra_size) * 8 == bit_len);
+
+ ID3D12Resource_Unmap(pic->output_buffer, 0, NULL);
+
+end:
+ av_buffer_unref(&pic->output_buffer_ref);
+ pic->output_buffer = NULL;
+ return err;
+}
+
+static int d3d12va_hw_base_encode_init_params_av1(FFHWBaseEncodeContext
*base_ctx,
+ AVCodecContext *avctx,
+ D3D12VAHWBaseEncodeAV1
*common,
+ D3D12VAHWBaseEncodeAV1Opts
*opts)
+{
+ AV1RawOBU *seqheader_obu = &common->raw_sequence_header;
+ AV1RawSequenceHeader *seq = &seqheader_obu->obu.sequence_header;
+ const AVPixFmtDescriptor *desc;
+
+ seq->seq_profile = avctx->profile;
+ if (!seq->seq_force_screen_content_tools)
+ seq->seq_force_integer_mv = AV1_SELECT_INTEGER_MV;
+ seq->seq_tier[0] = opts->tier;
+
+ desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
+ seq->color_config = (AV1RawColorConfig){
+ .high_bitdepth = desc->comp[0].depth == 8 ? 0 : 1,
+ .color_primaries = avctx->color_primaries,
+ .transfer_characteristics = avctx->color_trc,
+ .matrix_coefficients = avctx->colorspace,
+ .color_description_present_flag = (avctx->color_primaries !=
AVCOL_PRI_UNSPECIFIED ||
+ avctx->color_trc !=
AVCOL_TRC_UNSPECIFIED ||
+ avctx->colorspace !=
AVCOL_SPC_UNSPECIFIED),
+ .color_range = avctx->color_range == AVCOL_RANGE_JPEG,
+ .subsampling_x = desc->log2_chroma_w,
+ .subsampling_y = desc->log2_chroma_h,
+ };
+
+ switch (avctx->chroma_sample_location) {
+ case AVCHROMA_LOC_LEFT:
+ seq->color_config.chroma_sample_position = AV1_CSP_VERTICAL;
+ break;
+ case AVCHROMA_LOC_TOPLEFT:
+ seq->color_config.chroma_sample_position = AV1_CSP_COLOCATED;
+ break;
+ default:
+ seq->color_config.chroma_sample_position = AV1_CSP_UNKNOWN;
+ break;
+ }
+
+ if (avctx->level != AV_LEVEL_UNKNOWN) {
+ seq->seq_level_idx[0] = avctx->level;
+ }
+ else {
+ const AV1LevelDescriptor *level;
+ float framerate;
+
+ if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
+ framerate = avctx->framerate.num / avctx->framerate.den;
+ else
+ framerate = 0;
+
+ //currently only supporting 1 tile
+ level = ff_av1_guess_level(avctx->bit_rate, opts->tier,
+ base_ctx->surface_width, base_ctx->surface_height,
+ /*priv->tile_rows*/1 * 1/*priv->tile_cols*/,
+ /*priv->tile_cols*/1, framerate);
+ if (level) {
+ av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
+ seq->seq_level_idx[0] = level->level_idx;
+ }
+ else {
+ av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to "
+ "any normal level, using maximum parameters level by
default.\n");
+ seq->seq_level_idx[0] = 31;
+ seq->seq_tier[0] = 1;
+ }
+ }
+
+ // Still picture mode
+ seq->still_picture = (base_ctx->gop_size == 1);
+ seq->reduced_still_picture_header = seq->still_picture;
+
+ // Feature flags
+ seq->enable_filter_intra = opts->enable_filter_intra;
+ seq->enable_intra_edge_filter = opts->enable_intra_edge_filter;
+ seq->enable_interintra_compound = opts->enable_interintra_compound;
+ seq->enable_masked_compound = opts->enable_masked_compound;
+ seq->enable_warped_motion = opts->enable_warped_motion;
+ seq->enable_dual_filter = opts->enable_dual_filter;
+ seq->enable_order_hint = !seq->still_picture;
+ if (seq->enable_order_hint) {
+ seq->order_hint_bits_minus_1 = 7;
+ }
+ seq->enable_jnt_comp = opts->enable_jnt_comp && seq->enable_order_hint;
+ seq->enable_ref_frame_mvs = opts->enable_ref_frame_mvs &&
seq->enable_order_hint;
+ seq->enable_superres = opts->enable_superres;
+ seq->enable_cdef = opts->enable_cdef;
+ seq->enable_restoration = opts->enable_restoration;
+
+ return 0;
+
+}
+
+static int d3d12va_encode_av1_init_sequence_params(AVCodecContext *avctx)
+{
+ FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx;
+ AV1RawOBU *seqheader_obu = &priv->units.raw_sequence_header;
+ AV1RawSequenceHeader *seq =
&priv->units.raw_sequence_header.obu.sequence_header;
+
+ D3D12_VIDEO_ENCODER_AV1_PROFILE profile =
D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN;
+ D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS level = { 0 };
+ HRESULT hr;
+ int err;
+
+ D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 support = {
+ .NodeIndex = 0,
+ .Codec = D3D12_VIDEO_ENCODER_CODEC_AV1,
+ .InputFormat = hwctx->format,
+ .RateControl = ctx->rc,
+ .IntraRefresh =
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
+ .SubregionFrameEncoding =
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
+ .ResolutionsListCount = 1,
+ .pResolutionList = &ctx->resolution,
+ .CodecGopSequence = ctx->gop,
+ .MaxReferenceFramesInDPB = AV1_NUM_REF_FRAMES,
+ .CodecConfiguration = ctx->codec_conf,
+ .SuggestedProfile.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE),
+ .SuggestedProfile.pAV1Profile = &profile,
+ .SuggestedLevel.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS),
+ .SuggestedLevel.pAV1LevelSetting = &level,
+ .pResolutionDependentSupport = &ctx->res_limits,
+ .SubregionFrameEncodingData.pTilesPartition_AV1 =
ctx->subregions_layout.pTilesPartition_AV1,
+ };
+
+ hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1,
+ &support, sizeof(support));
+
+ if (FAILED(hr)) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to check encoder support(%lx).\n",
(long)hr);
+ return AVERROR(EINVAL);
+ }
+
+ if (!(support.SupportFlags &
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK)) {
+ av_log(avctx, AV_LOG_ERROR, "Driver does not support some request
D3D12VA AV1 features. %#x\n",
+ support.ValidationFlags);
+ return AVERROR(EINVAL);
+ }
+
+ if (support.SupportFlags &
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) {
+ ctx->is_texture_array = 1;
+ av_log(avctx, AV_LOG_DEBUG, "D3D12 video encode on this device uses
texture array mode.\n");
+ }
+
+ memset(seqheader_obu, 0, sizeof(*seqheader_obu));
+ seq->seq_profile = profile;
+ seq->seq_level_idx[0] = level.Level;
+ seq->seq_tier[0] = level.Tier;
+
+ seq->max_frame_width_minus_1 = ctx->resolution.Width - 1;
+ seq->max_frame_height_minus_1 = ctx->resolution.Height - 1;
+ seq->frame_width_bits_minus_1 = av_log2(ctx->resolution.Width);
+ seq->frame_height_bits_minus_1 = av_log2(ctx->resolution.Height);
+
+ seqheader_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER;
+
+ err = d3d12va_hw_base_encode_init_params_av1(base_ctx, avctx,
+ &priv->units,
&priv->unit_opts);
+ if (err < 0)
+ return err;
+
+ if (avctx->level == AV_LEVEL_UNKNOWN)
+ avctx->level = level.Level;
+
+ return 0;
+}
+
+static int d3d12va_encode_av1_get_encoder_caps(AVCodecContext *avctx)
+{
+ HRESULT hr = S_OK;
+ FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+
+ D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION *config;
+ D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT av1_caps;
+
+ D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codec_caps = {
+ .NodeIndex = 0,
+ .Codec = D3D12_VIDEO_ENCODER_CODEC_AV1,
+ .Profile = ctx->profile->d3d12_profile,
+ .CodecSupportLimits.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT),
+ };
+
+ codec_caps.CodecSupportLimits.pAV1Support = &av1_caps;
+
+ hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT,
+ &codec_caps,
sizeof(codec_caps));
+ if (!(SUCCEEDED(hr) && codec_caps.IsSupported))
+ return AVERROR(EINVAL);
+
+ ctx->codec_conf.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION);
+ ctx->codec_conf.pAV1Config = av_mallocz(ctx->codec_conf.DataSize);
+ if (!ctx->codec_conf.pAV1Config)
+ return AVERROR(ENOMEM);
+
+ priv->post_encode_values_flag = av1_caps.PostEncodeValuesFlags;
+ config = ctx->codec_conf.pAV1Config;
+
+ config->FeatureFlags = D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_NONE;
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) {
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK;
+ priv->unit_opts.enable_128x128_superblock = 1;
+ }
+
+ base_ctx->surface_width = FFALIGN(avctx->width,
priv->unit_opts.enable_128x128_superblock ? 128 : 64);
+ base_ctx->surface_height = FFALIGN(avctx->height,
priv->unit_opts.enable_128x128_superblock ? 128 : 64);
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) {
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER;
+ priv->unit_opts.enable_loop_filter = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) {
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING;
+ priv->unit_opts.enable_palette = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) {
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY;
+ priv->unit_opts.enable_intra_block_copy = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS) {
+ // Loop filter deltas
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS;
+ priv->unit_opts.enable_loop_filter_delta = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) {
+ // CDEF (Constrained Directional Enhancement Filter)
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING;
+ priv->unit_opts.enable_cdef = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) {
+ // Dual filter
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER;
+ priv->unit_opts.enable_dual_filter = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) {
+ // Joint compound prediction
+ config->FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP;
+ priv->unit_opts.enable_jnt_comp = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) {
+ // Frame reference motion vectors
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS;
+ priv->unit_opts.enable_ref_frame_mvs = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) {
+ // Super-resolution
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION;
+ priv->unit_opts.enable_superres = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) {
+ // Warped motion
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION;
+ priv->unit_opts.enable_warped_motion = 1;
+ }
+
+ if (av1_caps.SupportedFeatureFlags &
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) {
+ // Inter-intra compound prediction
+ config->FeatureFlags |=
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND;
+ priv->unit_opts.enable_interintra_compound = 1;
+ }
+
+ return 0;
+}
+
+static int d3d12va_encode_av1_configure(AVCodecContext *avctx)
+{
+ FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ int err = 0;
+ int fixed_qp_key, fixed_qp_inter;
+
+ err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_AV1, avctx);
+ if (err < 0)
+ return err;
+
+ if (ctx->rc.Mode == D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP) {
+ D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP *cqp_ctl;
+ fixed_qp_inter = av_clip_uintp2(ctx->rc_quality, 8);
+
+ if (avctx->i_quant_factor > 0.0)
+ fixed_qp_key = av_clip_uintp2((avctx->i_quant_factor *
fixed_qp_inter +
+ avctx->i_quant_offset) + 0.5, 8);
+ else
+ fixed_qp_key = fixed_qp_inter;
+
+ av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = "
+ "%d / %d for Key / Inter frames.\n",
+ fixed_qp_key, fixed_qp_inter);
+
+ ctx->rc.ConfigParams.DataSize =
sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP);
+ cqp_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
+ if (!cqp_ctl)
+ return AVERROR(ENOMEM);
+
+ cqp_ctl->ConstantQP_FullIntracodedFrame =
fixed_qp_key;
+ cqp_ctl->ConstantQP_InterPredictedFrame_PrevRefOnly =
fixed_qp_inter;
+ cqp_ctl->ConstantQP_InterPredictedFrame_BiDirectionalRef =
fixed_qp_inter;
+
+ ctx->rc.ConfigParams.pConfiguration_CQP = cqp_ctl;
+
+ priv->q_idx_idr = fixed_qp_key;
+ priv->q_idx_p = fixed_qp_inter;
+
+ }
+
+ // GOP configuration for AV1
+ ctx->gop.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE);
+ ctx->gop.pAV1SequenceStructure = av_mallocz(ctx->gop.DataSize);
+ if (!ctx->gop.pAV1SequenceStructure)
+ return AVERROR(ENOMEM);
+
+ ctx->gop.pAV1SequenceStructure->IntraDistance = base_ctx->gop_size;
+ ctx->gop.pAV1SequenceStructure->InterFramePeriod = base_ctx->b_per_p + 1;
+
+ return 0;
+}
+
+static int d3d12va_encode_av1_set_level(AVCodecContext *avctx)
+{
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ int i = 0;
+
+ ctx->level.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS);
+ ctx->level.pAV1LevelSetting = av_mallocz(ctx->level.DataSize);
+ if (!ctx->level.pAV1LevelSetting)
+ return AVERROR(ENOMEM);
+
+ if (avctx->level != AV_LEVEL_UNKNOWN) {
+ for (i = 0; i < FF_ARRAY_ELEMS(av1_levels); i++) {
+ if (avctx->level == av1_levels[i].level) {
+ ctx->level.pAV1LevelSetting->Level = av1_levels[i].d3d12_level;
+ break;
+ }
+ }
+
+ if (i == FF_ARRAY_ELEMS(av1_levels) ) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid AV1 level %d.\n",
avctx->level);
+ return AVERROR(EINVAL);
+ }
+ } else {
+ ctx->level.pAV1LevelSetting->Level =
D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2;
+ avctx->level = D3D12_VIDEO_ENCODER_AV1_LEVELS_5_2;
+ av_log(avctx, AV_LOG_DEBUG, "Using default AV1 level 5.2\n");
+ }
+
+ if (priv->tier == 1 || avctx->bit_rate > 30000000) {
+ ctx->level.pAV1LevelSetting->Tier = D3D12_VIDEO_ENCODER_AV1_TIER_HIGH;
+ av_log(avctx, AV_LOG_DEBUG, "Using AV1 High tier\n");
+ } else {
+ ctx->level.pAV1LevelSetting->Tier = D3D12_VIDEO_ENCODER_AV1_TIER_MAIN;
+ av_log(avctx, AV_LOG_DEBUG, "Using AV1 Main tier\n");
+ }
+
+ if (priv->tier >= 0) {
+ ctx->level.pAV1LevelSetting->Tier = priv->tier == 0 ?
+ D3D12_VIDEO_ENCODER_AV1_TIER_MAIN :
+ D3D12_VIDEO_ENCODER_AV1_TIER_HIGH;
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "AV1 level set to %d, tier: %s\n",
+ ctx->level.pAV1LevelSetting->Level,
+ ctx->level.pAV1LevelSetting->Tier ==
D3D12_VIDEO_ENCODER_AV1_TIER_MAIN ? "Main" : "High");
+
+ return 0;
+}
+
+static int d3d12va_encode_av1_set_tile(AVCodecContext *avctx)
+{
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+
+ ctx->subregions_layout.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES);
+ D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES
*tiles_layout = av_mallocz(ctx->subregions_layout.DataSize);
+ ctx->subregions_layout.pTilesPartition_AV1 = tiles_layout;
+
+ // Currently only support 1 tile
+ tiles_layout->RowCount = 1;
+ tiles_layout->ColCount = 1;
+
+ return 0;
+}
+
+static void d3d12va_encode_av1_free_picture_params(D3D12VAEncodePicture *pic)
+{
+ if (!pic->pic_ctl.pAV1PicData)
+ return;
+
+ av_freep(&pic->pic_ctl.pAV1PicData);
+}
+
+static int d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
+ FFHWBaseEncodePicture *pic)
+{
+ FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+ D3D12VAEncodePicture *d3d12va_pic = pic->priv;
+ D3D12VAEncodeAV1Picture *hpic = pic->codec_priv;
+ CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
+ AV1RawOBU *frameheader_obu =
&priv->units.raw_frame_header;
+ AV1RawFrameHeader *fh =
&frameheader_obu->obu.frame_header;
+
+ FFHWBaseEncodePicture *ref;
+ D3D12VAEncodeAV1Picture *href;
+ int i;
+
+ static const int8_t
default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] =
+ { 1, 0, 0, 0, -1, 0, -1, -1 };
+
+ memset(frameheader_obu, 0, sizeof(*frameheader_obu));
+
+ frameheader_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
+
+ d3d12va_pic->pic_ctl.DataSize =
sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA);
+ d3d12va_pic->pic_ctl.pAV1PicData =
av_mallocz(d3d12va_pic->pic_ctl.DataSize);
+ if (!d3d12va_pic->pic_ctl.pAV1PicData)
+ return AVERROR(ENOMEM);
+
+ // Initialize frame type and reference frame management
+ switch(pic->type) {
+ case FF_HW_PICTURE_TYPE_IDR:
+ fh->frame_type = AV1_FRAME_KEY;
+ fh->refresh_frame_flags = 0xFF;
+ fh->base_q_idx = priv->q_idx_idr;
+ hpic->slot = 0;
+ hpic->last_idr_frame = pic->display_order;
+ fh->tx_mode = AV1_TX_MODE_LARGEST;
+ break;
+
+ case FF_HW_PICTURE_TYPE_P:
+ fh->frame_type = AV1_FRAME_INTER;
+ fh->base_q_idx = priv->q_idx_p;
+ fh->tx_mode = AV1_TX_MODE_SELECT;
+
+ ref = pic->refs[0][pic->nb_refs[0] - 1];
+ href = ref->codec_priv;
+
+ /**
+ * The encoder uses a simple alternating reference frame strategy:
+ * - For P-frames, it uses the last reconstructed frame as a
reference.
+ * - To simplify the reference model of the encoder, the encoder
alternates between
+ * two reference frame slots (typically slot 0 and slot 1) for
storing reconstructed
+ * images and providing prediction references for the next frame.
+ */
+ if (base_ctx->ref_l0 > 1) {
+ hpic->slot = !href->slot;
+ } else {
+ hpic->slot = 0;
+ }
+ hpic->last_idr_frame = href->last_idr_frame;
+ fh->refresh_frame_flags = 1 << hpic->slot;
+
+ // Set the nearest frame in L0 as all reference frame.
+ for (i = 0; i < AV1_REFS_PER_FRAME; i++)
+ fh->ref_frame_idx[i] = href->slot;
+
+ fh->primary_ref_frame = href->slot;
+ fh->ref_order_hint[href->slot] = ref->display_order -
href->last_idr_frame;
+
+ // Set the 2nd nearest frame in L0 as Golden frame.
+ if (pic->nb_refs[0] > 1) {
+ ref = pic->refs[0][pic->nb_refs[0] - 2];
+ href = ref->codec_priv;
+ // Reference frame index 3 is the GOLDEN_FRAME
+ fh->ref_frame_idx[3] = href->slot;
+ fh->ref_order_hint[href->slot] = ref->display_order -
href->last_idr_frame;
+ } else if (base_ctx->ref_l0 == 1) {
+ fh->ref_order_hint[!href->slot] =
cbctx->ref[!href->slot].order_hint;
+ }
+ break;
+
+ case FF_HW_PICTURE_TYPE_B:
+ av_log(avctx, AV_LOG_ERROR, "D3D12 AV1 video encode on this device
requires B-frame support, "
+ "but it's not implemented.\n");
+ return AVERROR_PATCHWELCOME;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported picture type %d.\n",
pic->type);
+ }
+
+
+ cbctx->seen_frame_header = 0;
+
+ fh->show_frame = pic->display_order <= pic->encode_order;
+ fh->showable_frame = fh->frame_type != AV1_FRAME_KEY;
+ fh->order_hint = pic->display_order - hpic->last_idr_frame;
+ fh->frame_width_minus_1 = ctx->resolution.Width - 1;
+ fh->frame_height_minus_1 = ctx->resolution.Height - 1;
+ fh->render_width_minus_1 = fh->frame_width_minus_1;
+ fh->render_height_minus_1 = fh->frame_height_minus_1;
+ fh->is_filter_switchable = 1;
+ fh->interpolation_filter = AV1_INTERPOLATION_FILTER_SWITCHABLE;
+ fh->uniform_tile_spacing_flag = 1;
+ fh->width_in_sbs_minus_1[0] = (ctx->resolution.Width + 63 >> 6) -1; //
64x64 superblock size
+ fh->height_in_sbs_minus_1[0] = (ctx->resolution.Height + 63 >> 6) -1; //
64x64 superblock size
+
+ memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas,
+ AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t));
+
+ if (fh->frame_type == AV1_FRAME_KEY && fh->show_frame)
+ fh->error_resilient_mode = 1;
+
+ if (fh->frame_type == AV1_FRAME_KEY || fh->error_resilient_mode)
+ fh->primary_ref_frame = AV1_PRIMARY_REF_NONE;
+
+ d3d12va_pic->pic_ctl.pAV1PicData->FrameType = fh->frame_type;
+ d3d12va_pic->pic_ctl.pAV1PicData->TxMode = fh->tx_mode;
+ d3d12va_pic->pic_ctl.pAV1PicData->RefreshFrameFlags =
fh->refresh_frame_flags;
+ d3d12va_pic->pic_ctl.pAV1PicData->TemporalLayerIndexPlus1 =
hpic->temporal_id + 1;
+ d3d12va_pic->pic_ctl.pAV1PicData->SpatialLayerIndexPlus1 =
hpic->spatial_id + 1;
+ d3d12va_pic->pic_ctl.pAV1PicData->PictureIndex = pic->display_order;
+ d3d12va_pic->pic_ctl.pAV1PicData->InterpolationFilter =
D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE;
+ d3d12va_pic->pic_ctl.pAV1PicData->PrimaryRefFrame = fh->primary_ref_frame;
+ if (fh->error_resilient_mode)
+ d3d12va_pic->pic_ctl.pAV1PicData->Flags |=
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE;
+
+ if (pic->type == FF_HW_PICTURE_TYPE_IDR)
+ {
+ for (int i = 0; i < AV1_NUM_REF_FRAMES; i++) {
+
d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex
=
+ D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX;
+ }
+ } else if (pic->type == FF_HW_PICTURE_TYPE_P) {
+ for (i = 0; i < pic->nb_refs[0]; i++) {
+ FFHWBaseEncodePicture *ref_pic = pic->refs[0][i];
+
d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex
=
+ ((D3D12VAEncodeAV1Picture*)ref_pic->codec_priv)->slot;
+ }
+ }
+ // Set reference frame management
+ memset(d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices, 0, sizeof(UINT)
* AV1_REFS_PER_FRAME);
+ if (pic->type == FF_HW_PICTURE_TYPE_P) {
+ for (i = 0; i < AV1_REFS_PER_FRAME; i++)
+ d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices[i] =
fh->ref_frame_idx[i];
+ }
+
+ int ret = av_fifo_write(priv->picture_header_list,
&priv->units.raw_frame_header, 1);
+
+ return 0;
+}
+
+
+static const D3D12VAEncodeType d3d12va_encode_type_av1 = {
+ .profiles = d3d12va_encode_av1_profiles,
+
+ .d3d12_codec = D3D12_VIDEO_ENCODER_CODEC_AV1,
+
+ .flags = FF_HW_FLAG_B_PICTURES |
+ FF_HW_FLAG_B_PICTURE_REFERENCES |
+ FF_HW_FLAG_NON_IDR_KEY_PICTURES,
+
+ .default_quality = 25,
+
+ .get_encoder_caps = &d3d12va_encode_av1_get_encoder_caps,
+
+ .configure = &d3d12va_encode_av1_configure,
+
+ .set_level = &d3d12va_encode_av1_set_level,
+
+ .set_tile = &d3d12va_encode_av1_set_tile,
+
+ .picture_priv_data_size = sizeof(D3D12VAEncodeAV1Picture),
+
+ .init_sequence_params = &d3d12va_encode_av1_init_sequence_params,
+
+ .init_picture_params = &d3d12va_encode_av1_init_picture_params,
+
+ .free_picture_params = &d3d12va_encode_av1_free_picture_params,
+
+ .write_sequence_header = &d3d12va_encode_av1_write_sequence_header,
+
+#ifdef CONFIG_AV1_D3D12VA_ENCODER
+ .get_coded_data = &d3d12va_encode_av1_get_coded_data,
+#endif
+};
+
+static int d3d12va_encode_av1_init(AVCodecContext *avctx)
+{
+ D3D12VAEncodeContext *ctx = avctx->priv_data;
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+
+ ctx->codec = &d3d12va_encode_type_av1;
+
+ if (avctx->profile == AV_PROFILE_UNKNOWN)
+ avctx->profile = priv->profile;
+ if (avctx->level == AV_LEVEL_UNKNOWN)
+ avctx->level = priv->level;
+
+ if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0xff) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit "
+ "in 8-bit unsigned integer.\n", avctx->level);
+ return AVERROR(EINVAL);
+ }
+
+ if (priv->qp > 0)
+ ctx->explicit_qp = priv->qp;
+
+ priv->picture_header_list = av_fifo_alloc2(2, sizeof(AV1RawOBU),
AV_FIFO_FLAG_AUTO_GROW);
+
+ return ff_d3d12va_encode_init(avctx);
+}
+
+static int d3d12va_encode_av1_close(AVCodecContext *avctx)
+{
+ D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+
+ ff_cbs_fragment_free(&priv->current_obu);
+ ff_cbs_close(&priv->cbc);
+
+ av_freep(&priv->common.codec_conf.pAV1Config);
+ av_freep(&priv->common.gop.pAV1SequenceStructure);
+ av_freep(&priv->common.level.pAV1LevelSetting);
+ av_freep(&priv->common.subregions_layout.pTilesPartition_AV1);
+
+ av_fifo_freep2(&priv->picture_header_list);
+
+ return ff_d3d12va_encode_close(avctx);
+}
+
+#define OFFSET(x) offsetof(D3D12VAEncodeAV1Context, x)
+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
+static const AVOption d3d12va_encode_av1_options[] = {
+ HW_BASE_ENCODE_COMMON_OPTIONS,
+ D3D12VA_ENCODE_RC_OPTIONS,
+
+ { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)",
+ OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 52, FLAGS },
+
+ { "profile", "Set profile (general_profile_idc)",
+ OFFSET(profile), AV_OPT_TYPE_INT,
+ { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xff, FLAGS,
"profile" },
+
+#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
+ { .i64 = value }, 0, 0, FLAGS, "profile"
+ { PROFILE("main", AV_PROFILE_AV1_MAIN) },
+ { PROFILE("high", AV_PROFILE_AV1_HIGH) },
+ { PROFILE("professional", AV_PROFILE_AV1_PROFESSIONAL) },
+#undef PROFILE
+
+ { "tier", "Set tier (general_tier_flag)",
+ OFFSET(unit_opts.tier), AV_OPT_TYPE_INT,
+ { .i64 = 0 }, 0, 1, FLAGS, "tier" },
+ { "main", NULL, 0, AV_OPT_TYPE_CONST,
+ { .i64 = 0 }, 0, 0, FLAGS, "tier" },
+ { "high", NULL, 0, AV_OPT_TYPE_CONST,
+ { .i64 = 1 }, 0, 0, FLAGS, "tier" },
+
+ { "level", "Set level (general_level_idc)",
+ OFFSET(level), AV_OPT_TYPE_INT,
+ { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0xff, FLAGS, "level" },
+
+#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
+ { .i64 = value }, 0, 0, FLAGS, "level"
+ { LEVEL("2.0", 0) },
+ { LEVEL("2.1", 1) },
+ { LEVEL("2.2", 2) },
+ { LEVEL("2.3", 3) },
+ { LEVEL("3.0", 4) },
+ { LEVEL("3.1", 5) },
+ { LEVEL("3.2", 6) },
+ { LEVEL("3.3", 7) },
+ { LEVEL("4.0", 8) },
+ { LEVEL("4.1", 9) },
+ { LEVEL("4.2", 10) },
+ { LEVEL("4.3", 11) },
+ { LEVEL("5.0", 12) },
+ { LEVEL("5.1", 13) },
+ { LEVEL("5.2", 14) },
+ { LEVEL("5.3", 15) },
+ { LEVEL("6.0", 16) },
+ { LEVEL("6.1", 17) },
+ { LEVEL("6.2", 18) },
+ { LEVEL("6.3", 19) },
+ { LEVEL("7.0", 20) },
+ { LEVEL("7.1", 21) },
+ { LEVEL("7.2", 22) },
+ { LEVEL("7.3", 23) },
+#undef LEVEL
+ { NULL },
+};
+
+static const FFCodecDefault d3d12va_encode_av1_defaults[] = {
+ { "b", "0" },
+ { "bf", "0" },
+ { "g", "120" },
+ { "i_qfactor", "1" },
+ { "i_qoffset", "0" },
+ { "b_qfactor", "1" },
+ { "b_qoffset", "0" },
+ { "qmin", "-1" },
+ { "qmax", "-1" },
+ { "refs", "0" },
+ { NULL },
+};
+
+static const AVClass d3d12va_encode_av1_class = {
+ .class_name = "av1_d3d12va",
+ .item_name = av_default_item_name,
+ .option = d3d12va_encode_av1_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const FFCodec ff_av1_d3d12va_encoder = {
+ .p.name = "av1_d3d12va",
+ CODEC_LONG_NAME("D3D12VA av1 encoder"),
+ .p.type = AVMEDIA_TYPE_VIDEO,
+ .p.id = AV_CODEC_ID_AV1,
+ .priv_data_size = sizeof(D3D12VAEncodeAV1Context),
+ .init = &d3d12va_encode_av1_init,
+ FF_CODEC_RECEIVE_PACKET_CB(&ff_d3d12va_encode_receive_packet),
+ .close = &d3d12va_encode_av1_close,
+ .p.priv_class = &d3d12va_encode_av1_class,
+ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
+ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
+ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
+ FF_CODEC_CAP_INIT_CLEANUP,
+ .defaults = d3d12va_encode_av1_defaults,
+ CODEC_PIXFMTS(AV_PIX_FMT_D3D12),
+ .hw_configs = ff_d3d12va_encode_hw_configs,
+ .p.wrapper_name = "d3d12va",
+};
-----------------------------------------------------------------------
Summary of changes:
Changelog | 1 +
configure | 3 +
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/d3d12va_encode.c | 45 +-
libavcodec/d3d12va_encode.h | 13 +
libavcodec/d3d12va_encode_av1.c | 1182 +++++++++++++++++++++++++++++++++++++++
7 files changed, 1241 insertions(+), 5 deletions(-)
create mode 100644 libavcodec/d3d12va_encode_av1.c
hooks/post-receive
--
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]