PR #22921 opened by breunigs URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22921 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22921.patch
fix ticket: 8636 video_keyframe_size and video_keyframe_pos tracked the end of the previous P/B frame. In the case of I-frame only videos, this would result in byteoffsets always being 0@0 in the case of fmp4. For mpegts, the size would be correct but the pos still always be @0. Since size and pos already correctly track the start of a segment, we can re-use them even in I-frame only mode. >From 182b4f0678e358a799d91021ba4148ebd3b2de05 Mon Sep 17 00:00:00 2001 From: Stefan Breunig <[email protected]> Date: Sun, 26 Apr 2026 09:19:44 +0200 Subject: [PATCH 1/3] avformat/hlsplaylist: fix byte offsets for single_file+iframes_only fix ticket: 8636 video_keyframe_size and video_keyframe_pos tracked the end of the previous P/B frame. In the case of I-frame only videos, this would result in byteoffsets always being 0@0 in the case of fmp4. For mpegts, the size would be correct but the pos still always be @0. Since size and pos already correctly track the start of a segment, we can re-use them even in I-frame only mode. --- libavformat/dashenc.c | 2 +- libavformat/hlsenc.c | 4 ++-- libavformat/hlsplaylist.c | 4 +--- libavformat/hlsplaylist.h | 1 - 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index da7725fc3f..a041de89c5 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -432,7 +432,7 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s, (double) seg->duration / timescale, 0, seg->range_length, seg->start_pos, NULL, c->single_file ? os->initfile : seg->file, - &prog_date_time, 0, 0, 0); + &prog_date_time, 0); if (ret < 0) { av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index de49c059d2..f4f69b9435 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1605,7 +1605,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) en->size, en->pos, hls->baseurl, en->filename, en->discont_program_date_time ? &en->discont_program_date_time : prog_date_time_p, - en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY); + hls->flags & HLS_I_FRAMES_ONLY); if (en->discont_program_date_time) en->discont_program_date_time -= en->duration; if (ret < 0) { @@ -1629,7 +1629,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) for (en = vs->segments; en; en = en->next) { ret = ff_hls_write_file_entry(hls->sub_m3u8_out, en->discont, byterange_mode, en->duration, 0, en->size, en->pos, - hls->baseurl, en->sub_filename, NULL, 0, 0, 0); + hls->baseurl, en->sub_filename, NULL, 0); if (ret < 0) { av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index 5c6a384d84..774bc5ac84 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -147,7 +147,6 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, int64_t pos /* Used only if HLS_SINGLE_FILE flag is set */, const char *baseurl /* Ignored if NULL */, const char *filename, double *prog_date_time, - int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode) { if (!out || !filename) @@ -161,8 +160,7 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, else avio_printf(out, "#EXTINF:%f,\n", duration); if (byterange_mode) - avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", iframe_mode ? video_keyframe_size : size, - iframe_mode ? video_keyframe_pos : pos); + avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", size, pos); if (prog_date_time) { time_t tt, wrongsecs; diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index ec44e5a0ae..a9f8bab263 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -58,7 +58,6 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, int64_t pos /* Used only if HLS_SINGLE_FILE flag is set */, const char *baseurl /* Ignored if NULL */, const char *filename, double *prog_date_time, - int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode); void ff_hls_write_end_list (AVIOContext *out); -- 2.52.0 >From f55e9518fb3d7b2d3290db0f21d8b966edcc662a Mon Sep 17 00:00:00 2001 From: Stefan Breunig <[email protected]> Date: Sun, 26 Apr 2026 09:25:02 +0200 Subject: [PATCH 2/3] avformat/hlsenc: clean up unused keyframe tracking variables --- libavformat/hlsenc.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index f4f69b9435..229c148821 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -80,8 +80,6 @@ typedef struct HLSSegment { int discont; int64_t pos; int64_t size; - int64_t keyframe_pos; - int64_t keyframe_size; unsigned var_stream_idx; char key_uri[LINE_BUFFER_SIZE + 1]; @@ -139,8 +137,6 @@ typedef struct VariantStream { int64_t start_pts; int64_t end_pts; int64_t video_lastpos; - int64_t video_keyframe_pos; - int64_t video_keyframe_size; double duration; // last segment duration computed so far, in seconds int64_t start_pos; // last segment starting position int64_t size; // last segment size @@ -1079,8 +1075,6 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, en->duration = duration; en->pos = pos; en->size = size; - en->keyframe_pos = vs->video_keyframe_pos; - en->keyframe_size = vs->video_keyframe_size; en->next = NULL; en->discont = 0; en->discont_program_date_time = 0; @@ -2664,12 +2658,6 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) vs->packets_written++; if (oc->pb) { ret = ff_write_chained(oc, stream_index, pkt, s, 0); - vs->video_keyframe_size += pkt->size; - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) { - vs->video_keyframe_size = avio_tell(oc->pb); - } else { - vs->video_keyframe_pos = avio_tell(vs->out); - } if (hls->ignore_io_errors) ret = 0; } -- 2.52.0 >From 838c56ab57239141af01de7666c620c543e16b67 Mon Sep 17 00:00:00 2001 From: Stefan Breunig <[email protected]> Date: Sat, 25 Apr 2026 17:25:19 +0200 Subject: [PATCH 3/3] fate/hls: add byterange tests for iframe_only+single_file playlists --- tests/fate/hlsenc.mak | 28 ++++++++++++++++++++++++ tests/ref/fate/hls-iframes-single-fmp4 | 4 ++++ tests/ref/fate/hls-iframes-single-mpegts | 3 +++ 3 files changed, 35 insertions(+) create mode 100644 tests/ref/fate/hls-iframes-single-fmp4 create mode 100644 tests/ref/fate/hls-iframes-single-mpegts diff --git a/tests/fate/hlsenc.mak b/tests/fate/hlsenc.mak index b71fe219a6..421d6d0a74 100644 --- a/tests/fate/hlsenc.mak +++ b/tests/fate/hlsenc.mak @@ -224,6 +224,34 @@ 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 +tests/data/hls_iframes_single_mpegts.m3u8: TAG = GEN +tests/data/hls_iframes_single_mpegts.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \ + -f lavfi -i "testsrc2=size=128x72:rate=1:d=3" -f hls -hls_time 1 -map 0:v \ + -hls_list_size 0 -c:v mpeg2video -g 1 -flags +bitexact \ + -hls_segment_type mpegts -hls_flags iframes_only+single_file \ + -hls_segment_filename /dev/null \ + $(TARGET_PATH)/tests/data/hls_iframes_single_mpegts.m3u8 2>/dev/null + +FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-iframes-single-mpegts +fate-hls-iframes-single-mpegts: tests/data/hls_iframes_single_mpegts.m3u8 +fate-hls-iframes-single-mpegts: CMD = sed -n -e /^\#EXT-X-BYTERANGE:/p $(TARGET_PATH)/tests/data/hls_iframes_single_mpegts.m3u8 +fate-hls-iframes-single-mpegts: CMP = diff + +tests/data/hls_iframes_single_fmp4.m3u8: TAG = GEN +tests/data/hls_iframes_single_fmp4.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \ + -f lavfi -i "testsrc2=size=128x72:rate=1:d=3" -f hls -hls_time 1 -map 0:v \ + -hls_list_size 0 -c:v mpeg2video -g 1 -flags +bitexact \ + -hls_segment_type fmp4 -hls_flags iframes_only+single_file \ + -hls_segment_filename /dev/null \ + $(TARGET_PATH)/tests/data/hls_iframes_single_fmp4.m3u8 2>/dev/null + +FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MOV_MUXER FILE_PROTOCOL) += fate-hls-iframes-single-fmp4 +fate-hls-iframes-single-fmp4: tests/data/hls_iframes_single_fmp4.m3u8 +fate-hls-iframes-single-fmp4: CMD = sed -n -e /^\#EXT-X-MAP:/p -e /^\#EXT-X-BYTERANGE:/p $(TARGET_PATH)/tests/data/hls_iframes_single_fmp4.m3u8 +fate-hls-iframes-single-fmp4: 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-iframes-single-fmp4 b/tests/ref/fate/hls-iframes-single-fmp4 new file mode 100644 index 0000000000..69ddda8bbe --- /dev/null +++ b/tests/ref/fate/hls-iframes-single-fmp4 @@ -0,0 +1,4 @@ +#EXT-X-MAP:URI="null",BYTERANGE="847@0" +#EXT-X-BYTERANGE:4077@847 +#EXT-X-BYTERANGE:5584@4924 +#EXT-X-BYTERANGE:5723@10508 \ No newline at end of file diff --git a/tests/ref/fate/hls-iframes-single-mpegts b/tests/ref/fate/hls-iframes-single-mpegts new file mode 100644 index 0000000000..61bd280941 --- /dev/null +++ b/tests/ref/fate/hls-iframes-single-mpegts @@ -0,0 +1,3 @@ +#EXT-X-BYTERANGE:4700@0 +#EXT-X-BYTERANGE:6204@4700 +#EXT-X-BYTERANGE:6392@10904 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
