Skip to content

Commit ae5046e

Browse files
wm4BtbN
authored andcommitted
avcodec: allow multiple hwaccels for the same codec/pixfmt
Currently, AVHWAccels are looked up using a (codec_id, pixfmt) tuple. This means it's impossible to have 2 decoders for the same codec and using the same opaque hardware pixel format. This breaks merging Libav's CUVID hwaccel. FFmpeg has its own CUVID support, but it's a full stream decoder, using NVIDIA's codec parser. The Libav one is a true hwaccel, which is based on the builtin software decoders. Fix this by introducing another field to disambiguate AVHWAccels, and use it for our CUVID decoders. FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS makes this mechanism backwards compatible and optional.
1 parent 5593049 commit ae5046e

File tree

4 files changed

+22
-4
lines changed

4 files changed

+22
-4
lines changed

libavcodec/avcodec.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3532,6 +3532,13 @@ typedef struct AVHWAccel {
35323532
* Internal hwaccel capabilities.
35333533
*/
35343534
int caps_internal;
3535+
3536+
/**
3537+
* Some hwaccels are ambiguous if only the id and pix_fmt fields are used.
3538+
* If non-NULL, the associated AVCodec must have
3539+
* FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS set.
3540+
*/
3541+
const AVClass *decoder_class;
35353542
} AVHWAccel;
35363543

35373544
/**

libavcodec/cuviddec.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,7 @@ static const AVOption options[] = {
11061106
.type = AVMEDIA_TYPE_VIDEO, \
11071107
.id = AV_CODEC_ID_##X, \
11081108
.pix_fmt = AV_PIX_FMT_CUDA, \
1109+
.decoder_class = &x##_cuvid_class, \
11091110
}; \
11101111
AVCodec ff_##x##_cuvid_decoder = { \
11111112
.name = #x "_cuvid", \
@@ -1120,6 +1121,7 @@ static const AVOption options[] = {
11201121
.receive_frame = cuvid_output_frame, \
11211122
.flush = cuvid_flush, \
11221123
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
1124+
.caps_internal = FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS, \
11231125
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \
11241126
AV_PIX_FMT_NV12, \
11251127
AV_PIX_FMT_P010, \

libavcodec/decode.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,23 +1090,27 @@ enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const en
10901090
return fmt[0];
10911091
}
10921092

1093-
static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
1093+
static AVHWAccel *find_hwaccel(AVCodecContext *avctx,
10941094
enum AVPixelFormat pix_fmt)
10951095
{
10961096
AVHWAccel *hwaccel = NULL;
1097+
const AVClass *av_class =
1098+
(avctx->codec->caps_internal & FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS)
1099+
? avctx->codec->priv_class : NULL;
10971100

1098-
while ((hwaccel = av_hwaccel_next(hwaccel)))
1099-
if (hwaccel->id == codec_id
1101+
while ((hwaccel = av_hwaccel_next(hwaccel))) {
1102+
if (hwaccel->decoder_class == av_class && hwaccel->id == avctx->codec_id
11001103
&& hwaccel->pix_fmt == pix_fmt)
11011104
return hwaccel;
1105+
}
11021106
return NULL;
11031107
}
11041108

11051109
static int setup_hwaccel(AVCodecContext *avctx,
11061110
const enum AVPixelFormat fmt,
11071111
const char *name)
11081112
{
1109-
AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt);
1113+
AVHWAccel *hwa = find_hwaccel(avctx, fmt);
11101114
int ret = 0;
11111115

11121116
if (!hwa) {

libavcodec/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@
6969
*/
7070
#define FF_CODEC_CAP_SLICE_THREAD_HAS_MF (1 << 5)
7171

72+
/**
73+
* Allow only AVHWAccels which have a matching decoder_class field.
74+
*/
75+
#define FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS (1 << 6)
76+
7277
#ifdef TRACE
7378
# define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__)
7479
#else

0 commit comments

Comments
 (0)