2 * Direct3D12 WMV3/VC-1 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 "mpegutils.h"
27 #include "mpegvideodec.h"
30 #include "d3d12va_decode.h"
31 #include "dxva2_internal.h"
33 #define MAX_SLICES 1024
34 #define INVALID_REF 0xffff
36 typedef struct D3D12DecodePictureContext
{
37 DXVA_PictureParameters pp
;
39 DXVA_SliceInfo slices
[MAX_SLICES
];
40 const uint8_t *bitstream
;
41 unsigned bitstream_size
;
42 } D3D12DecodePictureContext
;
44 static int d3d12va_vc1_start_frame(AVCodecContext
*avctx
, av_unused
const uint8_t *buffer
, av_unused
uint32_t size
)
46 const VC1Context
*v
= avctx
->priv_data
;
47 D3D12VADecodeContext
*ctx
= D3D12VA_DECODE_CONTEXT(avctx
);
48 D3D12DecodePictureContext
*ctx_pic
= v
->s
.cur_pic
.ptr
->hwaccel_picture_private
;
57 ff_dxva2_vc1_fill_picture_parameters(avctx
, (AVDXVAContext
*)ctx
, &ctx_pic
->pp
);
58 ctx_pic
->pp
.wDeblockedPictureIndex
= INVALID_REF
;
60 ctx_pic
->bitstream
= NULL
;
61 ctx_pic
->bitstream_size
= 0;
62 ctx_pic
->slice_count
= 0;
67 static int d3d12va_vc1_decode_slice(AVCodecContext
*avctx
, const uint8_t *buffer
, uint32_t size
)
69 const VC1Context
*v
= avctx
->priv_data
;
70 D3D12DecodePictureContext
*ctx_pic
= v
->s
.cur_pic
.ptr
->hwaccel_picture_private
;
72 if (ctx_pic
->slice_count
>= MAX_SLICES
) {
73 return AVERROR(ERANGE
);
76 if (avctx
->codec_id
== AV_CODEC_ID_VC1
&&
77 size
>= 4 && IS_MARKER(AV_RB32(buffer
))) {
82 if (!ctx_pic
->bitstream
)
83 ctx_pic
->bitstream
= buffer
;
84 ctx_pic
->bitstream_size
+= size
;
86 ff_dxva2_vc1_fill_slice(avctx
, &ctx_pic
->slices
[ctx_pic
->slice_count
++],
87 buffer
- ctx_pic
->bitstream
, size
);
92 static int update_input_arguments(AVCodecContext
*avctx
, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS
*input_args
, ID3D12Resource
*buffer
)
94 const VC1Context
*v
= avctx
->priv_data
;
95 const MpegEncContext
*s
= &v
->s
;
96 D3D12DecodePictureContext
*ctx_pic
= s
->cur_pic
.ptr
->hwaccel_picture_private
;
97 D3D12_VIDEO_DECODE_FRAME_ARGUMENT
*args
= &input_args
->FrameArguments
[input_args
->NumFrameArguments
++];
99 const unsigned mb_count
= s
->mb_width
* (s
->mb_height
>> v
->field_mode
);
100 uint8_t *mapped_data
, *mapped_ptr
;
102 static const uint8_t start_code
[] = { 0, 0, 1, 0x0d };
104 if (FAILED(ID3D12Resource_Map(buffer
, 0, NULL
, (void **)&mapped_data
))) {
105 av_log(avctx
, AV_LOG_ERROR
, "Failed to map D3D12 Buffer resource!\n");
106 return AVERROR(EINVAL
);
109 mapped_ptr
= mapped_data
;
110 for (int i
= 0; i
< ctx_pic
->slice_count
; i
++) {
111 DXVA_SliceInfo
*slice
= &ctx_pic
->slices
[i
];
112 unsigned position
= slice
->dwSliceDataLocation
;
113 unsigned size
= slice
->dwSliceBitsInBuffer
/ 8;
115 slice
->dwSliceDataLocation
= mapped_ptr
- mapped_data
;
116 if (i
< ctx_pic
->slice_count
- 1)
117 slice
->wNumberMBsInSlice
= slice
[1].wNumberMBsInSlice
- slice
[0].wNumberMBsInSlice
;
119 slice
->wNumberMBsInSlice
= mb_count
- slice
[0].wNumberMBsInSlice
;
121 if (avctx
->codec_id
== AV_CODEC_ID_VC1
) {
122 memcpy(mapped_ptr
, start_code
, sizeof(start_code
));
123 if (i
== 0 && v
->second_field
)
124 mapped_ptr
[3] = 0x0c;
126 mapped_ptr
[3] = 0x0b;
128 mapped_ptr
+= sizeof(start_code
);
129 slice
->dwSliceBitsInBuffer
+= sizeof(start_code
) * 8;
132 memcpy(mapped_ptr
, &ctx_pic
->bitstream
[position
], size
);
136 ID3D12Resource_Unmap(buffer
, 0, NULL
);
138 args
->Type
= D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL
;
139 args
->Size
= sizeof(DXVA_SliceInfo
) * ctx_pic
->slice_count
;
140 args
->pData
= ctx_pic
->slices
;
142 input_args
->CompressedBitstream
= (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM
){
145 .Size
= mapped_ptr
- mapped_data
,
151 static int d3d12va_vc1_end_frame(AVCodecContext
*avctx
)
153 const VC1Context
*v
= avctx
->priv_data
;
154 D3D12DecodePictureContext
*ctx_pic
= v
->s
.cur_pic
.ptr
->hwaccel_picture_private
;
156 if (ctx_pic
->slice_count
<= 0 || ctx_pic
->bitstream_size
<= 0)
159 return ff_d3d12va_common_end_frame(avctx
, v
->s
.cur_pic
.ptr
->f
,
160 &ctx_pic
->pp
, sizeof(ctx_pic
->pp
),
162 update_input_arguments
);
165 static int d3d12va_vc1_decode_init(AVCodecContext
*avctx
)
168 D3D12VADecodeContext
*ctx
= D3D12VA_DECODE_CONTEXT(avctx
);
169 ctx
->cfg
.DecodeProfile
= D3D12_VIDEO_DECODE_PROFILE_VC1_D2010
;
171 ctx
->max_num_ref
= 3;
173 ret
= ff_d3d12va_decode_init(avctx
);
175 ctx
->cfg
.DecodeProfile
= D3D12_VIDEO_DECODE_PROFILE_VC1
;
176 ret
= ff_d3d12va_decode_init(avctx
);
182 #if CONFIG_WMV3_D3D12VA_HWACCEL
183 const FFHWAccel ff_wmv3_d3d12va_hwaccel
= {
184 .p
.name
= "wmv3_d3d12va",
185 .p
.type
= AVMEDIA_TYPE_VIDEO
,
186 .p
.id
= AV_CODEC_ID_WMV3
,
187 .p
.pix_fmt
= AV_PIX_FMT_D3D12
,
188 .init
= d3d12va_vc1_decode_init
,
189 .uninit
= ff_d3d12va_decode_uninit
,
190 .start_frame
= d3d12va_vc1_start_frame
,
191 .decode_slice
= d3d12va_vc1_decode_slice
,
192 .end_frame
= d3d12va_vc1_end_frame
,
193 .frame_params
= ff_d3d12va_common_frame_params
,
194 .frame_priv_data_size
= sizeof(D3D12DecodePictureContext
),
195 .priv_data_size
= sizeof(D3D12VADecodeContext
),
199 #if CONFIG_VC1_D3D12VA_HWACCEL
200 const FFHWAccel ff_vc1_d3d12va_hwaccel
= {
201 .p
.name
= "vc1_d3d12va",
202 .p
.type
= AVMEDIA_TYPE_VIDEO
,
203 .p
.id
= AV_CODEC_ID_VC1
,
204 .p
.pix_fmt
= AV_PIX_FMT_D3D12
,
205 .init
= d3d12va_vc1_decode_init
,
206 .uninit
= ff_d3d12va_decode_uninit
,
207 .start_frame
= d3d12va_vc1_start_frame
,
208 .decode_slice
= d3d12va_vc1_decode_slice
,
209 .end_frame
= d3d12va_vc1_end_frame
,
210 .frame_params
= ff_d3d12va_common_frame_params
,
211 .frame_priv_data_size
= sizeof(D3D12DecodePictureContext
),
212 .priv_data_size
= sizeof(D3D12VADecodeContext
),