From 41d47ea85fb4ad9cfb5c2dc808a46bc1d57f3986 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 16 Jun 2015 18:22:11 +0200 Subject: 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 | 213 ---------------------------------- libavcodec/qsvdec_h2645.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 4 +- 9 files changed, 296 insertions(+), 217 deletions(-) delete mode 100644 libavcodec/qsvdec_h264.c create mode 100644 libavcodec/qsvdec_h2645.c 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_h264.c deleted file mode 100644 index a9f48e8b43..0000000000 --- a/libavcodec/qsvdec_h264.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Intel MediaSDK QSV based H.264 decoder - * - * copyright (c) 2013 Luca Barbato - * copyright (c) 2015 Anton Khirnov - * - * This file is part of Libav. - * - * Libav 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. - * - * Libav 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 Libav; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include -#include - -#include - -#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" - -typedef struct QSVH264Context { - AVClass *class; - QSVContext qsv; - - // the filter for converting to Annex B - AVBitStreamFilterContext *bsf; - - AVFifoBuffer *packet_fifo; - - AVPacket input_ref; - AVPacket pkt_filtered; - uint8_t *filtered_data; -} QSVH264Context; - -static void qsv_clear_buffers(QSVH264Context *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); - } - - if (s->filtered_data != s->input_ref.data) - av_freep(&s->filtered_data); - s->filtered_data = NULL; - av_packet_unref(&s->input_ref); -} - -static av_cold int qsv_decode_close(AVCodecContext *avctx) -{ - QSVH264Context *s = avctx->priv_data; - - ff_qsv_decode_close(&s->qsv); - - qsv_clear_buffers(s); - - av_fifo_free(s->packet_fifo); - - av_bitstream_filter_close(s->bsf); - - return 0; -} - -static av_cold int qsv_decode_init(AVCodecContext *avctx) -{ - QSVH264Context *s = avctx->priv_data; - int ret; - - - s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); - if (!s->packet_fifo) { - ret = AVERROR(ENOMEM); - goto fail; - } - - s->bsf = av_bitstream_filter_init("h264_mp4toannexb"); - if (!s->bsf) { - ret = AVERROR(ENOMEM); - goto fail; - } - - s->qsv.iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; - - return 0; -fail: - qsv_decode_close(avctx); - return ret; -} - -static int qsv_decode_frame(AVCodecContext *avctx, void *data, - int *got_frame, AVPacket *avpkt) -{ - QSVH264Context *s = avctx->priv_data; - AVFrame *frame = data; - int ret; - - /* buffer the input packet */ - if (avpkt->size) { - AVPacket input_ref = { 0 }; - - 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 -- convert to Annex B if needed */ - if (s->pkt_filtered.size <= 0) { - int size; - - /* 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); - - if (s->filtered_data != s->input_ref.data) - av_freep(&s->filtered_data); - s->filtered_data = NULL; - av_packet_unref(&s->input_ref); - - av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL); - ret = av_bitstream_filter_filter(s->bsf, avctx, NULL, - &s->filtered_data, &size, - s->input_ref.data, s->input_ref.size, 0); - if (ret < 0) { - s->filtered_data = s->input_ref.data; - size = s->input_ref.size; - } - s->pkt_filtered = s->input_ref; - s->pkt_filtered.data = s->filtered_data; - s->pkt_filtered.size = size; - } - - ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered); - if (ret < 0) - return ret; - - s->pkt_filtered.size -= ret; - s->pkt_filtered.data += ret; - } - - return avpkt->size; -} - -static void qsv_decode_flush(AVCodecContext *avctx) -{ - QSVH264Context *s = avctx->priv_data; - - qsv_clear_buffers(s); - ff_qsv_decode_flush(avctx, &s->qsv); -} - -AVHWAccel ff_h264_qsv_hwaccel = { - .name = "h264_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .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 }, -}; - -static const AVClass class = { - .class_name = "h264_qsv", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - -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), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .init = qsv_decode_init, - .decode = qsv_decode_frame, - .flush = qsv_decode_flush, - .close = qsv_decode_close, - .capabilities = CODEC_CAP_DELAY, - .priv_class = &class, -}; diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c new file mode 100644 index 0000000000..99bce94639 --- /dev/null +++ b/libavcodec/qsvdec_h2645.c @@ -0,0 +1,282 @@ +/* + * Intel MediaSDK QSV based H.264 / HEVC decoder + * + * copyright (c) 2013 Luca Barbato + * copyright (c) 2015 Anton Khirnov + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include +#include + +#include + +#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, +}; + +typedef struct QSVH2645Context { + AVClass *class; + QSVContext qsv; + + int load_plugin; + + // the filter for converting to Annex B + AVBitStreamFilterContext *bsf; + + AVFifoBuffer *packet_fifo; + + AVPacket input_ref; + AVPacket pkt_filtered; + uint8_t *filtered_data; +} 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); + } + + if (s->filtered_data != s->input_ref.data) + av_freep(&s->filtered_data); + s->filtered_data = NULL; + av_packet_unref(&s->input_ref); +} + +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); + + av_bitstream_filter_close(s->bsf); + + 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 *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) { + ret = AVERROR(ENOMEM); + goto fail; + } + + 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; + } + + s->qsv.iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + + 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 = { 0 }; + + 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 -- convert to Annex B if needed */ + if (s->pkt_filtered.size <= 0) { + int size; + + /* 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); + + if (s->filtered_data != s->input_ref.data) + av_freep(&s->filtered_data); + s->filtered_data = NULL; + av_packet_unref(&s->input_ref); + + av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL); + ret = av_bitstream_filter_filter(s->bsf, avctx, NULL, + &s->filtered_data, &size, + s->input_ref.data, s->input_ref.size, 0); + if (ret < 0) { + s->filtered_data = s->input_ref.data; + size = s->input_ref.size; + } + s->pkt_filtered = s->input_ref; + s->pkt_filtered.data = s->filtered_data; + s->pkt_filtered.size = size; + } + + ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->pkt_filtered); + if (ret < 0) + return ret; + + s->pkt_filtered.size -= ret; + s->pkt_filtered.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 + +#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, + .id = AV_CODEC_ID_H264, + .pix_fmt = AV_PIX_FMT_QSV, +}; + +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 }, +}; + +static const AVClass class = { + .class_name = "h264_qsv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +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(QSVH2645Context), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .init = qsv_decode_init, + .decode = qsv_decode_frame, + .flush = qsv_decode_flush, + .close = qsv_decode_close, + .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, \ -- cgit v1.2.3