FFmpeg
d3d12va_mpeg2.c
Go to the documentation of this file.
1 /*
2  * Direct3D12 MPEG-2 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 "d3d12va_decode.h"
29 #include "dxva2_internal.h"
30 
31 #define MAX_SLICES 1024
32 #define INVALID_REF 0xffff
33 
34 typedef struct D3D12DecodePictureContext {
35  DXVA_PictureParameters pp;
36  DXVA_QmatrixData qm;
37  unsigned slice_count;
38  DXVA_SliceInfo slices[MAX_SLICES];
39  const uint8_t *bitstream;
40  unsigned bitstream_size;
42 
44  av_unused const AVBufferRef *buffer_ref,
45  av_unused const uint8_t *buffer,
46  av_unused uint32_t size)
47 {
48  const MpegEncContext *s = avctx->priv_data;
50  D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private;
51 
52  if (!ctx)
53  return -1;
54 
55  av_assert0(ctx_pic);
56 
57  ctx->used_mask = 0;
58 
61 
62  // Post processing operations are not supported in D3D12 Video
63  ctx_pic->pp.wDeblockedPictureIndex = INVALID_REF;
64 
65  ctx_pic->bitstream = NULL;
66  ctx_pic->bitstream_size = 0;
67  ctx_pic->slice_count = 0;
68 
69  return 0;
70 }
71 
72 static int d3d12va_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
73 {
74  const MpegEncContext *s = avctx->priv_data;
75  D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private;
76 
77  if (ctx_pic->slice_count >= MAX_SLICES) {
78  return AVERROR(ERANGE);
79  }
80 
81  if (!ctx_pic->bitstream)
82  ctx_pic->bitstream = buffer;
83  ctx_pic->bitstream_size += size;
84 
85  ff_dxva2_mpeg2_fill_slice(avctx, &ctx_pic->slices[ctx_pic->slice_count++],
86  buffer - ctx_pic->bitstream, buffer, size);
87 
88  return 0;
89 }
90 
91 static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
92 {
94  const MpegEncContext *s = avctx->priv_data;
95  D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private;
96 
97  const int is_field = s->picture_structure != PICT_FRAME;
98  const unsigned mb_count = s->mb_width * (s->mb_height >> is_field);
99 
100  int i;
101  void *mapped_data = NULL;
102  D3D12_VIDEO_DECODE_FRAME_ARGUMENT *args = &input_args->FrameArguments[input_args->NumFrameArguments++];
103 
104  D3D12_RANGE range = {
105  .Begin = 0,
106  .End = ctx_pic->bitstream_size,
107  };
108 
109  if (ctx_pic->bitstream_size > ctx->bitstream_size) {
110  av_log(avctx, AV_LOG_ERROR, "Input frame bitstream size exceeds internal buffer!\n");
111  return AVERROR(EINVAL);
112  }
113 
114  if (FAILED(ID3D12Resource_Map(buffer, 0, &range, &mapped_data))) {
115  av_log(avctx, AV_LOG_ERROR, "Failed to map D3D12 Buffer resource!\n");
116  return AVERROR(EINVAL);
117  }
118 
119  for (i = 0; i < ctx_pic->slice_count; i++) {
120  DXVA_SliceInfo *slice = &ctx_pic->slices[i];
121 
122  if (i < ctx_pic->slice_count - 1)
123  slice->wNumberMBsInSlice = slice[1].wNumberMBsInSlice - slice[0].wNumberMBsInSlice;
124  else
125  slice->wNumberMBsInSlice = mb_count - slice[0].wNumberMBsInSlice;
126  }
127 
128  memcpy(mapped_data, ctx_pic->bitstream, ctx_pic->bitstream_size);
129 
130  ID3D12Resource_Unmap(buffer, 0, &range);
131 
132  args->Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL;
133  args->Size = sizeof(DXVA_SliceInfo) * ctx_pic->slice_count;
134  args->pData = ctx_pic->slices;
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  return 0;
143 }
144 
146 {
147  int ret;
148  MpegEncContext *s = avctx->priv_data;
149  D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private;
150 
151  if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
152  return -1;
153 
154  ret = ff_d3d12va_common_end_frame(avctx, s->cur_pic.ptr->f, &ctx_pic->pp, sizeof(ctx_pic->pp),
155  &ctx_pic->qm, sizeof(ctx_pic->qm), update_input_arguments);
156  if (!ret)
157  ff_mpeg_draw_horiz_band(s, 0, avctx->height);
158 
159  return ret;
160 }
161 
163 {
165 
166  ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_MPEG2;
167 
168  ctx->max_num_ref = 3;
169 
170  return ff_d3d12va_decode_init(avctx);
171 }
172 
173 #if CONFIG_MPEG2_D3D12VA_HWACCEL
175  .p.name = "mpeg2_d3d12va",
176  .p.type = AVMEDIA_TYPE_VIDEO,
177  .p.id = AV_CODEC_ID_MPEG2VIDEO,
178  .p.pix_fmt = AV_PIX_FMT_D3D12,
180  .uninit = ff_d3d12va_decode_uninit,
181  .start_frame = d3d12va_mpeg2_start_frame,
182  .decode_slice = d3d12va_mpeg2_decode_slice,
183  .end_frame = d3d12va_mpeg2_end_frame,
184  .frame_params = ff_d3d12va_common_frame_params,
185  .frame_priv_data_size = sizeof(D3D12DecodePictureContext),
186  .priv_data_size = sizeof(D3D12VADecodeContext),
187 };
188 #endif
PICT_FRAME
#define PICT_FRAME
Definition: mpegutils.h:33
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
MAX_SLICES
#define MAX_SLICES
Definition: d3d12va_mpeg2.c:31
av_cold
#define av_cold
Definition: attributes.h:119
D3D12DecodePictureContext::bitstream_size
unsigned bitstream_size
Definition: d3d12va_mpeg2.c:40
FFHWAccel::p
AVHWAccel p
The public AVHWAccel.
Definition: hwaccel_internal.h:38
d3d12va_mpeg2_start_frame
static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size)
Definition: d3d12va_mpeg2.c:43
D3D12DecodePictureContext
Definition: d3d12va_mpeg2.c:34
d3d12va_mpeg2_decode_init
static av_cold int d3d12va_mpeg2_decode_init(AVCodecContext *avctx)
Definition: d3d12va_mpeg2.c:162
INVALID_REF
#define INVALID_REF
Definition: d3d12va_mpeg2.c:32
mpegutils.h
d3d12va_mpeg2_decode_slice
static int d3d12va_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
Definition: d3d12va_mpeg2.c:72
FFHWAccel
Definition: hwaccel_internal.h:34
ff_dxva2_mpeg2_fill_quantization_matrices
void ff_dxva2_mpeg2_fill_quantization_matrices(AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_QmatrixData *qm)
Definition: dxva2_mpeg2.c:109
ff_dxva2_mpeg2_fill_picture_parameters
void ff_dxva2_mpeg2_fill_picture_parameters(AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PictureParameters *pp)
Definition: dxva2_mpeg2.c:43
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
D3D12DecodePictureContext::slices
DXVA_SliceInfo slices[MAX_SLICES]
Definition: d3d12va_mpeg2.c:38
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
dxva2_internal.h
NULL
#define NULL
Definition: coverity.c:32
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
D3D12DecodePictureContext::slice_count
unsigned slice_count
Definition: d3d12va_mpeg2.c:37
d3d12va_mpeg2_end_frame
static int d3d12va_mpeg2_end_frame(AVCodecContext *avctx)
Definition: d3d12va_mpeg2.c:145
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
size
int size
Definition: twinvq_data.h:10344
update_input_arguments
static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
Definition: d3d12va_mpeg2.c:91
ff_mpeg_draw_horiz_band
void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h)
Definition: mpegvideo_dec.c:450
AVDXVAContext
Definition: dxva2_internal.h:74
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
ff_dxva2_mpeg2_fill_slice
void ff_dxva2_mpeg2_fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice, unsigned position, const uint8_t *buffer, unsigned size)
Definition: dxva2_mpeg2.c:126
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
D3D12DecodePictureContext::qm
DXVA_QmatrixData qm
Definition: d3d12va_mpeg2.c:36
s
uint8_t s
Definition: llvidencdsp.c:39
AVCodecContext::height
int height
Definition: avcodec.h:604
ret
ret
Definition: filter_design.txt:187
ff_mpeg2_d3d12va_hwaccel
const struct FFHWAccel ff_mpeg2_d3d12va_hwaccel
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
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_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
hwcontext_d3d12va_internal.h
AV_CODEC_ID_MPEG2VIDEO
@ AV_CODEC_ID_MPEG2VIDEO
preferred ID for MPEG-1/2 video decoding
Definition: codec_id.h:52
MpegEncContext
MpegEncContext.
Definition: mpegvideo.h:67
D3D12DecodePictureContext::bitstream
const uint8_t * bitstream
Definition: d3d12va_mpeg2.c:39
d3d12va_decode.h