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{
104 const HEVCContext *h = avctx->priv_data;
105 const HEVCFrame *current_picture = h->cur_frame;
106 HEVCDecodePictureContext *ctx_pic = current_picture->hwaccel_picture_private;
107
108 int i;
109 uint8_t *mapped_data, *mapped_ptr;
110 DXVA_Slice_HEVC_Short *slice;
111 D3D12_VIDEO_DECODE_FRAME_ARGUMENT *args;
112
113 if (FAILED(ID3D12Resource_Map(buffer, 0, NULL, (void **)&mapped_data))) {
114 av_log(avctx, AV_LOG_ERROR, "Failed to map D3D12 Buffer resource!\n");
115 return AVERROR(EINVAL);
116 }
117
118 mapped_ptr = mapped_data;
119 for (i = 0; i < ctx_pic->slice_count; i++) {
120 UINT position, size;
121 slice = &ctx_pic->slice_short[i];
122
123 position = slice->BSNALunitDataLocation;
124 size = slice->SliceBytesInBuffer;
125
126 slice->SliceBytesInBuffer += START_CODE_SIZE;
127 slice->BSNALunitDataLocation = mapped_ptr - mapped_data;
128
129 *(uint32_t *)mapped_ptr = START_CODE;
130 mapped_ptr += START_CODE_SIZE;
131
132 memcpy(mapped_ptr, &ctx_pic->bitstream[position], size);
133 mapped_ptr += size;
134 }
135
136 ID3D12Resource_Unmap(buffer, 0, NULL);
137
138 input_args->CompressedBitstream = (D3D12_VIDEO_DECODE_COMPRESSED_BITSTREAM){
139 .pBuffer = buffer,
140 .Offset = 0,
141 .Size = mapped_ptr - mapped_data,
142 };
143
144 args = &input_args->FrameArguments[input_args->NumFrameArguments++];
145 args->Type = D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL;
146 args->Size = sizeof(DXVA_Slice_HEVC_Short) * ctx_pic->slice_count;
147 args->pData = ctx_pic->slice_short;
148
149 return 0;
150}
151
153{
154 HEVCContext *h = avctx->priv_data;
155 HEVCDecodePictureContext *ctx_pic = h->cur_frame->hwaccel_picture_private;
156
157 int scale = ctx_pic->pp.dwCodingParamToolFlags & 1;
158 uint64_t bitstream_size;
159
160 if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
161 return -1;
162
163 bitstream_size = ctx_pic->bitstream_size +
164 (uint64_t)ctx_pic->slice_count * START_CODE_SIZE;
165
166 return ff_d3d12va_common_end_frame(avctx, h->cur_frame->f, &ctx_pic->pp, sizeof(ctx_pic->pp),
167 scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0,
168 bitstream_size, update_input_arguments);
169}
170
172{
174 DXVA_PicParams_HEVC pp;
175
176 switch (avctx->profile) {
178 ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10;
179 break;
180
183 ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN;
184 break;
185 } else {
186 av_log(avctx, AV_LOG_ERROR, "D3D12 doesn't support PROFILE_HEVC_MAIN_STILL_PICTURE!\n");
187 return AVERROR(EINVAL);
188 }
189
191 default:
192 ctx->cfg.DecodeProfile = D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN;
193 break;
194 };
195
196 ctx->max_num_ref = FF_ARRAY_ELEMS(pp.RefPicList) + 1;
197
198 return ff_d3d12va_decode_init(avctx);
199}
200
201#if CONFIG_HEVC_D3D12VA_HWACCEL
203 .p.name = "hevc_d3d12va",
204 .p.type = AVMEDIA_TYPE_VIDEO,
205 .p.id = AV_CODEC_ID_HEVC,
206 .p.pix_fmt = AV_PIX_FMT_D3D12,
208 .uninit = ff_d3d12va_decode_uninit,
209 .start_frame = d3d12va_hevc_start_frame,
210 .decode_slice = d3d12va_hevc_decode_slice,
211 .end_frame = d3d12va_hevc_end_frame,
212 .frame_params = ff_d3d12va_common_frame_params,
213 .frame_priv_data_size = sizeof(HEVCDecodePictureContext),
214 .priv_data_size = sizeof(D3D12VADecodeContext),
215};
216#endif
static AVFormatContext * ctx
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
int ff_d3d12va_common_end_frame(AVCodecContext *avctx, AVFrame *frame, const void *pp, unsigned pp_size, const void *qm, unsigned qm_size, UINT64 bitstream_size, int(*update_input_arguments)(AVCodecContext *, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *, ID3D12Resource *))
d3d12va common end frame
av_cold int ff_d3d12va_decode_uninit(AVCodecContext *avctx)
uninit D3D12VADecodeContext
#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:2029
#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:1503
int profile
profile
Definition avcodec.h:1637
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 char buffer[20]
Definition seek.c:32
int size