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.tags/n4.0
| @@ -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))) | |||||
| if (hwaccel->id == codec_id | |||||
| while ((hwaccel = av_hwaccel_next(hwaccel))) { | |||||
| 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 | ||||