2 * Direct3D 12 AV1 HW acceleration
4 * copyright (c) 2022-2023 Wu Jianhua <toqsxw@outlook.com>
6 * This file is part of FFmpeg.
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.
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.
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
23 #include "config_components.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/hwcontext_d3d12va_internal.h"
26 #include "libavutil/mem.h"
28 #include "dxva2_internal.h"
29 #include "d3d12va_decode.h"
33 typedef struct D3D12AV1DecodeContext
{
34 D3D12VADecodeContext ctx
;
35 uint8_t *bitstream_buffer
;
36 } D3D12AV1DecodeContext
;
38 #define D3D12_AV1_DECODE_CONTEXT(avctx) ((D3D12AV1DecodeContext *)D3D12VA_DECODE_CONTEXT(avctx))
40 typedef struct AV1DecodePictureContext
{
41 DXVA_PicParams_AV1 pp
;
43 DXVA_Tile_AV1 tiles
[MAX_TILES
];
45 unsigned bitstream_size
;
46 } AV1DecodePictureContext
;
48 static int d3d12va_av1_start_frame(AVCodecContext
*avctx
, av_unused
const uint8_t *buffer
, av_unused
uint32_t size
)
50 const AV1DecContext
*h
= avctx
->priv_data
;
51 AV1DecodePictureContext
*ctx_pic
= h
->cur_frame
.hwaccel_picture_private
;
52 D3D12VADecodeContext
*ctx
= D3D12VA_DECODE_CONTEXT(avctx
);
60 if (ff_dxva2_av1_fill_picture_parameters(avctx
, (AVDXVAContext
*)ctx
, &ctx_pic
->pp
) < 0)
63 ctx_pic
->bitstream
= NULL
;
64 ctx_pic
->bitstream_size
= 0;
65 ctx_pic
->tile_count
= 0;
70 static int d3d12va_av1_decode_slice(AVCodecContext
*avctx
,
71 const uint8_t *buffer
,
74 const AV1DecContext
*h
= avctx
->priv_data
;
75 const AV1RawFrameHeader
*frame_header
= h
->raw_frame_header
;
76 AV1DecodePictureContext
*ctx_pic
= h
->cur_frame
.hwaccel_picture_private
;
78 uint32_t tg_start
, tg_end
;
80 ctx_pic
->tile_count
= frame_header
->tile_cols
* frame_header
->tile_rows
;
82 if (ctx_pic
->tile_count
> MAX_TILES
)
83 return AVERROR(ENOSYS
);
85 if (ctx_pic
->tile_count
== h
->tg_end
- h
->tg_start
+ 1) {
87 tg_end
= ctx_pic
->tile_count
- 1;
88 ctx_pic
->bitstream
= (uint8_t *)buffer
;
89 ctx_pic
->bitstream_size
= size
;
91 ctx_pic
->bitstream
= D3D12_AV1_DECODE_CONTEXT(avctx
)->bitstream_buffer
;
92 memcpy(ctx_pic
->bitstream
+ ctx_pic
->bitstream_size
, buffer
, size
);
93 tg_start
= h
->tg_start
;
95 offset
= ctx_pic
->bitstream_size
;
96 ctx_pic
->bitstream_size
+= size
;
99 for (uint32_t tile_num
= tg_start
; tile_num
<= tg_end
; tile_num
++) {
100 ctx_pic
->tiles
[tile_num
].DataOffset
= offset
+ h
->tile_group_info
[tile_num
].tile_offset
;
101 ctx_pic
->tiles
[tile_num
].DataSize
= h
->tile_group_info
[tile_num
].tile_size
;
102 ctx_pic
->tiles
[tile_num
].row
= h
->tile_group_info
[tile_num
].tile_row
;
103 ctx_pic
->tiles
[tile_num
].column
= h
->tile_group_info
[tile_num
].tile_column
;
104 ctx_pic
->tiles
[tile_num
].anchor_frame
= 0xFF;
110 static int update_input_arguments(AVCodecContext
*avctx
, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS
*input_args
, ID3D12Resource
*buffer
)
112 const AV1DecContext
*h
= avctx
->priv_data
;
113 AV1DecodePictureContext
*ctx_pic
= h
->cur_frame
.hwaccel_picture_private
;
116 D3D12_VIDEO_DECODE_FRAME_ARGUMENT
*args
= &input_args
->FrameArguments
[input_args
->NumFrameArguments
++];
117 args
->Type
= D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL
;
118 args
->Size
= sizeof(DXVA_Tile_AV1
) * ctx_pic
->tile_count
;
119 args
->pData
= ctx_pic
->tiles
;
121 input_args
->CompressedBitstream
= (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM
){
124 .Size
= ctx_pic
->bitstream_size
,
127 if (FAILED(ID3D12Resource_Map(buffer
, 0, NULL
, &mapped_data
))) {
128 av_log(avctx
, AV_LOG_ERROR
, "Failed to map D3D12 Buffer resource!\n");
129 return AVERROR(EINVAL
);
132 memcpy(mapped_data
, ctx_pic
->bitstream
, ctx_pic
->bitstream_size
);
134 ID3D12Resource_Unmap(buffer
, 0, NULL
);
139 static int d3d12va_av1_end_frame(AVCodecContext
*avctx
)
142 const AV1DecContext
*h
= avctx
->priv_data
;
143 AV1DecodePictureContext
*ctx_pic
= h
->cur_frame
.hwaccel_picture_private
;
145 if (ctx_pic
->tiles
<= 0 || ctx_pic
->bitstream_size
<= 0)
148 ret
= ff_d3d12va_common_end_frame(avctx
, h
->cur_frame
.f
, &ctx_pic
->pp
, sizeof(ctx_pic
->pp
),
149 NULL
, 0, update_input_arguments
);
154 static int d3d12va_av1_decode_init(AVCodecContext
*avctx
)
156 D3D12VADecodeContext
*ctx
= D3D12VA_DECODE_CONTEXT(avctx
);
157 D3D12AV1DecodeContext
*av1_ctx
= D3D12_AV1_DECODE_CONTEXT(avctx
);
158 DXVA_PicParams_AV1 pp
;
162 if (avctx
->profile
!= AV_PROFILE_AV1_MAIN
)
163 return AVERROR(EINVAL
);
165 ctx
->cfg
.DecodeProfile
= D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0
;
167 ctx
->max_num_ref
= FF_ARRAY_ELEMS(pp
.RefFrameMapTextureIndex
) + 1;
169 ret
= ff_d3d12va_decode_init(avctx
);
173 if (!av1_ctx
->bitstream_buffer
) {
174 av1_ctx
->bitstream_buffer
= av_malloc(ff_d3d12va_get_suitable_max_bitstream_size(avctx
));
175 if (!av1_ctx
->bitstream_buffer
)
176 return AVERROR(ENOMEM
);
182 static int d3d12va_av1_decode_uninit(AVCodecContext
*avctx
)
184 D3D12AV1DecodeContext
*ctx
= D3D12_AV1_DECODE_CONTEXT(avctx
);
186 if (ctx
->bitstream_buffer
)
187 av_freep(&ctx
->bitstream_buffer
);
189 return ff_d3d12va_decode_uninit(avctx
);
192 #if CONFIG_AV1_D3D12VA_HWACCEL
193 const FFHWAccel ff_av1_d3d12va_hwaccel
= {
194 .p
.name
= "av1_d3d12va",
195 .p
.type
= AVMEDIA_TYPE_VIDEO
,
196 .p
.id
= AV_CODEC_ID_AV1
,
197 .p
.pix_fmt
= AV_PIX_FMT_D3D12
,
198 .init
= d3d12va_av1_decode_init
,
199 .uninit
= d3d12va_av1_decode_uninit
,
200 .start_frame
= d3d12va_av1_start_frame
,
201 .decode_slice
= d3d12va_av1_decode_slice
,
202 .end_frame
= d3d12va_av1_end_frame
,
203 .frame_params
= ff_d3d12va_common_frame_params
,
204 .frame_priv_data_size
= sizeof(AV1DecodePictureContext
),
205 .priv_data_size
= sizeof(D3D12AV1DecodeContext
),