Message ID | 20171003131518.4557-7-nfxjfg@googlemail.com |
---|---|
State | New |
Headers | show |
Am 03.10.2017 um 15:15 schrieb wm4: > 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/Makefile | 1 + > libavcodec/avcodec.h | 5 +++++ > libavcodec/cuviddec.c | 2 ++ > libavcodec/decode.c | 12 ++++++++---- > libavcodec/internal.h | 5 +++++ > 5 files changed, 21 insertions(+), 4 deletions(-) > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index fa3ab8f08a..3e0d654541 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -820,6 +820,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o > OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o > > # hardware accelerators > +OBJS-$(CONFIG_CUVID) += cuvid.o > OBJS-$(CONFIG_D3D11VA) += dxva2.o > OBJS-$(CONFIG_DXVA2) += dxva2.o > OBJS-$(CONFIG_VAAPI) += vaapi_decode.o > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > index 52cc5b0ca0..ecc49e5643 100644 > --- a/libavcodec/avcodec.h > +++ b/libavcodec/avcodec.h > @@ -4000,6 +4000,11 @@ typedef struct AVHWAccel { > * Internal hwaccel capabilities. > */ > int caps_internal; > + > + /** > + * Some hwaccels are ambiguous if only This seems to be truncated? > + */ > + const AVClass *decoder_class; > } AVHWAccel; > > /** > diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c > index 2ba8e00c6a..6370348639 100644 > --- a/libavcodec/cuviddec.c > +++ b/libavcodec/cuviddec.c > @@ -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, \ > diff --git a/libavcodec/decode.c b/libavcodec/decode.c > index 668ef9667f..7060f6a3b7 100644 > --- a/libavcodec/decode.c > +++ b/libavcodec/decode.c > @@ -1152,15 +1152,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->av_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; > } > > @@ -1168,7 +1172,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) { > diff --git a/libavcodec/internal.h b/libavcodec/internal.h > index faa923c11f..0177ea6521 100644 > --- a/libavcodec/internal.h > +++ b/libavcodec/internal.h > @@ -69,6 +69,11 @@ > */ > #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 >
On Tue, 3 Oct 2017 15:58:32 +0200 Timo Rothenpieler <timo@rothenpieler.org> wrote: > Am 03.10.2017 um 15:15 schrieb wm4: > > 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/Makefile | 1 + > > libavcodec/avcodec.h | 5 +++++ > > libavcodec/cuviddec.c | 2 ++ > > libavcodec/decode.c | 12 ++++++++---- > > libavcodec/internal.h | 5 +++++ > > 5 files changed, 21 insertions(+), 4 deletions(-) > > > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > > index fa3ab8f08a..3e0d654541 100644 > > --- a/libavcodec/Makefile > > +++ b/libavcodec/Makefile > > @@ -820,6 +820,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o > > OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o > > > > # hardware accelerators > > +OBJS-$(CONFIG_CUVID) += cuvid.o > > OBJS-$(CONFIG_D3D11VA) += dxva2.o > > OBJS-$(CONFIG_DXVA2) += dxva2.o > > OBJS-$(CONFIG_VAAPI) += vaapi_decode.o > > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > > index 52cc5b0ca0..ecc49e5643 100644 > > --- a/libavcodec/avcodec.h > > +++ b/libavcodec/avcodec.h > > @@ -4000,6 +4000,11 @@ typedef struct AVHWAccel { > > * Internal hwaccel capabilities. > > */ > > int caps_internal; > > + > > + /** > > + * Some hwaccels are ambiguous if only > > This seems to be truncated? Fixed locally with: /** * 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;
On Tue, 3 Oct 2017 15:15:17 +0200 wm4 <nfxjfg@googlemail.com> wrote: > 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/Makefile | 1 + > libavcodec/avcodec.h | 5 +++++ > libavcodec/cuviddec.c | 2 ++ > libavcodec/decode.c | 12 ++++++++---- > libavcodec/internal.h | 5 +++++ > 5 files changed, 21 insertions(+), 4 deletions(-) > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index fa3ab8f08a..3e0d654541 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -820,6 +820,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += > adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += > adpcmenc.o adpcm_data.o > # hardware accelerators > +OBJS-$(CONFIG_CUVID) += cuvid.o > OBJS-$(CONFIG_D3D11VA) += dxva2.o > OBJS-$(CONFIG_DXVA2) += dxva2.o > OBJS-$(CONFIG_VAAPI) += vaapi_decode.o > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > index 52cc5b0ca0..ecc49e5643 100644 > --- a/libavcodec/avcodec.h > +++ b/libavcodec/avcodec.h > @@ -4000,6 +4000,11 @@ typedef struct AVHWAccel { > * Internal hwaccel capabilities. > */ > int caps_internal; > + > + /** > + * Some hwaccels are ambiguous if only > + */ > + const AVClass *decoder_class; > } AVHWAccel; > > /** > diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c > index 2ba8e00c6a..6370348639 100644 > --- a/libavcodec/cuviddec.c > +++ b/libavcodec/cuviddec.c > @@ -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, > \ diff --git a/libavcodec/decode.c b/libavcodec/decode.c > index 668ef9667f..7060f6a3b7 100644 > --- a/libavcodec/decode.c > +++ b/libavcodec/decode.c > @@ -1152,15 +1152,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->av_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; > } > > @@ -1168,7 +1172,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) { > diff --git a/libavcodec/internal.h b/libavcodec/internal.h > index faa923c11f..0177ea6521 100644 > --- a/libavcodec/internal.h > +++ b/libavcodec/internal.h > @@ -69,6 +69,11 @@ > */ > #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 Looks fine. Nothing beyond what Timo said. --phil
On Tue, 3 Oct 2017 15:58:32 +0200 Timo Rothenpieler <timo@rothenpieler.org> wrote: > > -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->av_class : NULL; Also this is actually completely broken. It's trivially fixed, but if anyone actually wants to try the patches, here's an updated set: https://github.com/wm4/FFmpeg/tree/libav-cuvid
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index fa3ab8f08a..3e0d654541 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -820,6 +820,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o # hardware accelerators +OBJS-$(CONFIG_CUVID) += cuvid.o OBJS-$(CONFIG_D3D11VA) += dxva2.o OBJS-$(CONFIG_DXVA2) += dxva2.o OBJS-$(CONFIG_VAAPI) += vaapi_decode.o diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 52cc5b0ca0..ecc49e5643 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -4000,6 +4000,11 @@ typedef struct AVHWAccel { * Internal hwaccel capabilities. */ int caps_internal; + + /** + * Some hwaccels are ambiguous if only + */ + const AVClass *decoder_class; } AVHWAccel; /** diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c index 2ba8e00c6a..6370348639 100644 --- a/libavcodec/cuviddec.c +++ b/libavcodec/cuviddec.c @@ -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, \ diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 668ef9667f..7060f6a3b7 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -1152,15 +1152,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->av_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; } @@ -1168,7 +1172,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) { diff --git a/libavcodec/internal.h b/libavcodec/internal.h index faa923c11f..0177ea6521 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -69,6 +69,11 @@ */ #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