diff mbox series

[FFmpeg-devel,v3,1/2] qsvdec: add support for HW_DEVICE_CTX method

Message ID 20210811060155.6329-1-haihao.xiang@intel.com
State Accepted
Commit ecee3b07cde23e05bcc6b4eaa55d860b62dbd2dc
Headers show
Series [FFmpeg-devel,v3,1/2] qsvdec: add support for HW_DEVICE_CTX method | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Xiang, Haihao Aug. 11, 2021, 6:01 a.m. UTC
This allows user set hw_device_ctx instead of hw_frames_ctx for QSV
decoders, hence we may remove the ad-hoc libmfx setup code from FFmpeg.

"-hwaccel_output_format format" is applied to QSV decoders after
removing the ad-hoc libmfx code. In order to keep compatibility with old
commandlines, the default format is set to AV_PIX_FMT_QSV, but this
behavior will be removed in the future. Please set "-hwaccel_output_format qsv"
explicitly if AV_PIX_FMT_QSV is expected.

The normal device stuff works for QSV decoders now, user may use
"-init_hw_device args" to initialise device and "-hwaccel_device
devicename" to select a device for QSV decoders.

"-qsv_device device" which was added for workarounding device selection
in the ad-hoc libmfx code still works

For example:

$> ffmpeg -init_hw_device qsv=qsv:hw_any,child_device=/dev/dri/card0
-hwaccel qsv -c:v h264_qsv -i input.h264  -f null -

/dev/dri/renderD128 is actually open for h264_qsv decoder in the above
command without this patch. After applying this patch, /dev/dri/card0
is used.

$> ffmpeg -init_hw_device vaapi=va:/dev/dri/card0 -init_hw_device
qsv=hw@va -hwaccel_device hw -hwaccel qsv -c:v h264_qsv -i input.h264
-f null -

device hw of type qsv is not usable in the above command without this
patch. After applying this patch, this command works as expected.
---
v3:
 Don't deprecate -qsv_device option
 Use single-shot device initialization to implement qsv_device option
 Update the commit log

 fftools/Makefile     |   1 -
 fftools/ffmpeg.h     |   1 -
 fftools/ffmpeg_hw.c  |  12 +++++
 fftools/ffmpeg_opt.c |  28 +++++++++--
 fftools/ffmpeg_qsv.c | 109 -------------------------------------------
 libavcodec/qsvdec.c  |  31 +++++++++++-
 6 files changed, 66 insertions(+), 116 deletions(-)
 delete mode 100644 fftools/ffmpeg_qsv.c

Comments

