This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit b5bfb7716c4914efdccbc3b507a77d676616be51 Author: James Almer <[email protected]> AuthorDate: Mon Jun 29 19:24:39 2026 -0300 Commit: James Almer <[email protected]> CommitDate: Thu Jul 2 17:53:20 2026 -0300 avcodec/ac3enc: drain the buffered samples at the end of encoding When encoding a stream with an amount of samples multiple of a block, the last the last 256 samples would be lost as the encoders were not marked as AV_CODEC_CAP_DELAY. This can be easily reproduced with: ffmpeg -f lavfi -i sine -ac 2 -af atrim=start_sample=0:end_sample=4608 -c:a eac3 -f framecrc - Signed-off-by: James Almer <[email protected]> --- libavcodec/ac3enc.c | 35 ++++++++++++++++++++++++++++++++--- libavcodec/ac3enc.h | 6 +++++- libavcodec/ac3enc_fixed.c | 3 ++- libavcodec/ac3enc_float.c | 3 ++- libavcodec/ac3enc_template.c | 24 +++++++++++++++++++++++- libavcodec/eac3enc.c | 3 ++- tests/fate/ac3.mak | 12 ++++-------- tests/ref/fate/ac3-fixed-encode-2 | 1 + tests/ref/fate/shortest | 1 + 9 files changed, 72 insertions(+), 16 deletions(-) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 5a1a3ab63a..69744989ba 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -1982,8 +1982,19 @@ int ff_ac3_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { AC3EncodeContext *const s = avctx->priv_data; + int discard_padding; int ret; + /* add current frame to queue */ + if (frame) { + ret = ff_af_queue_add(&s->afq, frame); + if (ret < 0) + return ret; + } else { + if (!s->afq.remaining_samples || (!s->afq.frame_alloc && !s->afq.frame_count)) + return 0; + } + if (s->options.allow_per_frame_metadata) { ret = ac3_validate_metadata(s); if (ret) @@ -1993,7 +2004,7 @@ int ff_ac3_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, if (s->bit_alloc.sr_code == 1 || s->eac3) ac3_adjust_frame_size(s); - s->encode_frame(s, frame->extended_data); + s->encode_frame(s, frame); ac3_apply_rematrixing(s); @@ -2014,8 +2025,17 @@ int ff_ac3_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, return ret; ac3_output_frame(s, avpkt->data); - if (frame->pts != AV_NOPTS_VALUE) - avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); + ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, + &avpkt->duration); + + discard_padding = avctx->frame_size - ff_samples_from_time_base(avctx, avpkt->duration); + if (discard_padding > 0) { + uint8_t *side_data = + av_packet_new_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (!side_data) + return AVERROR(ENOMEM); + AV_WL32(side_data + 4, discard_padding); + } *got_packet_ptr = 1; return 0; @@ -2157,6 +2177,7 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) for (int ch = 0; ch < s->channels; ch++) av_freep(&s->planar_samples[ch]); + av_freep(&s->input_samples[0]); av_freep(&s->bap_buffer); av_freep(&s->bap1_buffer); av_freep(&s->mdct_coef_buffer); @@ -2170,6 +2191,7 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) av_freep(&s->cpl_coord_buffer); av_freep(&s->fdsp); + ff_af_queue_close(&s->afq); av_tx_uninit(&s->tx); return 0; @@ -2419,6 +2441,11 @@ static av_cold int allocate_buffers(AC3EncodeContext *s) if (!s->planar_samples[ch]) return AVERROR(ENOMEM); } + int ret = av_samples_alloc(s->input_samples, NULL, s->channels, + AC3_BLOCK_SIZE * s->num_blocks, + s->avctx->sample_fmt, 0); + if (ret < 0) + return ret; if (!FF_ALLOC_TYPED_ARRAY(s->bap_buffer, total_coefs) || !FF_ALLOC_TYPED_ARRAY(s->bap1_buffer, total_coefs) || @@ -2516,6 +2543,8 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) dprint_options(s); + ff_af_queue_init(avctx, &s->afq); + ff_thread_once(&init_static_once, exponent_init); return 0; diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h index 5e98ad188b..3e92af17f0 100644 --- a/libavcodec/ac3enc.h +++ b/libavcodec/ac3enc.h @@ -37,6 +37,7 @@ #include "ac3.h" #include "ac3defs.h" #include "ac3dsp.h" +#include "audio_frame_queue.h" #include "avcodec.h" #include "codec_internal.h" #include "mathops.h" @@ -233,6 +234,7 @@ typedef struct AC3EncodeContext { int exponent_bits; ///< number of bits used for exponents uint8_t *planar_samples[AC3_MAX_CHANNELS - 1]; + uint8_t *input_samples[AC3_MAX_CHANNELS - 1]; uint8_t *bap_buffer; uint8_t *bap1_buffer; CoefType *mdct_coef_buffer; @@ -252,8 +254,10 @@ typedef struct AC3EncodeContext { uint8_t *ref_bap [AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< bit allocation pointers (bap) int ref_bap_set; ///< indicates if ref_bap pointers have been set + AudioFrameQueue afq; + /** fixed vs. float function pointers */ - void (*encode_frame)(struct AC3EncodeContext *s, uint8_t * const *samples); + void (*encode_frame)(struct AC3EncodeContext *s, const AVFrame *frame); /* AC-3 vs. E-AC-3 function pointers */ void (*output_frame_header)(struct AC3EncodeContext *s, struct PutBitContext *pb); diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index 42530b0ea1..876bb6bbc6 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -114,7 +114,8 @@ const FFCodec ff_ac3_fixed_encoder = { CODEC_LONG_NAME("ATSC A/52A (AC-3)"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_AC3, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(AC3EncodeContext), .init = ac3_fixed_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 0ae7ddd7eb..974c38ac25 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -116,7 +116,8 @@ const FFCodec ff_ac3_encoder = { CODEC_LONG_NAME("ATSC A/52A (AC-3)"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_AC3, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(AC3EncodeContext), .init = ff_ac3_float_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index 049666fdca..5331b45cb9 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -346,9 +346,31 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s) } } +static void copy_input_samples(AC3EncodeContext *s, const AVFrame *frame) +{ + int end = frame ? frame->nb_samples : 0; + + /* copy new samples and zero any remaining samples */ + if (frame) { + av_samples_copy(s->input_samples, frame->extended_data, 0, 0, + frame->nb_samples, s->channels, + s->avctx->sample_fmt); + } + av_samples_set_silence(s->input_samples, end, + s->avctx->frame_size - end, + s->channels, s->avctx->sample_fmt); +} -static void encode_frame(AC3EncodeContext *s, uint8_t * const *samples) +static void encode_frame(AC3EncodeContext *s, const AVFrame *frame) { + uint8_t **samples; + + if (!frame || frame->nb_samples < s->avctx->frame_size) { + copy_input_samples(s, frame); + samples = s->input_samples; + } else + samples = frame->extended_data; + apply_mdct(s, samples); s->cpl_on = s->cpl_enabled; diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c index 10b1ab337c..7a678b518c 100644 --- a/libavcodec/eac3enc.c +++ b/libavcodec/eac3enc.c @@ -270,7 +270,8 @@ const FFCodec ff_eac3_encoder = { CODEC_LONG_NAME("ATSC A/52 E-AC-3"), .p.type = AVMEDIA_TYPE_AUDIO, .p.id = AV_CODEC_ID_EAC3, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(AC3EncodeContext), .init = eac3_encode_init, FF_CODEC_ENCODE_CB(ff_ac3_encode_frame), diff --git a/tests/fate/ac3.mak b/tests/fate/ac3.mak index 9f655c3ff4..362671ed91 100644 --- a/tests/fate/ac3.mak +++ b/tests/fate/ac3.mak @@ -68,18 +68,14 @@ $(FATE_AC3) $(FATE_EAC3): CMP = oneoff FATE_AC3-$(call PCM, AC3, AC3 AC3_FIXED, PCM_S16LE_MUXER ARESAMPLE_FILTER) += $(FATE_AC3) FATE_EAC3-$(call PCM, EAC3, EAC3, PCM_S16LE_MUXER ARESAMPLE_FILTER) += $(FATE_EAC3) -FATE_AC3-$(call ENCDEC, AC3, AC3, WAV_MUXER WAV_DEMUXER ARESAMPLE_FILTER PCM_S16LE_ENCODER PIPE_PROTOCOL) += fate-ac3-encode -fate-ac3-encode: CMD = enc_dec_pcm ac3 wav s16le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c:a ac3 -b:a 128k -fate-ac3-encode: CMP_SHIFT = -1024 +FATE_AC3-$(call ENCDEC, AC3, MP4 MOV, WAV_MUXER WAV_DEMUXER ARESAMPLE_FILTER PCM_S16LE_ENCODER PIPE_PROTOCOL) += fate-ac3-encode +fate-ac3-encode: CMD = enc_dec_pcm mp4 wav s16le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c:a ac3 -b:a 128k fate-ac3-encode: CMP_TARGET = 404.53 -fate-ac3-encode: SIZE_TOLERANCE = 488 -FATE_EAC3-$(call ENCDEC, EAC3, EAC3, WAV_MUXER WAV_DEMUXER ARESAMPLE_FILTER PCM_S16LE_ENCODER PIPE_PROTOCOL) += fate-eac3-encode -fate-eac3-encode: CMD = enc_dec_pcm eac3 wav s16le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c:a eac3 -b:a 128k -fate-eac3-encode: CMP_SHIFT = -1024 +FATE_EAC3-$(call ENCDEC, EAC3, MP4 MOV, WAV_MUXER WAV_DEMUXER ARESAMPLE_FILTER PCM_S16LE_ENCODER PIPE_PROTOCOL) += fate-eac3-encode +fate-eac3-encode: CMD = enc_dec_pcm mp4 wav s16le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c:a eac3 -b:a 128k fate-eac3-encode: CMP_TARGET = 516.94 -fate-eac3-encode: SIZE_TOLERANCE = 488 fate-ac3-encode fate-eac3-encode: CMP = stddev fate-ac3-encode fate-eac3-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav diff --git a/tests/ref/fate/ac3-fixed-encode-2 b/tests/ref/fate/ac3-fixed-encode-2 index 8e945b6637..468441cd7e 100644 --- a/tests/ref/fate/ac3-fixed-encode-2 +++ b/tests/ref/fate/ac3-fixed-encode-2 @@ -11,3 +11,4 @@ 0, 7424, 7424, 1536, 1114, 0xfbcc27ad 0, 8960, 8960, 1536, 1114, 0xe7ed3321 0, 10496, 10496, 1536, 1114, 0xa1823473 +0, 12032, 12032, 256, 1116, 0x7cc628e3, S=1, Skip Samples, 10, 0x00190005 diff --git a/tests/ref/fate/shortest b/tests/ref/fate/shortest index 3592b3f1f0..68d1038b71 100644 --- a/tests/ref/fate/shortest +++ b/tests/ref/fate/shortest @@ -115,3 +115,4 @@ 0, 48, 48, 1, 28143, 0x1df268c5, S=1, Quality stats, 8, 0x050000a1 1, 85760, 85760, 1536, 418, 0xae06ca91 0, 49, 49, 1, 10073, 0xedb9f031, F=0x0, S=1, Quality stats, 8, 0x050400a2 +1, 87296, 87296, 256, 418, 0x0a0bdddc, S=1, Skip Samples, 10, 0x00190005 _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
