1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-03-23 04:24:35 +02:00

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.
This commit is contained in:
wm4 2017-10-03 15:04:45 +02:00 committed by Timo Rothenpieler
parent 5593049466
commit ae5046e492
4 changed files with 22 additions and 4 deletions

@ -3532,6 +3532,13 @@ typedef struct AVHWAccel {
* Internal hwaccel capabilities. * Internal hwaccel capabilities.
*/ */
int caps_internal; int caps_internal;
/**
* Some hwaccels are ambiguous if only the id and pix_fmt fields are used.
* If non-NULL, the associated AVCodec must have
* FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS set.
*/
const AVClass *decoder_class;
} AVHWAccel; } AVHWAccel;
/** /**

@ -1106,6 +1106,7 @@ static const AVOption options[] = {
.type = AVMEDIA_TYPE_VIDEO, \ .type = AVMEDIA_TYPE_VIDEO, \
.id = AV_CODEC_ID_##X, \ .id = AV_CODEC_ID_##X, \
.pix_fmt = AV_PIX_FMT_CUDA, \ .pix_fmt = AV_PIX_FMT_CUDA, \
.decoder_class = &x##_cuvid_class, \
}; \ }; \
AVCodec ff_##x##_cuvid_decoder = { \ AVCodec ff_##x##_cuvid_decoder = { \
.name = #x "_cuvid", \ .name = #x "_cuvid", \
@ -1120,6 +1121,7 @@ static const AVOption options[] = {
.receive_frame = cuvid_output_frame, \ .receive_frame = cuvid_output_frame, \
.flush = cuvid_flush, \ .flush = cuvid_flush, \
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
.caps_internal = FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS, \
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \
AV_PIX_FMT_NV12, \ AV_PIX_FMT_NV12, \
AV_PIX_FMT_P010, \ AV_PIX_FMT_P010, \

@ -1090,15 +1090,19 @@ enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const en
return fmt[0]; return fmt[0];
} }
static AVHWAccel *find_hwaccel(enum AVCodecID codec_id, static AVHWAccel *find_hwaccel(AVCodecContext *avctx,
enum AVPixelFormat pix_fmt) enum AVPixelFormat pix_fmt)
{ {
AVHWAccel *hwaccel = NULL; AVHWAccel *hwaccel = NULL;
const AVClass *av_class =
(avctx->codec->caps_internal & FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS)
? avctx->codec->priv_class : NULL;
while ((hwaccel = av_hwaccel_next(hwaccel))) while ((hwaccel = av_hwaccel_next(hwaccel))) {
if (hwaccel->id == codec_id if (hwaccel->decoder_class == av_class && hwaccel->id == avctx->codec_id
&& hwaccel->pix_fmt == pix_fmt) && hwaccel->pix_fmt == pix_fmt)
return hwaccel; return hwaccel;
}
return NULL; return NULL;
} }
@ -1106,7 +1110,7 @@ static int setup_hwaccel(AVCodecContext *avctx,
const enum AVPixelFormat fmt, const enum AVPixelFormat fmt,
const char *name) const char *name)
{ {
AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt); AVHWAccel *hwa = find_hwaccel(avctx, fmt);
int ret = 0; int ret = 0;
if (!hwa) { if (!hwa) {

@ -69,6 +69,11 @@
*/ */
#define FF_CODEC_CAP_SLICE_THREAD_HAS_MF (1 << 5) #define FF_CODEC_CAP_SLICE_THREAD_HAS_MF (1 << 5)
/**
* Allow only AVHWAccels which have a matching decoder_class field.
*/
#define FF_CODEC_CAP_HWACCEL_REQUIRE_CLASS (1 << 6)
#ifdef TRACE #ifdef TRACE
# define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__) # define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__)
#else #else