[FFmpeg-devel] [PATCH] avformat/hlsenc: refine EXT-X-BYTERANGE support for segments

Steven Liu lingjiujianke at gmail.com
Mon Sep 12 10:01:24 EEST 2016


refine EXT-X-BYTERANGE tag,
the spec link:
https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-4.3.2.2

the apple doc:
https://developer.apple.com/library/ios/technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238-CH1-BYTE_RANGE_SUPPORT_FOR_SEGMENTS

command line:
./ffmpeg -i ~/Movies/objectC/a.mp4 -c copy -f hls -hls_time 7
-hls_list_size 100 -hls_segment_size 2500000 -t 40 output-test.m3u8

output:

localhost:ffmpeg liuqi$ ll *.ts ;cat output-test.m3u8
-rw-r--r--  1 liuqi  staff  2792176  9 12 14:44 output-test0.ts
-rw-r--r--  1 liuqi  staff  3112528  9 12 14:44 output-test3.ts
-rw-r--r--  1 liuqi  staff  3377420  9 12 14:44 output-test6.ts
-rw-r--r--  1 liuqi  staff  1228016  9 12 14:44 output-test7.ts
 #EXTM3U
 #EXT-X-VERSION:4
 #EXT-X-TARGETDURATION:10
 #EXT-X-MEDIA-SEQUENCE:0
 #EXTINF:9.021000,
 #EXT-X-BYTERANGE:1334988 at 0
 output-test0.ts
 #EXTINF:3.000000,
 #EXT-X-BYTERANGE:721356 at 1334988
 output-test0.ts
 #EXTINF:3.000000,
 #EXT-X-BYTERANGE:735832 at 2056344
 output-test0.ts
 #EXTINF:6.000000,
 #EXT-X-BYTERANGE:1645940 at 0
 output-test3.ts
 #EXTINF:3.000000,
 #EXT-X-BYTERANGE:715152 at 1645940
 output-test3.ts
 #EXTINF:3.000000,
 #EXT-X-BYTERANGE:751436 at 2361092
 output-test3.ts
 #EXTINF:9.000000,
 #EXT-X-BYTERANGE:3377420 at 0
 output-test6.ts
 #EXTINF:3.960000,
 #EXT-X-BYTERANGE:1228016 at 0
 output-test7.ts
 #EXT-X-ENDLIST
 localhost:ffmpeg liuqi$

 ticket-id: #5839

Signed-off-by: Steven Liu <lingjiujianke at gmail.com>
---
 libavformat/hlsenc.c | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index a376312..08995f6 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -104,6 +104,7 @@ typedef struct HLSContext {
     double duration;      // last segment duration computed so far, in
seconds
     int64_t start_pos;    // last segment starting position
     int64_t size;         // last segment size
+     int64_t max_seg_size; // every segment file max size
     int nb_entries;
     int discontinuity_set;

@@ -476,7 +477,7 @@ static int hls_window(AVFormatContext *s, int last)
     AVIOContext *sub_out = NULL;
     char temp_filename[1024];
     int64_t sequence = FFMAX(hls->start_sequence, hls->sequence -
hls->nb_entries);
-    int version = hls->flags & HLS_SINGLE_FILE ? 4 : 3;
+    int version = 0;
     const char *proto = avio_find_protocol_name(s->filename);
     int use_rename = proto && !strcmp(proto, "file");
     static unsigned warned_non_file;
@@ -485,6 +486,12 @@ static int hls_window(AVFormatContext *s, int last)
     AVDictionary *options = NULL;
     double prog_date_time = hls->initial_prog_date_time;

+    if (hls->flags & (HLS_SINGLE_FILE) || hls->max_seg_size > 0) {
+        version = 4;
+    } else {
+        version = 3;
+    }
+
     if (!use_rename && !warned_non_file++)
         av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol,
this may lead to races and temporarly partial files\n");

@@ -533,7 +540,8 @@ static int hls_window(AVFormatContext *s, int last)
             avio_printf(out, "#EXTINF:%ld,\n",  lrint(en->duration));
         else
             avio_printf(out, "#EXTINF:%f,\n", en->duration);
-        if (hls->flags & HLS_SINGLE_FILE)
+        if (hls->flags & HLS_SINGLE_FILE ||
+            hls->max_seg_size > 0)
              avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
                          en->size, en->pos);
         if (hls->flags & HLS_PROGRAM_DATE_TIME) {
@@ -573,7 +581,8 @@ static int hls_window(AVFormatContext *s, int last)

         for (en = hls->segments; en; en = en->next) {
             avio_printf(sub_out, "#EXTINF:%f,\n", en->duration);
-            if (hls->flags & HLS_SINGLE_FILE)
+            if (hls->flags & HLS_SINGLE_FILE ||
+                hls->max_seg_size > 0)
                  avio_printf(sub_out,
"#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
                          en->size, en->pos);
             if (hls->baseurl)
@@ -610,7 +619,14 @@ static int hls_start(AVFormatContext *s)
         if (c->vtt_basename)
             av_strlcpy(vtt_oc->filename, c->vtt_basename,
                   sizeof(vtt_oc->filename));
-    } else {
+    } else if (c->max_seg_size > 0) {
+        if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
+            c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
+            AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
+                av_log(oc, AV_LOG_ERROR, "Invalid segment filename
template '%s' you can try use -use_localtime 1 with it\n", c->basename);
+                return AVERROR(EINVAL);
+        }
+    } else {
         if (c->use_localtime) {
             time_t now0;
             struct tm *tm, tmpbuf;
@@ -943,7 +959,18 @@ static int hls_write_packet(AVFormatContext *s,
AVPacket *pkt)
             if (hls->avf->oformat->priv_class && hls->avf->priv_data)
                 av_opt_set(hls->avf->priv_data, "mpegts_flags",
"resend_headers", 0);
             hls->number++;
-        } else {
+        } else if (hls->max_seg_size > 0) {
+            if (hls->avf->oformat->priv_class && hls->avf->priv_data)
+                av_opt_set(hls->avf->priv_data, "mpegts_flags",
"resend_headers", 0);
+            if (hls->start_pos >= hls->max_seg_size ) {
+                ff_format_io_close(s, &oc->pb);
+                if (hls->vtt_avf)
+                    ff_format_io_close(s, &hls->vtt_avf->pb);
+                ret = hls_start(s);
+                hls->start_pos = 0;
+                hls->number++;
+            }
+        } else {
             ff_format_io_close(s, &oc->pb);
             if (hls->vtt_avf)
                 ff_format_io_close(s, &hls->vtt_avf->pb);
@@ -1020,6 +1047,7 @@ static const AVOption options[] = {
     {"hls_key_info_file",    "file with key URI and key file path",
OFFSET(key_info_file),      AV_OPT_TYPE_STRING, {.str = NULL},
 0,       0,         E},
     {"hls_subtitle_path",     "set path of hls subtitles",
OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,    E},
     {"hls_flags",     "set flags affecting HLS playlist and media file
generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E,
"flags"},
+    {"hls_segment_size", "set maximum size per segment file, (Byte)",
 OFFSET(max_seg_size),    AV_OPT_TYPE_INT,    {.i64 = 0},     0, INT_MAX,
E},
     {"single_file",   "generate a single media file indexed with byte
ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX,   E,
"flags"},
     {"delete_segments", "delete segment files that are no longer part of
the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0,
UINT_MAX,   E, "flags"},
     {"round_durations", "round durations in m3u8 to whole numbers", 0,
AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX,   E,
"flags"},
--
2.7.4 (Apple Git-66)


More information about the ffmpeg-devel mailing list