This is heavily based on MPEG-2 encoder, of course. --- Changelog | 1 + doc/general.texi | 2 +- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/mpegutils.h | 1 + libavcodec/mpegvideo.h | 3 + libavcodec/mpegvideo_enc.c | 52 +++++- libavcodec/speedhqenc.c | 316 +++++++++++++++++++++++++++++++++++++ libavcodec/speedhqenc.h | 47 ++++++ libavcodec/version.h | 2 +- 10 files changed, 421 insertions(+), 5 deletions(-) create mode 100644 libavcodec/speedhqenc.c create mode 100644 libavcodec/speedhqenc.h
diff --git a/Changelog b/Changelog index 49fc260458..8f3dcbec87 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,7 @@ version <next>: - PGX decoder - chromanr video filter - VDPAU accelerated HEVC 10/12bit decoding +- SpeedHQ encoder version 4.3: diff --git a/doc/general.texi b/doc/general.texi index 53d556c56c..7ab1c61267 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -971,7 +971,7 @@ following image formats are supported: @item MPEG-4 part 2 Microsoft variant version 1 @tab @tab X @item MPEG-4 part 2 Microsoft variant version 2 @tab X @tab X @item MPEG-4 part 2 Microsoft variant version 3 @tab X @tab X -@item Newtek SpeedHQ @tab @tab X +@item Newtek SpeedHQ @tab X @tab X @item Nintendo Gamecube THP video @tab @tab X @item NotchLC @tab @tab X @item NuppelVideo/RTjpeg @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 18353da549..52445130f4 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -614,6 +614,7 @@ OBJS-$(CONFIG_SONIC_DECODER) += sonic.o OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o OBJS-$(CONFIG_SPEEDHQ_DECODER) += speedhq.o mpeg12.o mpeg12data.o simple_idct.o +OBJS-$(CONFIG_SPEEDHQ_ENCODER) += speedhq.o mpeg12data.o speedhqenc.o OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o OBJS-$(CONFIG_SRGC_DECODER) += mscc.o OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o htmlsubtitles.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index a5048290f7..b542910303 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -290,6 +290,7 @@ extern AVCodec ff_snow_encoder; extern AVCodec ff_snow_decoder; extern AVCodec ff_sp5x_decoder; extern AVCodec ff_speedhq_decoder; +extern AVCodec ff_speedhq_encoder; extern AVCodec ff_srgc_decoder; extern AVCodec ff_sunrast_encoder; extern AVCodec ff_sunrast_decoder; diff --git a/libavcodec/mpegutils.h b/libavcodec/mpegutils.h index 1ed21c19be..81f0b73bb1 100644 --- a/libavcodec/mpegutils.h +++ b/libavcodec/mpegutils.h @@ -125,6 +125,7 @@ enum OutputFormat { FMT_H261, FMT_H263, FMT_MJPEG, + FMT_SPEEDHQ, }; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 29e692f245..974c71b6bd 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -444,6 +444,9 @@ typedef struct MpegEncContext { int inter_intra_pred; int mspel; + /* SpeedHQ specific */ + int slice_start; + /* decompression specific */ GetBitContext gb; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index c3ef40556a..221079452c 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -51,6 +51,7 @@ #include "mathops.h" #include "mpegutils.h" #include "mjpegenc.h" +#include "speedhqenc.h" #include "msmpeg4.h" #include "pixblockdsp.h" #include "qpeldsp.h" @@ -326,6 +327,15 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } break; + case AV_CODEC_ID_SPEEDHQ: + if (avctx->pix_fmt != AV_PIX_FMT_YUV420P && + avctx->pix_fmt != AV_PIX_FMT_YUV422P && + avctx->pix_fmt != AV_PIX_FMT_YUV444P) { + av_log(avctx, AV_LOG_ERROR, + "only YUV420/YUV422/YUV444 are supported (no alpha support yet)\n"); + return AVERROR(EINVAL); + } + break; default: if (avctx->pix_fmt != AV_PIX_FMT_YUV420P) { av_log(avctx, AV_LOG_ERROR, "only YUV420 is supported\n"); @@ -732,7 +742,7 @@ FF_ENABLE_DEPRECATION_WARNINGS //return -1; } - if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO || s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG || s->codec_id==AV_CODEC_ID_AMV) { + if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO || s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG || s->codec_id==AV_CODEC_ID_AMV || s->codec_id == AV_CODEC_ID_SPEEDHQ) { // (a + x * 3 / 8) / x s->intra_quant_bias = 3 << (QUANT_BIAS_SHIFT - 3); s->inter_quant_bias = 0; @@ -783,6 +793,16 @@ FF_ENABLE_DEPRECATION_WARNINGS avctx->delay = 0; s->low_delay = 1; break; + case AV_CODEC_ID_SPEEDHQ: + s->out_format = FMT_SPEEDHQ; + s->intra_only = 1; /* force intra only for SHQ */ + if (!CONFIG_SPEEDHQ_ENCODER) + return AVERROR_ENCODER_NOT_FOUND; + if ((ret = ff_speedhq_encode_init(s)) < 0) + return ret; + avctx->delay = 0; + s->low_delay = 1; + break; case AV_CODEC_ID_H261: if (!CONFIG_H261_ENCODER) return AVERROR_ENCODER_NOT_FOUND; @@ -997,6 +1017,9 @@ FF_ENABLE_DEPRECATION_WARNINGS } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { s->intra_matrix[j] = s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i]; + } else if (CONFIG_SPEEDHQ_ENCODER && s->codec_id == AV_CODEC_ID_SPEEDHQ) { + s->intra_matrix[j] = + s->inter_matrix[j] = ff_mpeg1_default_intra_matrix[i]; } else { /* MPEG-1/2 */ s->chroma_intra_matrix[j] = @@ -2562,6 +2585,10 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, if (CONFIG_MJPEG_ENCODER) ff_mjpeg_encode_mb(s, s->block); break; + case AV_CODEC_ID_SPEEDHQ: + if (CONFIG_SPEEDHQ_ENCODER) + ff_speedhq_encode_mb(s, s->block); + break; default: av_assert1(0); } @@ -2816,6 +2843,8 @@ static void write_slice_end(MpegEncContext *s){ ff_mpeg4_stuffing(&s->pb); }else if(CONFIG_MJPEG_ENCODER && s->out_format == FMT_MJPEG){ ff_mjpeg_encode_stuffing(s); + }else if(CONFIG_SPEEDHQ_ENCODER && s->out_format == FMT_SPEEDHQ){ + ff_speedhq_end_slice(s); } avpriv_align_put_bits(&s->pb); @@ -2906,7 +2935,7 @@ int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t s static int encode_thread(AVCodecContext *c, void *arg){ MpegEncContext *s= *(void**)arg; - int mb_x, mb_y; + int mb_x, mb_y, mb_y_order; int chr_h= 16>>s->chroma_y_shift; int i, j; MpegEncContext best_s = { 0 }, backup_s; @@ -2967,7 +2996,16 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->resync_mb_y=0; s->first_slice_line = 1; s->ptr_lastgob = s->pb.buf; - for(mb_y= s->start_mb_y; mb_y < s->end_mb_y; mb_y++) { + for(mb_y_order= s->start_mb_y; mb_y_order < s->end_mb_y; mb_y_order++) { + if (s->codec_id == AV_CODEC_ID_SPEEDHQ) { + int first_in_slice; + mb_y = ff_speedhq_mb_y_order_to_mb(mb_y_order, s->mb_height, &first_in_slice); + if (first_in_slice && mb_y_order != s->start_mb_y) + ff_speedhq_end_slice(s); + s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 1024 << s->intra_dc_precision; + } else { + mb_y = mb_y_order; + } s->mb_x=0; s->mb_y= mb_y; @@ -3855,6 +3893,10 @@ static int encode_picture(MpegEncContext *s, int picture_number) s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1); s->qscale= 8; } + if (s->out_format == FMT_SPEEDHQ) { + s->y_dc_scale_table= + s->c_dc_scale_table= ff_mpeg2_dc_scale_table[3]; + } //FIXME var duplication s->current_picture_ptr->f->key_frame = @@ -3873,6 +3915,10 @@ static int encode_picture(MpegEncContext *s, int picture_number) ff_mjpeg_encode_picture_header(s->avctx, &s->pb, &s->intra_scantable, s->pred, s->intra_matrix, s->chroma_intra_matrix); break; + case FMT_SPEEDHQ: + if (CONFIG_SPEEDHQ_ENCODER) + ff_speedhq_encode_picture_header(s); + break; case FMT_H261: if (CONFIG_H261_ENCODER) ff_h261_encode_picture_header(s, picture_number); diff --git a/libavcodec/speedhqenc.c b/libavcodec/speedhqenc.c new file mode 100644 index 0000000000..539278f1a6 --- /dev/null +++ b/libavcodec/speedhqenc.c @@ -0,0 +1,316 @@ +/* + * SpeedHQ encoder + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2003 Alex Beregszaszi + * Copyright (c) 2003-2004 Michael Niedermayer + * Copyright (c) 2020 FFmpeg + * + * 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 + */ + +/** + * @file + * SpeedHQ encoder. + */ + +#include "libavutil/pixdesc.h" + +#include "avcodec.h" +#include "mpeg12.h" +#include "mpegvideo.h" +#include "speedhqenc.h" + +extern RLTable ff_rl_speedhq; +static uint8_t ff_speedhq_static_rl_table_store[2][2*MAX_RUN + MAX_LEVEL + 3]; + +static uint16_t ff_mpeg12_vlc_dc_lum_code_reversed[12]; +static uint16_t ff_mpeg12_vlc_dc_chroma_code_reversed[12]; + +/* simple include everything table for dc, first byte is bits + * number next 3 are code */ +static uint32_t speedhq_lum_dc_uni[512]; +static uint32_t speedhq_chr_dc_uni[512]; + +static uint8_t speedhq_index_run[2][64]; +static int8_t speedhq_max_level[2][64]; + +static uint8_t uni_speedhq_ac_vlc_len[64 * 64 * 2]; + +static uint32_t reverse(uint32_t num, int bits) +{ + return bitswap_32(num) >> (32 - bits); +} + +static void reverse_code(const uint16_t *code, const uint8_t *bits, + uint16_t *reversed_code, int num_entries) +{ + int i; + for (i = 0; i < num_entries; i++) { + reversed_code[i] = reverse(code[i], bits[i]); + } +} + +av_cold int ff_speedhq_encode_init(MpegEncContext *s) +{ + int i; + + av_assert0(s->slice_context_count == 1); + + if (s->width > 65500 || s->height > 65500) { + av_log(s, AV_LOG_ERROR, "SpeedHQ does not support resolutions above 65500x65500\n"); + return AVERROR(EINVAL); + } + + s->min_qcoeff = -2048; + s->max_qcoeff = 2047; + + /* Exactly the same as MPEG-2, except little-endian. */ + reverse_code(ff_mpeg12_vlc_dc_lum_code, + ff_mpeg12_vlc_dc_lum_bits, + ff_mpeg12_vlc_dc_lum_code_reversed, + 12); + reverse_code(ff_mpeg12_vlc_dc_chroma_code, + ff_mpeg12_vlc_dc_chroma_bits, + ff_mpeg12_vlc_dc_chroma_code_reversed, + 12); + + ff_rl_init(&ff_rl_speedhq, ff_speedhq_static_rl_table_store); + + for (i = 0; i < 64; i++) { + speedhq_max_level[0][i] = ff_rl_speedhq.max_level[0][i]; + speedhq_index_run[0][i] = ff_rl_speedhq.index_run[0][i]; + } + + /* build unified dc encoding tables */ + for (i = -255; i < 256; i++) { + int adiff, index; + int bits, code; + int diff = i; + + adiff = FFABS(diff); + if (diff < 0) + diff--; + index = av_log2(2 * adiff); + + bits = ff_mpeg12_vlc_dc_lum_bits[index] + index; + code = ff_mpeg12_vlc_dc_lum_code_reversed[index] + + (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index]); + speedhq_lum_dc_uni[i + 255] = bits + (code << 8); + + bits = ff_mpeg12_vlc_dc_chroma_bits[index] + index; + code = ff_mpeg12_vlc_dc_chroma_code_reversed[index] + + (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index]); + speedhq_chr_dc_uni[i + 255] = bits + (code << 8); + } + + ff_init_uni_ac_vlc(&ff_rl_speedhq, uni_speedhq_ac_vlc_len); + s->intra_ac_vlc_length = + s->intra_ac_vlc_last_length = + s->intra_chroma_ac_vlc_length = + s->intra_chroma_ac_vlc_last_length = uni_speedhq_ac_vlc_len; + + switch (s->avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + s->avctx->codec_tag = MKTAG('S','H','Q','0'); + break; + case AV_PIX_FMT_YUV422P: + s->avctx->codec_tag = MKTAG('S','H','Q','2'); + break; + case AV_PIX_FMT_YUV444P: + s->avctx->codec_tag = MKTAG('S','H','Q','4'); + break; + default: + av_assert0(0); + } + + return 0; +} + +void ff_speedhq_encode_picture_header(MpegEncContext *s) +{ + avpriv_align_put_bits(&s->pb); + put_bits_le(&s->pb, 8, 100 - s->qscale * 2); /* FIXME why doubled */ + put_bits_le(&s->pb, 24, 4); /* no second field */ + + /* length of first slice, will be filled out later */ + s->slice_start = 4; + put_bits_le(&s->pb, 24, 0); +} + +void ff_speedhq_end_slice(MpegEncContext *s) +{ + int slice_len; + + flush_put_bits_le(&s->pb); + slice_len = s->pb.buf_ptr - (s->pb.buf + s->slice_start); + AV_WL24(s->pb.buf + s->slice_start, slice_len); + + /* length of next slice, will be filled out later */ + s->slice_start = s->pb.buf_ptr - s->pb.buf; + put_bits_le(&s->pb, 24, 0); +} + +static inline void encode_dc(PutBitContext *pb, int diff, int component) +{ + unsigned int diff_u = diff + 255; + if (diff_u >= 511) { + int index; + + if (diff < 0) { + index = av_log2_16bit(-2 * diff); + diff--; + } else { + index = av_log2_16bit(2 * diff); + } + if (component == 0) + put_bits_le(pb, + ff_mpeg12_vlc_dc_lum_bits[index] + index, + ff_mpeg12_vlc_dc_lum_code_reversed[index] + + (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index])); + else + put_bits_le(pb, + ff_mpeg12_vlc_dc_chroma_bits[index] + index, + ff_mpeg12_vlc_dc_chroma_code_reversed[index] + + (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index])); + } else { + if (component == 0) + put_bits_le(pb, + speedhq_lum_dc_uni[diff + 255] & 0xFF, + speedhq_lum_dc_uni[diff + 255] >> 8); + else + put_bits_le(pb, + speedhq_chr_dc_uni[diff + 255] & 0xFF, + speedhq_chr_dc_uni[diff + 255] >> 8); + } +} + +static void encode_block(MpegEncContext *s, int16_t *block, int n) +{ + int alevel, level, last_non_zero, dc, i, j, run, last_index, sign; + int code; + int component, val; + + /* DC coef */ + component = (n <= 3 ? 0 : (n&1) + 1); + dc = block[0]; /* overflow is impossible */ + val = s->last_dc[component] - dc; /* opposite of most codecs */ + encode_dc(&s->pb, val, component); + s->last_dc[component] = dc; + + /* now quantify & encode AC coefs */ + last_non_zero = 0; + last_index = s->block_last_index[n]; + + for (i = 1; i <= last_index; i++) { + j = s->intra_scantable.permutated[i]; + level = block[j]; + + /* encode using VLC */ + if (level != 0) { + run = i - last_non_zero - 1; + + alevel = level; + MASK_ABS(sign, alevel); + sign &= 1; + + if (alevel <= speedhq_max_level[0][run]) { + code = speedhq_index_run[0][run] + alevel - 1; + /* store the VLC & sign at once */ + put_bits_le(&s->pb, ff_rl_speedhq.table_vlc[code][1] + 1, + ff_rl_speedhq.table_vlc[code][0] + (sign << ff_rl_speedhq.table_vlc[code][1])); + } else { + /* escape seems to be pretty rare <5% so I do not optimize it */ + put_bits_le(&s->pb, ff_rl_speedhq.table_vlc[121][1], ff_rl_speedhq.table_vlc[121][0]); + /* escape: only clip in this case */ + put_bits_le(&s->pb, 6, run); + put_bits_le(&s->pb, 12, level + 2048); + } + last_non_zero = i; + } + } + /* end of block */ + put_bits_le(&s->pb, ff_rl_speedhq.table_vlc[122][1], ff_rl_speedhq.table_vlc[122][0]); +} + +void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) +{ + int i; + for(i=0;i<6;i++) { + encode_block(s, block[i], i); + } + if (s->chroma_format == CHROMA_444) { + encode_block(s, block[8], 8); + encode_block(s, block[9], 9); + + encode_block(s, block[6], 6); + encode_block(s, block[7], 7); + + encode_block(s, block[10], 10); + encode_block(s, block[11], 11); + } else if (s->chroma_format == CHROMA_422) { + encode_block(s, block[6], 6); + encode_block(s, block[7], 7); + } + + s->i_tex_bits += get_bits_diff(s); +} + +static int ff_speedhq_mb_rows_in_slice(int slice_num, int mb_height) +{ + return mb_height / 4 + (slice_num < (mb_height % 4)); +} + +int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice) +{ + int slice_num = 0; + while (mb_y_order >= ff_speedhq_mb_rows_in_slice(slice_num, mb_height)) { + mb_y_order -= ff_speedhq_mb_rows_in_slice(slice_num, mb_height); + slice_num++; + } + *first_in_slice = (mb_y_order == 0); + return mb_y_order * 4 + slice_num; +} + +static const AVOption options[] = { +FF_MPV_COMMON_OPTS +{ NULL}, +}; + +#if CONFIG_SPEEDHQ_ENCODER +static const AVClass speedhq_class = { + .class_name = "speedhq encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_speedhq_encoder = { + .name = "speedhq", + .long_name = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_SPEEDHQ, + .priv_data_size = sizeof(MpegEncContext), + .init = ff_mpv_encode_init, + .encode2 = ff_mpv_encode_picture, + .close = ff_mpv_encode_end, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE + }, + .priv_class = &speedhq_class, +}; +#endif diff --git a/libavcodec/speedhqenc.h b/libavcodec/speedhqenc.h new file mode 100644 index 0000000000..196c2aebe8 --- /dev/null +++ b/libavcodec/speedhqenc.h @@ -0,0 +1,47 @@ +/* + * SpeedHQ encoder + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2003 Alex Beregszaszi + * Copyright (c) 2003-2004 Michael Niedermayer + * + * 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 + */ + +/** + * @file + * SpeedHQ encoder. + */ + +#ifndef AVCODEC_SPEEDHQENC_H +#define AVCODEC_SPEEDHQENC_H + +#include <stdint.h> + +#include "mjpeg.h" +#include "mpegvideo.h" +#include "put_bits.h" + +int ff_speedhq_encode_init(MpegEncContext *s); +void ff_speedhq_encode_close(MpegEncContext *s); +void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]); + +void ff_speedhq_encode_picture_header(MpegEncContext *s); +void ff_speedhq_end_slice(MpegEncContext *s); + +int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice); + +#endif /* AVCODEC_SPEEDHQENC_H */ diff --git a/libavcodec/version.h b/libavcodec/version.h index e75891d463..3e34af5348 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #define LIBAVCODEC_VERSION_MAJOR 58 #define LIBAVCODEC_VERSION_MINOR 95 -#define LIBAVCODEC_VERSION_MICRO 100 +#define LIBAVCODEC_VERSION_MICRO 101 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ -- 2.27.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".