avcodec: allow multiple hwaccels for the same codec/pixfmt
authorwm4 <nfxjfg@googlemail.com>
Tue, 3 Oct 2017 13:04:45 +0000 (15:04 +0200)
committerTimo Rothenpieler <timo@rothenpieler.org>
Fri, 10 Nov 2017 21:48:34 +0000 (22:48 +0100)
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.

libavcodec/avcodec.h
libavcodec/cuviddec.c
libavcodec/decode.c
libavcodec/internal.h

index 429d62a..15ca871 100644 (file)
@@ -3532,6 +3532,13 @@ typedef struct AVHWAccel {
      * Internal hwaccel capabilities.
      */
     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;
 
 /**
index 2ba8e00..6370348 100644 (file)
@@ -1106,6 +1106,7 @@ static const AVOption options[] = {
         .type           = AVMEDIA_TYPE_VIDEO, \
         .id             = AV_CODEC_ID_##X, \
         .pix_fmt        = AV_PIX_FMT_CUDA, \
+        .decoder_class  = &x##_cuvid_class, \
     }; \
     AVCodec ff_##x##_cuvid_decoder = { \
         .name           = #x "_cuvid", \
@@ -1120,6 +1121,7 @@ static const AVOption options[] = {
         .receive_frame  = cuvid_output_frame, \
         .flush          = cuvid_flush, \
         .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, \
                                                         AV_PIX_FMT_NV12, \
                                                         AV_PIX_FMT_P010, \
index 44b874d..9fdc7bb 100644 (file)
@@ -1090,15 +1090,19 @@ enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const en
     return fmt[0];
 }
 
-static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
+static AVHWAccel *find_hwaccel(AVCodecContext *avctx,
                                enum AVPixelFormat pix_fmt)
 {
     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)
             return hwaccel;
+    }
     return NULL;
 }
 
@@ -1106,7 +1110,7 @@ static int setup_hwaccel(AVCodecContext *avctx,
                          const enum AVPixelFormat fmt,
                          const char *name)
 {
-    AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt);
+    AVHWAccel *hwa = find_hwaccel(avctx, fmt);
     int ret        = 0;
 
     if (!hwa) {
index 7748f09..948d546 100644 (file)
  */
 #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
 #   define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__)
 #else