PR #23400 opened by u6bkep
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23400
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23400.patch

Follow-up to #22726 (merged as 45cb56c520), which fixed segment-duration
calculation in the HLS muxer when streams have different time bases.

In the review of that PR, the suggestion was made to add a regression test:

> if you respin this, please consider adding a regression test. The current
> HLS FATE coverage in `tests/fate/hlsenc.mak` exercises a number of HLS cases,
> including fMP4, but I did not find a mixed audio+video / mixed-time-base
> segment-splitting case there. [...] reducing it to a portable lavfi-only FATE
> case would make this much harder to regress later.

This adds that test, `fate-hls-mixed-timebase`, using lavfi-only input (no
external samples required).

## What it does

The test reproduces the exact scenario the fix addressed:

1. Generate an mpegts source where the audio stream (`1/48000`) starts 0.5s
   before the video stream and timestamps carry a large offset
   (`-output_ts_offset 3600`), so `vs->start_pts` is captured from an audio
   packet and is non-zero.
2. HLS-mux it with **video passthrough** (`-c:v copy`, time base `1/90000`) +
   **audio transcode** (`-c:a aac`, time base `1/48000`) into fMP4 segments at
   `-hls_time 3` - the real-world Blu-ray-remux case from the original report.
3. Assert the resulting `#EXTINF` durations via `sed`/`diff`.

## Why this guards the fix

Before the fix, `vs->start_pts` was stored in audio ticks and then subtracted
from video PTS without time-base conversion. The cross-time-base elapsed value
overflowed `-hls_time`, so every keyframe forced a new segment.

Verified against both states of `libavformat/hlsenc.c`:

| build                 | `#EXTINF` output                                      
  |
| --------------------- | 
------------------------------------------------------- |
| with fix (HEAD)       | `3.000000`, `3.000000`, `3.000000`, `1.000000` - 
passes |
| fix reverted (HEAD~1) | 10 * `1.000000` - test fails                          
 |

The full lavfi-only `hlsenc` FATE group still passes.


>From c0a9f5308fd40dda0d1d81d392e824145225b331 Mon Sep 17 00:00:00 2001
From: Ben Kepner <[email protected]>
Date: Sun, 7 Jun 2026 15:20:00 -0400
Subject: [PATCH] tests/fate/hlsenc: add regression test for mixed stream time
 base segmenting

Follow-up to 45cb56c520 ("avformat/hlsenc: fix segment duration with
mixed stream time bases"), adding the regression test requested in
review.

The test generates an mpegts source where audio (1/48000) starts before
video and timestamps carry a large offset, then HLS-muxes it with video
passthrough (1/90000) and audio transcode (1/48000) into fmp4 segments
at -hls_time 3, asserting the resulting EXTINF durations. Input is
lavfi-only, so no external samples are required.

Without the fix, vs->start_pts is captured from the audio packet in
audio ticks and subtracted from video PTS without conversion, so every
keyframe forces a new segment (ten 1s segments instead of ~3s). The test
fails on the pre-fix code and passes with the fix in place.

Signed-off-by: Ben Kepner <[email protected]>
---
 tests/fate/hlsenc.mak             | 25 +++++++++++++++++++++++++
 tests/ref/fate/hls-mixed-timebase |  4 ++++
 2 files changed, 29 insertions(+)
 create mode 100644 tests/ref/fate/hls-mixed-timebase

diff --git a/tests/fate/hlsenc.mak b/tests/fate/hlsenc.mak
index b71fe219a6..7fd407a2d7 100644
--- a/tests/fate/hlsenc.mak
+++ b/tests/fate/hlsenc.mak
@@ -224,6 +224,31 @@ fate-hls-start-number: tests/data/hls_start_number.m3u8
 fate-hls-start-number: CMD = sed -n -e /^\#EXT-X-MEDIA-SEQUENCE:/p -e 
/^[^\#]/p $(TARGET_PATH)/tests/data/hls_start_number.m3u8
 fate-hls-start-number: CMP = diff
 
+# This tests that the HLS muxer splits segments at the right points when the
+# audio and video streams have different time bases (1/48000 and 1/90000) and
+# the first packet seen is audio. The source is built so audio precedes video
+# with a large timestamp offset; the EXTINF durations must honour -hls_time
+# rather than splitting on every keyframe.
+tests/data/hls_mixed_timebase.m3u8: TAG = GEN
+tests/data/hls_mixed_timebase.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
+       $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \
+       -f lavfi -i "sine=frequency=440:duration=11:sample_rate=48000" \
+       -itsoffset 0.5 -f lavfi -i "testsrc2=size=128x72:rate=24:d=10" \
+       -c:v mpeg2video -g 24 -c:a mp2 -b:a 128k -output_ts_offset 3600 \
+       -flags +bitexact -f mpegts 
$(TARGET_PATH)/tests/data/hls_mixed_timebase_src.ts 2>/dev/null && \
+       $(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin -copyts \
+       -i $(TARGET_PATH)/tests/data/hls_mixed_timebase_src.ts \
+       -c:v copy -c:a aac -b:a 128k -flags +bitexact \
+       -hls_segment_type fmp4 -hls_fmp4_init_filename 
hls_mixed_timebase_init.mp4 \
+       -f hls -hls_time 3 -hls_list_size 0 -hls_playlist_type vod \
+       -hls_segment_filename 
$(TARGET_PATH)/tests/data/hls_mixed_timebase_%d.m4s \
+       $(TARGET_PATH)/tests/data/hls_mixed_timebase.m3u8 2>/dev/null
+
+FATE_HLSENC_LAVFI-$(call ALLYES, SINE_FILTER TESTSRC2_FILTER LAVFI_INDEV 
MPEG2VIDEO_ENCODER MP2_ENCODER MP2_DECODER AAC_ENCODER HLS_MUXER MP4_MUXER 
MPEGTS_MUXER MPEGTS_DEMUXER FILE_PROTOCOL) += fate-hls-mixed-timebase
+fate-hls-mixed-timebase: tests/data/hls_mixed_timebase.m3u8
+fate-hls-mixed-timebase: CMD = sed -n -e /^\#EXTINF:/p 
$(TARGET_PATH)/tests/data/hls_mixed_timebase.m3u8
+fate-hls-mixed-timebase: CMP = diff
+
 FATE_HLSENC_LAVFI-yes := $(if $(call FRAMECRC), $(FATE_HLSENC_LAVFI-yes))
 
 FATE_FFMPEG += $(FATE_HLSENC_LAVFI-yes)
diff --git a/tests/ref/fate/hls-mixed-timebase 
b/tests/ref/fate/hls-mixed-timebase
new file mode 100644
index 0000000000..e9560c65c6
--- /dev/null
+++ b/tests/ref/fate/hls-mixed-timebase
@@ -0,0 +1,4 @@
+#EXTINF:3.000000,
+#EXTINF:3.000000,
+#EXTINF:3.000000,
+#EXTINF:1.000000,
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to