[FFmpeg-devel] [PATCH v3 1/2] qsvdec: add support for HW_DEVICE_CTX method
James Almer
jamrial at gmail.com
Wed Aug 11 19:54:09 EEST 2021
On 8/11/2021 1:29 PM, Soft Works wrote:
>
>
>> -----Original Message-----
>> From: ffmpeg-devel <ffmpeg-devel-bounces at ffmpeg.org> On Behalf Of
>> Haihao Xiang
>> Sent: Wednesday, 11 August 2021 08:02
>> To: ffmpeg-devel at ffmpeg.org
>> Cc: Haihao Xiang <haihao.xiang at 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 at 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.
More information about the ffmpeg-devel
mailing list