Soft Works Aug. 11, 2021, 4:29 p.m. UTC | #1
> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
> Haihao Xiang
> Sent: Wednesday, 11 August 2021 08:02
> To: ffmpeg-devel@ffmpeg.org
> Cc: Haihao Xiang <haihao.xiang@intel.com>
> Subject: [FFmpeg-devel] [PATCH v3 1/2] qsvdec: add support for
> HW_DEVICE_CTX method
> 
> This allows user set hw_device_ctx instead of hw_frames_ctx for QSV
> decoders, hence we may remove the ad-hoc libmfx setup code from
> FFmpeg.
> 
> "-hwaccel_output_format format" is applied to QSV decoders after
> removing the ad-hoc libmfx code. In order to keep compatibility with
> old
> commandlines, the default format is set to AV_PIX_FMT_QSV, but this
> behavior will be removed in the future. Please set "-
> hwaccel_output_format qsv"
> explicitly if AV_PIX_FMT_QSV is expected.
> 
> The normal device stuff works for QSV decoders now, user may use
> "-init_hw_device args" to initialise device and "-hwaccel_device
> devicename" to select a device for QSV decoders.
> 
> "-qsv_device device" which was added for workarounding device
> selection
> in the ad-hoc libmfx code still works
> 
> For example:
> 
> $> ffmpeg -init_hw_device qsv=qsv:hw_any,child_device=/dev/dri/card0
> -hwaccel qsv -c:v h264_qsv -i input.h264  -f null -
> 
> /dev/dri/renderD128 is actually open for h264_qsv decoder in the
> above
> command without this patch. After applying this patch, /dev/dri/card0
> is used.
> 
> $> ffmpeg -init_hw_device vaapi=va:/dev/dri/card0 -init_hw_device
> qsv=hw@va -hwaccel_device hw -hwaccel qsv -c:v h264_qsv -i input.h264
> -f null -
> 
> device hw of type qsv is not usable in the above command without this
> patch. After applying this patch, this command works as expected.
> ---
> v3:
>  Don't deprecate -qsv_device option
>  Use single-shot device initialization to implement qsv_device option
>  Update the commit log
> 
>  fftools/Makefile     |   1 -
>  fftools/ffmpeg.h     |   1 -
>  fftools/ffmpeg_hw.c  |  12 +++++
>  fftools/ffmpeg_opt.c |  28 +++++++++--
>  fftools/ffmpeg_qsv.c | 109 -----------------------------------------
> --
>  libavcodec/qsvdec.c  |  31 +++++++++++-
>  6 files changed, 66 insertions(+), 116 deletions(-)
>  delete mode 100644 fftools/ffmpeg_qsv.c
> 
> diff --git a/fftools/Makefile b/fftools/Makefile
> index 5affaa3f56..5234932ab0 100644
> --- a/fftools/Makefile
> +++ b/fftools/Makefile
> @@ -10,7 +10,6 @@ ALLAVPROGS   =
> $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
>  ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
> 
>  OBJS-ffmpeg                        += fftools/ffmpeg_opt.o
> fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o
> -OBJS-ffmpeg-$(CONFIG_LIBMFX)       += fftools/ffmpeg_qsv.o
>  ifndef CONFIG_VIDEOTOOLBOX
>  OBJS-ffmpeg-$(CONFIG_VDA)          += fftools/ffmpeg_videotoolbox.o
>  endif
> diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> index d9c0628657..d2dd7ca092 100644
> --- a/fftools/ffmpeg.h
> +++ b/fftools/ffmpeg.h
> @@ -61,7 +61,6 @@ enum HWAccelID {
>      HWACCEL_AUTO,
>      HWACCEL_GENERIC,
>      HWACCEL_VIDEOTOOLBOX,
> -    HWACCEL_QSV,
>  };
> 
>  typedef struct HWAccel {
> diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c
> index fc4a5d31d6..6923c4c5a1 100644
> --- a/fftools/ffmpeg_hw.c
> +++ b/fftools/ffmpeg_hw.c
> @@ -339,6 +339,18 @@ int hw_device_setup_for_decode(InputStream *ist)
>          } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
>              type = ist->hwaccel_device_type;
>              dev = hw_device_get_by_type(type);
> +
> +            // When "-qsv_device device" is used, an internal QSV
> device named
> +            // as "__qsv_device" is created. Another QSV device is
> created too
> +            // if "-init_hw_device qsv=name:device" is used. There
> are 2 QSV devices
> +            // if both "-qsv_device device" and "-init_hw_device
> qsv=name:device"
> +            // are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV)
> returns NULL.
> +            // To keep back-compatibility with the removed ad-hoc
> libmfx setup code,
> +            // call hw_device_get_by_name("__qsv_device") to select
> the internal QSV
> +            // device.
> +            if (!dev && type == AV_HWDEVICE_TYPE_QSV)
> +                dev = hw_device_get_by_name("__qsv_device");
> +
>              if (!dev)
>                  err = hw_device_init_from_type(type, NULL, &dev);
>          } else {
> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> index 34cc6c4fd3..428934a3d8 100644
> --- a/fftools/ffmpeg_opt.c
> +++ b/fftools/ffmpeg_opt.c
> @@ -137,9 +137,6 @@ static const char *const
> opt_name_enc_time_bases[]            = {"enc_time_base"
>  const HWAccel hwaccels[] = {
>  #if CONFIG_VIDEOTOOLBOX
>      { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX,
> AV_PIX_FMT_VIDEOTOOLBOX },
> -#endif
> -#if CONFIG_LIBMFX
> -    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV },
>  #endif
>      { 0 },
>  };
> @@ -571,6 +568,23 @@ static int opt_vaapi_device(void *optctx, const
> char *opt, const char *arg)
>  }
>  #endif
> 
> +#if CONFIG_QSV
> +static int opt_qsv_device(void *optctx, const char *opt, const char
> *arg)
> +{
> +    const char *prefix = "qsv=__qsv_device:hw_any,child_device=";
> +    int err;
> +    char *tmp = av_asprintf("%s%s", prefix, arg);
> +
> +    if (!tmp)
> +        return AVERROR(ENOMEM);
> +
> +    err = hw_device_init_from_string(tmp, NULL);
> +    av_free(tmp);
> +
> +    return err;
> +}
> +#endif
> +
>  static int opt_init_hw_device(void *optctx, const char *opt, const
> char *arg)
>  {
>      if (!strcmp(arg, "list")) {
> @@ -898,6 +912,12 @@ static void add_input_streams(OptionsContext *o,
> AVFormatContext *ic)
>                      "with old commandlines. This behaviour is
> DEPRECATED and will be removed "
>                      "in the future. Please explicitly set \"-
> hwaccel_output_format cuda\".\n");
>                  ist->hwaccel_output_format = AV_PIX_FMT_CUDA;
> +            } else if (!hwaccel_output_format && hwaccel &&
> !strcmp(hwaccel, "qsv")) {
> +                av_log(NULL, AV_LOG_WARNING,
> +                    "WARNING: defaulting hwaccel_output_format to
> qsv for compatibility "
> +                    "with old commandlines. This behaviour is
> DEPRECATED and will be removed "
> +                    "in the future. Please explicitly set \"-
> hwaccel_output_format qsv\".\n");
> +                ist->hwaccel_output_format = AV_PIX_FMT_QSV;
>              } else if (hwaccel_output_format) {
>                  ist->hwaccel_output_format =
> av_get_pix_fmt(hwaccel_output_format);
>                  if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) {
> @@ -3848,7 +3868,7 @@ const OptionDef options[] = {
>  #endif
> 
>  #if CONFIG_QSV
> -    { "qsv_device", HAS_ARG | OPT_STRING | OPT_EXPERT, { &qsv_device
> },
> +    { "qsv_device", HAS_ARG | OPT_EXPERT, { .func_arg =
> opt_qsv_device },
>          "set QSV hardware device (DirectX adapter index, DRM path or
> X11 display name)", "device"},
>  #endif
> 
> diff --git a/fftools/ffmpeg_qsv.c b/fftools/ffmpeg_qsv.c
> deleted file mode 100644
> index 7bd999d310..0000000000
> --- a/fftools/ffmpeg_qsv.c
> +++ /dev/null
> @@ -1,109 +0,0 @@
> -/*
> - * This file is part of FFmpeg.
> - *
> - * FFmpeg is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU Lesser General Public
> - * License as published by the Free Software Foundation; either
> - * version 2.1 of the License, or (at your option) any later
> version.
> - *
> - * FFmpeg is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> - * Lesser General Public License for more details.
> - *
> - * You should have received a copy of the GNU Lesser General Public
> - * License along with FFmpeg; if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> - */
> -
> -#include <mfx/mfxvideo.h>
> -#include <stdlib.h>
> -
> -#include "libavutil/dict.h"
> -#include "libavutil/hwcontext.h"
> -#include "libavutil/hwcontext_qsv.h"
> -#include "libavutil/opt.h"
> -#include "libavcodec/qsv.h"
> -
> -#include "ffmpeg.h"
> -
> -static AVBufferRef *hw_device_ctx;
> -char *qsv_device = NULL;
> -
> -static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int
> flags)
> -{
> -    InputStream *ist = s->opaque;
> -
> -    return av_hwframe_get_buffer(ist->hw_frames_ctx, frame, 0);
> -}
> -
> -static void qsv_uninit(AVCodecContext *s)
> -{
> -    InputStream *ist = s->opaque;
> -    av_buffer_unref(&ist->hw_frames_ctx);
> -}
> -
> -static int qsv_device_init(InputStream *ist)
> -{
> -    int err;
> -    AVDictionary *dict = NULL;
> -
> -    if (qsv_device) {
> -        err = av_dict_set(&dict, "child_device", qsv_device, 0);
> -        if (err < 0)
> -            return err;
> -    }
> -
> -    err = av_hwdevice_ctx_create(&hw_device_ctx,
> AV_HWDEVICE_TYPE_QSV,
> -                                 ist->hwaccel_device, dict, 0);
> -    if (err < 0) {
> -        av_log(NULL, AV_LOG_ERROR, "Error creating a QSV device\n");
> -        goto err_out;
> -    }
> -
> -err_out:
> -    if (dict)
> -        av_dict_free(&dict);
> -
> -    return err;
> -}
> -
> -int qsv_init(AVCodecContext *s)
> -{
> -    InputStream *ist = s->opaque;
> -    AVHWFramesContext *frames_ctx;
> -    AVQSVFramesContext *frames_hwctx;
> -    int ret;
> -
> -    if (!hw_device_ctx) {
> -        ret = qsv_device_init(ist);
> -        if (ret < 0)
> -            return ret;
> -    }
> -
> -    av_buffer_unref(&ist->hw_frames_ctx);
> -    ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
> -    if (!ist->hw_frames_ctx)
> -        return AVERROR(ENOMEM);
> -
> -    frames_ctx   = (AVHWFramesContext*)ist->hw_frames_ctx->data;
> -    frames_hwctx = frames_ctx->hwctx;
> -
> -    frames_ctx->width             = FFALIGN(s->coded_width,  32);
> -    frames_ctx->height            = FFALIGN(s->coded_height, 32);
> -    frames_ctx->format            = AV_PIX_FMT_QSV;
> -    frames_ctx->sw_format         = s->sw_pix_fmt;
> -    frames_ctx->initial_pool_size = 64 + s->extra_hw_frames;
> -    frames_hwctx->frame_type      =
> MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
> -
> -    ret = av_hwframe_ctx_init(ist->hw_frames_ctx);
> -    if (ret < 0) {
> -        av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV frame
> pool\n");
> -        return ret;
> -    }
> -
> -    ist->hwaccel_get_buffer = qsv_get_buffer;
> -    ist->hwaccel_uninit     = qsv_uninit;
> -
> -    return 0;
> -}
> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> index 19a6a776db..8bce9f2cf0 100644
> --- a/libavcodec/qsvdec.c
> +++ b/libavcodec/qsvdec.c
> @@ -99,7 +99,7 @@ static const AVCodecHWConfigInternal *const
> qsv_hw_configs[] = {
>          .public = {
>              .pix_fmt     = AV_PIX_FMT_QSV,
>              .methods     = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX |
> -                           AV_CODEC_HW_CONFIG_METHOD_AD_HOC,
> +                           AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
>              .device_type = AV_HWDEVICE_TYPE_QSV,
>          },
>          .hwaccel = NULL,
> @@ -248,6 +248,35 @@ static int qsv_decode_preinit(AVCodecContext
> *avctx, QSVContext *q, enum AVPixel
>          q->nb_ext_buffers = user_ctx->nb_ext_buffers;
>      }
> 
> +    if (avctx->hw_device_ctx && !avctx->hw_frames_ctx && ret ==
> AV_PIX_FMT_QSV) {
> +        AVHWFramesContext *hwframes_ctx;
> +        AVQSVFramesContext *frames_hwctx;
> +
> +        avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx-
> >hw_device_ctx);
> +
> +        if (!avctx->hw_frames_ctx) {
> +            av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_alloc
> failed\n");
> +            return AVERROR(ENOMEM);
> +        }
> +
> +        hwframes_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx-
> >data;
> +        frames_hwctx = hwframes_ctx->hwctx;
> +        hwframes_ctx->width             = FFALIGN(avctx-
> >coded_width,  32);
> +        hwframes_ctx->height            = FFALIGN(avctx-
> >coded_height, 32);
> +        hwframes_ctx->format            = AV_PIX_FMT_QSV;
> +        hwframes_ctx->sw_format         = avctx->sw_pix_fmt;
> +        hwframes_ctx->initial_pool_size = 64 + avctx-
> >extra_hw_frames;
> +        frames_hwctx->frame_type        =
> MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
> +
> +        ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
> +
> +        if (ret < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV
> frame pool\n");
> +            av_buffer_unref(&avctx->hw_frames_ctx);
> +            return ret;
> +        }
> +    }
> +
>      if (avctx->hw_frames_ctx) {
>          AVHWFramesContext    *frames_ctx =
> (AVHWFramesContext*)avctx->hw_frames_ctx->data;
>          AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
> --

LGTM.

Thanks,
softworkz
James Almer Aug. 11, 2021, 4:54 p.m. UTC | #2
On 8/11/2021 1:29 PM, Soft Works wrote:
> 
> 
>> -----Original Message-----
>> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
>> Haihao Xiang
>> Sent: Wednesday, 11 August 2021 08:02
>> To: ffmpeg-devel@ffmpeg.org
>> Cc: Haihao Xiang <haihao.xiang@intel.com>
>> Subject: [FFmpeg-devel] [PATCH v3 1/2] qsvdec: add support for
>> HW_DEVICE_CTX method
>>
>> This allows user set hw_device_ctx instead of hw_frames_ctx for QSV
>> decoders, hence we may remove the ad-hoc libmfx setup code from
>> FFmpeg.
>>
>> "-hwaccel_output_format format" is applied to QSV decoders after
>> removing the ad-hoc libmfx code. In order to keep compatibility with
>> old
>> commandlines, the default format is set to AV_PIX_FMT_QSV, but this
>> behavior will be removed in the future. Please set "-
>> hwaccel_output_format qsv"
>> explicitly if AV_PIX_FMT_QSV is expected.
>>
>> The normal device stuff works for QSV decoders now, user may use
>> "-init_hw_device args" to initialise device and "-hwaccel_device
>> devicename" to select a device for QSV decoders.
>>
>> "-qsv_device device" which was added for workarounding device
>> selection
>> in the ad-hoc libmfx code still works
>>
>> For example:
>>
>> $> ffmpeg -init_hw_device qsv=qsv:hw_any,child_device=/dev/dri/card0
>> -hwaccel qsv -c:v h264_qsv -i input.h264  -f null -
>>
>> /dev/dri/renderD128 is actually open for h264_qsv decoder in the
>> above
>> command without this patch. After applying this patch, /dev/dri/card0
>> is used.
>>
>> $> ffmpeg -init_hw_device vaapi=va:/dev/dri/card0 -init_hw_device
>> qsv=hw@va -hwaccel_device hw -hwaccel qsv -c:v h264_qsv -i input.h264
>> -f null -
>>
>> device hw of type qsv is not usable in the above command without this
>> patch. After applying this patch, this command works as expected.
>> ---
>> v3:
>>   Don't deprecate -qsv_device option
>>   Use single-shot device initialization to implement qsv_device option
>>   Update the commit log
>>
>>   fftools/Makefile     |   1 -
>>   fftools/ffmpeg.h     |   1 -
>>   fftools/ffmpeg_hw.c  |  12 +++++
>>   fftools/ffmpeg_opt.c |  28 +++++++++--
>>   fftools/ffmpeg_qsv.c | 109 -----------------------------------------
>> --
>>   libavcodec/qsvdec.c  |  31 +++++++++++-
>>   6 files changed, 66 insertions(+), 116 deletions(-)
>>   delete mode 100644 fftools/ffmpeg_qsv.c
>>
>> diff --git a/fftools/Makefile b/fftools/Makefile
>> index 5affaa3f56..5234932ab0 100644
>> --- a/fftools/Makefile
>> +++ b/fftools/Makefile
>> @@ -10,7 +10,6 @@ ALLAVPROGS   =
>> $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
>>   ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
>>
>>   OBJS-ffmpeg                        += fftools/ffmpeg_opt.o
>> fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o
>> -OBJS-ffmpeg-$(CONFIG_LIBMFX)       += fftools/ffmpeg_qsv.o
>>   ifndef CONFIG_VIDEOTOOLBOX
>>   OBJS-ffmpeg-$(CONFIG_VDA)          += fftools/ffmpeg_videotoolbox.o
>>   endif
>> diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
>> index d9c0628657..d2dd7ca092 100644
>> --- a/fftools/ffmpeg.h
>> +++ b/fftools/ffmpeg.h
>> @@ -61,7 +61,6 @@ enum HWAccelID {
>>       HWACCEL_AUTO,
>>       HWACCEL_GENERIC,
>>       HWACCEL_VIDEOTOOLBOX,
>> -    HWACCEL_QSV,
>>   };
>>
>>   typedef struct HWAccel {
>> diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c
>> index fc4a5d31d6..6923c4c5a1 100644
>> --- a/fftools/ffmpeg_hw.c
>> +++ b/fftools/ffmpeg_hw.c
>> @@ -339,6 +339,18 @@ int hw_device_setup_for_decode(InputStream *ist)
>>           } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
>>               type = ist->hwaccel_device_type;
>>               dev = hw_device_get_by_type(type);
>> +
>> +            // When "-qsv_device device" is used, an internal QSV
>> device named
>> +            // as "__qsv_device" is created. Another QSV device is
>> created too
>> +            // if "-init_hw_device qsv=name:device" is used. There
>> are 2 QSV devices
>> +            // if both "-qsv_device device" and "-init_hw_device
>> qsv=name:device"
>> +            // are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV)
>> returns NULL.
>> +            // To keep back-compatibility with the removed ad-hoc
>> libmfx setup code,
>> +            // call hw_device_get_by_name("__qsv_device") to select
>> the internal QSV
>> +            // device.
>> +            if (!dev && type == AV_HWDEVICE_TYPE_QSV)
>> +                dev = hw_device_get_by_name("__qsv_device");
>> +
>>               if (!dev)
>>                   err = hw_device_init_from_type(type, NULL, &dev);
>>           } else {
>> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
>> index 34cc6c4fd3..428934a3d8 100644
>> --- a/fftools/ffmpeg_opt.c
>> +++ b/fftools/ffmpeg_opt.c
>> @@ -137,9 +137,6 @@ static const char *const
>> opt_name_enc_time_bases[]            = {"enc_time_base"
>>   const HWAccel hwaccels[] = {
>>   #if CONFIG_VIDEOTOOLBOX
>>       { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX,
>> AV_PIX_FMT_VIDEOTOOLBOX },
>> -#endif
>> -#if CONFIG_LIBMFX
>> -    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV },
>>   #endif
>>       { 0 },
>>   };
>> @@ -571,6 +568,23 @@ static int opt_vaapi_device(void *optctx, const
>> char *opt, const char *arg)
>>   }
>>   #endif
>>
>> +#if CONFIG_QSV
>> +static int opt_qsv_device(void *optctx, const char *opt, const char
>> *arg)
>> +{
>> +    const char *prefix = "qsv=__qsv_device:hw_any,child_device=";
>> +    int err;
>> +    char *tmp = av_asprintf("%s%s", prefix, arg);
>> +
>> +    if (!tmp)
>> +        return AVERROR(ENOMEM);
>> +
>> +    err = hw_device_init_from_string(tmp, NULL);
>> +    av_free(tmp);
>> +
>> +    return err;
>> +}
>> +#endif
>> +
>>   static int opt_init_hw_device(void *optctx, const char *opt, const
>> char *arg)
>>   {
>>       if (!strcmp(arg, "list")) {
>> @@ -898,6 +912,12 @@ static void add_input_streams(OptionsContext *o,
>> AVFormatContext *ic)
>>                       "with old commandlines. This behaviour is
>> DEPRECATED and will be removed "
>>                       "in the future. Please explicitly set \"-
>> hwaccel_output_format cuda\".\n");
>>                   ist->hwaccel_output_format = AV_PIX_FMT_CUDA;
>> +            } else if (!hwaccel_output_format && hwaccel &&
>> !strcmp(hwaccel, "qsv")) {
>> +                av_log(NULL, AV_LOG_WARNING,
>> +                    "WARNING: defaulting hwaccel_output_format to
>> qsv for compatibility "
>> +                    "with old commandlines. This behaviour is
>> DEPRECATED and will be removed "
>> +                    "in the future. Please explicitly set \"-
>> hwaccel_output_format qsv\".\n");
>> +                ist->hwaccel_output_format = AV_PIX_FMT_QSV;
>>               } else if (hwaccel_output_format) {
>>                   ist->hwaccel_output_format =
>> av_get_pix_fmt(hwaccel_output_format);
>>                   if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) {
>> @@ -3848,7 +3868,7 @@ const OptionDef options[] = {
>>   #endif
>>
>>   #if CONFIG_QSV
>> -    { "qsv_device", HAS_ARG | OPT_STRING | OPT_EXPERT, { &qsv_device
>> },
>> +    { "qsv_device", HAS_ARG | OPT_EXPERT, { .func_arg =
>> opt_qsv_device },
>>           "set QSV hardware device (DirectX adapter index, DRM path or
>> X11 display name)", "device"},
>>   #endif
>>
>> diff --git a/fftools/ffmpeg_qsv.c b/fftools/ffmpeg_qsv.c
>> deleted file mode 100644
>> index 7bd999d310..0000000000
>> --- a/fftools/ffmpeg_qsv.c
>> +++ /dev/null
>> @@ -1,109 +0,0 @@
>> -/*
>> - * This file is part of FFmpeg.
>> - *
>> - * FFmpeg is free software; you can redistribute it and/or
>> - * modify it under the terms of the GNU Lesser General Public
>> - * License as published by the Free Software Foundation; either
>> - * version 2.1 of the License, or (at your option) any later
>> version.
>> - *
>> - * FFmpeg is distributed in the hope that it will be useful,
>> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> - * Lesser General Public License for more details.
>> - *
>> - * You should have received a copy of the GNU Lesser General Public
>> - * License along with FFmpeg; if not, write to the Free Software
>> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>> 02110-1301 USA
>> - */
>> -
>> -#include <mfx/mfxvideo.h>
>> -#include <stdlib.h>
>> -
>> -#include "libavutil/dict.h"
>> -#include "libavutil/hwcontext.h"
>> -#include "libavutil/hwcontext_qsv.h"
>> -#include "libavutil/opt.h"
>> -#include "libavcodec/qsv.h"
>> -
>> -#include "ffmpeg.h"
>> -
>> -static AVBufferRef *hw_device_ctx;
>> -char *qsv_device = NULL;
>> -
>> -static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int
>> flags)
>> -{
>> -    InputStream *ist = s->opaque;
>> -
>> -    return av_hwframe_get_buffer(ist->hw_frames_ctx, frame, 0);
>> -}
>> -
>> -static void qsv_uninit(AVCodecContext *s)
>> -{
>> -    InputStream *ist = s->opaque;
>> -    av_buffer_unref(&ist->hw_frames_ctx);
>> -}
>> -
>> -static int qsv_device_init(InputStream *ist)
>> -{
>> -    int err;
>> -    AVDictionary *dict = NULL;
>> -
>> -    if (qsv_device) {
>> -        err = av_dict_set(&dict, "child_device", qsv_device, 0);
>> -        if (err < 0)
>> -            return err;
>> -    }
>> -
>> -    err = av_hwdevice_ctx_create(&hw_device_ctx,
>> AV_HWDEVICE_TYPE_QSV,
>> -                                 ist->hwaccel_device, dict, 0);
>> -    if (err < 0) {
>> -        av_log(NULL, AV_LOG_ERROR, "Error creating a QSV device\n");
>> -        goto err_out;
>> -    }
>> -
>> -err_out:
>> -    if (dict)
>> -        av_dict_free(&dict);
>> -
>> -    return err;
>> -}
>> -
>> -int qsv_init(AVCodecContext *s)
>> -{
>> -    InputStream *ist = s->opaque;
>> -    AVHWFramesContext *frames_ctx;
>> -    AVQSVFramesContext *frames_hwctx;
>> -    int ret;
>> -
>> -    if (!hw_device_ctx) {
>> -        ret = qsv_device_init(ist);
>> -        if (ret < 0)
>> -            return ret;
>> -    }
>> -
>> -    av_buffer_unref(&ist->hw_frames_ctx);
>> -    ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
>> -    if (!ist->hw_frames_ctx)
>> -        return AVERROR(ENOMEM);
>> -
>> -    frames_ctx   = (AVHWFramesContext*)ist->hw_frames_ctx->data;
>> -    frames_hwctx = frames_ctx->hwctx;
>> -
>> -    frames_ctx->width             = FFALIGN(s->coded_width,  32);
>> -    frames_ctx->height            = FFALIGN(s->coded_height, 32);
>> -    frames_ctx->format            = AV_PIX_FMT_QSV;
>> -    frames_ctx->sw_format         = s->sw_pix_fmt;
>> -    frames_ctx->initial_pool_size = 64 + s->extra_hw_frames;
>> -    frames_hwctx->frame_type      =
>> MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
>> -
>> -    ret = av_hwframe_ctx_init(ist->hw_frames_ctx);
>> -    if (ret < 0) {
>> -        av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV frame
>> pool\n");
>> -        return ret;
>> -    }
>> -
>> -    ist->hwaccel_get_buffer = qsv_get_buffer;
>> -    ist->hwaccel_uninit     = qsv_uninit;
>> -
>> -    return 0;
>> -}
>> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
>> index 19a6a776db..8bce9f2cf0 100644
>> --- a/libavcodec/qsvdec.c
>> +++ b/libavcodec/qsvdec.c
>> @@ -99,7 +99,7 @@ static const AVCodecHWConfigInternal *const
>> qsv_hw_configs[] = {
>>           .public = {
>>               .pix_fmt     = AV_PIX_FMT_QSV,
>>               .methods     = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX |
>> -                           AV_CODEC_HW_CONFIG_METHOD_AD_HOC,
>> +                           AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
>>               .device_type = AV_HWDEVICE_TYPE_QSV,
>>           },
>>           .hwaccel = NULL,
>> @@ -248,6 +248,35 @@ static int qsv_decode_preinit(AVCodecContext
>> *avctx, QSVContext *q, enum AVPixel
>>           q->nb_ext_buffers = user_ctx->nb_ext_buffers;
>>       }
>>
>> +    if (avctx->hw_device_ctx && !avctx->hw_frames_ctx && ret ==
>> AV_PIX_FMT_QSV) {
>> +        AVHWFramesContext *hwframes_ctx;
>> +        AVQSVFramesContext *frames_hwctx;
>> +
>> +        avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx-
>>> hw_device_ctx);
>> +
>> +        if (!avctx->hw_frames_ctx) {
>> +            av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_alloc
>> failed\n");
>> +            return AVERROR(ENOMEM);
>> +        }
>> +
>> +        hwframes_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx-
>>> data;
>> +        frames_hwctx = hwframes_ctx->hwctx;
>> +        hwframes_ctx->width             = FFALIGN(avctx-
>>> coded_width,  32);
>> +        hwframes_ctx->height            = FFALIGN(avctx-
>>> coded_height, 32);
>> +        hwframes_ctx->format            = AV_PIX_FMT_QSV;
>> +        hwframes_ctx->sw_format         = avctx->sw_pix_fmt;
>> +        hwframes_ctx->initial_pool_size = 64 + avctx-
>>> extra_hw_frames;
>> +        frames_hwctx->frame_type        =
>> MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
>> +
>> +        ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
>> +
>> +        if (ret < 0) {
>> +            av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV
>> frame pool\n");
>> +            av_buffer_unref(&avctx->hw_frames_ctx);
>> +            return ret;
>> +        }
>> +    }
>> +
>>       if (avctx->hw_frames_ctx) {
>>           AVHWFramesContext    *frames_ctx =
>> (AVHWFramesContext*)avctx->hw_frames_ctx->data;
>>           AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
>> --
> 
> LGTM.
> 
> Thanks,
> softworkz

Pushed.
diff mbox series

Patch

diff --git a/fftools/Makefile b/fftools/Makefile
index 5affaa3f56..5234932ab0 100644
--- a/fftools/Makefile
+++ b/fftools/Makefile
@@ -10,7 +10,6 @@  ALLAVPROGS   = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
 ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
 
 OBJS-ffmpeg                        += fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o
-OBJS-ffmpeg-$(CONFIG_LIBMFX)       += fftools/ffmpeg_qsv.o
 ifndef CONFIG_VIDEOTOOLBOX
 OBJS-ffmpeg-$(CONFIG_VDA)          += fftools/ffmpeg_videotoolbox.o
 endif
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index d9c0628657..d2dd7ca092 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -61,7 +61,6 @@  enum HWAccelID {
     HWACCEL_AUTO,
     HWACCEL_GENERIC,
     HWACCEL_VIDEOTOOLBOX,
-    HWACCEL_QSV,
 };
 
 typedef struct HWAccel {
diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c
index fc4a5d31d6..6923c4c5a1 100644
--- a/fftools/ffmpeg_hw.c
+++ b/fftools/ffmpeg_hw.c
@@ -339,6 +339,18 @@  int hw_device_setup_for_decode(InputStream *ist)
         } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
             type = ist->hwaccel_device_type;
             dev = hw_device_get_by_type(type);
+
+            // When "-qsv_device device" is used, an internal QSV device named
+            // as "__qsv_device" is created. Another QSV device is created too
+            // if "-init_hw_device qsv=name:device" is used. There are 2 QSV devices
+            // if both "-qsv_device device" and "-init_hw_device qsv=name:device"
+            // are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV) returns NULL.
+            // To keep back-compatibility with the removed ad-hoc libmfx setup code,
+            // call hw_device_get_by_name("__qsv_device") to select the internal QSV
+            // device.
+            if (!dev && type == AV_HWDEVICE_TYPE_QSV)
+                dev = hw_device_get_by_name("__qsv_device");
+
             if (!dev)
                 err = hw_device_init_from_type(type, NULL, &dev);
         } else {
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 34cc6c4fd3..428934a3d8 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -137,9 +137,6 @@  static const char *const opt_name_enc_time_bases[]            = {"enc_time_base"
 const HWAccel hwaccels[] = {
 #if CONFIG_VIDEOTOOLBOX
     { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
-#endif
-#if CONFIG_LIBMFX
-    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV },
 #endif
     { 0 },
 };
@@ -571,6 +568,23 @@  static int opt_vaapi_device(void *optctx, const char *opt, const char *arg)
 }
 #endif
 
+#if CONFIG_QSV
+static int opt_qsv_device(void *optctx, const char *opt, const char *arg)
+{
+    const char *prefix = "qsv=__qsv_device:hw_any,child_device=";
+    int err;
+    char *tmp = av_asprintf("%s%s", prefix, arg);
+
+    if (!tmp)
+        return AVERROR(ENOMEM);
+
+    err = hw_device_init_from_string(tmp, NULL);
+    av_free(tmp);
+
+    return err;
+}
+#endif
+
 static int opt_init_hw_device(void *optctx, const char *opt, const char *arg)
 {
     if (!strcmp(arg, "list")) {
@@ -898,6 +912,12 @@  static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
                     "with old commandlines. This behaviour is DEPRECATED and will be removed "
                     "in the future. Please explicitly set \"-hwaccel_output_format cuda\".\n");
                 ist->hwaccel_output_format = AV_PIX_FMT_CUDA;
+            } else if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "qsv")) {
+                av_log(NULL, AV_LOG_WARNING,
+                    "WARNING: defaulting hwaccel_output_format to qsv for compatibility "
+                    "with old commandlines. This behaviour is DEPRECATED and will be removed "
+                    "in the future. Please explicitly set \"-hwaccel_output_format qsv\".\n");
+                ist->hwaccel_output_format = AV_PIX_FMT_QSV;
             } else if (hwaccel_output_format) {
                 ist->hwaccel_output_format = av_get_pix_fmt(hwaccel_output_format);
                 if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) {
@@ -3848,7 +3868,7 @@  const OptionDef options[] = {
 #endif
 
 #if CONFIG_QSV
-    { "qsv_device", HAS_ARG | OPT_STRING | OPT_EXPERT, { &qsv_device },
+    { "qsv_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_qsv_device },
         "set QSV hardware device (DirectX adapter index, DRM path or X11 display name)", "device"},
 #endif
 
diff --git a/fftools/ffmpeg_qsv.c b/fftools/ffmpeg_qsv.c
deleted file mode 100644
index 7bd999d310..0000000000
--- a/fftools/ffmpeg_qsv.c
+++ /dev/null
@@ -1,109 +0,0 @@ 
-/*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <mfx/mfxvideo.h>
-#include <stdlib.h>
-
-#include "libavutil/dict.h"
-#include "libavutil/hwcontext.h"
-#include "libavutil/hwcontext_qsv.h"
-#include "libavutil/opt.h"
-#include "libavcodec/qsv.h"
-
-#include "ffmpeg.h"
-
-static AVBufferRef *hw_device_ctx;
-char *qsv_device = NULL;
-
-static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
-{
-    InputStream *ist = s->opaque;
-
-    return av_hwframe_get_buffer(ist->hw_frames_ctx, frame, 0);
-}
-
-static void qsv_uninit(AVCodecContext *s)
-{
-    InputStream *ist = s->opaque;
-    av_buffer_unref(&ist->hw_frames_ctx);
-}
-
-static int qsv_device_init(InputStream *ist)
-{
-    int err;
-    AVDictionary *dict = NULL;
-
-    if (qsv_device) {
-        err = av_dict_set(&dict, "child_device", qsv_device, 0);
-        if (err < 0)
-            return err;
-    }
-
-    err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV,
-                                 ist->hwaccel_device, dict, 0);
-    if (err < 0) {
-        av_log(NULL, AV_LOG_ERROR, "Error creating a QSV device\n");
-        goto err_out;
-    }
-
-err_out:
-    if (dict)
-        av_dict_free(&dict);
-
-    return err;
-}
-
-int qsv_init(AVCodecContext *s)
-{
-    InputStream *ist = s->opaque;
-    AVHWFramesContext *frames_ctx;
-    AVQSVFramesContext *frames_hwctx;
-    int ret;
-
-    if (!hw_device_ctx) {
-        ret = qsv_device_init(ist);
-        if (ret < 0)
-            return ret;
-    }
-
-    av_buffer_unref(&ist->hw_frames_ctx);
-    ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
-    if (!ist->hw_frames_ctx)
-        return AVERROR(ENOMEM);
-
-    frames_ctx   = (AVHWFramesContext*)ist->hw_frames_ctx->data;
-    frames_hwctx = frames_ctx->hwctx;
-
-    frames_ctx->width             = FFALIGN(s->coded_width,  32);
-    frames_ctx->height            = FFALIGN(s->coded_height, 32);
-    frames_ctx->format            = AV_PIX_FMT_QSV;
-    frames_ctx->sw_format         = s->sw_pix_fmt;
-    frames_ctx->initial_pool_size = 64 + s->extra_hw_frames;
-    frames_hwctx->frame_type      = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
-
-    ret = av_hwframe_ctx_init(ist->hw_frames_ctx);
-    if (ret < 0) {
-        av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV frame pool\n");
-        return ret;
-    }
-
-    ist->hwaccel_get_buffer = qsv_get_buffer;
-    ist->hwaccel_uninit     = qsv_uninit;
-
-    return 0;
-}
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index 19a6a776db..8bce9f2cf0 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -99,7 +99,7 @@  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
         .public = {
             .pix_fmt     = AV_PIX_FMT_QSV,
             .methods     = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX |
-                           AV_CODEC_HW_CONFIG_METHOD_AD_HOC,
+                           AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
             .device_type = AV_HWDEVICE_TYPE_QSV,
         },
         .hwaccel = NULL,
@@ -248,6 +248,35 @@  static int qsv_decode_preinit(AVCodecContext *avctx, QSVContext *q, enum AVPixel
         q->nb_ext_buffers = user_ctx->nb_ext_buffers;
     }
 
+    if (avctx->hw_device_ctx && !avctx->hw_frames_ctx && ret == AV_PIX_FMT_QSV) {
+        AVHWFramesContext *hwframes_ctx;
+        AVQSVFramesContext *frames_hwctx;
+
+        avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
+
+        if (!avctx->hw_frames_ctx) {
+            av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n");
+            return AVERROR(ENOMEM);
+        }
+
+        hwframes_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
+        frames_hwctx = hwframes_ctx->hwctx;
+        hwframes_ctx->width             = FFALIGN(avctx->coded_width,  32);
+        hwframes_ctx->height            = FFALIGN(avctx->coded_height, 32);
+        hwframes_ctx->format            = AV_PIX_FMT_QSV;
+        hwframes_ctx->sw_format         = avctx->sw_pix_fmt;
+        hwframes_ctx->initial_pool_size = 64 + avctx->extra_hw_frames;
+        frames_hwctx->frame_type        = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
+
+        ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
+
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_ERROR, "Error initializing a QSV frame pool\n");
+            av_buffer_unref(&avctx->hw_frames_ctx);
+            return ret;
+        }
+    }
+
     if (avctx->hw_frames_ctx) {
         AVHWFramesContext    *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
         AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;