FFmpeg
Loading...
Searching...
No Matches
d3d12va_hevc.c
Go to the documentation of this file.
1/*
2 * Direct3D 12 HEVC 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
25#include "libavutil/avassert.h"
27#include "hevc/data.h"
28#include "hevc/hevcdec.h"
29#include "dxva2_internal.h"
30#include "d3d12va_decode.h"
31#include <dxva.h>
32
33#define MAX_SLICES 256
34
36 DXVA_PicParams_HEVC pp;
37 DXVA_Qmatrix_HEVC qm;
38 unsigned slice_count;
39 DXVA_Slice_HEVC_Short slice_short[MAX_SLICES];
40 const uint8_t *bitstream;
43
44static void fill_slice_short(DXVA_Slice_HEVC_Short *slice, unsigned position, unsigned size)
45{
46 memset(slice, 0, sizeof(*slice));
47 slice->BSNALunitDataLocation = position;
48 slice->SliceBytesInBuffer = size;
49 slice->wBadSliceChopping = 0;
50}
51
53 av_unused const AVBufferRef *buffer_ref,
54 av_unused const uint8_t *buffer,
55 av_unused uint32_t size)
56{
57 const HEVCContext *h = avctx->priv_data;
59 HEVCDecodePictureContext *ctx_pic = h->cur_frame->hwaccel_picture_private;
60
61 if (!ctx)
62 return -1;
63
64 av_assert0(ctx_pic);
65
66 ctx->used_mask = 0;
67
69
71
72 ctx_pic->slice_count = 0;
73 ctx_pic->bitstream_size = 0;
74 ctx_pic->bitstream = NULL;
75
76 return 0;
77}
78
79static int d3d12va_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
80{
81 const HEVCContext *h = avctx->priv_data;
82 const HEVCFrame *current_picture = h->cur_frame;
83 HEVCDecodePictureContext *ctx_pic = current_picture->hwaccel_picture_private;
84 unsigned position;
85
86 if (ctx_pic->slice_count >= MAX_SLICES)
87 return AVERROR(ERANGE);
88
89 if (!ctx_pic->bitstream)
90 ctx_pic->bitstream = buffer;
91 ctx_pic->bitstream_size += size;
92
93 position = buffer - ctx_pic->bitstream;
94 fill_slice_short(&ctx_pic->slice_short[ctx_pic->slice_count], position, size);
95 ctx_pic->slice_count++;
96
97 return 0;
98}
99
100#define START_CODE 65536
101#define START_CODE_SIZE 3
102static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
103{
105 const HEVCContext *h = avctx->priv_data;
106 const HEVCFrame *current_picture = h->cur_frame;
107 HEVCDecodePictureContext *ctx_pic = current_picture->hwaccel_picture_private;
108
109 int i;
110 uint8_t *mapped_data, *mapped_ptr;
111 DXVA_Slice_HEVC_Short *slice;
112 D3D12_VIDEO_DECODE_FRAME_ARGUMENT *args;
113 UINT bitstream_size = ctx->bitstream_size;
114
115 if (FAILED(ID3D12Resource_Map(buffer, 0, NULL, (void **)&mapped_data))) {
116 av_log(avctx, AV_LOG_ERROR, "Failed to map D3D12 Buffer resource!\n");
117 return AVERROR(EINVAL);
118 }
119
120 mapped_ptr = mapped_data;
121 for (i = 0; i < ctx_pic->slice_count; i++) {
122 UINT position, size;
123 slice = &ctx_pic->slice_short[i];
124
125 position = slice->BSNALunitDataLocation;
126 size = slice->SliceBytesInBuffer;
127
128 if (START_CODE_SIZE + (uint64_t)size > bitstream_size) {
129 av_log(avctx, AV_LOG_ERROR, "Input frame bitstream size exceeds internal buffer!\n");
130 ID3D12Resource_Unmap(buffer, 0, NULL);
131 return AVERROR(EINVAL);
132 }
133
134 slice->SliceBytesInBuffer += START_CODE_SIZE;
135 slice->BSNALunitDataLocation = mapped_ptr - mapped_data;
136
137 *(uint32_t *)mapped_ptr = START_CODE;
138 mapped_ptr += START_CODE_SIZE;
139 bitstream_size -= START_CODE_SIZE;
140
141 memcpy(mapped_ptr, &ctx_pic->bitstream[position], size);
142 mapped_ptr += size;
143 bitstream_size -= size;
144 }
145
146 ID3D12Resource_Unmap(buffer, 0, NULL);
147
148 input_args->CompressedBitstream = (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM){
149 .pBuffer = buffer,
150 .Offset = 0,
151 .Size = mapped_ptr - mapped_data,
152 };
153
154 args = &input_args->FrameArguments[input_args->NumFrameArguments++];
155 args->Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL;
156 args->Size = sizeof(DXVA_Slice_HEVC_Short) * ctx_pic->slice_count;
157 args->pData = ctx_pic->slice_short;
158
159 return 0;
160}
161
163{
164 HEVCContext *h = avctx->priv_data;
165 HEVCDecodePictureContext *ctx_pic = h->cur_frame->hwaccel_picture_private;
166
167 int scale = ctx_pic->pp.dwCodingParamToolFlags & 1;
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, h->cur_frame->f, &ctx_pic->pp, sizeof(ctx_pic->pp),
173 scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0, update_input_arguments);
174}
175
177{
179 DXVA_PicParams_HEVC pp;
180
181 switch (avctx->profile) {
183 ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10;
184 break;
185
188 ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN;
189 break;
190 } else {
191 av_log(avctx, AV_LOG_ERROR, "D3D12 doesn't support PROFILE_HEVC_MAIN_STILL_PICTURE!\n");
192 return AVERROR(EINVAL);
193 }
194
196 default:
197 ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN;
198 break;
199 };
200
201 ctx->max_num_ref = FF_ARRAY_ELEMS(pp.RefPicList) + 1;
202
203 return ff_d3d12va_decode_init(avctx);
204}
205
206#if CONFIG_HEVC_D3D12VA_HWACCEL
208 .p.name = "hevc_d3d12va",
209 .p.type = AVMEDIA_TYPE_VIDEO,
210 .p.id = AV_CODEC_ID_HEVC,
211 .p.pix_fmt = AV_PIX_FMT_D3D12,
213 .uninit = ff_d3d12va_decode_uninit,
214 .start_frame = d3d12va_hevc_start_frame,
215 .decode_slice = d3d12va_hevc_decode_slice,
216 .end_frame = d3d12va_hevc_end_frame,
217 .frame_params = ff_d3d12va_common_frame_params,
218 .frame_priv_data_size = sizeof(HEVCDecodePictureContext),
219 .priv_data_size = sizeof(D3D12VADecodeContext),
220};
221#endif
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define NULL
Definition coverity.c:32
static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
av_cold int ff_d3d12va_decode_init(AVCodecContext *avctx)
init D3D12VADecodeContext
int ff_d3d12va_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
d3d12va common frame params
av_cold int ff_d3d12va_decode_uninit(AVCodecContext *avctx)
uninit D3D12VADecodeContext
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
#define D3D12VA_DECODE_CONTEXT(avctx)
#define START_CODE_SIZE
static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer)
static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const AVBufferRef *buffer_ref, av_unused const uint8_t *buffer, av_unused uint32_t size)
static int d3d12va_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
static int d3d12va_hevc_end_frame(AVCodecContext *avctx)
static av_cold int d3d12va_hevc_decode_init(AVCodecContext *avctx)
static void fill_slice_short(DXVA_Slice_HEVC_Short *slice, unsigned position, unsigned size)
#define MAX_SLICES
#define AV_PROFILE_HEVC_MAIN
Definition defs.h:159
#define AV_PROFILE_HEVC_MAIN_10
Definition defs.h:160
#define AV_PROFILE_HEVC_MAIN_STILL_PICTURE
Definition defs.h:161
void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC *pp)
Definition dxva2_hevc.c:60
void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_HEVC *qm)
Definition dxva2_hevc.c:205
@ AV_CODEC_ID_HEVC
Definition codec_id.h:223
#define AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH
Hardware acceleration should still be attempted for decoding when the codec profile does not match th...
Definition avcodec.h:2018
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
const struct FFHWAccel ff_hevc_d3d12va_hwaccel
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition intra.c:278
#define av_unused
Definition attributes.h:164
#define av_cold
Definition attributes.h:117
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition pixfmt.h:440
#define START_CODE
#define FF_ARRAY_ELEMS(a)
A reference to a data buffer.
Definition buffer.h:82
main external API structure.
Definition avcodec.h:443
int hwaccel_flags
Bit set of AV_HWACCEL_FLAG_* flags, which affect hardware accelerated decoding (if active).
Definition avcodec.h:1502
int profile
profile
Definition avcodec.h:1636
void * priv_data
Definition avcodec.h:470
This structure is used to provide the necessary configurations and data to the FFmpeg Direct3D 12 HWA...
DXVA_Slice_HEVC_Short slice_short[MAX_SLICES]
DXVA_Qmatrix_HEVC qm
DXVA_PicParams_HEVC pp
const uint8_t * bitstream
void * hwaccel_picture_private
RefStruct reference.
Definition hevcdec.h:379
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
static char buffer[20]
Definition seek.c:32
int size