FFmpeg
d3d12va_vc1.c
Go to the documentation of this file.
1 /*
2  * Direct3D12 WMV3/VC-1 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 "mpegutils.h"
27 #include "mpegvideodec.h"
28 #include "vc1.h"
29 #include "vc1data.h"
30 #include "d3d12va_decode.h"
31 #include "dxva2_internal.h"
32 
33 #define MAX_SLICES 1024
34 #define INVALID_REF 0xffff
35 
36 typedef struct D3D12DecodePictureContext {
37  DXVA_PictureParameters pp;
38  unsigned slice_count;
39  DXVA_SliceInfo slices[MAX_SLICES];
40  const uint8_t *bitstream;
41  unsigned bitstream_size;
43 
45  av_unused const AVBufferRef *buffer_ref,
46  av_unused const uint8_t *buffer,
47  av_unused uint32_t size)
48 {
49  const VC1Context *v = avctx->priv_data;
52 
53  if (!ctx)
54  return -1;
55 
56  av_assert0(ctx_pic);
57 
58  ctx->used_mask = 0;
59 
61  ctx_pic->pp.wDeblockedPictureIndex = INVALID_REF;
62 
63  ctx_pic->bitstream = NULL;
64  ctx_pic->bitstream_size = 0;
65  ctx_pic->slice_count = 0;
66 
67  return 0;
68 }
69 
70 static int d3d12va_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
71 {
72  const VC1Context *v = avctx->priv_data;
74 
75  if (ctx_pic->slice_count >= MAX_SLICES) {
76  return AVERROR(ERANGE);
77  }
78 
79  if (avctx->codec_id == AV_CODEC_ID_VC1 &&
80  size >= 4 && IS_MARKER(AV_RB32(buffer))) {
81  buffer += 4;
82  size -= 4;
83  }
84 
85  if (!ctx_pic->bitstream)
86  ctx_pic->bitstream = buffer;
87  ctx_pic->bitstream_size += size;
88 
89  ff_dxva2_vc1_fill_slice(avctx, &ctx_pic->slices[ctx_pic->slice_count++],
90  buffer - ctx_pic->bitstream, size);
91 
92  return 0;
93 }
94 
95 static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
96 {
98  const VC1Context *v = avctx->priv_data;
99  const MpegEncContext *s = &v->s;
100  D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private;
101  D3D12_VIDEO_DECODE_FRAME_ARGUMENT *args = &input_args->FrameArguments[input_args->NumFrameArguments++];
102 
103  const unsigned mb_count = s->mb_width * (s->mb_height >> v->field_mode);
104  uint8_t *mapped_data, *mapped_ptr;
105  UINT bitstream_size = ctx->bitstream_size;
106 
107  static const uint8_t start_code[] = { 0, 0, 1, 0x0d };
108 
109  if (FAILED(ID3D12Resource_Map(buffer, 0, NULL, (void **)&mapped_data))) {
110  av_log(avctx, AV_LOG_ERROR, "Failed to map D3D12 Buffer resource!\n");
111  return AVERROR(EINVAL);
112  }
113 
114  mapped_ptr = mapped_data;
115  for (int i = 0; i < ctx_pic->slice_count; i++) {
116  DXVA_SliceInfo *slice = &ctx_pic->slices[i];
117  unsigned position = slice->dwSliceDataLocation;
118  unsigned size = slice->dwSliceBitsInBuffer / 8;
119 
120  if ((uint64_t)size + ((avctx->codec_id == AV_CODEC_ID_VC1) ? sizeof(start_code) : 0) > bitstream_size) {
121  av_log(avctx, AV_LOG_ERROR, "Input frame bitstream size exceeds internal buffer!\n");
122  ID3D12Resource_Unmap(buffer, 0, NULL);
123  return AVERROR(EINVAL);
124  }
125 
126  slice->dwSliceDataLocation = mapped_ptr - mapped_data;
127  if (i < ctx_pic->slice_count - 1)
128  slice->wNumberMBsInSlice = slice[1].wNumberMBsInSlice - slice[0].wNumberMBsInSlice;
129  else
130  slice->wNumberMBsInSlice = mb_count - slice[0].wNumberMBsInSlice;
131 
132  if (avctx->codec_id == AV_CODEC_ID_VC1) {
133  memcpy(mapped_ptr, start_code, sizeof(start_code));
134  if (i == 0 && v->second_field)
135  mapped_ptr[3] = 0x0c;
136  else if (i > 0)
137  mapped_ptr[3] = 0x0b;
138 
139  mapped_ptr += sizeof(start_code);
140  bitstream_size -= sizeof(start_code);
141  slice->dwSliceBitsInBuffer += sizeof(start_code) * 8;
142  }
143 
144  memcpy(mapped_ptr, &ctx_pic->bitstream[position], size);
145  mapped_ptr += size;
146  bitstream_size -= size;
147  }
148 
149  ID3D12Resource_Unmap(buffer, 0, NULL);
150 
151  args->Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL;
152  args->Size = sizeof(DXVA_SliceInfo) * ctx_pic->slice_count;
153  args->pData = ctx_pic->slices;
154 
155  input_args->CompressedBitstream = (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM){
156  .pBuffer = buffer,
157  .Offset = 0,
158  .Size = mapped_ptr - mapped_data,
159  };
160 
161  return 0;
162 }
163 
165 {
166  const VC1Context *v = avctx->priv_data;
168 
169  if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
170  return -1;
171 
172  return ff_d3d12va_common_end_frame(avctx, v->s.cur_pic.ptr->f,
173  &ctx_pic->pp, sizeof(ctx_pic->pp),
174  NULL, 0,
176 }
177 
179 {
180  int ret;
182  ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_VC1_D2010;
183 
184  ctx->max_num_ref = 3;
185 
186  ret = ff_d3d12va_decode_init(avctx);
187  if (ret < 0) {
188  ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_VC1;
189  ret = ff_d3d12va_decode_init(avctx);
190  }
191 
192  return ret;
193 }
194 
195 #if CONFIG_WMV3_D3D12VA_HWACCEL
197  .p.name = "wmv3_d3d12va",
198  .p.type = AVMEDIA_TYPE_VIDEO,
199  .p.id = AV_CODEC_ID_WMV3,
200  .p.pix_fmt = AV_PIX_FMT_D3D12,
201  .init = d3d12va_vc1_decode_init,
202  .uninit = ff_d3d12va_decode_uninit,
203  .start_frame = d3d12va_vc1_start_frame,
204  .decode_slice = d3d12va_vc1_decode_slice,
205  .end_frame = d3d12va_vc1_end_frame,
206  .frame_params = ff_d3d12va_common_frame_params,
207  .frame_priv_data_size = sizeof(D3D12DecodePictureContext),
208  .priv_data_size = sizeof(D3D12VADecodeContext),
209 };
210 #endif
211 
212 #if CONFIG_VC1_D3D12VA_HWACCEL
214  .p.name = "vc1_d3d12va",
215  .p.type = AVMEDIA_TYPE_VIDEO,
216  .p.id = AV_CODEC_ID_VC1,
217  .p.pix_fmt = AV_PIX_FMT_D3D12,
218  .init = d3d12va_vc1_decode_init,
219  .uninit = ff_d3d12va_decode_uninit,
220  .start_frame = d3d12va_vc1_start_frame,
221  .decode_slice = d3d12va_vc1_decode_slice,
222  .end_frame = d3d12va_vc1_end_frame,
223  .frame_params = ff_d3d12va_common_frame_params,
224  .frame_priv_data_size = sizeof(D3D12DecodePictureContext),
225  .priv_data_size = sizeof(D3D12VADecodeContext),
226 };
227 #endif
VC1Context
The VC1 Context.
Definition: vc1.h:176
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
vc1.h
av_cold
#define av_cold
Definition: attributes.h:119
d3d12va_vc1_decode_slice
static int d3d12va_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
Definition: d3d12va_vc1.c:70
D3D12DecodePictureContext::bitstream_size
unsigned bitstream_size
Definition: d3d12va_mpeg2.c:40
FFHWAccel::p
AVHWAccel p
The public AVHWAccel.
Definition: hwaccel_internal.h:38
start_code
static const uint8_t start_code[]
Definition: videotoolboxenc.c:231
D3D12DecodePictureContext
Definition: d3d12va_mpeg2.c:34
mpegutils.h
FFHWAccel
Definition: hwaccel_internal.h:34
av_unused
#define av_unused
Definition: attributes.h:164
avassert.h
mpegvideodec.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
ff_dxva2_vc1_fill_picture_parameters
void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PictureParameters *pp)
Definition: dxva2_vc1.c:43
MpegEncContext::cur_pic
MPVWorkPicture cur_pic
copy of the current picture structure.
Definition: mpegvideo.h:132
MPVWorkPicture::ptr
MPVPicture * ptr
RefStruct reference.
Definition: mpegpicture.h:99
D3D12DecodePictureContext::slices
DXVA_SliceInfo slices[MAX_SLICES]
Definition: d3d12va_mpeg2.c:38
ff_wmv3_d3d12va_hwaccel
const struct FFHWAccel ff_wmv3_d3d12va_hwaccel
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
D3D12DecodePictureContext::pp
DXVA_PictureParameters pp
Definition: d3d12va_mpeg2.c:35
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
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
AVCodecContext::codec_id
enum AVCodecID codec_id
Definition: avcodec.h:453
dxva2_internal.h
update_input_arguments
static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
Definition: d3d12va_vc1.c:95
AV_CODEC_ID_WMV3
@ AV_CODEC_ID_WMV3
Definition: codec_id.h:121
NULL
#define NULL
Definition: coverity.c:32
VC1Context::field_mode
int field_mode
1 for interlaced field pictures
Definition: vc1.h:356
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:554
IS_MARKER
#define IS_MARKER(state)
Definition: dca_parser.c:52
AV_PIX_FMT_D3D12
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition: pixfmt.h:440
d3d12va_vc1_start_frame
static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size)
Definition: d3d12va_vc1.c:44
D3D12VA_DECODE_CONTEXT
#define D3D12VA_DECODE_CONTEXT(avctx)
Definition: d3d12va_decode.h:141
ff_vc1_d3d12va_hwaccel
const struct FFHWAccel ff_vc1_d3d12va_hwaccel
D3D12DecodePictureContext::slice_count
unsigned slice_count
Definition: d3d12va_mpeg2.c:37
ff_dxva2_vc1_fill_slice
void ff_dxva2_vc1_fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice, unsigned position, unsigned size)
Definition: dxva2_vc1.c:167
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
size
int size
Definition: twinvq_data.h:10344
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:96
AVDXVAContext
Definition: dxva2_internal.h:74
vc1data.h
AVHWAccel::name
const char * name
Name of the hardware accelerated codec.
Definition: avcodec.h:1954
MPVPicture::hwaccel_picture_private
void * hwaccel_picture_private
RefStruct reference for hardware accelerator private data.
Definition: mpegpicture.h:75
ff_d3d12va_decode_init
av_cold int ff_d3d12va_decode_init(AVCodecContext *avctx)
init D3D12VADecodeContext
Definition: d3d12va_decode.c:401
s
uint8_t s
Definition: llvidencdsp.c:39
d3d12va_vc1_decode_init
static av_cold int d3d12va_vc1_decode_init(AVCodecContext *avctx)
Definition: d3d12va_vc1.c:178
VC1Context::s
MpegEncContext s
Definition: vc1.h:177
AV_CODEC_ID_VC1
@ AV_CODEC_ID_VC1
Definition: codec_id.h:120
VC1Context::second_field
int second_field
Definition: vc1.h:358
ret
ret
Definition: filter_design.txt:187
MPVPicture::f
struct AVFrame * f
Definition: mpegpicture.h:59
AVCodecContext
main external API structure.
Definition: avcodec.h:443
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
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
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
MAX_SLICES
#define MAX_SLICES
Definition: d3d12va_vc1.c:33
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:491
d3d12va_vc1_end_frame
static int d3d12va_vc1_end_frame(AVCodecContext *avctx)
Definition: d3d12va_vc1.c:164
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
INVALID_REF
#define INVALID_REF
Definition: d3d12va_vc1.c:34
hwcontext_d3d12va_internal.h
MpegEncContext
MpegEncContext.
Definition: mpegvideo.h:67
D3D12DecodePictureContext::bitstream
const uint8_t * bitstream
Definition: d3d12va_mpeg2.c:39
d3d12va_decode.h