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]

Reply via email to