From 41d47ea85fb4ad9cfb5c2dc808a46bc1d57f3986 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 16 Jun 2015 18:22:11 +0200 Subject: [PATCH] lavc: add Intel libmfx-based HEVC decoder. --- Changelog | 1 + configure | 3 + libavcodec/Makefile | 3 +- libavcodec/allcodecs.c | 2 + libavcodec/qsvdec.c | 3 +- libavcodec/qsvdec.h | 2 + libavcodec/{qsvdec_h264.c => qsvdec_h2645.c} | 93 ++++++++++++++++++++++++---- libavcodec/version.h | 4 +- 8 files changed, 95 insertions(+), 16 deletions(-) rename libavcodec/{qsvdec_h264.c => qsvdec_h2645.c} (64%) diff --git a/Changelog b/Changelog index 99e23d686e..26efbf3965 100644 --- a/Changelog +++ b/Changelog @@ -40,6 +40,7 @@ version : - Go2Meeting decoding support - Intel QSV-accelerated MPEG-2 video and HEVC encoding - bitstream filter for converting HEVC from MP4 to Annex B +- Intel QSV-accelerated MPEG-2 video and HEVC decoding version 11: diff --git a/configure b/configure index 575fdf74b5..973edb46d4 100755 --- a/configure +++ b/configure @@ -1881,6 +1881,8 @@ hap_encoder_select="texturedspenc" hevc_decoder_select="bswapdsp cabac golomb videodsp" hevc_nvenc_encoder_deps="nvenc" 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" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp" @@ -2045,6 +2047,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" mpeg1_vdpau_hwaccel_deps="vdpau" mpeg1_vdpau_hwaccel_select="mpeg1video_decoder" mpeg2_d3d11va_hwaccel_deps="d3d11va" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 6493d76db6..40f653b53b 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -241,7 +241,7 @@ 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_NVENC_ENCODER) += nvenc_h264.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 OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o @@ -249,6 +249,7 @@ 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_NVENC_ENCODER) += nvenc_hevc.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 fdd8b56596..69790d6c77 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(MPEG1_VDPAU, mpeg1_vdpau); REGISTER_HWACCEL(MPEG2_D3D11VA, mpeg2_d3d11va); REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2); @@ -173,6 +174,7 @@ void avcodec_register_all(void) REGISTER_DECODER(H264_QSV, h264_qsv); 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 5263bf5971..8c324f42c9 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -53,7 +53,8 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses { if (!session) { if (!q->internal_session) { - int ret = ff_qsv_init_internal_session(avctx, &q->internal_session, NULL); + int ret = ff_qsv_init_internal_session(avctx, &q->internal_session, + q->load_plugins); if (ret < 0) return ret; } diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index d5f2bce254..5627f06e13 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 64% rename from libavcodec/qsvdec_h264.c rename to libavcodec/qsvdec_h2645.c index a9f48e8b43..99bce94639 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 @@ -37,10 +37,17 @@ #include "qsvdec.h" #include "qsv.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; @@ -49,9 +56,9 @@ typedef struct QSVH264Context { AVPacket input_ref; AVPacket pkt_filtered; uint8_t *filtered_data; -} QSVH264Context; +} QSVH2645Context; -static void qsv_clear_buffers(QSVH264Context *s) +static void qsv_clear_buffers(QSVH2645Context *s) { AVPacket pkt; while (av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { @@ -67,7 +74,7 @@ static void qsv_clear_buffers(QSVH264Context *s) 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); @@ -82,9 +89,23 @@ 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; + 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); + } + } s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); if (!s->packet_fifo) { @@ -92,7 +113,10 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx) goto fail; } - s->bsf = av_bitstream_filter_init("h264_mp4toannexb"); + 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; @@ -109,7 +133,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; @@ -171,12 +195,58 @@ 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; 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 + +#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, @@ -184,8 +254,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 }, @@ -201,7 +269,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, @@ -211,3 +279,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 892ff6b327..eaa108436a 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 56 -#define LIBAVCODEC_VERSION_MINOR 33 -#define LIBAVCODEC_VERSION_MICRO 1 +#define LIBAVCODEC_VERSION_MINOR 34 +#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ -- 2.11.0