diff --git a/Changelog b/Changelog index 6eedfb66ae..7865c8edc0 100644 --- a/Changelog +++ b/Changelog @@ -15,7 +15,7 @@ version : - adrawgraph audio and drawgraph video filter - removegrain video filter - Intel QSV-accelerated MPEG-2 video and HEVC encoding -- Intel QSV-accelerated MPEG-2 video decoding +- Intel QSV-accelerated MPEG-2 video and HEVC decoding - Intel QSV-accelerated VC-1 video decoding - libkvazaar HEVC encoder - erosion, dilation, deflate and inflate video filters diff --git a/configure b/configure index f4ee178350..bfed9e6769 100755 --- a/configure +++ b/configure @@ -2231,6 +2231,8 @@ hap_encoder_deps="libsnappy" hap_encoder_select="texturedspenc" hevc_decoder_select="bswapdsp cabac golomb videodsp" hevc_qsv_encoder_deps="libmfx" +hevc_qsv_decoder_deps="libmfx" +hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec hevc_qsv_hwaccel" hevc_qsv_encoder_select="qsvenc" huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llviddsp" @@ -2412,6 +2414,7 @@ hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" hevc_d3d11va_hwaccel_select="hevc_decoder" hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" hevc_dxva2_hwaccel_select="hevc_decoder" +hevc_qsv_hwaccel_deps="libmfx" hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC" hevc_vdpau_hwaccel_select="hevc_decoder" mpeg_vdpau_decoder_deps="vdpau" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index cbdf139713..7cf24031d3 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -289,13 +289,14 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o h264_cabac.o h264_cavlc.o \ h264_refs.o h264_sei.o h264_slice.o OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.o -OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h264.o +OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o OBJS-$(CONFIG_HAP_DECODER) += hapdec.o hap.o OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \ hevc_cabac.o hevc_refs.o hevcpred.o \ hevcdsp.o hevc_filter.o hevc_parse.o hevc_data.o +OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o hevc_parse.o OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d4831e400c..417f824041 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -86,6 +86,7 @@ void avcodec_register_all(void) REGISTER_HWACCEL(H264_VDPAU, h264_vdpau); REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va); REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2); + REGISTER_HWACCEL(HEVC_QSV, hevc_qsv); REGISTER_HWACCEL(HEVC_VDPAU, hevc_vdpau); REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc); REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau); @@ -187,6 +188,7 @@ void avcodec_register_all(void) REGISTER_DECODER(H264_VDPAU, h264_vdpau); REGISTER_ENCDEC (HAP, hap); REGISTER_DECODER(HEVC, hevc); + REGISTER_DECODER(HEVC_QSV, hevc_qsv); REGISTER_DECODER(HNM4_VIDEO, hnm4_video); REGISTER_DECODER(HQ_HQA, hq_hqa); REGISTER_DECODER(HQX, hqx); diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index 036015f751..d1261add2c 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -66,7 +66,8 @@ int ff_qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt) q->nb_ext_buffers = qsv->nb_ext_buffers; } if (!q->session) { - ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, NULL); + ret = ff_qsv_init_internal_session(avctx, &q->internal_qs, + q->load_plugins); if (ret < 0) return ret; diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index 2fadacbff8..c30627a4bd 100644 --- a/libavcodec/qsvdec.h +++ b/libavcodec/qsvdec.h @@ -59,6 +59,8 @@ typedef struct QSVContext { int async_depth; int iopattern; + char *load_plugins; + mfxExtBuffer **ext_buffers; int nb_ext_buffers; } QSVContext; diff --git a/libavcodec/qsvdec_h264.c b/libavcodec/qsvdec_h2645.c similarity index 57% rename from libavcodec/qsvdec_h264.c rename to libavcodec/qsvdec_h2645.c index 78356e3140..d231b4618c 100644 --- a/libavcodec/qsvdec_h264.c +++ b/libavcodec/qsvdec_h2645.c @@ -1,5 +1,5 @@ /* - * Intel MediaSDK QSV based H.264 decoder + * Intel MediaSDK QSV based H.264 / HEVC decoder * * copyright (c) 2013 Luca Barbato * copyright (c) 2015 Anton Khirnov @@ -35,18 +35,25 @@ #include "internal.h" #include "qsvdec.h" -typedef struct QSVH264Context { +enum LoadPlugin { + LOAD_PLUGIN_NONE, + LOAD_PLUGIN_HEVC_SW, +}; + +typedef struct QSVH2645Context { AVClass *class; QSVContext qsv; + int load_plugin; + // the filter for converting to Annex B AVBitStreamFilterContext *bsf; -} QSVH264Context; +} QSVH2645Context; static av_cold int qsv_decode_close(AVCodecContext *avctx) { - QSVH264Context *s = avctx->priv_data; + QSVH2645Context *s = avctx->priv_data; ff_qsv_decode_close(&s->qsv); @@ -57,10 +64,28 @@ static av_cold int qsv_decode_close(AVCodecContext *avctx) static av_cold int qsv_decode_init(AVCodecContext *avctx) { - QSVH264Context *s = avctx->priv_data; + QSVH2645Context *s = avctx->priv_data; int ret; - s->bsf = av_bitstream_filter_init("h264_mp4toannexb"); + if (avctx->codec_id == AV_CODEC_ID_HEVC && s->load_plugin != LOAD_PLUGIN_NONE) { + static const char *uid_hevcenc_sw = "15dd936825ad475ea34e35f3f54217a6"; + + 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); + s->qsv.load_plugins = av_strdup(uid_hevcenc_sw); + if (!s->qsv.load_plugins) + return AVERROR(ENOMEM); + } + } + + if (avctx->codec_id == AV_CODEC_ID_H264) + s->bsf = av_bitstream_filter_init("h264_mp4toannexb"); + else + s->bsf = av_bitstream_filter_init("hevc_mp4toannexb"); if (!s->bsf) { ret = AVERROR(ENOMEM); goto fail; @@ -75,7 +100,7 @@ fail: static int qsv_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { - QSVH264Context *s = avctx->priv_data; + QSVH2645Context *s = avctx->priv_data; AVFrame *frame = data; int ret; uint8_t *p_filtered = NULL; @@ -112,10 +137,56 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data, static void qsv_decode_flush(AVCodecContext *avctx) { -// QSVH264Context *s = avctx->priv_data; +// QSVH2645Context *s = avctx->priv_data; /* TODO: flush qsv engine if necessary */ } +#define OFFSET(x) offsetof(QSVH2645Context, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM + +#if CONFIG_HEVC_QSV_DECODER +AVHWAccel ff_hevc_qsv_hwaccel = { + .name = "hevc_qsv", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .pix_fmt = AV_PIX_FMT_QSV, +}; + +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 }, 0, 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_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_SW, 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" }, + + { "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 }, + { NULL }, +}; + +static const AVClass hevc_class = { + .class_name = "hevc_qsv", + .item_name = av_default_item_name, + .option = hevc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_hevc_qsv_decoder = { + .name = "hevc_qsv", + .long_name = NULL_IF_CONFIG_SMALL("HEVC (Intel Quick Sync Video acceleration)"), + .priv_data_size = sizeof(QSVH2645Context), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .init = qsv_decode_init, + .decode = qsv_decode_frame, + .flush = qsv_decode_flush, + .close = qsv_decode_close, + .capabilities = CODEC_CAP_DELAY, + .priv_class = &hevc_class, +}; +#endif + +#if CONFIG_H264_QSV_DECODER AVHWAccel ff_h264_qsv_hwaccel = { .name = "h264_qsv", .type = AVMEDIA_TYPE_VIDEO, @@ -123,8 +194,6 @@ AVHWAccel ff_h264_qsv_hwaccel = { .pix_fmt = AV_PIX_FMT_QSV, }; -#define OFFSET(x) offsetof(QSVH264Context, x) -#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM 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 }, 0, INT_MAX, VD }, { NULL }, @@ -140,7 +209,7 @@ static const AVClass class = { AVCodec ff_h264_qsv_decoder = { .name = "h264_qsv", .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration)"), - .priv_data_size = sizeof(QSVH264Context), + .priv_data_size = sizeof(QSVH2645Context), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .init = qsv_decode_init, @@ -150,3 +219,4 @@ AVCodec ff_h264_qsv_decoder = { .capabilities = CODEC_CAP_DELAY, .priv_class = &class, }; +#endif diff --git a/libavcodec/version.h b/libavcodec/version.h index 47786580a4..75061e47da 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 56 -#define LIBAVCODEC_VERSION_MINOR 54 +#define LIBAVCODEC_VERSION_MINOR 55 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \