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 |
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 |
> -----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
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 --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;