1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-02-04 06:08:26 +02:00
FFmpeg/libavcodec/dxva2_av1.c
Wu Jianhua 349ce30e4e avcodec: add D3D12VA hardware accelerated H264 decoding
The implementation is based on:
https://learn.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-overview

With the Direct3D 12 video decoding support, we can render or process
the decoded images by the pixel shaders or compute shaders directly
without the extra copy overhead, which is beneficial especially if you
are trying to render or post-process a 4K or 8K video.

The command below is how to enable d3d12va:
ffmpeg -hwaccel d3d12va -i input.mp4 output.mp4

Signed-off-by: Wu Jianhua <toqsxw@outlook.com>
Signed-off-by: Tong Wu <tong1.wu@intel.com>
2023-12-21 16:15:23 +08:00

510 lines
22 KiB
C

/*
* DXVA2 AV1 HW acceleration.
*
* copyright (c) 2020 Hendrik Leppkes
*
* 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 "config_components.h"
#include "libavutil/avassert.h"
#include "libavutil/pixdesc.h"
#include "dxva2_internal.h"
#include "av1dec.h"
#include "hwaccel_internal.h"
#define MAX_TILES 256
struct AV1DXVAContext {
FFDXVASharedContext shared;
unsigned int bitstream_allocated;
uint8_t *bitstream_cache;
};
struct av1_dxva2_picture_context {
DXVA_PicParams_AV1 pp;
unsigned tile_count;
DXVA_Tile_AV1 tiles[MAX_TILES];
uint8_t *bitstream;
unsigned bitstream_size;
};
static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq)
{
if (seq->seq_profile == 2 && seq->color_config.high_bitdepth)
return seq->color_config.twelve_bit ? 12 : 10;
else if (seq->seq_profile <= 2 && seq->color_config.high_bitdepth)
return 10;
else
return 8;
}
static int fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, const AV1DecContext *h,
DXVA_PicParams_AV1 *pp)
{
int i,j, uses_lr;
const AV1RawSequenceHeader *seq = h->raw_seq;
const AV1RawFrameHeader *frame_header = h->raw_frame_header;
const AV1RawFilmGrainParams *film_grain = &h->cur_frame.film_grain;
unsigned char remap_lr_type[4] = { AV1_RESTORE_NONE, AV1_RESTORE_SWITCHABLE, AV1_RESTORE_WIENER, AV1_RESTORE_SGRPROJ };
int apply_grain = !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && film_grain->apply_grain;
memset(pp, 0, sizeof(*pp));
pp->width = avctx->width;
pp->height = avctx->height;
pp->max_width = seq->max_frame_width_minus_1 + 1;
pp->max_height = seq->max_frame_height_minus_1 + 1;
pp->CurrPicTextureIndex = ff_dxva2_get_surface_index(avctx, ctx, h->cur_frame.f, 1);
pp->superres_denom = frame_header->use_superres ? frame_header->coded_denom + AV1_SUPERRES_DENOM_MIN : AV1_SUPERRES_NUM;
pp->bitdepth = get_bit_depth_from_seq(seq);
pp->seq_profile = seq->seq_profile;
/* Tiling info */
pp->tiles.cols = frame_header->tile_cols;
pp->tiles.rows = frame_header->tile_rows;
pp->tiles.context_update_id = frame_header->context_update_tile_id;
for (i = 0; i < pp->tiles.cols; i++)
pp->tiles.widths[i] = frame_header->width_in_sbs_minus_1[i] + 1;
for (i = 0; i < pp->tiles.rows; i++)
pp->tiles.heights[i] = frame_header->height_in_sbs_minus_1[i] + 1;
/* Coding tools */
pp->coding.use_128x128_superblock = seq->use_128x128_superblock;
pp->coding.intra_edge_filter = seq->enable_intra_edge_filter;
pp->coding.interintra_compound = seq->enable_interintra_compound;
pp->coding.masked_compound = seq->enable_masked_compound;
pp->coding.warped_motion = frame_header->allow_warped_motion;
pp->coding.dual_filter = seq->enable_dual_filter;
pp->coding.jnt_comp = seq->enable_jnt_comp;
pp->coding.screen_content_tools = frame_header->allow_screen_content_tools;
pp->coding.integer_mv = frame_header->force_integer_mv || !(frame_header->frame_type & 1);
pp->coding.cdef = seq->enable_cdef;
pp->coding.restoration = seq->enable_restoration;
pp->coding.film_grain = seq->film_grain_params_present && !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN);
pp->coding.intrabc = frame_header->allow_intrabc;
pp->coding.high_precision_mv = frame_header->allow_high_precision_mv;
pp->coding.switchable_motion_mode = frame_header->is_motion_mode_switchable;
pp->coding.filter_intra = seq->enable_filter_intra;
pp->coding.disable_frame_end_update_cdf = frame_header->disable_frame_end_update_cdf;
pp->coding.disable_cdf_update = frame_header->disable_cdf_update;
pp->coding.reference_mode = frame_header->reference_select;
pp->coding.skip_mode = frame_header->skip_mode_present;
pp->coding.reduced_tx_set = frame_header->reduced_tx_set;
pp->coding.superres = frame_header->use_superres;
pp->coding.tx_mode = frame_header->tx_mode;
pp->coding.use_ref_frame_mvs = frame_header->use_ref_frame_mvs;
pp->coding.enable_ref_frame_mvs = seq->enable_ref_frame_mvs;
pp->coding.reference_frame_update = 1; // 0 for show_existing_frame with key frames, but those are not passed to the hwaccel
/* Format & Picture Info flags */
pp->format.frame_type = frame_header->frame_type;
pp->format.show_frame = frame_header->show_frame;
pp->format.showable_frame = frame_header->showable_frame;
pp->format.subsampling_x = seq->color_config.subsampling_x;
pp->format.subsampling_y = seq->color_config.subsampling_y;
pp->format.mono_chrome = seq->color_config.mono_chrome;
/* References */
pp->primary_ref_frame = frame_header->primary_ref_frame;
pp->order_hint = frame_header->order_hint;
pp->order_hint_bits = seq->enable_order_hint ? seq->order_hint_bits_minus_1 + 1 : 0;
memset(pp->RefFrameMapTextureIndex, 0xFF, sizeof(pp->RefFrameMapTextureIndex));
for (i = 0; i < AV1_REFS_PER_FRAME; i++) {
int8_t ref_idx = frame_header->ref_frame_idx[i];
AVFrame *ref_frame = h->ref[ref_idx].f;
pp->frame_refs[i].width = ref_frame->width;
pp->frame_refs[i].height = ref_frame->height;
pp->frame_refs[i].Index = ref_frame->buf[0] ? ref_idx : 0xFF;
/* Global Motion */
pp->frame_refs[i].wminvalid = h->cur_frame.gm_invalid[AV1_REF_FRAME_LAST + i];
pp->frame_refs[i].wmtype = h->cur_frame.gm_type[AV1_REF_FRAME_LAST + i];
for (j = 0; j < 6; ++j) {
pp->frame_refs[i].wmmat[j] = h->cur_frame.gm_params[AV1_REF_FRAME_LAST + i][j];
}
}
for (i = 0; i < AV1_NUM_REF_FRAMES; i++) {
AVFrame *ref_frame = h->ref[i].f;
if (ref_frame->buf[0])
pp->RefFrameMapTextureIndex[i] = ff_dxva2_get_surface_index(avctx, ctx, ref_frame, 0);
}
/* Loop filter parameters */
pp->loop_filter.filter_level[0] = frame_header->loop_filter_level[0];
pp->loop_filter.filter_level[1] = frame_header->loop_filter_level[1];
pp->loop_filter.filter_level_u = frame_header->loop_filter_level[2];
pp->loop_filter.filter_level_v = frame_header->loop_filter_level[3];
pp->loop_filter.sharpness_level = frame_header->loop_filter_sharpness;
pp->loop_filter.mode_ref_delta_enabled = frame_header->loop_filter_delta_enabled;
pp->loop_filter.mode_ref_delta_update = frame_header->loop_filter_delta_update;
pp->loop_filter.delta_lf_multi = frame_header->delta_lf_multi;
pp->loop_filter.delta_lf_present = frame_header->delta_lf_present;
pp->loop_filter.delta_lf_res = frame_header->delta_lf_res;
for (i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) {
pp->loop_filter.ref_deltas[i] = frame_header->loop_filter_ref_deltas[i];
}
pp->loop_filter.mode_deltas[0] = frame_header->loop_filter_mode_deltas[0];
pp->loop_filter.mode_deltas[1] = frame_header->loop_filter_mode_deltas[1];
pp->loop_filter.frame_restoration_type[0] = remap_lr_type[frame_header->lr_type[0]];
pp->loop_filter.frame_restoration_type[1] = remap_lr_type[frame_header->lr_type[1]];
pp->loop_filter.frame_restoration_type[2] = remap_lr_type[frame_header->lr_type[2]];
uses_lr = frame_header->lr_type[0] || frame_header->lr_type[1] || frame_header->lr_type[2];
pp->loop_filter.log2_restoration_unit_size[0] = uses_lr ? (6 + frame_header->lr_unit_shift) : 8;
pp->loop_filter.log2_restoration_unit_size[1] = uses_lr ? (6 + frame_header->lr_unit_shift - frame_header->lr_uv_shift) : 8;
pp->loop_filter.log2_restoration_unit_size[2] = uses_lr ? (6 + frame_header->lr_unit_shift - frame_header->lr_uv_shift) : 8;
/* Quantization */
pp->quantization.delta_q_present = frame_header->delta_q_present;
pp->quantization.delta_q_res = frame_header->delta_q_res;
pp->quantization.base_qindex = frame_header->base_q_idx;
pp->quantization.y_dc_delta_q = frame_header->delta_q_y_dc;
pp->quantization.u_dc_delta_q = frame_header->delta_q_u_dc;
pp->quantization.v_dc_delta_q = frame_header->delta_q_v_dc;
pp->quantization.u_ac_delta_q = frame_header->delta_q_u_ac;
pp->quantization.v_ac_delta_q = frame_header->delta_q_v_ac;
pp->quantization.qm_y = frame_header->using_qmatrix ? frame_header->qm_y : 0xFF;
pp->quantization.qm_u = frame_header->using_qmatrix ? frame_header->qm_u : 0xFF;
pp->quantization.qm_v = frame_header->using_qmatrix ? frame_header->qm_v : 0xFF;
/* Cdef parameters */
pp->cdef.damping = frame_header->cdef_damping_minus_3;
pp->cdef.bits = frame_header->cdef_bits;
for (i = 0; i < 8; i++) {
pp->cdef.y_strengths[i].primary = frame_header->cdef_y_pri_strength[i];
pp->cdef.y_strengths[i].secondary = frame_header->cdef_y_sec_strength[i];
pp->cdef.uv_strengths[i].primary = frame_header->cdef_uv_pri_strength[i];
pp->cdef.uv_strengths[i].secondary = frame_header->cdef_uv_sec_strength[i];
}
/* Misc flags */
pp->interp_filter = frame_header->interpolation_filter;
/* Segmentation */
pp->segmentation.enabled = frame_header->segmentation_enabled;
pp->segmentation.update_map = frame_header->segmentation_update_map;
pp->segmentation.update_data = frame_header->segmentation_update_data;
pp->segmentation.temporal_update = frame_header->segmentation_temporal_update;
for (i = 0; i < AV1_MAX_SEGMENTS; i++) {
for (j = 0; j < AV1_SEG_LVL_MAX; j++) {
pp->segmentation.feature_mask[i].mask |= frame_header->feature_enabled[i][j] << j;
pp->segmentation.feature_data[i][j] = frame_header->feature_value[i][j];
}
}
/* Film grain */
if (apply_grain) {
pp->film_grain.apply_grain = 1;
pp->film_grain.scaling_shift_minus8 = film_grain->grain_scaling_minus_8;
pp->film_grain.chroma_scaling_from_luma = film_grain->chroma_scaling_from_luma;
pp->film_grain.ar_coeff_lag = film_grain->ar_coeff_lag;
pp->film_grain.ar_coeff_shift_minus6 = film_grain->ar_coeff_shift_minus_6;
pp->film_grain.grain_scale_shift = film_grain->grain_scale_shift;
pp->film_grain.overlap_flag = film_grain->overlap_flag;
pp->film_grain.clip_to_restricted_range = film_grain->clip_to_restricted_range;
pp->film_grain.matrix_coeff_is_identity = (seq->color_config.matrix_coefficients == AVCOL_SPC_RGB);
pp->film_grain.grain_seed = film_grain->grain_seed;
pp->film_grain.num_y_points = film_grain->num_y_points;
for (i = 0; i < film_grain->num_y_points; i++) {
pp->film_grain.scaling_points_y[i][0] = film_grain->point_y_value[i];
pp->film_grain.scaling_points_y[i][1] = film_grain->point_y_scaling[i];
}
pp->film_grain.num_cb_points = film_grain->num_cb_points;
for (i = 0; i < film_grain->num_cb_points; i++) {
pp->film_grain.scaling_points_cb[i][0] = film_grain->point_cb_value[i];
pp->film_grain.scaling_points_cb[i][1] = film_grain->point_cb_scaling[i];
}
pp->film_grain.num_cr_points = film_grain->num_cr_points;
for (i = 0; i < film_grain->num_cr_points; i++) {
pp->film_grain.scaling_points_cr[i][0] = film_grain->point_cr_value[i];
pp->film_grain.scaling_points_cr[i][1] = film_grain->point_cr_scaling[i];
}
for (i = 0; i < 24; i++) {
pp->film_grain.ar_coeffs_y[i] = film_grain->ar_coeffs_y_plus_128[i];
}
for (i = 0; i < 25; i++) {
pp->film_grain.ar_coeffs_cb[i] = film_grain->ar_coeffs_cb_plus_128[i];
pp->film_grain.ar_coeffs_cr[i] = film_grain->ar_coeffs_cr_plus_128[i];
}
pp->film_grain.cb_mult = film_grain->cb_mult;
pp->film_grain.cb_luma_mult = film_grain->cb_luma_mult;
pp->film_grain.cr_mult = film_grain->cr_mult;
pp->film_grain.cr_luma_mult = film_grain->cr_luma_mult;
pp->film_grain.cb_offset = film_grain->cb_offset;
pp->film_grain.cr_offset = film_grain->cr_offset;
pp->film_grain.cr_offset = film_grain->cr_offset;
}
// XXX: Setting the StatusReportFeedbackNumber breaks decoding on some drivers (tested on NVIDIA 457.09)
// Status Reporting is not used by FFmpeg, hence not providing a number does not cause any issues
//pp->StatusReportFeedbackNumber = 1 + DXVA_CONTEXT_REPORT_ID(avctx, ctx)++;
return 0;
}
static int dxva2_av1_start_frame(AVCodecContext *avctx,
av_unused const uint8_t *buffer,
av_unused uint32_t size)
{
const AV1DecContext *h = avctx->priv_data;
AVDXVAContext *ctx = DXVA_CONTEXT(avctx);
struct av1_dxva2_picture_context *ctx_pic = h->cur_frame.hwaccel_picture_private;
if (!DXVA_CONTEXT_VALID(avctx, ctx))
return -1;
av_assert0(ctx_pic);
/* Fill up DXVA_PicParams_AV1 */
if (fill_picture_parameters(avctx, ctx, h, &ctx_pic->pp) < 0)
return -1;
ctx_pic->bitstream_size = 0;
ctx_pic->bitstream = NULL;
return 0;
}
static int dxva2_av1_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
{
const AV1DecContext *h = avctx->priv_data;
const AV1RawFrameHeader *frame_header = h->raw_frame_header;
struct av1_dxva2_picture_context *ctx_pic = h->cur_frame.hwaccel_picture_private;
struct AV1DXVAContext *ctx = avctx->internal->hwaccel_priv_data;
void *tmp;
ctx_pic->tile_count = frame_header->tile_cols * frame_header->tile_rows;
/* too many tiles, exceeding all defined levels in the AV1 spec */
if (ctx_pic->tile_count > MAX_TILES)
return AVERROR(ENOSYS);
/* Shortcut if all tiles are in the same buffer */
if (ctx_pic->tile_count == h->tg_end - h->tg_start + 1) {
ctx_pic->bitstream = (uint8_t *)buffer;
ctx_pic->bitstream_size = size;
for (uint32_t tile_num = 0; tile_num < ctx_pic->tile_count; tile_num++) {
ctx_pic->tiles[tile_num].DataOffset = h->tile_group_info[tile_num].tile_offset;
ctx_pic->tiles[tile_num].DataSize = h->tile_group_info[tile_num].tile_size;
ctx_pic->tiles[tile_num].row = h->tile_group_info[tile_num].tile_row;
ctx_pic->tiles[tile_num].column = h->tile_group_info[tile_num].tile_column;
ctx_pic->tiles[tile_num].anchor_frame = 0xFF;
}
return 0;
}
/* allocate an internal buffer */
tmp = av_fast_realloc(ctx->bitstream_cache, &ctx->bitstream_allocated,
ctx_pic->bitstream_size + size);
if (!tmp) {
return AVERROR(ENOMEM);
}
ctx_pic->bitstream = ctx->bitstream_cache = tmp;
memcpy(ctx_pic->bitstream + ctx_pic->bitstream_size, buffer, size);
for (uint32_t tile_num = h->tg_start; tile_num <= h->tg_end; tile_num++) {
ctx_pic->tiles[tile_num].DataOffset = ctx_pic->bitstream_size + h->tile_group_info[tile_num].tile_offset;
ctx_pic->tiles[tile_num].DataSize = h->tile_group_info[tile_num].tile_size;
ctx_pic->tiles[tile_num].row = h->tile_group_info[tile_num].tile_row;
ctx_pic->tiles[tile_num].column = h->tile_group_info[tile_num].tile_column;
ctx_pic->tiles[tile_num].anchor_frame = 0xFF;
}
ctx_pic->bitstream_size += size;
return 0;
}
static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx,
DECODER_BUFFER_DESC *bs,
DECODER_BUFFER_DESC *sc)
{
const AV1DecContext *h = avctx->priv_data;
AVDXVAContext *ctx = DXVA_CONTEXT(avctx);
struct av1_dxva2_picture_context *ctx_pic = h->cur_frame.hwaccel_picture_private;
void *dxva_data_ptr;
uint8_t *dxva_data;
unsigned dxva_size;
unsigned padding;
unsigned type;
#if CONFIG_D3D11VA
if (ff_dxva2_is_d3d11(avctx)) {
type = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM;
if (FAILED(ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
D3D11VA_CONTEXT(ctx)->decoder,
type,
&dxva_size, &dxva_data_ptr)))
return -1;
}
#endif
#if CONFIG_DXVA2
if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
type = DXVA2_BitStreamDateBufferType;
if (FAILED(IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder,
type,
&dxva_data_ptr, &dxva_size)))
return -1;
}
#endif
dxva_data = dxva_data_ptr;
if (ctx_pic->bitstream_size > dxva_size) {
av_log(avctx, AV_LOG_ERROR, "Bitstream size exceeds hardware buffer");
return -1;
}
memcpy(dxva_data, ctx_pic->bitstream, ctx_pic->bitstream_size);
padding = FFMIN(128 - ((ctx_pic->bitstream_size) & 127), dxva_size - ctx_pic->bitstream_size);
if (padding > 0) {
memset(dxva_data + ctx_pic->bitstream_size, 0, padding);
ctx_pic->bitstream_size += padding;
}
#if CONFIG_D3D11VA
if (ff_dxva2_is_d3d11(avctx))
if (FAILED(ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type)))
return -1;
#endif
#if CONFIG_DXVA2
if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
if (FAILED(IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type)))
return -1;
#endif
#if CONFIG_D3D11VA
if (ff_dxva2_is_d3d11(avctx)) {
D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = bs;
memset(dsc11, 0, sizeof(*dsc11));
dsc11->BufferType = type;
dsc11->DataSize = ctx_pic->bitstream_size;
dsc11->NumMBsInBuffer = 0;
type = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL;
}
#endif
#if CONFIG_DXVA2
if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
DXVA2_DecodeBufferDesc *dsc2 = bs;
memset(dsc2, 0, sizeof(*dsc2));
dsc2->CompressedBufferType = type;
dsc2->DataSize = ctx_pic->bitstream_size;
dsc2->NumMBsInBuffer = 0;
type = DXVA2_SliceControlBufferType;
}
#endif
return ff_dxva2_commit_buffer(avctx, ctx, sc, type,
ctx_pic->tiles, sizeof(*ctx_pic->tiles) * ctx_pic->tile_count, 0);
}
static int dxva2_av1_end_frame(AVCodecContext *avctx)
{
const AV1DecContext *h = avctx->priv_data;
struct av1_dxva2_picture_context *ctx_pic = h->cur_frame.hwaccel_picture_private;
int ret;
if (ctx_pic->bitstream_size <= 0)
return -1;
ret = ff_dxva2_common_end_frame(avctx, h->cur_frame.f,
&ctx_pic->pp, sizeof(ctx_pic->pp),
NULL, 0,
commit_bitstream_and_slice_buffer);
return ret;
}
static int dxva2_av1_uninit(AVCodecContext *avctx)
{
struct AV1DXVAContext *ctx = avctx->internal->hwaccel_priv_data;
av_freep(&ctx->bitstream_cache);
ctx->bitstream_allocated = 0;
return ff_dxva2_decode_uninit(avctx);
}
#if CONFIG_AV1_DXVA2_HWACCEL
const FFHWAccel ff_av1_dxva2_hwaccel = {
.p.name = "av1_dxva2",
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_AV1,
.p.pix_fmt = AV_PIX_FMT_DXVA2_VLD,
.init = ff_dxva2_decode_init,
.uninit = dxva2_av1_uninit,
.start_frame = dxva2_av1_start_frame,
.decode_slice = dxva2_av1_decode_slice,
.end_frame = dxva2_av1_end_frame,
.frame_params = ff_dxva2_common_frame_params,
.frame_priv_data_size = sizeof(struct av1_dxva2_picture_context),
.priv_data_size = sizeof(struct AV1DXVAContext),
};
#endif
#if CONFIG_AV1_D3D11VA_HWACCEL
const FFHWAccel ff_av1_d3d11va_hwaccel = {
.p.name = "av1_d3d11va",
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_AV1,
.p.pix_fmt = AV_PIX_FMT_D3D11VA_VLD,
.init = ff_dxva2_decode_init,
.uninit = dxva2_av1_uninit,
.start_frame = dxva2_av1_start_frame,
.decode_slice = dxva2_av1_decode_slice,
.end_frame = dxva2_av1_end_frame,
.frame_params = ff_dxva2_common_frame_params,
.frame_priv_data_size = sizeof(struct av1_dxva2_picture_context),
.priv_data_size = sizeof(struct AV1DXVAContext),
};
#endif
#if CONFIG_AV1_D3D11VA2_HWACCEL
const FFHWAccel ff_av1_d3d11va2_hwaccel = {
.p.name = "av1_d3d11va2",
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_AV1,
.p.pix_fmt = AV_PIX_FMT_D3D11,
.init = ff_dxva2_decode_init,
.uninit = dxva2_av1_uninit,
.start_frame = dxva2_av1_start_frame,
.decode_slice = dxva2_av1_decode_slice,
.end_frame = dxva2_av1_end_frame,
.frame_params = ff_dxva2_common_frame_params,
.frame_priv_data_size = sizeof(struct av1_dxva2_picture_context),
.priv_data_size = sizeof(struct AV1DXVAContext),
};
#endif