FFmpeg
d3d12va_av1.c
Go to the documentation of this file.
1 /*
2  * Direct3D 12 AV1 HW acceleration
3  *
4  * copyright (c) 2022-2023 Wu Jianhua <toqsxw@outlook.com>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "config_components.h"
24 #include "libavutil/avassert.h"
26 #include "libavutil/mem.h"
27 #include "av1dec.h"
28 #include "dxva2_internal.h"
29 #include "d3d12va_decode.h"
30 
31 #define MAX_TILES 256
32 
33 typedef struct D3D12AV1DecodeContext {
35  uint8_t *bitstream_buffer;
38 
39 #define D3D12_AV1_DECODE_CONTEXT(avctx) ((D3D12AV1DecodeContext *)D3D12VA_DECODE_CONTEXT(avctx))
40 
41 typedef struct AV1DecodePictureContext {
42  DXVA_PicParams_AV1 pp;
43  unsigned tile_count;
44  DXVA_Tile_AV1 tiles[MAX_TILES];
45  uint8_t *bitstream;
46  unsigned bitstream_size;
48 
50  av_unused const AVBufferRef *buffer_ref,
51  av_unused const uint8_t *buffer,
52  av_unused uint32_t size)
53 {
54  const AV1DecContext *h = avctx->priv_data;
55  AV1DecodePictureContext *ctx_pic = h->cur_frame.hwaccel_picture_private;
57  if (!ctx)
58  return -1;
59 
60  av_assert0(ctx_pic);
61 
62  ctx->used_mask = 0;
63 
64  if (ff_dxva2_av1_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, &ctx_pic->pp) < 0)
65  return -1;
66 
67  ctx_pic->bitstream = NULL;
68  ctx_pic->bitstream_size = 0;
69  ctx_pic->tile_count = 0;
70 
71  return 0;
72 }
73 
75  const uint8_t *buffer,
76  uint32_t size)
77 {
78  const AV1DecContext *h = avctx->priv_data;
79  const AV1RawFrameHeader *frame_header = h->raw_frame_header;
80  AV1DecodePictureContext *ctx_pic = h->cur_frame.hwaccel_picture_private;
82  int offset = 0;
83  uint32_t tg_start, tg_end;
84 
85  ctx_pic->tile_count = frame_header->tile_cols * frame_header->tile_rows;
86 
87  if (ctx_pic->tile_count > MAX_TILES)
88  return AVERROR(ENOSYS);
89 
90  if (ctx_pic->tile_count == h->tg_end - h->tg_start + 1) {
91  tg_start = 0;
92  tg_end = ctx_pic->tile_count - 1;
93  ctx_pic->bitstream = (uint8_t *)buffer;
94  ctx_pic->bitstream_size = size;
95  } else {
96  if (ctx_pic->bitstream_size + (uint64_t)size > av1_ctx->bitstream_size) {
97  av_log(avctx, AV_LOG_ERROR, "Slice bitstream size exceeds internal buffer!\n");
98  return AVERROR(EINVAL);
99  }
100  ctx_pic->bitstream = av1_ctx->bitstream_buffer;
101  memcpy(ctx_pic->bitstream + ctx_pic->bitstream_size, buffer, size);
102  tg_start = h->tg_start;
103  tg_end = h->tg_end;
104  offset = ctx_pic->bitstream_size;
105  ctx_pic->bitstream_size += size;
106  }
107 
108  for (uint32_t tile_num = tg_start; tile_num <= tg_end; tile_num++) {
109  ctx_pic->tiles[tile_num].DataOffset = offset + h->tile_group_info[tile_num].tile_offset;
110  ctx_pic->tiles[tile_num].DataSize = h->tile_group_info[tile_num].tile_size;
111  ctx_pic->tiles[tile_num].row = h->tile_group_info[tile_num].tile_row;
112  ctx_pic->tiles[tile_num].column = h->tile_group_info[tile_num].tile_column;
113  ctx_pic->tiles[tile_num].anchor_frame = 0xFF;
114  }
115 
116  return 0;
117 }
118 
119 static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
120 {
122  const AV1DecContext *h = avctx->priv_data;
123  AV1DecodePictureContext *ctx_pic = h->cur_frame.hwaccel_picture_private;
124  void *mapped_data;
125 
126  D3D12_VIDEO_DECODE_FRAME_ARGUMENT *args = &input_args->FrameArguments[input_args->NumFrameArguments++];
127  args->Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL;
128  args->Size = sizeof(DXVA_Tile_AV1) * ctx_pic->tile_count;
129  args->pData = ctx_pic->tiles;
130 
131  if (ctx_pic->bitstream_size > ctx->bitstream_size) {
132  av_log(avctx, AV_LOG_ERROR, "Input frame bitstream size exceeds internal buffer!\n");
133  return AVERROR(EINVAL);
134  }
135 
136  input_args->CompressedBitstream = (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM){
137  .pBuffer = buffer,
138  .Offset = 0,
139  .Size = ctx_pic->bitstream_size,
140  };
141 
142  if (FAILED(ID3D12Resource_Map(buffer, 0, NULL, &mapped_data))) {
143  av_log(avctx, AV_LOG_ERROR, "Failed to map D3D12 Buffer resource!\n");
144  return AVERROR(EINVAL);
145  }
146 
147  memcpy(mapped_data, ctx_pic->bitstream, ctx_pic->bitstream_size);
148 
149  ID3D12Resource_Unmap(buffer, 0, NULL);
150 
151  return 0;
152 }
153 
155 {
156  int ret;
157  const AV1DecContext *h = avctx->priv_data;
158  AV1DecodePictureContext *ctx_pic = h->cur_frame.hwaccel_picture_private;
159 
160  if (ctx_pic->tiles <= 0 || ctx_pic->bitstream_size <= 0)
161  return -1;
162 
163  ret = ff_d3d12va_common_end_frame(avctx, h->cur_frame.f, &ctx_pic->pp, sizeof(ctx_pic->pp),
165 
166  return ret;
167 }
168 
170 {
173  DXVA_PicParams_AV1 pp;
174 
175  int ret;
176 
177  switch (avctx->profile) {
178  case AV_PROFILE_AV1_MAIN:
179  ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0;
180  break;
182  ctx->cfg.DecodeProfile = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P12 ?
183  D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420 :
184  D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2;
185  break;
186  default:
187  return AVERROR(EINVAL);
188  }
189 
190  ctx->max_num_ref = FF_ARRAY_ELEMS(pp.RefFrameMapTextureIndex) + 1;
191 
192  ret = ff_d3d12va_decode_init(avctx);
193  if (ret < 0)
194  return ret;
195 
196  if (!av1_ctx->bitstream_buffer) {
198  av1_ctx->bitstream_buffer = av_malloc(av1_ctx->bitstream_size);
199  if (!av1_ctx->bitstream_buffer)
200  return AVERROR(ENOMEM);
201  }
202 
203  return 0;
204 }
205 
207 {
209 
210  if (ctx->bitstream_buffer)
211  av_freep(&ctx->bitstream_buffer);
212  ctx->bitstream_size = 0;
213 
214  return ff_d3d12va_decode_uninit(avctx);
215 }
216 
217 #if CONFIG_AV1_D3D12VA_HWACCEL
219  .p.name = "av1_d3d12va",
220  .p.type = AVMEDIA_TYPE_VIDEO,
221  .p.id = AV_CODEC_ID_AV1,
222  .p.pix_fmt = AV_PIX_FMT_D3D12,
223  .init = d3d12va_av1_decode_init,
224  .uninit = d3d12va_av1_decode_uninit,
225  .start_frame = d3d12va_av1_start_frame,
226  .decode_slice = d3d12va_av1_decode_slice,
227  .end_frame = d3d12va_av1_end_frame,
228  .frame_params = ff_d3d12va_common_frame_params,
229  .frame_priv_data_size = sizeof(AV1DecodePictureContext),
230  .priv_data_size = sizeof(D3D12AV1DecodeContext),
231 };
232 #endif
D3D12AV1DecodeContext::ctx
D3D12VADecodeContext ctx
Definition: d3d12va_av1.c:34
AV1DecodePictureContext
Definition: d3d12va_av1.c:41
d3d12va_av1_end_frame
static int d3d12va_av1_end_frame(AVCodecContext *avctx)
Definition: d3d12va_av1.c:154
D3D12AV1DecodeContext::bitstream_size
size_t bitstream_size
Definition: d3d12va_av1.c:36
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
d3d12va_av1_decode_init
static av_cold int d3d12va_av1_decode_init(AVCodecContext *avctx)
Definition: d3d12va_av1.c:169
ff_av1_d3d12va_hwaccel
const struct FFHWAccel ff_av1_d3d12va_hwaccel
MAX_TILES
#define MAX_TILES
Definition: d3d12va_av1.c:31
av_cold
#define av_cold
Definition: attributes.h:119
FFHWAccel::p
AVHWAccel p
The public AVHWAccel.
Definition: hwaccel_internal.h:38
AV1DecodePictureContext::tiles
DXVA_Tile_AV1 tiles[MAX_TILES]
Definition: d3d12va_av1.c:44
D3D12AV1DecodeContext
Definition: d3d12va_av1.c:33
AV_PROFILE_AV1_PROFESSIONAL
#define AV_PROFILE_AV1_PROFESSIONAL
Definition: defs.h:171
FFHWAccel
Definition: hwaccel_internal.h:34
av_unused
#define av_unused
Definition: attributes.h:164
AV1DecodePictureContext::bitstream_size
unsigned bitstream_size
Definition: d3d12va_av1.c:46
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
AV1DecodePictureContext::bitstream
uint8_t * bitstream
Definition: d3d12va_av1.c:45
ff_d3d12va_common_frame_params
int ff_d3d12va_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
d3d12va common frame params
Definition: d3d12va_decode.c:389
av1dec.h
dxva2_internal.h
if
if(ret)
Definition: filter_design.txt:179
NULL
#define NULL
Definition: coverity.c:32
AV_CODEC_ID_AV1
@ AV_CODEC_ID_AV1
Definition: codec_id.h:275
AV1RawFrameHeader
Definition: cbs_av1.h:174
d3d12va_av1_start_frame
static int d3d12va_av1_start_frame(AVCodecContext *avctx, av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size)
Definition: d3d12va_av1.c:49
ff_d3d12va_common_end_frame
int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, const void *pp, unsigned pp_size, const void *qm, unsigned qm_size, int(*update_input_arguments)(AVCodecContext *, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *, ID3D12Resource *))
d3d12va common end frame
Definition: d3d12va_decode.c:558
AV_PIX_FMT_D3D12
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition: pixfmt.h:440
D3D12VA_DECODE_CONTEXT
#define D3D12VA_DECODE_CONTEXT(avctx)
Definition: d3d12va_decode.h:141
AV1DecodePictureContext::pp
DXVA_PicParams_AV1 pp
Definition: d3d12va_av1.c:42
d3d12va_av1_decode_slice
static int d3d12va_av1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
Definition: d3d12va_av1.c:74
size
int size
Definition: twinvq_data.h:10344
AV1DecContext
Definition: av1dec.h:85
av_malloc
#define av_malloc(s)
Definition: ops_static.c:52
AVDXVAContext
Definition: dxva2_internal.h:74
ff_d3d12va_get_suitable_max_bitstream_size
int ff_d3d12va_get_suitable_max_bitstream_size(AVCodecContext *avctx)
Get a suitable maximum bitstream size.
Definition: d3d12va_decode.c:150
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
AVHWAccel::name
const char * name
Name of the hardware accelerated codec.
Definition: avcodec.h:1954
ff_d3d12va_decode_init
av_cold int ff_d3d12va_decode_init(AVCodecContext *avctx)
init D3D12VADecodeContext
Definition: d3d12va_decode.c:405
D3D12_AV1_DECODE_CONTEXT
#define D3D12_AV1_DECODE_CONTEXT(avctx)
Definition: d3d12va_av1.c:39
ret
ret
Definition: filter_design.txt:187
AV_PIX_FMT_YUV420P12
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:549
AV1DecodePictureContext::tile_count
unsigned tile_count
Definition: d3d12va_av1.c:43
AVCodecContext
main external API structure.
Definition: avcodec.h:443
frame_header
Definition: truemotion1.c:88
d3d12va_av1_decode_uninit
static av_cold int d3d12va_av1_decode_uninit(AVCodecContext *avctx)
Definition: d3d12va_av1.c:206
D3D12AV1DecodeContext::bitstream_buffer
uint8_t * bitstream_buffer
Definition: d3d12va_av1.c:35
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
AVCodecContext::profile
int profile
profile
Definition: avcodec.h:1636
ff_dxva2_av1_fill_picture_parameters
int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_AV1 *pp)
Definition: dxva2_av1.c:60
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
D3D12VADecodeContext
This structure is used to provide the necessary configurations and data to the FFmpeg Direct3D 12 HWA...
Definition: d3d12va_decode.h:37
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:470
ff_d3d12va_decode_uninit
av_cold int ff_d3d12va_decode_uninit(AVCodecContext *avctx)
uninit D3D12VADecodeContext
Definition: d3d12va_decode.c:495
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2070
update_input_arguments
static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
Definition: d3d12va_av1.c:119
AVCodecContext::sw_pix_fmt
enum AVPixelFormat sw_pix_fmt
Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:650
hwcontext_d3d12va_internal.h
AV_PROFILE_AV1_MAIN
#define AV_PROFILE_AV1_MAIN
Definition: defs.h:169
d3d12va_decode.h