Message ID | 20201126102026.27202-3-guangxin.xu@intel.com |
---|---|
State | Superseded |
Headers | show |
Series | [FFmpeg-devel,1/5] avcodec/qsvdec_other: refact, use DEFINE_QSV_DECODER to remove duplicate code | expand |
Context | Check | Description |
---|---|---|
andriy/x86_make | success | Make finished |
andriy/x86_make_fate | success | Make fate finished |
On Thu, 2020-11-26 at 18:20 +0800, Xu Guangxin wrote: > --- > libavcodec/Makefile | 8 +- > libavcodec/qsvdec.c | 215 ++++++++++++++++++++++++++++++++- > libavcodec/qsvdec_h2645.c | 248 -------------------------------------- > 3 files changed, 217 insertions(+), 254 deletions(-) > delete mode 100644 libavcodec/qsvdec_h2645.c > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index a6435c9e85..3ee8aa7f86 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -374,7 +374,7 @@ OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o > OBJS-$(CONFIG_NVENC_ENCODER) += nvenc_h264.o > OBJS-$(CONFIG_NVENC_H264_ENCODER) += nvenc_h264.o > OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o > -OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o > +OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o > OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o > OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o > OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o > @@ -394,7 +394,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o > OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o > OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o > OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o > -OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o > +OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o > OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ > hevc_data.o > OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o > @@ -922,14 +922,14 @@ OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += > videotoolbox.o > OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o > OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o > OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o > -OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec_h2645.o > +OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec.o > OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o > OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o > OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o > OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o > OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o > OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o > -OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec_h2645.o > +OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec.o > OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o > h265_profile_level.o > OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o > h265_profile_level.o > OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o > diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c > index c666aaeb52..0a79d00eac 100644 > --- a/libavcodec/qsvdec.c > +++ b/libavcodec/qsvdec.c > @@ -31,6 +31,7 @@ > #include "libavutil/hwcontext_qsv.h" > #include "libavutil/mem.h" > #include "libavutil/log.h" > +#include "libavutil/opt.h" > #include "libavutil/pixdesc.h" > #include "libavutil/pixfmt.h" > #include "libavutil/time.h" > @@ -228,7 +229,7 @@ static int qsv_decode_preinit(AVCodecContext *avctx, > QSVContext *q, enum AVPixel > return 0; > } > > -static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, > mfxVideoParam *param) > +static int qsv_decode_init_context(AVCodecContext *avctx, QSVContext *q, > mfxVideoParam *param) > { > int ret; > > @@ -615,7 +616,7 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext > *q, > } > > if (!q->initialized) { > - ret = qsv_decode_init(avctx, q, ¶m); > + ret = qsv_decode_init_context(avctx, q, ¶m); > if (ret < 0) > goto reinit_fail; > q->initialized = 1; > @@ -633,3 +634,213 @@ void ff_qsv_decode_flush(AVCodecContext *avctx, > QSVContext *q) > q->orig_pix_fmt = AV_PIX_FMT_NONE; > q->initialized = 0; > } > + > +enum LoadPlugin { > + LOAD_PLUGIN_NONE, > + LOAD_PLUGIN_HEVC_SW, > + LOAD_PLUGIN_HEVC_HW, > +}; > + > +typedef struct QSVDecContext { > + AVClass *class; > + QSVContext qsv; > + > + int load_plugin; > + > + AVFifoBuffer *packet_fifo; > + > + AVPacket buffer_pkt; > +} QSVDecContext; > + > +static void qsv_clear_buffers(QSVDecContext *s) > +{ > + AVPacket pkt; > + while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { > + av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); > + av_packet_unref(&pkt); > + } > + > + av_packet_unref(&s->buffer_pkt); > +} > + > +static av_cold int qsv_decode_close(AVCodecContext *avctx) > +{ > + QSVDecContext *s = avctx->priv_data; > + av_strdup() is called for s->qsv.load_plugins, so need to call av_freep() to free s->qsv.load_plugins. av_freep(&s->qsv.load_plugins); > + ff_qsv_decode_close(&s->qsv); > + > + qsv_clear_buffers(s); > + > + av_fifo_free(s->packet_fifo); > + > + return 0; > +} > + > +static av_cold int qsv_decode_init(AVCodecContext *avctx) > +{ > + QSVDecContext *s = avctx->priv_data; > + int ret; > + > + if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != > LOAD_PLUGIN_NONE) { > + static const char * const uid_hevcdec_sw = > "15dd936825ad475ea34e35f3f54217a6"; > + static const char * const uid_hevcdec_hw = > "33a61c0b4c27454ca8d85dde757c6f8e"; > + > + if (s->qsv.load_plugins[0]) { > + av_log(avctx, AV_LOG_WARNING, > + "load_plugins is not empty, but load_plugin is not set to > 'none'." > + "The load_plugin value will be ignored.\n"); > + } else { > + av_freep(&s->qsv.load_plugins); > + > + if (s->load_plugin == LOAD_PLUGIN_HEVC_SW) > + s->qsv.load_plugins = av_strdup(uid_hevcdec_sw); > + else > + s->qsv.load_plugins = av_strdup(uid_hevcdec_hw); > + if (!s->qsv.load_plugins) > + return AVERROR(ENOMEM); > + } > + } > + > + s->qsv.orig_pix_fmt = AV_PIX_FMT_NV12; > + s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); > + if (!s->packet_fifo) { > + ret = AVERROR(ENOMEM); > + goto fail; > + } > + > + return 0; > +fail: > + qsv_decode_close(avctx); > + return ret; > +} > + > +static int qsv_decode_frame(AVCodecContext *avctx, void *data, > + int *got_frame, AVPacket *avpkt) > +{ > + QSVDecContext *s = avctx->priv_data; > + AVFrame *frame = data; > + int ret; > + > + /* buffer the input packet */ > + if (avpkt->size) { > + AVPacket input_ref; > + > + if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { > + ret = av_fifo_realloc2(s->packet_fifo, > + av_fifo_size(s->packet_fifo) + > sizeof(input_ref)); > + if (ret < 0) > + return ret; > + } > + > + ret = av_packet_ref(&input_ref, avpkt); > + if (ret < 0) > + return ret; > + av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), > NULL); > + } > + > + /* process buffered data */ > + while (!*got_frame) { > + /* prepare the input data */ > + if (s->buffer_pkt.size <= 0) { > + /* no more data */ > + if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) > + return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, > &s->qsv, frame, got_frame, avpkt); > + /* in progress of reinit, no read from fifo and keep the > buffer_pkt */ > + if (!s->qsv.reinit_flag) { > + av_packet_unref(&s->buffer_pkt); > + av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, > sizeof(s->buffer_pkt), NULL); > + } > + } > + > + ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s- > >buffer_pkt); > + if (ret < 0){ > + /* Drop buffer_pkt when failed to decode the packet. Otherwise, > + the decoder will keep decoding the failure packet. */ > + av_packet_unref(&s->buffer_pkt); > + return ret; > + } > + if (s->qsv.reinit_flag) > + continue; > + > + s->buffer_pkt.size -= ret; > + s->buffer_pkt.data += ret; > + } > + > + return avpkt->size; > +} > + > +static void qsv_decode_flush(AVCodecContext *avctx) > +{ > + QSVDecContext *s = avctx->priv_data; > + > + qsv_clear_buffers(s); > + ff_qsv_decode_flush(avctx, &s->qsv); > +} > + > +#define OFFSET(x) offsetof(QSVDecContext, x) > +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM > + > +#define DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, opt) \ > +static const AVClass x##_qsv_class = { \ > + .class_name = #x "_qsv", \ > + .item_name = av_default_item_name, \ > + .option = opt, \ > + .version = LIBAVUTIL_VERSION_INT, \ > +}; \ > +AVCodec ff_##x##_qsv_decoder = { \ > + .name = #x "_qsv", \ > + .long_name = NULL_IF_CONFIG_SMALL(#X " video (Intel Quick Sync Video > acceleration)"), \ > + .priv_data_size = sizeof(QSVDecContext), \ > + .type = AVMEDIA_TYPE_VIDEO, \ > + .id = AV_CODEC_ID_##X, \ > + .init = qsv_decode_init, \ > + .decode = qsv_decode_frame, \ > + .flush = qsv_decode_flush, \ > + .close = qsv_decode_close, \ > + .bsfs = bsf_name, \ > + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | > AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, \ > + .priv_class = &x##_qsv_class, \ > + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ > + AV_PIX_FMT_P010, \ > + AV_PIX_FMT_QSV, \ > + AV_PIX_FMT_NONE }, \ > + .hw_configs = ff_qsv_hw_configs, \ > + .wrapper_name = "qsv", \ > +}; \ > + > +#define DEFINE_QSV_DECODER(x, X, bsf_name) DEFINE_QSV_DECODER_WITH_OPTION(x, > X, bsf_name, options) > + > +#if CONFIG_HEVC_QSV_DECODER > +static const AVOption hevc_options[] = { > + { "async_depth", "Internal parallelization depth, the higher the value > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > + > + { "load_plugin", "A user plugin to load in an internal session", > OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, > LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, > + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE > }, 0, 0, VD, "load_plugin" }, > + { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, > 0, 0, VD, "load_plugin" }, > + { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, > 0, 0, VD, "load_plugin" }, > + > + { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load > in an internal session", > + OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD > }, > + > + { "gpu_copy", "A GPU-accelerated copy between video and system memory", > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT > }, 0, 0, VD, "gpu_copy"}, > + { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > }, 0, 0, VD, "gpu_copy"}, > + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF > }, 0, 0, VD, "gpu_copy"}, > + { NULL }, > +}; > +DEFINE_QSV_DECODER_WITH_OPTION(hevc, HEVC, "hevc_mp4toannexb", hevc_options) > +#endif > + > +static const AVOption options[] = { > + { "async_depth", "Internal parallelization depth, the higher the value > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > + > + { "gpu_copy", "A GPU-accelerated copy between video and system memory", > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT > }, 0, 0, VD, "gpu_copy"}, > + { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > }, 0, 0, VD, "gpu_copy"}, > + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF > }, 0, 0, VD, "gpu_copy"}, > + { NULL }, > +}; > + > +#if CONFIG_H264_QSV_DECODER > +DEFINE_QSV_DECODER(h264, H264, "h264_mp4toannexb") > +#endif > diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c > deleted file mode 100644 > index b0ab23a922..0000000000 > --- a/libavcodec/qsvdec_h2645.c > +++ /dev/null > @@ -1,248 +0,0 @@ > -/* > - * Intel MediaSDK QSV based H.264 / HEVC decoder > - * > - * copyright (c) 2013 Luca Barbato > - * copyright (c) 2015 Anton Khirnov > - * > - * 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 <stdint.h> > -#include <string.h> > - > -#include <mfx/mfxvideo.h> > - > -#include "libavutil/common.h" > -#include "libavutil/fifo.h" > -#include "libavutil/opt.h" > - > -#include "avcodec.h" > -#include "internal.h" > -#include "qsv_internal.h" > -#include "qsvdec.h" > -#include "qsv.h" > - > -enum LoadPlugin { > - LOAD_PLUGIN_NONE, > - LOAD_PLUGIN_HEVC_SW, > - LOAD_PLUGIN_HEVC_HW, > -}; > - > -typedef struct QSVH2645Context { > - AVClass *class; > - QSVContext qsv; > - > - int load_plugin; > - > - AVFifoBuffer *packet_fifo; > - > - AVPacket buffer_pkt; > -} QSVH2645Context; > - > -static void qsv_clear_buffers(QSVH2645Context *s) > -{ > - AVPacket pkt; > - while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { > - av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); > - av_packet_unref(&pkt); > - } > - > - av_packet_unref(&s->buffer_pkt); > -} > - > -static av_cold int qsv_decode_close(AVCodecContext *avctx) > -{ > - QSVH2645Context *s = avctx->priv_data; > - > - ff_qsv_decode_close(&s->qsv); > - > - qsv_clear_buffers(s); > - > - av_fifo_free(s->packet_fifo); > - > - return 0; > -} > - > -static av_cold int qsv_decode_init(AVCodecContext *avctx) > -{ > - QSVH2645Context *s = avctx->priv_data; > - int ret; > - > - if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != > LOAD_PLUGIN_NONE) { > - static const char * const uid_hevcdec_sw = > "15dd936825ad475ea34e35f3f54217a6"; > - static const char * const uid_hevcdec_hw = > "33a61c0b4c27454ca8d85dde757c6f8e"; > - > - if (s->qsv.load_plugins[0]) { > - av_log(avctx, AV_LOG_WARNING, > - "load_plugins is not empty, but load_plugin is not set to > 'none'." > - "The load_plugin value will be ignored.\n"); > - } else { > - av_freep(&s->qsv.load_plugins); > - > - if (s->load_plugin == LOAD_PLUGIN_HEVC_SW) > - s->qsv.load_plugins = av_strdup(uid_hevcdec_sw); > - else > - s->qsv.load_plugins = av_strdup(uid_hevcdec_hw); > - if (!s->qsv.load_plugins) > - return AVERROR(ENOMEM); > - } > - } > - > - s->qsv.orig_pix_fmt = AV_PIX_FMT_NV12; > - s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); > - if (!s->packet_fifo) { > - ret = AVERROR(ENOMEM); > - goto fail; > - } > - > - return 0; > -fail: > - qsv_decode_close(avctx); > - return ret; > -} > - > -static int qsv_decode_frame(AVCodecContext *avctx, void *data, > - int *got_frame, AVPacket *avpkt) > -{ > - QSVH2645Context *s = avctx->priv_data; > - AVFrame *frame = data; > - int ret; > - > - /* buffer the input packet */ > - if (avpkt->size) { > - AVPacket input_ref; > - > - if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { > - ret = av_fifo_realloc2(s->packet_fifo, > - av_fifo_size(s->packet_fifo) + > sizeof(input_ref)); > - if (ret < 0) > - return ret; > - } > - > - ret = av_packet_ref(&input_ref, avpkt); > - if (ret < 0) > - return ret; > - av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), > NULL); > - } > - > - /* process buffered data */ > - while (!*got_frame) { > - /* prepare the input data */ > - if (s->buffer_pkt.size <= 0) { > - /* no more data */ > - if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) > - return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, > &s->qsv, frame, got_frame, avpkt); > - /* in progress of reinit, no read from fifo and keep the > buffer_pkt */ > - if (!s->qsv.reinit_flag) { > - av_packet_unref(&s->buffer_pkt); > - av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, > sizeof(s->buffer_pkt), NULL); > - } > - } > - > - ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s- > >buffer_pkt); > - if (ret < 0){ > - /* Drop buffer_pkt when failed to decode the packet. Otherwise, > - the decoder will keep decoding the failure packet. */ > - av_packet_unref(&s->buffer_pkt); > - return ret; > - } > - if (s->qsv.reinit_flag) > - continue; > - > - s->buffer_pkt.size -= ret; > - s->buffer_pkt.data += ret; > - } > - > - return avpkt->size; > -} > - > -static void qsv_decode_flush(AVCodecContext *avctx) > -{ > - QSVH2645Context *s = avctx->priv_data; > - > - qsv_clear_buffers(s); > - ff_qsv_decode_flush(avctx, &s->qsv); > -} > - > -#define OFFSET(x) offsetof(QSVH2645Context, x) > -#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM > - > -#define DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, opt) \ > -static const AVClass x##_qsv_class = { \ > - .class_name = #x "_qsv", \ > - .item_name = av_default_item_name, \ > - .option = opt, \ > - .version = LIBAVUTIL_VERSION_INT, \ > -}; \ > -AVCodec ff_##x##_qsv_decoder = { \ > - .name = #x "_qsv", \ > - .long_name = NULL_IF_CONFIG_SMALL(#X " video (Intel Quick Sync Video > acceleration)"), \ > - .priv_data_size = sizeof(QSVH2645Context), \ > - .type = AVMEDIA_TYPE_VIDEO, \ > - .id = AV_CODEC_ID_##X, \ > - .init = qsv_decode_init, \ > - .decode = qsv_decode_frame, \ > - .flush = qsv_decode_flush, \ > - .close = qsv_decode_close, \ > - .bsfs = bsf_name, \ > - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | > AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, \ > - .priv_class = &x##_qsv_class, \ > - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ > - AV_PIX_FMT_P010, \ > - AV_PIX_FMT_QSV, \ > - AV_PIX_FMT_NONE }, \ > - .hw_configs = ff_qsv_hw_configs, \ > - .wrapper_name = "qsv", \ > -}; \ > - > -#define DEFINE_QSV_DECODER(x, X, bsf_name) DEFINE_QSV_DECODER_WITH_OPTION(x, > X, bsf_name, options) > - > -#if CONFIG_HEVC_QSV_DECODER > -static const AVOption hevc_options[] = { > - { "async_depth", "Internal parallelization depth, the higher the value > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > - > - { "load_plugin", "A user plugin to load in an internal session", > OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, > LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, > - { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE > }, 0, 0, VD, "load_plugin" }, > - { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, > 0, 0, VD, "load_plugin" }, > - { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, > 0, 0, VD, "load_plugin" }, > - > - { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load > in an internal session", > - OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD > }, > - > - { "gpu_copy", "A GPU-accelerated copy between video and system memory", > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > - { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT > }, 0, 0, VD, "gpu_copy"}, > - { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > }, 0, 0, VD, "gpu_copy"}, > - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF > }, 0, 0, VD, "gpu_copy"}, > - { NULL }, > -}; > -DEFINE_QSV_DECODER_WITH_OPTION(hevc, HEVC, "hevc_mp4toannexb", hevc_options) > -#endif > - > -static const AVOption options[] = { > - { "async_depth", "Internal parallelization depth, the higher the value > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > - > - { "gpu_copy", "A GPU-accelerated copy between video and system memory", > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > - { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT > }, 0, 0, VD, "gpu_copy"}, > - { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > }, 0, 0, VD, "gpu_copy"}, > - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF > }, 0, 0, VD, "gpu_copy"}, > - { NULL }, > -}; > - > -#if CONFIG_H264_QSV_DECODER > -DEFINE_QSV_DECODER(h264, H264, "h264_mp4toannexb") > -#endif
Hi Haihao, Thanks for the review. This patch just moves all code from qsvdec_h2645.c to qsvdec.c. The original code in qsvdec_h2645.c did not free the point, so the code will not free it. The av_freep(&s->qsv.load_plugins); will addressed by https://patchwork.ffmpeg.org/project/ffmpeg/patch/20201126102026.27202-4-guangxin.xu@intel.com/ Your finding is a good example, tell us why we need to remove duplicate codes. :) thanks On Wed, Dec 2, 2020 at 12:50 PM Xiang, Haihao <haihao.xiang@intel.com> wrote: > On Thu, 2020-11-26 at 18:20 +0800, Xu Guangxin wrote: > > --- > > libavcodec/Makefile | 8 +- > > libavcodec/qsvdec.c | 215 ++++++++++++++++++++++++++++++++- > > libavcodec/qsvdec_h2645.c | 248 -------------------------------------- > > 3 files changed, 217 insertions(+), 254 deletions(-) > > delete mode 100644 libavcodec/qsvdec_h2645.c > > > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > > index a6435c9e85..3ee8aa7f86 100644 > > --- a/libavcodec/Makefile > > +++ b/libavcodec/Makefile > > @@ -374,7 +374,7 @@ OBJS-$(CONFIG_H264_NVENC_ENCODER) += > nvenc_h264.o > > OBJS-$(CONFIG_NVENC_ENCODER) += nvenc_h264.o > > OBJS-$(CONFIG_NVENC_H264_ENCODER) += nvenc_h264.o > > OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o > > -OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o > > +OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o > > OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o > > OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o > > OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o > h264_levels.o > > @@ -394,7 +394,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += > mediacodecdec.o > > OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o > > OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o > > OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o > > -OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o > > +OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o > > OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o > \ > > hevc_data.o > > OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o > > @@ -922,14 +922,14 @@ OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += > > videotoolbox.o > > OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o > > OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o > > OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o > > -OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec_h2645.o > > +OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec.o > > OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o > > OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o > > OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o > > OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o > > OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o > > OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o > > -OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec_h2645.o > > +OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec.o > > OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o > > h265_profile_level.o > > OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o > > h265_profile_level.o > > OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o > > diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c > > index c666aaeb52..0a79d00eac 100644 > > --- a/libavcodec/qsvdec.c > > +++ b/libavcodec/qsvdec.c > > @@ -31,6 +31,7 @@ > > #include "libavutil/hwcontext_qsv.h" > > #include "libavutil/mem.h" > > #include "libavutil/log.h" > > +#include "libavutil/opt.h" > > #include "libavutil/pixdesc.h" > > #include "libavutil/pixfmt.h" > > #include "libavutil/time.h" > > @@ -228,7 +229,7 @@ static int qsv_decode_preinit(AVCodecContext *avctx, > > QSVContext *q, enum AVPixel > > return 0; > > } > > > > -static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, > > mfxVideoParam *param) > > +static int qsv_decode_init_context(AVCodecContext *avctx, QSVContext *q, > > mfxVideoParam *param) > > { > > int ret; > > > > @@ -615,7 +616,7 @@ int ff_qsv_process_data(AVCodecContext *avctx, > QSVContext > > *q, > > } > > > > if (!q->initialized) { > > - ret = qsv_decode_init(avctx, q, ¶m); > > + ret = qsv_decode_init_context(avctx, q, ¶m); > > if (ret < 0) > > goto reinit_fail; > > q->initialized = 1; > > @@ -633,3 +634,213 @@ void ff_qsv_decode_flush(AVCodecContext *avctx, > > QSVContext *q) > > q->orig_pix_fmt = AV_PIX_FMT_NONE; > > q->initialized = 0; > > } > > + > > +enum LoadPlugin { > > + LOAD_PLUGIN_NONE, > > + LOAD_PLUGIN_HEVC_SW, > > + LOAD_PLUGIN_HEVC_HW, > > +}; > > + > > +typedef struct QSVDecContext { > > + AVClass *class; > > + QSVContext qsv; > > + > > + int load_plugin; > > + > > + AVFifoBuffer *packet_fifo; > > + > > + AVPacket buffer_pkt; > > +} QSVDecContext; > > + > > +static void qsv_clear_buffers(QSVDecContext *s) > > +{ > > + AVPacket pkt; > > + while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { > > + av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); > > + av_packet_unref(&pkt); > > + } > > + > > + av_packet_unref(&s->buffer_pkt); > > +} > > + > > +static av_cold int qsv_decode_close(AVCodecContext *avctx) > > +{ > > + QSVDecContext *s = avctx->priv_data; > > + > > av_strdup() is called for s->qsv.load_plugins, so need to call av_freep() > to > free s->qsv.load_plugins. > > av_freep(&s->qsv.load_plugins); > > > + ff_qsv_decode_close(&s->qsv); > > + > > + qsv_clear_buffers(s); > > + > > + av_fifo_free(s->packet_fifo); > > + > > + return 0; > > +} > > + > > +static av_cold int qsv_decode_init(AVCodecContext *avctx) > > +{ > > + QSVDecContext *s = avctx->priv_data; > > + int ret; > > + > > + if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != > > LOAD_PLUGIN_NONE) { > > + static const char * const uid_hevcdec_sw = > > "15dd936825ad475ea34e35f3f54217a6"; > > + static const char * const uid_hevcdec_hw = > > "33a61c0b4c27454ca8d85dde757c6f8e"; > > + > > + if (s->qsv.load_plugins[0]) { > > + av_log(avctx, AV_LOG_WARNING, > > + "load_plugins is not empty, but load_plugin is not > set to > > 'none'." > > + "The load_plugin value will be ignored.\n"); > > + } else { > > + av_freep(&s->qsv.load_plugins); > > + > > + if (s->load_plugin == LOAD_PLUGIN_HEVC_SW) > > + s->qsv.load_plugins = av_strdup(uid_hevcdec_sw); > > + else > > + s->qsv.load_plugins = av_strdup(uid_hevcdec_hw); > > + if (!s->qsv.load_plugins) > > + return AVERROR(ENOMEM); > > + } > > + } > > + > > + s->qsv.orig_pix_fmt = AV_PIX_FMT_NV12; > > + s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); > > + if (!s->packet_fifo) { > > + ret = AVERROR(ENOMEM); > > + goto fail; > > + } > > + > > + return 0; > > +fail: > > + qsv_decode_close(avctx); > > + return ret; > > +} > > + > > +static int qsv_decode_frame(AVCodecContext *avctx, void *data, > > + int *got_frame, AVPacket *avpkt) > > +{ > > + QSVDecContext *s = avctx->priv_data; > > + AVFrame *frame = data; > > + int ret; > > + > > + /* buffer the input packet */ > > + if (avpkt->size) { > > + AVPacket input_ref; > > + > > + if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { > > + ret = av_fifo_realloc2(s->packet_fifo, > > + av_fifo_size(s->packet_fifo) + > > sizeof(input_ref)); > > + if (ret < 0) > > + return ret; > > + } > > + > > + ret = av_packet_ref(&input_ref, avpkt); > > + if (ret < 0) > > + return ret; > > + av_fifo_generic_write(s->packet_fifo, &input_ref, > sizeof(input_ref), > > NULL); > > + } > > + > > + /* process buffered data */ > > + while (!*got_frame) { > > + /* prepare the input data */ > > + if (s->buffer_pkt.size <= 0) { > > + /* no more data */ > > + if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) > > + return avpkt->size ? avpkt->size : > ff_qsv_process_data(avctx, > > &s->qsv, frame, got_frame, avpkt); > > + /* in progress of reinit, no read from fifo and keep the > > buffer_pkt */ > > + if (!s->qsv.reinit_flag) { > > + av_packet_unref(&s->buffer_pkt); > > + av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, > > sizeof(s->buffer_pkt), NULL); > > + } > > + } > > + > > + ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s- > > >buffer_pkt); > > + if (ret < 0){ > > + /* Drop buffer_pkt when failed to decode the packet. > Otherwise, > > + the decoder will keep decoding the failure packet. */ > > + av_packet_unref(&s->buffer_pkt); > > + return ret; > > + } > > + if (s->qsv.reinit_flag) > > + continue; > > + > > + s->buffer_pkt.size -= ret; > > + s->buffer_pkt.data += ret; > > + } > > + > > + return avpkt->size; > > +} > > + > > +static void qsv_decode_flush(AVCodecContext *avctx) > > +{ > > + QSVDecContext *s = avctx->priv_data; > > + > > + qsv_clear_buffers(s); > > + ff_qsv_decode_flush(avctx, &s->qsv); > > +} > > + > > +#define OFFSET(x) offsetof(QSVDecContext, x) > > +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM > > + > > +#define DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, opt) \ > > +static const AVClass x##_qsv_class = { \ > > + .class_name = #x "_qsv", \ > > + .item_name = av_default_item_name, \ > > + .option = opt, \ > > + .version = LIBAVUTIL_VERSION_INT, \ > > +}; \ > > +AVCodec ff_##x##_qsv_decoder = { \ > > + .name = #x "_qsv", \ > > + .long_name = NULL_IF_CONFIG_SMALL(#X " video (Intel Quick Sync > Video > > acceleration)"), \ > > + .priv_data_size = sizeof(QSVDecContext), \ > > + .type = AVMEDIA_TYPE_VIDEO, \ > > + .id = AV_CODEC_ID_##X, \ > > + .init = qsv_decode_init, \ > > + .decode = qsv_decode_frame, \ > > + .flush = qsv_decode_flush, \ > > + .close = qsv_decode_close, \ > > + .bsfs = bsf_name, \ > > + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | > > AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, \ > > + .priv_class = &x##_qsv_class, \ > > + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ > > + AV_PIX_FMT_P010, \ > > + AV_PIX_FMT_QSV, \ > > + AV_PIX_FMT_NONE }, \ > > + .hw_configs = ff_qsv_hw_configs, \ > > + .wrapper_name = "qsv", \ > > +}; \ > > + > > +#define DEFINE_QSV_DECODER(x, X, bsf_name) > DEFINE_QSV_DECODER_WITH_OPTION(x, > > X, bsf_name, options) > > + > > +#if CONFIG_HEVC_QSV_DECODER > > +static const AVOption hevc_options[] = { > > + { "async_depth", "Internal parallelization depth, the higher the > value > > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { > .i64 = > > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > > + > > + { "load_plugin", "A user plugin to load in an internal session", > > OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, > > LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, > > + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE > > }, 0, 0, VD, "load_plugin" }, > > + { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > LOAD_PLUGIN_HEVC_SW }, > > 0, 0, VD, "load_plugin" }, > > + { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > LOAD_PLUGIN_HEVC_HW }, > > 0, 0, VD, "load_plugin" }, > > + > > + { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to > load > > in an internal session", > > + OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, > 0, VD > > }, > > + > > + { "gpu_copy", "A GPU-accelerated copy between video and system > memory", > > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > > + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_DEFAULT > > }, 0, 0, VD, "gpu_copy"}, > > + { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > > }, 0, 0, VD, "gpu_copy"}, > > + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_OFF > > }, 0, 0, VD, "gpu_copy"}, > > + { NULL }, > > +}; > > +DEFINE_QSV_DECODER_WITH_OPTION(hevc, HEVC, "hevc_mp4toannexb", > hevc_options) > > +#endif > > + > > +static const AVOption options[] = { > > + { "async_depth", "Internal parallelization depth, the higher the > value > > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { > .i64 = > > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > > + > > + { "gpu_copy", "A GPU-accelerated copy between video and system > memory", > > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > > + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_DEFAULT > > }, 0, 0, VD, "gpu_copy"}, > > + { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > > }, 0, 0, VD, "gpu_copy"}, > > + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_OFF > > }, 0, 0, VD, "gpu_copy"}, > > + { NULL }, > > +}; > > + > > +#if CONFIG_H264_QSV_DECODER > > +DEFINE_QSV_DECODER(h264, H264, "h264_mp4toannexb") > > +#endif > > diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c > > deleted file mode 100644 > > index b0ab23a922..0000000000 > > --- a/libavcodec/qsvdec_h2645.c > > +++ /dev/null > > @@ -1,248 +0,0 @@ > > -/* > > - * Intel MediaSDK QSV based H.264 / HEVC decoder > > - * > > - * copyright (c) 2013 Luca Barbato > > - * copyright (c) 2015 Anton Khirnov > > - * > > - * 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 <stdint.h> > > -#include <string.h> > > - > > -#include <mfx/mfxvideo.h> > > - > > -#include "libavutil/common.h" > > -#include "libavutil/fifo.h" > > -#include "libavutil/opt.h" > > - > > -#include "avcodec.h" > > -#include "internal.h" > > -#include "qsv_internal.h" > > -#include "qsvdec.h" > > -#include "qsv.h" > > - > > -enum LoadPlugin { > > - LOAD_PLUGIN_NONE, > > - LOAD_PLUGIN_HEVC_SW, > > - LOAD_PLUGIN_HEVC_HW, > > -}; > > - > > -typedef struct QSVH2645Context { > > - AVClass *class; > > - QSVContext qsv; > > - > > - int load_plugin; > > - > > - AVFifoBuffer *packet_fifo; > > - > > - AVPacket buffer_pkt; > > -} QSVH2645Context; > > - > > -static void qsv_clear_buffers(QSVH2645Context *s) > > -{ > > - AVPacket pkt; > > - while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { > > - av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); > > - av_packet_unref(&pkt); > > - } > > - > > - av_packet_unref(&s->buffer_pkt); > > -} > > - > > -static av_cold int qsv_decode_close(AVCodecContext *avctx) > > -{ > > - QSVH2645Context *s = avctx->priv_data; > > - > > - ff_qsv_decode_close(&s->qsv); > > - > > - qsv_clear_buffers(s); > > - > > - av_fifo_free(s->packet_fifo); > > - > > - return 0; > > -} > > - > > -static av_cold int qsv_decode_init(AVCodecContext *avctx) > > -{ > > - QSVH2645Context *s = avctx->priv_data; > > - int ret; > > - > > - if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != > > LOAD_PLUGIN_NONE) { > > - static const char * const uid_hevcdec_sw = > > "15dd936825ad475ea34e35f3f54217a6"; > > - static const char * const uid_hevcdec_hw = > > "33a61c0b4c27454ca8d85dde757c6f8e"; > > - > > - if (s->qsv.load_plugins[0]) { > > - av_log(avctx, AV_LOG_WARNING, > > - "load_plugins is not empty, but load_plugin is not > set to > > 'none'." > > - "The load_plugin value will be ignored.\n"); > > - } else { > > - av_freep(&s->qsv.load_plugins); > > - > > - if (s->load_plugin == LOAD_PLUGIN_HEVC_SW) > > - s->qsv.load_plugins = av_strdup(uid_hevcdec_sw); > > - else > > - s->qsv.load_plugins = av_strdup(uid_hevcdec_hw); > > - if (!s->qsv.load_plugins) > > - return AVERROR(ENOMEM); > > - } > > - } > > - > > - s->qsv.orig_pix_fmt = AV_PIX_FMT_NV12; > > - s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); > > - if (!s->packet_fifo) { > > - ret = AVERROR(ENOMEM); > > - goto fail; > > - } > > - > > - return 0; > > -fail: > > - qsv_decode_close(avctx); > > - return ret; > > -} > > - > > -static int qsv_decode_frame(AVCodecContext *avctx, void *data, > > - int *got_frame, AVPacket *avpkt) > > -{ > > - QSVH2645Context *s = avctx->priv_data; > > - AVFrame *frame = data; > > - int ret; > > - > > - /* buffer the input packet */ > > - if (avpkt->size) { > > - AVPacket input_ref; > > - > > - if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { > > - ret = av_fifo_realloc2(s->packet_fifo, > > - av_fifo_size(s->packet_fifo) + > > sizeof(input_ref)); > > - if (ret < 0) > > - return ret; > > - } > > - > > - ret = av_packet_ref(&input_ref, avpkt); > > - if (ret < 0) > > - return ret; > > - av_fifo_generic_write(s->packet_fifo, &input_ref, > sizeof(input_ref), > > NULL); > > - } > > - > > - /* process buffered data */ > > - while (!*got_frame) { > > - /* prepare the input data */ > > - if (s->buffer_pkt.size <= 0) { > > - /* no more data */ > > - if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) > > - return avpkt->size ? avpkt->size : > ff_qsv_process_data(avctx, > > &s->qsv, frame, got_frame, avpkt); > > - /* in progress of reinit, no read from fifo and keep the > > buffer_pkt */ > > - if (!s->qsv.reinit_flag) { > > - av_packet_unref(&s->buffer_pkt); > > - av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, > > sizeof(s->buffer_pkt), NULL); > > - } > > - } > > - > > - ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s- > > >buffer_pkt); > > - if (ret < 0){ > > - /* Drop buffer_pkt when failed to decode the packet. > Otherwise, > > - the decoder will keep decoding the failure packet. */ > > - av_packet_unref(&s->buffer_pkt); > > - return ret; > > - } > > - if (s->qsv.reinit_flag) > > - continue; > > - > > - s->buffer_pkt.size -= ret; > > - s->buffer_pkt.data += ret; > > - } > > - > > - return avpkt->size; > > -} > > - > > -static void qsv_decode_flush(AVCodecContext *avctx) > > -{ > > - QSVH2645Context *s = avctx->priv_data; > > - > > - qsv_clear_buffers(s); > > - ff_qsv_decode_flush(avctx, &s->qsv); > > -} > > - > > -#define OFFSET(x) offsetof(QSVH2645Context, x) > > -#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM > > - > > -#define DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, opt) \ > > -static const AVClass x##_qsv_class = { \ > > - .class_name = #x "_qsv", \ > > - .item_name = av_default_item_name, \ > > - .option = opt, \ > > - .version = LIBAVUTIL_VERSION_INT, \ > > -}; \ > > -AVCodec ff_##x##_qsv_decoder = { \ > > - .name = #x "_qsv", \ > > - .long_name = NULL_IF_CONFIG_SMALL(#X " video (Intel Quick Sync > Video > > acceleration)"), \ > > - .priv_data_size = sizeof(QSVH2645Context), \ > > - .type = AVMEDIA_TYPE_VIDEO, \ > > - .id = AV_CODEC_ID_##X, \ > > - .init = qsv_decode_init, \ > > - .decode = qsv_decode_frame, \ > > - .flush = qsv_decode_flush, \ > > - .close = qsv_decode_close, \ > > - .bsfs = bsf_name, \ > > - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | > > AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, \ > > - .priv_class = &x##_qsv_class, \ > > - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ > > - AV_PIX_FMT_P010, \ > > - AV_PIX_FMT_QSV, \ > > - AV_PIX_FMT_NONE }, \ > > - .hw_configs = ff_qsv_hw_configs, \ > > - .wrapper_name = "qsv", \ > > -}; \ > > - > > -#define DEFINE_QSV_DECODER(x, X, bsf_name) > DEFINE_QSV_DECODER_WITH_OPTION(x, > > X, bsf_name, options) > > - > > -#if CONFIG_HEVC_QSV_DECODER > > -static const AVOption hevc_options[] = { > > - { "async_depth", "Internal parallelization depth, the higher the > value > > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { > .i64 = > > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > > - > > - { "load_plugin", "A user plugin to load in an internal session", > > OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, > > LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, > > - { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE > > }, 0, 0, VD, "load_plugin" }, > > - { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > LOAD_PLUGIN_HEVC_SW }, > > 0, 0, VD, "load_plugin" }, > > - { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > LOAD_PLUGIN_HEVC_HW }, > > 0, 0, VD, "load_plugin" }, > > - > > - { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to > load > > in an internal session", > > - OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, > 0, VD > > }, > > - > > - { "gpu_copy", "A GPU-accelerated copy between video and system > memory", > > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > > - { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_DEFAULT > > }, 0, 0, VD, "gpu_copy"}, > > - { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > > }, 0, 0, VD, "gpu_copy"}, > > - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_OFF > > }, 0, 0, VD, "gpu_copy"}, > > - { NULL }, > > -}; > > -DEFINE_QSV_DECODER_WITH_OPTION(hevc, HEVC, "hevc_mp4toannexb", > hevc_options) > > -#endif > > - > > -static const AVOption options[] = { > > - { "async_depth", "Internal parallelization depth, the higher the > value > > the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { > .i64 = > > ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, > > - > > - { "gpu_copy", "A GPU-accelerated copy between video and system > memory", > > OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, > > MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, > > - { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_DEFAULT > > }, 0, 0, VD, "gpu_copy"}, > > - { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON > > }, 0, 0, VD, "gpu_copy"}, > > - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = > MFX_GPUCOPY_OFF > > }, 0, 0, VD, "gpu_copy"}, > > - { NULL }, > > -}; > > - > > -#if CONFIG_H264_QSV_DECODER > > -DEFINE_QSV_DECODER(h264, H264, "h264_mp4toannexb") > > -#endif > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index a6435c9e85..3ee8aa7f86 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -374,7 +374,7 @@ OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_NVENC_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_NVENC_H264_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o -OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o +OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o @@ -394,7 +394,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o -OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o +OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ hevc_data.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o @@ -922,14 +922,14 @@ OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o -OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec_h2645.o +OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec.o OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o -OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec_h2645.o +OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec.o OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o h265_profile_level.o OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o h265_profile_level.o OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index c666aaeb52..0a79d00eac 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -31,6 +31,7 @@ #include "libavutil/hwcontext_qsv.h" #include "libavutil/mem.h" #include "libavutil/log.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" #include "libavutil/time.h" @@ -228,7 +229,7 @@ static int qsv_decode_preinit(AVCodecContext *avctx, QSVContext *q, enum AVPixel return 0; } -static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, mfxVideoParam *param) +static int qsv_decode_init_context(AVCodecContext *avctx, QSVContext *q, mfxVideoParam *param) { int ret; @@ -615,7 +616,7 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, } if (!q->initialized) { - ret = qsv_decode_init(avctx, q, ¶m); + ret = qsv_decode_init_context(avctx, q, ¶m); if (ret < 0) goto reinit_fail; q->initialized = 1; @@ -633,3 +634,213 @@ void ff_qsv_decode_flush(AVCodecContext *avctx, QSVContext *q) q->orig_pix_fmt = AV_PIX_FMT_NONE; q->initialized = 0; } + +enum LoadPlugin { + LOAD_PLUGIN_NONE, + LOAD_PLUGIN_HEVC_SW, + LOAD_PLUGIN_HEVC_HW, +}; + +typedef struct QSVDecContext { + AVClass *class; + QSVContext qsv; + + int load_plugin; + + AVFifoBuffer *packet_fifo; + + AVPacket buffer_pkt; +} QSVDecContext; + +static void qsv_clear_buffers(QSVDecContext *s) +{ + AVPacket pkt; + while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { + av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); + av_packet_unref(&pkt); + } + + av_packet_unref(&s->buffer_pkt); +} + +static av_cold int qsv_decode_close(AVCodecContext *avctx) +{ + QSVDecContext *s = avctx->priv_data; + + ff_qsv_decode_close(&s->qsv); + + qsv_clear_buffers(s); + + av_fifo_free(s->packet_fifo); + + return 0; +} + +static av_cold int qsv_decode_init(AVCodecContext *avctx) +{ + QSVDecContext *s = avctx->priv_data; + int ret; + + if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != LOAD_PLUGIN_NONE) { + static const char * const uid_hevcdec_sw = "15dd936825ad475ea34e35f3f54217a6"; + static const char * const uid_hevcdec_hw = "33a61c0b4c27454ca8d85dde757c6f8e"; + + if (s->qsv.load_plugins[0]) { + av_log(avctx, AV_LOG_WARNING, + "load_plugins is not empty, but load_plugin is not set to 'none'." + "The load_plugin value will be ignored.\n"); + } else { + av_freep(&s->qsv.load_plugins); + + if (s->load_plugin == LOAD_PLUGIN_HEVC_SW) + s->qsv.load_plugins = av_strdup(uid_hevcdec_sw); + else + s->qsv.load_plugins = av_strdup(uid_hevcdec_hw); + if (!s->qsv.load_plugins) + return AVERROR(ENOMEM); + } + } + + s->qsv.orig_pix_fmt = AV_PIX_FMT_NV12; + s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); + if (!s->packet_fifo) { + ret = AVERROR(ENOMEM); + goto fail; + } + + return 0; +fail: + qsv_decode_close(avctx); + return ret; +} + +static int qsv_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + QSVDecContext *s = avctx->priv_data; + AVFrame *frame = data; + int ret; + + /* buffer the input packet */ + if (avpkt->size) { + AVPacket input_ref; + + if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { + ret = av_fifo_realloc2(s->packet_fifo, + av_fifo_size(s->packet_fifo) + sizeof(input_ref)); + if (ret < 0) + return ret; + } + + ret = av_packet_ref(&input_ref, avpkt); + if (ret < 0) + return ret; + av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL); + } + + /* process buffered data */ + while (!*got_frame) { + /* prepare the input data */ + if (s->buffer_pkt.size <= 0) { + /* no more data */ + if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) + return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt); + /* in progress of reinit, no read from fifo and keep the buffer_pkt */ + if (!s->qsv.reinit_flag) { + av_packet_unref(&s->buffer_pkt); + av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, sizeof(s->buffer_pkt), NULL); + } + } + + ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->buffer_pkt); + if (ret < 0){ + /* Drop buffer_pkt when failed to decode the packet. Otherwise, + the decoder will keep decoding the failure packet. */ + av_packet_unref(&s->buffer_pkt); + return ret; + } + if (s->qsv.reinit_flag) + continue; + + s->buffer_pkt.size -= ret; + s->buffer_pkt.data += ret; + } + + return avpkt->size; +} + +static void qsv_decode_flush(AVCodecContext *avctx) +{ + QSVDecContext *s = avctx->priv_data; + + qsv_clear_buffers(s); + ff_qsv_decode_flush(avctx, &s->qsv); +} + +#define OFFSET(x) offsetof(QSVDecContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM + +#define DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, opt) \ +static const AVClass x##_qsv_class = { \ + .class_name = #x "_qsv", \ + .item_name = av_default_item_name, \ + .option = opt, \ + .version = LIBAVUTIL_VERSION_INT, \ +}; \ +AVCodec ff_##x##_qsv_decoder = { \ + .name = #x "_qsv", \ + .long_name = NULL_IF_CONFIG_SMALL(#X " video (Intel Quick Sync Video acceleration)"), \ + .priv_data_size = sizeof(QSVDecContext), \ + .type = AVMEDIA_TYPE_VIDEO, \ + .id = AV_CODEC_ID_##X, \ + .init = qsv_decode_init, \ + .decode = qsv_decode_frame, \ + .flush = qsv_decode_flush, \ + .close = qsv_decode_close, \ + .bsfs = bsf_name, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, \ + .priv_class = &x##_qsv_class, \ + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ + AV_PIX_FMT_P010, \ + AV_PIX_FMT_QSV, \ + AV_PIX_FMT_NONE }, \ + .hw_configs = ff_qsv_hw_configs, \ + .wrapper_name = "qsv", \ +}; \ + +#define DEFINE_QSV_DECODER(x, X, bsf_name) DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, options) + +#if CONFIG_HEVC_QSV_DECODER +static const AVOption hevc_options[] = { + { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, + + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VD, "load_plugin" }, + { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VD, "load_plugin" }, + { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VD, "load_plugin" }, + + { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load in an internal session", + OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD }, + + { "gpu_copy", "A GPU-accelerated copy between video and system memory", OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT }, 0, 0, VD, "gpu_copy"}, + { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON }, 0, 0, VD, "gpu_copy"}, + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF }, 0, 0, VD, "gpu_copy"}, + { NULL }, +}; +DEFINE_QSV_DECODER_WITH_OPTION(hevc, HEVC, "hevc_mp4toannexb", hevc_options) +#endif + +static const AVOption options[] = { + { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, + + { "gpu_copy", "A GPU-accelerated copy between video and system memory", OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, + { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT }, 0, 0, VD, "gpu_copy"}, + { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON }, 0, 0, VD, "gpu_copy"}, + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF }, 0, 0, VD, "gpu_copy"}, + { NULL }, +}; + +#if CONFIG_H264_QSV_DECODER +DEFINE_QSV_DECODER(h264, H264, "h264_mp4toannexb") +#endif diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c deleted file mode 100644 index b0ab23a922..0000000000 --- a/libavcodec/qsvdec_h2645.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Intel MediaSDK QSV based H.264 / HEVC decoder - * - * copyright (c) 2013 Luca Barbato - * copyright (c) 2015 Anton Khirnov - * - * 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 <stdint.h> -#include <string.h> - -#include <mfx/mfxvideo.h> - -#include "libavutil/common.h" -#include "libavutil/fifo.h" -#include "libavutil/opt.h" - -#include "avcodec.h" -#include "internal.h" -#include "qsv_internal.h" -#include "qsvdec.h" -#include "qsv.h" - -enum LoadPlugin { - LOAD_PLUGIN_NONE, - LOAD_PLUGIN_HEVC_SW, - LOAD_PLUGIN_HEVC_HW, -}; - -typedef struct QSVH2645Context { - AVClass *class; - QSVContext qsv; - - int load_plugin; - - AVFifoBuffer *packet_fifo; - - AVPacket buffer_pkt; -} QSVH2645Context; - -static void qsv_clear_buffers(QSVH2645Context *s) -{ - AVPacket pkt; - while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { - av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); - av_packet_unref(&pkt); - } - - av_packet_unref(&s->buffer_pkt); -} - -static av_cold int qsv_decode_close(AVCodecContext *avctx) -{ - QSVH2645Context *s = avctx->priv_data; - - ff_qsv_decode_close(&s->qsv); - - qsv_clear_buffers(s); - - av_fifo_free(s->packet_fifo); - - return 0; -} - -static av_cold int qsv_decode_init(AVCodecContext *avctx) -{ - QSVH2645Context *s = avctx->priv_data; - int ret; - - if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != LOAD_PLUGIN_NONE) { - static const char * const uid_hevcdec_sw = "15dd936825ad475ea34e35f3f54217a6"; - static const char * const uid_hevcdec_hw = "33a61c0b4c27454ca8d85dde757c6f8e"; - - if (s->qsv.load_plugins[0]) { - av_log(avctx, AV_LOG_WARNING, - "load_plugins is not empty, but load_plugin is not set to 'none'." - "The load_plugin value will be ignored.\n"); - } else { - av_freep(&s->qsv.load_plugins); - - if (s->load_plugin == LOAD_PLUGIN_HEVC_SW) - s->qsv.load_plugins = av_strdup(uid_hevcdec_sw); - else - s->qsv.load_plugins = av_strdup(uid_hevcdec_hw); - if (!s->qsv.load_plugins) - return AVERROR(ENOMEM); - } - } - - s->qsv.orig_pix_fmt = AV_PIX_FMT_NV12; - s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); - if (!s->packet_fifo) { - ret = AVERROR(ENOMEM); - goto fail; - } - - return 0; -fail: - qsv_decode_close(avctx); - return ret; -} - -static int qsv_decode_frame(AVCodecContext *avctx, void *data, - int *got_frame, AVPacket *avpkt) -{ - QSVH2645Context *s = avctx->priv_data; - AVFrame *frame = data; - int ret; - - /* buffer the input packet */ - if (avpkt->size) { - AVPacket input_ref; - - if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { - ret = av_fifo_realloc2(s->packet_fifo, - av_fifo_size(s->packet_fifo) + sizeof(input_ref)); - if (ret < 0) - return ret; - } - - ret = av_packet_ref(&input_ref, avpkt); - if (ret < 0) - return ret; - av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL); - } - - /* process buffered data */ - while (!*got_frame) { - /* prepare the input data */ - if (s->buffer_pkt.size <= 0) { - /* no more data */ - if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) - return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt); - /* in progress of reinit, no read from fifo and keep the buffer_pkt */ - if (!s->qsv.reinit_flag) { - av_packet_unref(&s->buffer_pkt); - av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, sizeof(s->buffer_pkt), NULL); - } - } - - ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->buffer_pkt); - if (ret < 0){ - /* Drop buffer_pkt when failed to decode the packet. Otherwise, - the decoder will keep decoding the failure packet. */ - av_packet_unref(&s->buffer_pkt); - return ret; - } - if (s->qsv.reinit_flag) - continue; - - s->buffer_pkt.size -= ret; - s->buffer_pkt.data += ret; - } - - return avpkt->size; -} - -static void qsv_decode_flush(AVCodecContext *avctx) -{ - QSVH2645Context *s = avctx->priv_data; - - qsv_clear_buffers(s); - ff_qsv_decode_flush(avctx, &s->qsv); -} - -#define OFFSET(x) offsetof(QSVH2645Context, x) -#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM - -#define DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, opt) \ -static const AVClass x##_qsv_class = { \ - .class_name = #x "_qsv", \ - .item_name = av_default_item_name, \ - .option = opt, \ - .version = LIBAVUTIL_VERSION_INT, \ -}; \ -AVCodec ff_##x##_qsv_decoder = { \ - .name = #x "_qsv", \ - .long_name = NULL_IF_CONFIG_SMALL(#X " video (Intel Quick Sync Video acceleration)"), \ - .priv_data_size = sizeof(QSVH2645Context), \ - .type = AVMEDIA_TYPE_VIDEO, \ - .id = AV_CODEC_ID_##X, \ - .init = qsv_decode_init, \ - .decode = qsv_decode_frame, \ - .flush = qsv_decode_flush, \ - .close = qsv_decode_close, \ - .bsfs = bsf_name, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, \ - .priv_class = &x##_qsv_class, \ - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ - AV_PIX_FMT_P010, \ - AV_PIX_FMT_QSV, \ - AV_PIX_FMT_NONE }, \ - .hw_configs = ff_qsv_hw_configs, \ - .wrapper_name = "qsv", \ -}; \ - -#define DEFINE_QSV_DECODER(x, X, bsf_name) DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, options) - -#if CONFIG_HEVC_QSV_DECODER -static const AVOption hevc_options[] = { - { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, - - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, - { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VD, "load_plugin" }, - { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VD, "load_plugin" }, - { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VD, "load_plugin" }, - - { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load in an internal session", - OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD }, - - { "gpu_copy", "A GPU-accelerated copy between video and system memory", OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, - { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT }, 0, 0, VD, "gpu_copy"}, - { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON }, 0, 0, VD, "gpu_copy"}, - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF }, 0, 0, VD, "gpu_copy"}, - { NULL }, -}; -DEFINE_QSV_DECODER_WITH_OPTION(hevc, HEVC, "hevc_mp4toannexb", hevc_options) -#endif - -static const AVOption options[] = { - { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, - - { "gpu_copy", "A GPU-accelerated copy between video and system memory", OFFSET(qsv.gpu_copy), AV_OPT_TYPE_INT, { .i64 = MFX_GPUCOPY_DEFAULT }, MFX_GPUCOPY_DEFAULT, MFX_GPUCOPY_OFF, VD, "gpu_copy"}, - { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_DEFAULT }, 0, 0, VD, "gpu_copy"}, - { "on", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_ON }, 0, 0, VD, "gpu_copy"}, - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_GPUCOPY_OFF }, 0, 0, VD, "gpu_copy"}, - { NULL }, -}; - -#if CONFIG_H264_QSV_DECODER -DEFINE_QSV_DECODER(h264, H264, "h264_mp4toannexb") -#endif