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 
44 static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size)
45 {
46  const VC1Context *v = avctx->priv_data;
49 
50  if (!ctx)
51  return -1;
52 
53  av_assert0(ctx_pic);
54 
55  ctx->used_mask = 0;
56 
58  ctx_pic->pp.wDeblockedPictureIndex = INVALID_REF;
59 
60  ctx_pic->bitstream = NULL;
61  ctx_pic->bitstream_size = 0;
62  ctx_pic->slice_count = 0;
63 
64  return 0;
65 }
66 
67 static int d3d12va_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
68 {
69  const VC1Context *v = avctx->priv_data;
71 
72  if (ctx_pic->slice_count >= MAX_SLICES) {
73  return AVERROR(ERANGE);
74  }
75 
76  if (avctx->codec_id == AV_CODEC_ID_VC1 &&
77  size >= 4 && IS_MARKER(AV_RB32(buffer))) {
78  buffer += 4;
79  size -= 4;
80  }
81 
82  if (!ctx_pic->bitstream)
83  ctx_pic->bitstream = buffer;
84  ctx_pic->bitstream_size += size;
85 
86  ff_dxva2_vc1_fill_slice(avctx, &ctx_pic->slices[ctx_pic->slice_count++],
87  buffer - ctx_pic->bitstream, size);
88 
89  return 0;
90 }
91 
92 static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
93 {
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++];
98 
99  const unsigned mb_count = s->mb_width * (s->mb_height >> v->field_mode);
100  uint8_t *mapped_data, *mapped_ptr;
101 
102  static const uint8_t start_code[] = { 0, 0, 1, 0x0d };
103 
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);
107  }
108 
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;
114 
115  slice->dwSliceDataLocation = mapped_ptr - mapped_data;
116  if (i < ctx_pic->slice_count - 1)
117  slice->wNumberMBsInSlice = slice[1].wNumberMBsInSlice - slice[0].wNumberMBsInSlice;
118  else
119  slice->wNumberMBsInSlice = mb_count - slice[0].wNumberMBsInSlice;
120 
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;
125  else if (i > 0)
126  mapped_ptr[3] = 0x0b;
127 
128  mapped_ptr += sizeof(start_code);
129  slice->dwSliceBitsInBuffer += sizeof(start_code) * 8;
130  }
131 
132  memcpy(mapped_ptr, &ctx_pic->bitstream[position], size);
133  mapped_ptr += size;
134  }
135 
136  ID3D12Resource_Unmap(buffer, 0, NULL);
137 
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;
141 
142  input_args->CompressedBitstream = (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM){
143  .pBuffer = buffer,
144  .Offset = 0,
145  .Size = mapped_ptr - mapped_data,
146  };
147 
148  return 0;
149 }
150 
152 {
153  const VC1Context *v = avctx->priv_data;
155 
156  if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
157  return -1;
158 
159  return ff_d3d12va_common_end_frame(avctx, v->s.cur_pic.ptr->f,
160  &ctx_pic->pp, sizeof(ctx_pic->pp),
161  NULL, 0,
163 }
164 
166 {
167  int ret;
169  ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_VC1_D2010;
170 
171  ctx->max_num_ref = 3;
172 
173  ret = ff_d3d12va_decode_init(avctx);
174  if (ret < 0) {
175  ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_VC1;
176  ret = ff_d3d12va_decode_init(avctx);
177  }
178 
179  return ret;
180 }
181 
182 #if CONFIG_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),
196 };
197 #endif
198 
199 #if CONFIG_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),
213 };
214 #endif
VC1Context
The VC1 Context.
Definition: vc1.h:173
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
d3d12va_vc1_decode_slice
static int d3d12va_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
Definition: d3d12va_vc1.c:67
D3D12DecodePictureContext::bitstream_size
unsigned bitstream_size
Definition: d3d12va_mpeg2.c:40
av_unused
#define av_unused
Definition: attributes.h:131
FFHWAccel::p
AVHWAccel p
The public AVHWAccel.
Definition: hwaccel_internal.h:38
start_code
static const uint8_t start_code[]
Definition: videotoolboxenc.c:221
D3D12DecodePictureContext
Definition: d3d12va_mpeg2.c:34
ff_d3d12va_decode_uninit
int ff_d3d12va_decode_uninit(AVCodecContext *avctx)
uninit D3D12VADecodeContext
Definition: d3d12va_decode.c:373
mpegutils.h
FFHWAccel
Definition: hwaccel_internal.h:34
avassert.h
mpegvideodec.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
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
s
#define s(width, name)
Definition: cbs_vp9.c:198
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:40
D3D12DecodePictureContext::pp
DXVA_PictureParameters pp
Definition: d3d12va_mpeg2.c:35
ctx
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:271
MpegEncContext::cur_pic
MPVWorkPicture cur_pic
copy of the current picture structure.
Definition: mpegvideo.h:177
AVCodecContext::codec_id
enum AVCodecID codec_id
Definition: avcodec.h:461
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:92
AV_CODEC_ID_WMV3
@ AV_CODEC_ID_WMV3
Definition: codec_id.h:123
NULL
#define NULL
Definition: coverity.c:32
VC1Context::field_mode
int field_mode
1 for interlaced field pictures
Definition: vc1.h:350
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:434
IS_MARKER
#define IS_MARKER(state)
Definition: dca_parser.c:51
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:128
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
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:2105
MPVPicture::hwaccel_picture_private
void * hwaccel_picture_private
RefStruct reference for hardware accelerator private data.
Definition: mpegpicture.h:75
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
d3d12va_vc1_start_frame
static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size)
Definition: d3d12va_vc1.c:44
VC1Context::s
MpegEncContext s
Definition: vc1.h:174
AV_CODEC_ID_VC1
@ AV_CODEC_ID_VC1
Definition: codec_id.h:122
VC1Context::second_field
int second_field
Definition: vc1.h:352
ret
ret
Definition: filter_design.txt:187
MPVPicture::f
struct AVFrame * f
Definition: mpegpicture.h:59
AVCodecContext
main external API structure.
Definition: avcodec.h:451
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
d3d12va_vc1_decode_init
static int d3d12va_vc1_decode_init(AVCodecContext *avctx)
Definition: d3d12va_vc1.c:165
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
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:478
d3d12va_vc1_end_frame
static int d3d12va_vc1_end_frame(AVCodecContext *avctx)
Definition: d3d12va_vc1.c:151
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:73
D3D12DecodePictureContext::bitstream
const uint8_t * bitstream
Definition: d3d12va_mpeg2.c:39
ff_d3d12va_decode_init
int ff_d3d12va_decode_init(AVCodecContext *avctx)
init D3D12VADecodeContext
Definition: d3d12va_decode.c:283
d3d12va_decode.h