From 8a48f8d46db0cf4439e8473a50fdb547f8a73f1a Mon Sep 17 00:00:00 2001 From: wrapper Date: Fri, 15 Aug 2025 17:18:54 +0700 Subject: [PATCH 01/22] libaac ffmpeg module --- .gitignore | 1 + configure | 6 + libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 2 + libavcodec/libaac_nextdec.c | 170 ++++++++++++++++++++ libavcodec/libaac_nextenc.c | 302 ++++++++++++++++++++++++++++++++++++ 6 files changed, 483 insertions(+) create mode 100644 libavcodec/libaac_nextdec.c create mode 100755 libavcodec/libaac_nextenc.c diff --git a/.gitignore b/.gitignore index 4aa49c52c7..a54527cf89 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ /libavfilter/vulkan/*.c /.*/ !/.forgejo/ +*.orig \ No newline at end of file diff --git a/configure b/configure index 416cd2d1d6..eaa52b63ad 100755 --- a/configure +++ b/configure @@ -212,6 +212,7 @@ External library support: --enable-jni enable JNI support [no] --enable-ladspa enable LADSPA audio filtering [no] --enable-lcms2 enable ICC profile support via LittleCMS 2 [no] + --enable-libaac-next enable AAC encoding using libaac-next [no] --enable-libaom enable AV1 video encoding/decoding via libaom [no] --enable-libaribb24 enable ARIB text and caption decoding via libaribb24 [no] --enable-libaribcaption enable ARIB text and caption decoding via libaribcaption [no] @@ -1901,6 +1902,7 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" EXTERNAL_LIBRARY_VERSION3_LIST=" gmp + libaac_next libaribb24 liblensfun libopencore_amrnb @@ -3592,6 +3594,9 @@ hevc_videotoolbox_encoder_deps="pthreads" hevc_videotoolbox_encoder_select="atsc_a53 videotoolbox_encoder" prores_videotoolbox_encoder_deps="pthreads" prores_videotoolbox_encoder_select="videotoolbox_encoder" +libaac_next_decoder_deps="libaac_next" +libaac_next_encoder_deps="libaac_next" +libaac_next_encoder_select="audio_frame_queue" libaom_av1_decoder_deps="libaom" libaom_av1_encoder_deps="libaom" libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc" @@ -7016,6 +7021,7 @@ enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gn enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; } enabled ladspa && require_headers "ladspa.h dlfcn.h" enabled lcms2 && require_pkg_config lcms2 "lcms2 >= 2.13" lcms2.h cmsCreateContext +enabled libaac_next && require_pkg_config libaac_next "libaac >= 1.0.0" libaac.h aac_encode_open enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version enabled liboapv && require_pkg_config liboapv "oapv >= 0.2.0.0" "oapv/oapv.h" oapve_encode enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || diff --git a/libavcodec/Makefile b/libavcodec/Makefile index fb22541f8d..740a008131 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1144,6 +1144,8 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_ILBC_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_LIBAAC_NEXT_ENCODER) += libaac_nextenc.o +OBJS-$(CONFIG_LIBAAC_NEXT_DECODER) += libaac_nextdec.o OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index f5ec2e01e8..8fcd1a806c 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -766,6 +766,8 @@ extern const FFCodec ff_pcm_mulaw_at_encoder; extern const FFCodec ff_pcm_mulaw_at_decoder; extern const FFCodec ff_qdmc_at_decoder; extern const FFCodec ff_qdm2_at_decoder; +extern const FFCodec ff_libaac_next_encoder; +extern const FFCodec ff_libaac_next_decoder; extern FFCodec ff_libaom_av1_encoder; /* preferred over libaribb24 */ extern const FFCodec ff_libaribcaption_decoder; diff --git a/libavcodec/libaac_nextdec.c b/libavcodec/libaac_nextdec.c new file mode 100644 index 0000000000..7450c14322 --- /dev/null +++ b/libavcodec/libaac_nextdec.c @@ -0,0 +1,170 @@ +/* + * Libaac-next decoder (libxaac based) + * Copyright (c) 2025 Wrapper + * + * 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 + * Interface to libaac-next decoder. + */ + +#include "avcodec.h" +#include +#include "libavcodec/codec_id.h" +#include "libavutil/channel_layout.h" +#include "libavutil/error.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "avcodec.h" +#include "codec_internal.h" +#include "decode.h" +#include "libavutil/samplefmt.h" +#include "libavutil/mem.h" + +typedef struct { + AVClass *class; + AACDecode *decoder; + int error_conceal; + int esbr; + unsigned char *decode_buffer; +} libaacDecodeCTX; + +static const AVChannelLayout aac_ch_layouts[6] = { + AV_CHANNEL_LAYOUT_MONO, + AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_SURROUND, + AV_CHANNEL_LAYOUT_4POINT0, + AV_CHANNEL_LAYOUT_5POINT0_BACK, + AV_CHANNEL_LAYOUT_5POINT1_BACK, +}; + +static const AVOption aac_dec_options[] = { + { "conceal", "Error concealment", offsetof(libaacDecodeCTX, error_conceal), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, + { "esbr", "Enable the use of Enhanced SBR", offsetof(libaacDecodeCTX, esbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, + { NULL } +}; + +static const AVClass aac_dec_class = { + .class_name = "libaac", + .item_name = av_default_item_name, + .option = aac_dec_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void aac_dec_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) { + AVCodecContext *ctx = (AVCodecContext *)handle; + av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode); +} + +static av_cold int libaac_decode_init(AVCodecContext *avctx) +{ + libaacDecodeCTX *s = avctx->priv_data; + AACDecodeSettings cfg = {0}; + + cfg.bitsPerSamples = 16; + cfg.errorConceal = s->error_conceal; + cfg.eSBR = s->esbr; + cfg.frameSize = 0; + cfg.asc = avctx->extradata; + cfg.ascSize = avctx->extradata_size; + cfg.errorHandleCtx = avctx; + cfg.errorHandler = aac_dec_error_handler; + + s->decoder = aac_decode_open(cfg); + if (!s->decoder) + { + return AVERROR(EINVAL); + } + + s->decode_buffer = av_mallocz(4096 * 8); + if (!s->decode_buffer) + { + return AVERROR(ENOMEM); + } + + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + return 0; +} + +static av_cold int libaac_decode_close(AVCodecContext *avctx) +{ + libaacDecodeCTX *s = avctx->priv_data; + + if (s->decoder) + aac_decode_close(s->decoder); + + return 0; +} + +static int libaac_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + libaacDecodeCTX *s = avctx->priv_data; + uint32_t decode_size, read_size; + int ret; + + ret = aac_decode(s->decoder, avpkt->data, avpkt->size, s->decode_buffer, &decode_size, &read_size); + if (ret < 0) + return AVERROR_EXTERNAL; + + avctx->sample_rate = s->decoder->sampleRate; + avctx->profile = s->decoder->aot - 1; + avctx->ch_layout = aac_ch_layouts[s->decoder->noChannels - 1]; + avctx->frame_size = 1024; + + if (decode_size <= 0) + return AVERROR_EOF; + + frame->nb_samples = decode_size / av_get_bytes_per_sample(avctx->sample_fmt) / avctx->ch_layout.nb_channels; + + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + av_log(avctx, AV_LOG_TRACE, "aac decode size: %d, decode buf: %d\n", decode_size, avctx->ch_layout.nb_channels * frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt)); + memcpy(frame->data[0], s->decode_buffer, decode_size); + + *got_frame_ptr = 1; + return read_size; +} + +static av_cold void libaac_decode_flush(AVCodecContext *avctx) +{ + libaacDecodeCTX *s = avctx->priv_data; + + if (!s->decoder) + return; + + aac_decode_flush_buffer(s->decoder); +} + +const FFCodec ff_libaac_next_decoder = { + .p.name = "libaac", + CODEC_LONG_NAME("custom libxaac-based AAC decoder"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AAC, + .priv_data_size = sizeof(libaacDecodeCTX), + .init = libaac_decode_init, + FF_CODEC_DECODE_CB(libaac_decode_frame), + .close = libaac_decode_close, + .flush = libaac_decode_flush, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, + .p.priv_class = &aac_dec_class, + .p.wrapper_name = "libaac", +}; diff --git a/libavcodec/libaac_nextenc.c b/libavcodec/libaac_nextenc.c new file mode 100755 index 0000000000..c5b21f2095 --- /dev/null +++ b/libavcodec/libaac_nextenc.c @@ -0,0 +1,302 @@ +/* + * Libaac-next encoder (libxaac based) + * Copyright (c) 2025 Wrapper + * + * 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 + * Interface to libaac-next encoder. + */ + +#include + +#include "libavcodec/defs.h" +#include "libavutil/channel_layout.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/mem.h" +#include "avcodec.h" +#include "audio_frame_queue.h" +#include "codec_internal.h" +#include "encode.h" +#include "libavutil/samplefmt.h" +#include "profiles.h" + +typedef struct +{ + const AVClass *class; + AACContext *encoder; + int delay_sent; + int flush_delay; + + int eld_v2; + int esbr; + int frame_length; + int iq; + int tns; + + AudioFrameQueue afq; +} libaacEncodeCTX; + +static const AVOption aac_enc_options[] = { + { "eld_v2", "Enable ELDv2 (LD-MPS extension for ELD stereo signals)", offsetof(libaacEncodeCTX, eld_v2), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { "esbr", "Enable the use of Enhanced SBR", offsetof(libaacEncodeCTX, esbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { "frame_length", "The desired frame length", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1024, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { "iq", "Inverse quantization", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + { "tns", "Temporal Noise Shaping", offsetof(libaacEncodeCTX, tns), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, + FF_AAC_PROFILE_OPTS + { NULL } +}; + +static const AVClass aac_enc_class = { + .class_name = "libaac", + .item_name = av_default_item_name, + .option = aac_enc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void aac_enc_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) { + AVCodecContext *ctx = (AVCodecContext *)handle; + av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode); +} + +static av_cold int libaac_encode_init(AVCodecContext *avctx) +{ + libaacEncodeCTX *s = avctx->priv_data; + AACSettings cfg = {0}; + + /* number of channels */ + if (avctx->ch_layout.nb_channels < 1 || avctx->ch_layout.nb_channels > 6) + { + av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->ch_layout.nb_channels); + return AVERROR(EINVAL); + } + + cfg.sampleRate = avctx->sample_rate; + cfg.noChannels = avctx->ch_layout.nb_channels; + cfg.bitsPerSamples = avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? 32 : 16; + cfg.bitrate = avctx->bit_rate; + cfg.adts = !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER); + cfg.cutoff = avctx->cutoff; + switch (avctx->profile) { + case AV_PROFILE_AAC_LOW: + case AV_PROFILE_UNKNOWN: + cfg.profile = AAC_LC; + break; + + case AV_PROFILE_AAC_HE: + cfg.profile = AAC_HE; + break; + + case AV_PROFILE_AAC_HE_V2: + cfg.profile = AAC_HEV2; + break; + + case AV_PROFILE_AAC_LD: + cfg.profile = AAC_LD; + break; + + case AV_PROFILE_AAC_ELD: + cfg.profile = AAC_ELD; + break; + } + cfg.tns = s->tns; + cfg.frameSize = s->frame_length; + cfg.eSBR = s->esbr; + cfg.iq = s->iq; + + cfg.errorHandleCtx = avctx; + cfg.errorHandler = aac_enc_error_handler; + + s->encoder = aac_encode_open(cfg); + + if (!s->encoder) + { + return AVERROR(EINVAL); + } + + avctx->frame_size = s->encoder->no_samples / avctx->ch_layout.nb_channels; + avctx->initial_padding = s->encoder->inputDelay; + s->flush_delay = s->encoder->inputDelay; + + av_log(avctx, AV_LOG_TRACE, "frame size: %d, initial delay: %d\n", avctx->frame_size, avctx->initial_padding); + + ff_af_queue_init(avctx, &s->afq); + + /* Set decoder specific info */ + avctx->extradata_size = 0; + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) + { + avctx->extradata = av_mallocz(s->encoder->ascSize + AV_INPUT_BUFFER_PADDING_SIZE); + + if (!avctx->extradata) + { + return AVERROR(ENOMEM); + } + + memcpy(avctx->extradata, s->encoder->asc, s->encoder->ascSize); + } + return 0; +} + +static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + libaacEncodeCTX *s = avctx->priv_data; + int ret; + int discard_padding; + + if ((ret = ff_alloc_packet(avctx, pkt, s->encoder->max_out_bytes)) < 0) + return ret; + + if (!frame) + { + int isFlush = s->encoder->in_buf_offset <= 0; + av_log(avctx, AV_LOG_TRACE, "frame_queue_count: %d, frame_queue_size: %d, in_buf: %d, is_flush: %d, flush_delay: %d\n", s->afq.frame_count, s->afq.remaining_samples, s->encoder->in_buf_offset, isFlush, s->flush_delay); + + if (isFlush && s->flush_delay <= 0) + return 0; + + /* Flushing */ + if ((ret = aac_encode(s->encoder, NULL, 0, pkt->data, (unsigned int *)&pkt->size)) < 0) + { + return AVERROR(EINVAL); + } + + if (isFlush) + s->flush_delay -= avctx->frame_size; + } + else + { + /* Encoding */ + if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) + return ret; + + int encodeSize = (avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? 4 : 2) * avctx->ch_layout.nb_channels * frame->nb_samples; + av_log(avctx, AV_LOG_TRACE, "encode size: %d\n", encodeSize); + + if ((ret = aac_encode(s->encoder, frame->data[0], encodeSize, pkt->data, (unsigned int *)&pkt->size)) < 0) + { + return AVERROR(EINVAL); + } + } + + ff_af_queue_remove(&s->afq, avctx->frame_size, &pkt->pts, &pkt->duration); + + /* discard padding copied from fdkaac encoder */ + discard_padding = avctx->frame_size - pkt->duration; + + // Check if subtraction resulted in an overflow + if ((discard_padding < avctx->frame_size) != (pkt->duration > 0)) + { + av_log(avctx, AV_LOG_ERROR, "discard padding overflow\n"); + return AVERROR(EINVAL); + } + + if ((!s->delay_sent && avctx->initial_padding > 0) || discard_padding > 0) + { + uint8_t *side_data = + av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (!side_data) + return AVERROR(ENOMEM); + if (!s->delay_sent) + { + AV_WL32(side_data, avctx->initial_padding); + s->delay_sent = 1; + } + AV_WL32(side_data + 4, discard_padding); + } + + pkt->flags |= AV_PKT_FLAG_KEY; + *got_packet = 1; + return 0; +} + +static void libaac_encode_flush(AVCodecContext *avctx) +{ + libaacEncodeCTX *s = avctx->priv_data; + uint8_t sink_null[32768]; + int64_t pts, duration; + uint32_t out_bytes; + + av_log(avctx, AV_LOG_TRACE, "encoder flush\n"); + ff_af_queue_remove(&s->afq, s->afq.frame_count, &pts, &duration); + aac_encode(s->encoder, NULL, 0, sink_null, &out_bytes); +} + +static av_cold int libaac_encode_close(AVCodecContext *avctx) +{ + libaacEncodeCTX *s = avctx->priv_data; + + if (s->encoder) + aac_encode_close(s->encoder); + + ff_af_queue_close(&s->afq); + + return 0; +} + +static const FFCodecDefault defaults[] = { + {"b", "128000"}, + {NULL}}; + +static const AVProfile libaac_profiles[] = { + { AV_PROFILE_AAC_LOW, "LC" }, + { AV_PROFILE_AAC_HE, "HE-AAC" }, + { AV_PROFILE_AAC_HE_V2, "HE-AACv2" }, + { AV_PROFILE_AAC_LD, "LD" }, + { AV_PROFILE_AAC_ELD, "ELD" }, + {AV_PROFILE_UNKNOWN}, +}; + +static const int aac_sample_rates[] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, 0 +}; + +static const AVChannelLayout aac_ch_layouts[6] = { + AV_CHANNEL_LAYOUT_MONO, + AV_CHANNEL_LAYOUT_STEREO, + AV_CHANNEL_LAYOUT_SURROUND, + AV_CHANNEL_LAYOUT_4POINT0, + AV_CHANNEL_LAYOUT_5POINT0_BACK, + AV_CHANNEL_LAYOUT_5POINT1_BACK, +}; + +const FFCodec ff_libaac_next_encoder = { + .p.name = "libaac", + CODEC_LONG_NAME("custom libxaac-based AAC encoder"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AAC, + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_FLUSH, + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, + .priv_data_size = sizeof(libaacEncodeCTX), + .init = libaac_encode_init, + FF_CODEC_ENCODE_CB(libaac_encode_frame), + .flush = libaac_encode_flush, + .close = libaac_encode_close, + CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), + .p.priv_class = &aac_enc_class, + .defaults = defaults, + .p.profiles = libaac_profiles, + CODEC_SAMPLERATES_ARRAY(aac_sample_rates), + .p.wrapper_name = "libaac", + CODEC_CH_LAYOUTS_ARRAY(aac_ch_layouts), +}; From ac5303a5b9cdc17e4ebddfdc3203a4c325d42c52 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Wed, 25 Jun 2025 08:46:23 +0200 Subject: [PATCH 02/22] hw_base_encode: Support refs option to limit number of references Set default value to 0 to keep the old behavior of using maximum number of references. --- libavcodec/d3d12va_encode_hevc.c | 1 + libavcodec/hw_base_encode.c | 5 +++++ libavcodec/vaapi_encode_av1.c | 1 + libavcodec/vaapi_encode_h264.c | 1 + libavcodec/vaapi_encode_h265.c | 1 + libavcodec/vaapi_encode_vp8.c | 1 + libavcodec/vaapi_encode_vp9.c | 1 + libavcodec/vulkan_encode_av1.c | 1 + libavcodec/vulkan_encode_h264.c | 1 + libavcodec/vulkan_encode_h265.c | 1 + 10 files changed, 14 insertions(+) diff --git a/libavcodec/d3d12va_encode_hevc.c b/libavcodec/d3d12va_encode_hevc.c index ce5d1bf110..0aa1a1d3a4 100644 --- a/libavcodec/d3d12va_encode_hevc.c +++ b/libavcodec/d3d12va_encode_hevc.c @@ -762,6 +762,7 @@ static const FFCodecDefault d3d12va_encode_hevc_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/hw_base_encode.c b/libavcodec/hw_base_encode.c index 33a30c8d10..927aeb4bad 100644 --- a/libavcodec/hw_base_encode.c +++ b/libavcodec/hw_base_encode.c @@ -666,6 +666,11 @@ int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *av ctx->ref_l0 = FFMIN(ref_l0, MAX_PICTURE_REFERENCES); ctx->ref_l1 = FFMIN(ref_l1, MAX_PICTURE_REFERENCES); + if (avctx->refs > 0) { + ctx->ref_l0 = FFMIN(ctx->ref_l0, avctx->refs); + ctx->ref_l1 = FFMIN(ctx->ref_l1, avctx->refs); + } + if (flags & FF_HW_FLAG_INTRA_ONLY || avctx->gop_size <= 1) { av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n"); ctx->gop_size = 1; diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c index 3d8f29d599..9d837f5c6b 100644 --- a/libavcodec/vaapi_encode_av1.c +++ b/libavcodec/vaapi_encode_av1.c @@ -1027,6 +1027,7 @@ static const FFCodecDefault vaapi_encode_av1_defaults[] = { { "g", "120" }, { "qmin", "1" }, { "qmax", "255" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 0cd5b0ac50..27f6551719 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -1153,6 +1153,7 @@ static const FFCodecDefault vaapi_encode_h264_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 1539bfbf79..baf0d77c8a 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -1184,6 +1184,7 @@ static const FFCodecDefault vaapi_encode_h265_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c index 125d760b9b..69a56a17af 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -235,6 +235,7 @@ static const FFCodecDefault vaapi_encode_vp8_defaults[] = { { "g", "120" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c index e88967a053..ca8de541d9 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -292,6 +292,7 @@ static const FFCodecDefault vaapi_encode_vp9_defaults[] = { { "g", "250" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vulkan_encode_av1.c b/libavcodec/vulkan_encode_av1.c index 840092cf6d..08ffbfa393 100644 --- a/libavcodec/vulkan_encode_av1.c +++ b/libavcodec/vulkan_encode_av1.c @@ -1367,6 +1367,7 @@ static const FFCodecDefault vulkan_encode_av1_defaults[] = { { "g", "300" }, { "qmin", "1" }, { "qmax", "255" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vulkan_encode_h264.c b/libavcodec/vulkan_encode_h264.c index 8bbb4639e6..942e911fb7 100644 --- a/libavcodec/vulkan_encode_h264.c +++ b/libavcodec/vulkan_encode_h264.c @@ -1634,6 +1634,7 @@ static const FFCodecDefault vulkan_encode_h264_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; diff --git a/libavcodec/vulkan_encode_h265.c b/libavcodec/vulkan_encode_h265.c index f0ec852557..c30b7e8f93 100644 --- a/libavcodec/vulkan_encode_h265.c +++ b/libavcodec/vulkan_encode_h265.c @@ -1761,6 +1761,7 @@ static const FFCodecDefault vulkan_encode_h265_defaults[] = { { "b_qoffset", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, + { "refs", "0" }, { NULL }, }; From c9e93df4eed93fe0044c52d953688c4180de1d48 Mon Sep 17 00:00:00 2001 From: Oliver Chang Date: Thu, 14 Aug 2025 22:11:41 -0700 Subject: [PATCH 03/22] avcodec/prores_raw: Fix heap buffer overflow When dimensions differ from context, those were updated using ff_set_dimensions, however this overwrote the aligned coded_width and coded_height that were set before, leading to a buffer overflow when writing the frame data. Fixes: OssFuzz 438771336 Fixes: Heap-buffer-overflow Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Marvin Scholz Reviewed-by: Marvin Scholz --- libavcodec/prores_raw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libavcodec/prores_raw.c b/libavcodec/prores_raw.c index 748e176815..b2aa97ddda 100644 --- a/libavcodec/prores_raw.c +++ b/libavcodec/prores_raw.c @@ -367,9 +367,6 @@ static int decode_frame(AVCodecContext *avctx, if ((w & 1) || (h & 1)) return AVERROR_INVALIDDATA; - avctx->coded_width = FFALIGN(w, 16); - avctx->coded_height = FFALIGN(h, 16); - if (w != avctx->width || h != avctx->height) { av_log(avctx, AV_LOG_WARNING, "picture resolution change: %ix%i -> %ix%i\n", avctx->width, avctx->height, w, h); @@ -377,6 +374,9 @@ static int decode_frame(AVCodecContext *avctx, return ret; } + avctx->coded_width = FFALIGN(w, 16); + avctx->coded_height = FFALIGN(h, 16); + enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16; if (pix_fmt != s->pix_fmt) { s->pix_fmt = pix_fmt; From 2a22972db3b390d82dedbdbb5f44cc09a43912b5 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Fri, 15 Aug 2025 17:55:05 +0200 Subject: [PATCH 04/22] avcodec/utvideodec: Clear plane_start array in pack mode the array is passed into decode_plane() without being initialized or used Fixes: use of uninitialized memory Fixes: 438780119/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_UTVIDEO_DEC_fuzzer-5464037027807232 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer --- libavcodec/utvideodec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 934945c1be..bc02ac44d5 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -585,7 +585,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int buf_size = avpkt->size; UtvideoContext *c = avctx->priv_data; int i, j; - const uint8_t *plane_start[5]; + const uint8_t *plane_start[5] = {NULL}; int plane_size, max_slice_size = 0, slice_start, slice_end, slice_size; int ret; GetByteContext gb; From 6e4805056851338fa00768931f29d4c6281495b9 Mon Sep 17 00:00:00 2001 From: wangbin Date: Fri, 15 Aug 2025 23:14:47 +0800 Subject: [PATCH 05/22] configure: fix -L flags for lld-link --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 416cd2d1d6..6c1d6868ea 100755 --- a/configure +++ b/configure @@ -5174,7 +5174,7 @@ probe_cc(){ # but we can force it back to gnu mode and get the version from there. _ident=$($_cc -flavor gnu --version 2>/dev/null) _ld_o='-out:$@' - _flags_filter=msvc_flags + _flags_filter=msvc_flags_link _ld_lib='%.lib' _ld_path='-libpath:' elif VSLANG=1033 $_cc -nologo- 2>&1 | grep -q ^Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then From 5ff2500514a0224b7c2822d3b4e950b473f5bcff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Fri, 15 Aug 2025 19:23:31 +0200 Subject: [PATCH 06/22] avcodec/x86/Makefile: add missing x86/proresdsp.o for prores raw --- libavcodec/x86/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index ebf458453e..ebd2bdb310 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -170,6 +170,7 @@ X86ASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o +X86ASM-OBJS-$(CONFIG_PRORES_RAW_DECODER) += x86/proresdsp.o X86ASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp.o X86ASM-OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp.o X86ASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o From 1f4fed5cc3be0737305e342f753c42716d6bf432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Tue, 4 Mar 2025 13:49:56 +0100 Subject: [PATCH 07/22] w32pthreads: add support for setting thread name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kacper Michajłow --- compat/w32pthreads.h | 35 +++++++++++++++++++++++++++++++++++ libavutil/thread.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h index fd6428e29f..6f2734b470 100644 --- a/compat/w32pthreads.h +++ b/compat/w32pthreads.h @@ -44,6 +44,7 @@ #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/time.h" +#include "libavutil/wchar_filename.h" typedef struct pthread_t { void *handle; @@ -209,4 +210,38 @@ static inline int pthread_setcancelstate(int state, int *oldstate) return 0; } +static inline int win32_thread_setname(const char *name) +{ +#if !HAVE_UWP + typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR); + + // Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016, + // Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in + // kernelbase.dll. So, load it from there for maximum coverage. + HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); + if (!kernelbase) + return AVERROR(ENOSYS); + + SetThreadDescriptionFn pSetThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(kernelbase, "SetThreadDescription"); + if (!pSetThreadDescription) + return AVERROR(ENOSYS); + + wchar_t *wname; + if (utf8towchar(name, &wname) < 0) + return AVERROR(ENOMEM); + + HRESULT hr = pSetThreadDescription(GetCurrentThread(), wname); + av_free(wname); + return SUCCEEDED(hr) ? 0 : AVERROR(EINVAL); +#else + // UWP is not supported because we cannot use LoadLibrary/GetProcAddress to + // detect the availability of the SetThreadDescription API. There is a small + // gap in Windows builds 1507-1607 where it was not available. UWP allows + // querying the availability of APIs with QueryOptionalDelayLoadedAPI, but it + // requires /DELAYLOAD:kernel32.dll during linking, and we cannot enforce that. + return AVERROR(ENOSYS); +#endif +} + #endif /* COMPAT_W32PTHREADS_H */ diff --git a/libavutil/thread.h b/libavutil/thread.h index 2c00c7cc35..184e2d8c5f 100644 --- a/libavutil/thread.h +++ b/libavutil/thread.h @@ -229,6 +229,8 @@ static inline int ff_thread_setname(const char *name) #endif #elif HAVE_PTHREAD_SET_NAME_NP pthread_set_name_np(pthread_self(), name); +#elif HAVE_W32THREADS + ret = win32_thread_setname(name); #else ret = AVERROR(ENOSYS); #endif From 3a8b3dfeca2ddbee9999262f3240bfe05b55c66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Mon, 28 Jul 2025 19:07:32 +0200 Subject: [PATCH 08/22] avformat/tls_openssl: use ascii - (0x2D) instead of 0x2010 hyphen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Too much AI is bad for you... Fixes: 167e343bbe75515a80db8ee72ffa0c607c944a00 Signed-off-by: Kacper Michajłow --- libavformat/tls_openssl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index bab2e711c6..a1073da216 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -35,8 +35,8 @@ #include /** - * Returns a heap‐allocated null‐terminated string containing - * the PEM‐encoded public key. Caller must free. + * Returns a heap-allocated null-terminated string containing + * the PEM-encoded public key. Caller must free. */ static char *pkey_to_pem_string(EVP_PKEY *pkey) { BIO *mem = NULL; @@ -61,7 +61,7 @@ static char *pkey_to_pem_string(EVP_PKEY *pkey) { if (!pem_str) goto err; - // Copy data & NUL‐terminate + // Copy data & NUL-terminate memcpy(pem_str, bptr->data, bptr->length); pem_str[bptr->length] = '\0'; @@ -427,7 +427,7 @@ error: /** - * Deserialize a PEM‐encoded private or public key from a NUL-terminated C string. + * Deserialize a PEM-encoded private or public key from a NUL-terminated C string. * * @param pem_str The PEM text, e.g. * "-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----\n" @@ -458,7 +458,7 @@ static EVP_PKEY *pkey_from_pem_string(const char *pem_str, int is_priv) } /** - * Deserialize a PEM‐encoded certificate from a NUL-terminated C string. + * Deserialize a PEM-encoded certificate from a NUL-terminated C string. * * @param pem_str The PEM text, e.g. * "-----BEGIN CERTIFICATE-----\n…\n-----END CERTIFICATE-----\n" From 113c9c6cf36a703afc5ef10bbb40f248df521425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 30 Jul 2025 20:08:38 +0200 Subject: [PATCH 09/22] configure: require at least OpenSSL 1.1.1 (LTS) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f256487cd8f29f24036efa5d91a84a26b048861a bumped requirement to 1.1.0 for OPENSSL_init_ssl. Bump this again to 1.1.1, because it was an LTS version. Although it has no mainline support anymore, it still has paid/premium support. 1.1.0 has no support at all. Motivated for use of BIO_read_ex() for next commits. Signed-off-by: Kacper Michajłow --- Changelog | 1 + configure | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 0b0e6ecbf4..98b259f17f 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,7 @@ version 8.0: - Whisper filter - Drop support for OpenSSL < 1.1.0 - Enable TLS peer certificate verification by default (on next major version bump) +- Drop support for OpenSSL < 1.1.1 - yasm support dropped, users need to use nasm - VVC VAAPI decoder - RealVideo 6.0 decoder diff --git a/configure b/configure index 6c1d6868ea..e1809a3e58 100755 --- a/configure +++ b/configure @@ -7260,10 +7260,10 @@ enabled omx && require_headers OMX_Core.h && \ enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" openssl/ssl.h OPENSSL_init_ssl && { enabled gplv3 || ! enabled gpl || enabled nonfree || die "ERROR: OpenSSL >=3.0.0 requires --enable-version3"; }; } || { enabled gpl && ! enabled nonfree && die "ERROR: OpenSSL <3.0.0 is incompatible with the gpl"; } || - check_pkg_config openssl "openssl >= 1.1.0" openssl/ssl.h OPENSSL_init_ssl || + check_pkg_config openssl "openssl >= 1.1.1" openssl/ssl.h OPENSSL_init_ssl || check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto || check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto -lws2_32 -lgdi32 || - die "ERROR: openssl (>= 1.1.0) not found"; } + die "ERROR: openssl (>= 1.1.1) not found"; } enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && From 4676f97928c1c38753d4f5da4ec13a75d5f22944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Tue, 29 Jul 2025 23:55:33 +0200 Subject: [PATCH 10/22] avformat/tls_openssl: clean keys serialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was unnecessary convoluted, remove not needed memory allocations, snprintf. Also fixes posibility to call snprinft with NULL as %s input. Signed-off-by: Kacper Michajłow --- libavformat/tls_openssl.c | 107 +++++++++++++------------------------- 1 file changed, 36 insertions(+), 71 deletions(-) diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index a1073da216..ba5895316a 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -35,80 +35,57 @@ #include /** - * Returns a heap-allocated null-terminated string containing - * the PEM-encoded public key. Caller must free. + * Convert an EVP_PKEY to a PEM string. */ -static char *pkey_to_pem_string(EVP_PKEY *pkey) { - BIO *mem = NULL; - BUF_MEM *bptr = NULL; - char *pem_str = NULL; +static int pkey_to_pem_string(EVP_PKEY *pkey, char *out, size_t out_sz) +{ + BIO *mem = NULL; + size_t read_bytes = 0; + + if (!pkey || !out || !out_sz) + goto done; - // Create a memory BIO if (!(mem = BIO_new(BIO_s_mem()))) - goto err; + goto done; - // Write public key in PEM form if (!PEM_write_bio_PrivateKey(mem, pkey, NULL, NULL, 0, NULL, NULL)) - goto err; + goto done; - // Extract pointer/length - BIO_get_mem_ptr(mem, &bptr); - if (!bptr || !bptr->length) - goto err; + if (!BIO_read_ex(mem, out, out_sz - 1, &read_bytes)) + goto done; - // Allocate string (+1 for NUL) - pem_str = av_malloc(bptr->length + 1); - if (!pem_str) - goto err; - - // Copy data & NUL-terminate - memcpy(pem_str, bptr->data, bptr->length); - pem_str[bptr->length] = '\0'; - -cleanup: +done: BIO_free(mem); - return pem_str; - -err: - // error path: free and return NULL - free(pem_str); - pem_str = NULL; - goto cleanup; + if (out && out_sz) + out[read_bytes] = '\0'; + return read_bytes; } /** - * Serialize an X509 certificate to a av_malloc’d PEM string. - * Caller must free the returned pointer. + * Convert an X509 certificate to a PEM string. */ -static char *cert_to_pem_string(X509 *cert) +static int cert_to_pem_string(X509 *cert, char *out, size_t out_sz) { - BIO *mem = BIO_new(BIO_s_mem()); - BUF_MEM *bptr = NULL; - char *out = NULL; + BIO *mem = NULL; + size_t read_bytes = 0; - if (!mem) goto err; + if (!cert || !out || !out_sz) + goto done; + + if (!(mem = BIO_new(BIO_s_mem()))) + goto done; - /* Write the PEM certificate */ if (!PEM_write_bio_X509(mem, cert)) - goto err; + goto done; - BIO_get_mem_ptr(mem, &bptr); - if (!bptr || !bptr->length) goto err; + if (!BIO_read_ex(mem, out, out_sz - 1, &read_bytes)) + goto done; - out = av_malloc(bptr->length + 1); - if (!out) goto err; - - memcpy(out, bptr->data, bptr->length); - out[bptr->length] = '\0'; - -cleanup: +done: BIO_free(mem); - return out; - -err: - free(out); - out = NULL; - goto cleanup; + if (out && out_sz) + out[read_bytes] = '\0'; + return read_bytes; } @@ -165,7 +142,6 @@ int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t ke AVBPrint key_bp, cert_bp; EVP_PKEY *pkey = NULL; X509 *cert = NULL; - char *key_tem = NULL, *cert_tem = NULL; /* To prevent a crash during cleanup, always initialize it. */ av_bprint_init(&key_bp, 1, MAX_CERTIFICATE_SIZE); @@ -211,11 +187,8 @@ int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t ke goto end; } - key_tem = pkey_to_pem_string(pkey); - cert_tem = cert_to_pem_string(cert); - - snprintf(key_buf, key_sz, "%s", key_tem); - snprintf(cert_buf, cert_sz, "%s", cert_tem); + pkey_to_pem_string(pkey, key_buf, key_sz); + cert_to_pem_string(cert, cert_buf, cert_sz); /* Generate fingerprint. */ if (fingerprint) { @@ -232,8 +205,6 @@ end: av_bprint_finalize(&key_bp, NULL); BIO_free(cert_b); av_bprint_finalize(&cert_bp, NULL); - av_free(key_tem); - av_free(cert_tem); EVP_PKEY_free(pkey); X509_free(cert); return ret; @@ -403,7 +374,6 @@ int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cer int ret = 0; EVP_PKEY *pkey = NULL; X509 *cert = NULL; - char *key_tem = NULL, *cert_tem = NULL; ret = openssl_gen_private_key(&pkey); if (ret < 0) goto error; @@ -411,14 +381,9 @@ int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cer ret = openssl_gen_certificate(pkey, &cert, fingerprint); if (ret < 0) goto error; - key_tem = pkey_to_pem_string(pkey); - cert_tem = cert_to_pem_string(cert); + pkey_to_pem_string(pkey, key_buf, key_sz); + cert_to_pem_string(cert, cert_buf, cert_sz); - snprintf(key_buf, key_sz, "%s", key_tem); - snprintf(cert_buf, cert_sz, "%s", cert_tem); - - av_free(key_tem); - av_free(cert_tem); error: X509_free(cert); EVP_PKEY_free(pkey); From 61d00509244d7503b3ad467c719da2662d11b6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 30 Jul 2025 00:23:20 +0200 Subject: [PATCH 11/22] avformat/tls_openssl: simplify fingerprint generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kacper Michajłow --- libavformat/tls_openssl.c | 63 ++++++++++----------------------------- 1 file changed, 16 insertions(+), 47 deletions(-) diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index ba5895316a..0f2dbc8da6 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -91,48 +91,26 @@ done: /** * Generate a SHA-256 fingerprint of an X.509 certificate. - * - * @param ctx AVFormatContext for logging (can be NULL) - * @param cert X509 certificate to fingerprint - * @return Newly allocated fingerprint string in "AA:BB:CC:…" format, - * or NULL on error (logs via av_log if ctx is not NULL). - * Caller must free() the returned string. */ -static char *generate_fingerprint(X509 *cert) +static int x509_fingerprint(X509 *cert, char **fingerprint) { unsigned char md[EVP_MAX_MD_SIZE]; int n = 0; - AVBPrint fingerprint; - char *result = NULL; - int i; - - /* To prevent a crash during cleanup, always initialize it. */ - av_bprint_init(&fingerprint, 0, AV_BPRINT_SIZE_UNLIMITED); + AVBPrint buf; if (X509_digest(cert, EVP_sha256(), md, &n) != 1) { - av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint, %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto end; + av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint, %s\n", + ERR_error_string(ERR_get_error(), NULL)); + return AVERROR(ENOMEM); } - for (i = 0; i < n; i++) { - av_bprintf(&fingerprint, "%02X", md[i]); - if (i + 1 < n) - av_bprintf(&fingerprint, ":"); - } + av_bprint_init(&buf, n*3, n*3); - if (!fingerprint.str || !strlen(fingerprint.str)) { - av_log(NULL, AV_LOG_ERROR, "TLS: Fingerprint is empty\n"); - goto end; - } + for (int i = 0; i < n - 1; i++) + av_bprintf(&buf, "%02X:", md[i]); + av_bprintf(&buf, "%02X", md[n - 1]); - result = av_strdup(fingerprint.str); - if (!result) { - av_log(NULL, AV_LOG_ERROR, "TLS: Out of memory generating fingerprint\n"); - } - -end: - av_bprint_finalize(&fingerprint, NULL); - return result; + return av_bprint_finalize(&buf, fingerprint); } int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint) @@ -190,15 +168,9 @@ int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t ke pkey_to_pem_string(pkey, key_buf, key_sz); cert_to_pem_string(cert, cert_buf, cert_sz); - /* Generate fingerprint. */ - if (fingerprint) { - *fingerprint = generate_fingerprint(cert); - if (!*fingerprint) { - av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint from %s\n", cert_url); - ret = AVERROR(EIO); - goto end; - } - } + ret = x509_fingerprint(cert, fingerprint); + if (ret < 0) + av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint from %s\n", cert_url); end: BIO_free(key_b); @@ -347,12 +319,9 @@ static int openssl_gen_certificate(EVP_PKEY *pkey, X509 **cert, char **fingerpri goto einval_end; } - if (fingerprint) { - *fingerprint = generate_fingerprint(*cert); - if (!*fingerprint) { - goto enomem_end; - } - } + ret = x509_fingerprint(*cert, fingerprint); + if (ret < 0) + goto end; goto end; enomem_end: From 50affd2b09ca7ebf6beb287a087947be887b2417 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Fri, 15 Aug 2025 19:49:19 +0200 Subject: [PATCH 12/22] avcodec/rv60dec: clear pu_info pu_info is read uninitialized on damaged input and at that point the following codepath is dependant on the uninitialized data. In one of these pathes out of array accesses happen. None of this is replicatable Less uninitialized data also should result in more reproducable reports Fixes: Use of uninitialized memory Fixes: 418335931/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_RV60_fuzzer-5103986067963904 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer --- libavcodec/rv60dec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavcodec/rv60dec.c b/libavcodec/rv60dec.c index 4a3d9067db..208fbc68f7 100644 --- a/libavcodec/rv60dec.c +++ b/libavcodec/rv60dec.c @@ -308,6 +308,8 @@ static int update_dimensions_clear_info(RV60Context *s, int width, int height) if ((ret = av_reallocp_array(&s->blk_info, s->blk_stride * (s->cu_height << 4), sizeof(s->blk_info[0]))) < 0) return ret; + memset(s->pu_info, 0, s->pu_stride * (s->cu_height << 3) * sizeof(s->pu_info[0])); + for (int j = 0; j < s->cu_height << 4; j++) for (int i = 0; i < s->cu_width << 4; i++) s->blk_info[j*s->blk_stride + i].mv.mvref = MVREF_NONE; From 37507c6a78ab63bbf8dda1c0525545d30877bca2 Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Mon, 21 Jul 2025 15:47:37 +0800 Subject: [PATCH 13/22] avformat/whip: remove DTLSState enum This patch aims to simplify the dtls handshake process since dtls handshake use force block mode We can just use the return code instead of DTLSState enum Signed-off-by: Jack Lau --- libavformat/tls.h | 15 ---------- libavformat/tls_openssl.c | 7 ----- libavformat/tls_schannel.c | 7 ----- libavformat/whip.c | 61 ++++++++------------------------------ 4 files changed, 13 insertions(+), 77 deletions(-) diff --git a/libavformat/tls.h b/libavformat/tls.h index 4d4999aa7c..2afa248f4c 100644 --- a/libavformat/tls.h +++ b/libavformat/tls.h @@ -34,17 +34,6 @@ */ #define MAX_CERTIFICATE_SIZE 8192 -enum DTLSState { - DTLS_STATE_NONE, - - /* Whether DTLS handshake is finished. */ - DTLS_STATE_FINISHED, - /* Whether DTLS session is closed. */ - DTLS_STATE_CLOSED, - /* Whether DTLS handshake is failed. */ - DTLS_STATE_FAILED, -}; - typedef struct TLSShared { char *ca_file; int verify; @@ -65,8 +54,6 @@ typedef struct TLSShared { int is_dtls; int use_srtp; - enum DTLSState state; - /* The certificate and private key content used for DTLS handshake */ char* cert_buf; char* key_buf; @@ -112,8 +99,6 @@ int ff_tls_set_external_socket(URLContext *h, URLContext *sock); int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz); -int ff_dtls_state(URLContext *h); - int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint); int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint); diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 0f2dbc8da6..db7147e491 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -476,12 +476,6 @@ int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t ma return 0; } -int ff_dtls_state(URLContext *h) -{ - TLSContext *c = h->priv_data; - return c->tls_shared.state; -} - static int print_ssl_error(URLContext *h, int ret) { TLSContext *c = h->priv_data; @@ -656,7 +650,6 @@ static int dtls_handshake(URLContext *h) goto end; ret = 0; - c->tls_shared.state = DTLS_STATE_FINISHED; end: return ret; } diff --git a/libavformat/tls_schannel.c b/libavformat/tls_schannel.c index b60e3100be..b854f484fa 100644 --- a/libavformat/tls_schannel.c +++ b/libavformat/tls_schannel.c @@ -681,12 +681,6 @@ int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t ma #endif } -int ff_dtls_state(URLContext *h) -{ - TLSContext *c = h->priv_data; - return c->tls_shared.state; -} - static void init_sec_buffer(SecBuffer *buffer, unsigned long type, void *data, unsigned long size) { @@ -1111,7 +1105,6 @@ static int tls_handshake(URLContext *h) #endif c->connected = 1; - s->state = DTLS_STATE_FINISHED; fail: return ret; diff --git a/libavformat/whip.c b/libavformat/whip.c index 65fd3b39b2..e2fa774c6f 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -198,9 +198,6 @@ typedef struct WHIPContext { /* The state of the RTC connection. */ enum WHIPState state; - /* The callback return value for DTLS. */ - int dtls_ret; - int dtls_closed; /* Parameters for the input audio and video codecs. */ AVCodecParameters *audio_par; @@ -348,41 +345,6 @@ static av_cold int certificate_key_init(AVFormatContext *s) return ret; } -/** - * When DTLS state change. - */ -static int dtls_context_on_state(AVFormatContext *s, const char* type, const char* desc) -{ - int ret = 0; - WHIPContext *whip = s->priv_data; - int state = ff_dtls_state(whip->dtls_uc); - - if (state == DTLS_STATE_CLOSED) { - whip->dtls_closed = 1; - av_log(whip, AV_LOG_VERBOSE, "DTLS session closed, type=%s, desc=%s, elapsed=%dms\n", - type ? type : "", desc ? desc : "", ELAPSED(whip->whip_starttime, av_gettime())); - goto error; - } - - if (state == DTLS_STATE_FAILED) { - whip->state = WHIP_STATE_FAILED; - av_log(whip, AV_LOG_ERROR, "DTLS session failed, type=%s, desc=%s\n", - type ? type : "", desc ? desc : ""); - whip->dtls_ret = AVERROR(EIO); - goto error; - } - - if (state == DTLS_STATE_FINISHED && whip->state < WHIP_STATE_DTLS_FINISHED) { - whip->state = WHIP_STATE_DTLS_FINISHED; - whip->whip_dtls_time = av_gettime(); - av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n", - ELAPSED(whip->whip_starttime, av_gettime())); - return ret; - } -error: - return -1; -} - static av_cold int dtls_initialize(AVFormatContext *s) { WHIPContext *whip = s->priv_data; @@ -1326,9 +1288,18 @@ next_packet: /* If got any DTLS messages, handle it. */ if (is_dtls_packet(whip->buf, ret) && whip->state >= WHIP_STATE_ICE_CONNECTED || whip->state == WHIP_STATE_DTLS_CONNECTING) { whip->state = WHIP_STATE_DTLS_CONNECTING; - if ((ret = ffurl_handshake(whip->dtls_uc)) < 0) + ret = ffurl_handshake(whip->dtls_uc); + if (ret < 0) { + whip->state = WHIP_STATE_FAILED; + av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n"); goto end; - dtls_context_on_state(s, NULL, NULL); + } + if (!ret) { + whip->state = WHIP_STATE_DTLS_FINISHED; + whip->whip_dtls_time = av_gettime(); + av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n", + ELAPSED(whip->whip_starttime, whip->whip_dtls_time)); + } goto next_packet; } } @@ -1771,10 +1742,8 @@ static av_cold int whip_init(AVFormatContext *s) goto end; end: - if (ret < 0 && whip->state < WHIP_STATE_FAILED) + if (ret < 0) whip->state = WHIP_STATE_FAILED; - if (ret >= 0 && whip->state >= WHIP_STATE_FAILED && whip->dtls_ret < 0) - ret = whip->dtls_ret; return ret; } @@ -1822,12 +1791,8 @@ static int whip_write_packet(AVFormatContext *s, AVPacket *pkt) } end: - if (ret < 0 && whip->state < WHIP_STATE_FAILED) + if (ret < 0) whip->state = WHIP_STATE_FAILED; - if (ret >= 0 && whip->state >= WHIP_STATE_FAILED && whip->dtls_ret < 0) - ret = whip->dtls_ret; - if (ret >= 0 && whip->dtls_closed) - ret = AVERROR(EIO); return ret; } From 30e695692041888d727159c6279f433540453c3f Mon Sep 17 00:00:00 2001 From: Leo Izen Date: Wed, 13 Aug 2025 22:54:04 -0400 Subject: [PATCH 14/22] .forgejo/CODEOWNERS: add myself to JPEG XL and PNG Add myself to JPEG XL and PNG decoders/encoders/parsers/etc. as a suggested reviewer. I'm the maintainer of the JXL files and I know the PNG code very well. Signed-off-by: Leo Izen --- .forgejo/CODEOWNERS | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS index a4ea6dd50f..0d310fb71f 100644 --- a/.forgejo/CODEOWNERS +++ b/.forgejo/CODEOWNERS @@ -20,9 +20,10 @@ libavcodec/.*ffv1.* @lynne @michaelni libavcodec/golomb.* @michaelni libavcodec/.*h266.* @frankplow @NuoMi @jianhuaw libavcodec/h26x/.* @frankplow @NuoMi @jianhuaw -libavcodec/.*jpegxl.* @lynne -libavcodec/.*jxl.* @lynne +libavcodec/.*jpegxl.* @lynne @Traneptora +libavcodec/.*jxl.* @lynne @Traneptora libavcodec/.*opus.* @lynne +libavcodec/.*png.* @Traneptora libavcodec/.*prores.* @lynne libavcodec/rangecoder.* @michaelni libavcodec/ratecontrol.* @michaelni @@ -45,6 +46,8 @@ libavfilter/vsrc_mandelbrot.* @michaelni # avformat # ======= libavformat/iamf.* @jamrial +libavformat/.*jpegxl.* @Traneptora +libavformat/.*jxl.* @Traneptora # avutil # ====== From 1d06e8ddcd8c14232d0a3c2b1c21e50b232549b4 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Fri, 15 Aug 2025 20:39:49 +0800 Subject: [PATCH 15/22] avfilter/af_whisper: fix broken output for multibyte character text + 1 can break a multibyte character, e.g., Chinese in UTF-8. There is no space at the beginning in this case. --- libavfilter/af_whisper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libavfilter/af_whisper.c b/libavfilter/af_whisper.c index 186b624504..bd145d6d1d 100644 --- a/libavfilter/af_whisper.c +++ b/libavfilter/af_whisper.c @@ -215,7 +215,9 @@ static void run_transcription(AVFilterContext *ctx, AVFrame *frame, int samples) for (int i = 0; i < n_segments; ++i) { const char *text = whisper_full_get_segment_text(wctx->ctx_wsp, i); - char *text_cleaned = av_strireplace(text + 1, "[BLANK_AUDIO]", ""); + if (av_isspace(text[0])) + text++; + char *text_cleaned = av_strireplace(text, "[BLANK_AUDIO]", ""); if (av_strnlen(text_cleaned, 1) == 0) { av_freep(&text_cleaned); From 7df92712723dee0ace3596684a90282c0e12a8ef Mon Sep 17 00:00:00 2001 From: Gyan Doshi Date: Sat, 16 Aug 2025 16:12:10 +0530 Subject: [PATCH 16/22] avfilter/whisper: correct option formatting --- libavfilter/af_whisper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libavfilter/af_whisper.c b/libavfilter/af_whisper.c index bd145d6d1d..385180b4ed 100644 --- a/libavfilter/af_whisper.c +++ b/libavfilter/af_whisper.c @@ -430,7 +430,8 @@ static int query_formats(const AVFilterContext *ctx, #define HOURS 3600000000 static const AVOption whisper_options[] = { - { "model", "Path to the whisper.cpp model file", OFFSET(model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, { "language", "Language for transcription ('auto' for auto-detect)", OFFSET(language), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS }, + { "model", "Path to the whisper.cpp model file", OFFSET(model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, + { "language", "Language for transcription ('auto' for auto-detect)", OFFSET(language), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS }, { "queue", "Audio queue size", OFFSET(queue), AV_OPT_TYPE_DURATION, {.i64 = 3000000}, 20000, HOURS, .flags = FLAGS }, { "use_gpu", "Use GPU for processing", OFFSET(use_gpu), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags = FLAGS }, { "gpu_device", "GPU device to use", OFFSET(gpu_device), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, .flags = FLAGS }, From a28e01a6c16430da689340d0af6eec094020b719 Mon Sep 17 00:00:00 2001 From: James Almer Date: Sat, 16 Aug 2025 14:16:38 -0300 Subject: [PATCH 17/22] avformat/mov: don't use an allocated array for sample_size with HEIF images The array is only ever needed for streams where each sample entry may have a different value. Given that for non animated HEIF there's a single value that applies to the image, use the field defined for that. Fixes: NULL pointer dereference Fixes: 437528618/clusterfuzz-testcase-minimized-ffmpeg_dem_MOV_fuzzer-6537287645331456 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: James Almer --- libavformat/mov.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index 86037c6712..b29c41a6b6 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -5456,10 +5456,6 @@ static int heif_add_stream(MOVContext *c, HEIFItem *item) if (!sc->chunk_offsets) goto fail; sc->chunk_count = 1; - sc->sample_sizes = av_malloc_array(1, sizeof(*sc->sample_sizes)); - if (!sc->sample_sizes) - goto fail; - sc->sample_count = 1; sc->stts_data = av_malloc_array(1, sizeof(*sc->stts_data)); if (!sc->stts_data) goto fail; @@ -10471,11 +10467,13 @@ static int mov_parse_heif_items(AVFormatContext *s) st->codecpar->width = item->width; st->codecpar->height = item->height; + sc->sample_size = sc->stsz_sample_size = item->extent_length; + sc->sample_count = 1; + err = sanity_checks(s, sc, item->item_id); - if (err || !sc->sample_count) + if (err) return AVERROR_INVALIDDATA; - sc->sample_sizes[0] = item->extent_length; sc->chunk_offsets[0] = item->extent_offset + offset; if (item->item_id == mov->primary_item_id) From a2cfaf1b916cd4519249031adc37e339baca7a7b Mon Sep 17 00:00:00 2001 From: James Almer Date: Sat, 16 Aug 2025 21:38:32 -0300 Subject: [PATCH 18/22] avformat/mov: pass stream index to sanity_checks on HEIF images Instead of item_id. Same behavior as with standard video tracks. Signed-off-by: James Almer --- libavformat/mov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index b29c41a6b6..e9a582e5aa 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -10470,7 +10470,7 @@ static int mov_parse_heif_items(AVFormatContext *s) sc->sample_size = sc->stsz_sample_size = item->extent_length; sc->sample_count = 1; - err = sanity_checks(s, sc, item->item_id); + err = sanity_checks(s, sc, st->index); if (err) return AVERROR_INVALIDDATA; From 134fbfd1dcb59441e38d870ddd231772f4e8e127 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Sun, 17 Aug 2025 15:31:48 +0200 Subject: [PATCH 19/22] avcodec/sanm: Check w,h,left,top The setup code fow w,h,left,top is complex, the code using it also falls in at least 2 different classes, one using left/top the other not. To ensure no out of array access happens we add this clear check. Fixes: out of array access Fixes: 439261995/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_SANM_fuzzer-5383455572819968 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer --- libavcodec/sanm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index a066a864eb..9e99aa9dd9 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -1757,6 +1757,11 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb) memset(ctx->fbuf, 0, ctx->frm0_size); } + if (w + FFMAX(left, 0) > ctx->avctx->width || h + FFMAX(top, 0) > ctx->avctx->height) { + avpriv_request_sample(ctx->avctx, "overly large frame\n"); + return AVERROR_PATCHWELCOME; + } + switch (codec) { case 1: case 3: From 8426622bb9584ec4fc32215f006a91e7ddc480cc Mon Sep 17 00:00:00 2001 From: Valerii Zapodovnikov Date: Mon, 4 Aug 2025 23:53:49 +0300 Subject: [PATCH 20/22] avformat/avio: clarify that AVSEEK_FORCE has no effect avio_seek() never supported SEEK_END and returned AVERROR(EINVAL) when specified, so the later check "(whence != SEEK_END || force)" was always true. This also means that AVSEEK_FORCE had no effect since 7a6fe01f99, that is 15 years ago. Rather than changing behaviour, let's document instead that the flag has no effect. Also fixed other commit 41ed7ab45f which confused ORing / passing AVSEEK_FORCE and AVSEEK_SIZE in the docs. Signed-off-by: Valerii Zapodovnikov --- libavformat/avio.h | 6 +++--- libavformat/aviobuf.c | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libavformat/avio.h b/libavformat/avio.h index ebf611187d..fbcb7dbfc3 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -461,17 +461,17 @@ int avio_put_str16be(AVIOContext *s, const char *str); void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type); /** - * ORing this as the "whence" parameter to a seek function causes it to + * Passing this as the "whence" parameter to a seek function causes it to * return the filesize without seeking anywhere. Supporting this is optional. * If it is not supported then the seek function will return <0. */ #define AVSEEK_SIZE 0x10000 /** - * Passing this flag as the "whence" parameter to a seek function causes it to + * OR'ing this flag into the "whence" parameter to a seek function causes it to * seek by any means (like reopening and linear reading) or other normally unreasonable * means that can be extremely slow. - * This may be ignored by the seek code. + * This is the default and therefore ignored by the seek code since 2010. */ #define AVSEEK_FORCE 0x20000 diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 34743556ae..2e65f50006 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -238,10 +238,9 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) FFIOContext *const ctx = ffiocontext(s); int64_t offset1; int64_t pos; - int force = whence & AVSEEK_FORCE; int buffer_size; int short_seek; - whence &= ~AVSEEK_FORCE; + whence &= ~AVSEEK_FORCE; // force flag does nothing if(!s) return AVERROR(EINVAL); @@ -282,8 +281,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) } else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) || offset1 <= buffer_size + short_seek) && !s->write_flag && offset1 >= 0 && - (!s->direct || !s->seek) && - (whence != SEEK_END || force)) { + (!s->direct || !s->seek)) { while(s->pos < offset && !s->eof_reached) fill_buffer(s); if (s->eof_reached) @@ -300,7 +298,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) s->pos = pos; s->eof_reached = 0; fill_buffer(s); - return avio_seek(s, offset, SEEK_SET | force); + return avio_seek(s, offset, SEEK_SET); } else { int64_t res; if (s->write_flag) { From 9b8d85a96fa0b1650b52ab914b2c70fc745e8f3a Mon Sep 17 00:00:00 2001 From: wrapper Date: Mon, 18 Aug 2025 15:49:02 +0700 Subject: [PATCH 21/22] check profiles --- libavcodec/libaac_nextenc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libavcodec/libaac_nextenc.c b/libavcodec/libaac_nextenc.c index c5b21f2095..8bc7fccb0f 100755 --- a/libavcodec/libaac_nextenc.c +++ b/libavcodec/libaac_nextenc.c @@ -26,13 +26,14 @@ #include -#include "libavcodec/defs.h" #include "libavutil/channel_layout.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/mem.h" #include "avcodec.h" +#include "defs.h" #include "audio_frame_queue.h" #include "codec_internal.h" #include "encode.h" @@ -116,6 +117,10 @@ static av_cold int libaac_encode_init(AVCodecContext *avctx) case AV_PROFILE_AAC_ELD: cfg.profile = AAC_ELD; break; + + default: + av_log(avctx, AV_LOG_ERROR, "unsupported profile, supported profiles are LC, HE, HEv2, LD and ELD\n"); + return AVERROR(EINVAL); } cfg.tns = s->tns; cfg.frameSize = s->frame_length; @@ -168,10 +173,9 @@ static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (!frame) { - int isFlush = s->encoder->in_buf_offset <= 0; - av_log(avctx, AV_LOG_TRACE, "frame_queue_count: %d, frame_queue_size: %d, in_buf: %d, is_flush: %d, flush_delay: %d\n", s->afq.frame_count, s->afq.remaining_samples, s->encoder->in_buf_offset, isFlush, s->flush_delay); + av_log(avctx, AV_LOG_TRACE, "flush_delay: %d\n", s->flush_delay); - if (isFlush && s->flush_delay <= 0) + if (s->flush_delay <= 0) return 0; /* Flushing */ @@ -180,8 +184,7 @@ static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return AVERROR(EINVAL); } - if (isFlush) - s->flush_delay -= avctx->frame_size; + s->flush_delay -= avctx->frame_size; } else { @@ -189,7 +192,7 @@ static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) return ret; - int encodeSize = (avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? 4 : 2) * avctx->ch_layout.nb_channels * frame->nb_samples; + int encodeSize = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels * frame->nb_samples; av_log(avctx, AV_LOG_TRACE, "encode size: %d\n", encodeSize); if ((ret = aac_encode(s->encoder, frame->data[0], encodeSize, pkt->data, (unsigned int *)&pkt->size)) < 0) From 0226b6fb2c0855eca417feb0a4e3bdf1f1193332 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 14 Aug 2025 00:21:09 +0200 Subject: [PATCH 22/22] avcodec/sanm: bl16: fix artifacts in larger videos The DOS/Windows decoder precomputes a table of linear offsets of all motion vectors given the current image width. For larger widths (>=762), the pairs starting at indices 1 and 254 of motion_vectors[] will overflow the int16_t, changing the sign. Playing back the 800x600 "jonesopn_8.snm" video of "Indiana Jones and the Infernal Machine" reveals a lot of artifacts and a lot of "Ignoring invalid motion vector (149, -41)->(136, 0), block size = 8" messages, hinting at the wrong direction of the motion vectors. Fix this by doing the calculation that the DOS/Windows players do, let the value overflow and reextract the "new" mvec x/y components. --- libavcodec/sanm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index 9e99aa9dd9..e4308af647 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -2074,6 +2074,20 @@ static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) mx = motion_vectors[opcode][0]; my = motion_vectors[opcode][1]; + /* The original implementation of this codec precomputes a table + * of int16_t all motion vectors for given image width. + * For larger widths, starting with 762 pixels, the calculation of + * mv table indices 1+ and 255- overflow the int16_t, inverting the + * sign of the offset. This is actively exploited in e.g. the + * "jonesopn_8.snm" video of "Indiana Jones and the Infernal Machine". + * Therefore let the overflow happen and extract x/y components from + * the new value. + */ + if (ctx->width > 761) { + index = (int16_t)(my * ctx->width + mx); + mx = index % ctx->width; + my = index / ctx->width; + } if (good_mvec(ctx, cx, cy, mx, my, blk_size)) { copy_block(ctx->frm0 + cx + ctx->pitch * cy, ctx->frm2 + cx + mx + ctx->pitch * (cy + my),