[FFmpeg-devel,v2] avformat/hlsenc: support fmp4 single file mode

Submitted by Steven Liu on Aug. 1, 2017, 3:57 p.m.

Details

Message ID 20170801155703.29117-1-lq@chinaffmpeg.org
State New
Headers show

Commit Message

Steven Liu Aug. 1, 2017, 3:57 p.m.
add byterange mode of the hls fmp4

Signed-off-by: Steven Liu <lq@onvideo.cn>
---
 libavformat/hlsenc.c | 83 +++++++++++++++++++++++++++++++++-------------------
 1 file changed, 53 insertions(+), 30 deletions(-)

Comments

Derek Buitenhuis Aug. 4, 2017, 12:49 p.m.
On 8/1/2017 4:57 PM, Steven Liu wrote:
> add byterange mode of the hls fmp4
> 
> Signed-off-by: Steven Liu <lq@onvideo.cn>
> ---
>  libavformat/hlsenc.c | 83 +++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 53 insertions(+), 30 deletions(-)

[...]

> +        if (hls->max_seg_size > 0) {
> +            av_log(s, AV_LOG_WARNING, "Have not support multiple fmp4 byterange mode file in hls yet now\n");
> +            return AVERROR_PATCHWELCOME;
> +        }

Not entirely sure what this message is trying to say?

Is this accurate: "Multi-file byterange moe is currently unsupported in the HLS muxer." ?

> -    int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
> +    int byterange_mode = ((hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0));

Doesn't change anything, as far as I can tell?

Rest is OK, I think.

- Derek
Steven Liu Aug. 4, 2017, 1:33 p.m.
2017-08-04 20:49 GMT+08:00 Derek Buitenhuis <derek.buitenhuis@gmail.com>:
> On 8/1/2017 4:57 PM, Steven Liu wrote:
>> add byterange mode of the hls fmp4
>>
>> Signed-off-by: Steven Liu <lq@onvideo.cn>
>> ---
>>  libavformat/hlsenc.c | 83 +++++++++++++++++++++++++++++++++-------------------
>>  1 file changed, 53 insertions(+), 30 deletions(-)
>
> [...]
>
>> +        if (hls->max_seg_size > 0) {
>> +            av_log(s, AV_LOG_WARNING, "Have not support multiple fmp4 byterange mode file in hls yet now\n");
>> +            return AVERROR_PATCHWELCOME;
>> +        }
>
> Not entirely sure what this message is trying to say?
>
> Is this accurate: "Multi-file byterange moe is currently unsupported in the HLS muxer." ?
Ok, use your suggestion,
>
>> -    int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
>> +    int byterange_mode = ((hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0));
>
> Doesn't change anything, as far as I can tell?
reserve it for wait the specification :)
>
> Rest is OK, I think.
>
> - Derek
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

adopt suggestion and applied the patch.

Thanks

Patch hide | download patch | download mbox

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index f98f04100c..9f8472bb87 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -531,6 +531,7 @@  static int hls_mux_init(AVFormatContext *s)
     HLSContext *hls = s->priv_data;
     AVFormatContext *oc;
     AVFormatContext *vtt_oc = NULL;
+    int byterange_mode = ((hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0));
     int i, ret;
 
     ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL);
@@ -584,7 +585,11 @@  static int hls_mux_init(AVFormatContext *s)
     hls->fmp4_init_mode = 0;
 
     if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-        hls->fmp4_init_mode = 1;
+        if (hls->max_seg_size > 0) {
+            av_log(s, AV_LOG_WARNING, "Have not support multiple fmp4 byterange mode file in hls yet now\n");
+            return AVERROR_PATCHWELCOME;
+        }
+        hls->fmp4_init_mode = !byterange_mode;
         if ((ret = s->io_open(s, &oc->pb, hls->base_output_dirname, AVIO_FLAG_WRITE, NULL)) < 0) {
             av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", hls->fmp4_init_filename);
             return ret;
@@ -780,7 +785,7 @@  static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double
 {
     HLSSegment *en = av_malloc(sizeof(*en));
     const char  *filename;
-    int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
+    int byterange_mode = ((hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0));
     int ret;
 
     if (!en)
@@ -980,9 +985,6 @@  static void write_m3u8_head_block(HLSContext *hls, AVIOContext *out, int version
     }
     avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration);
     avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);
-    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-        avio_printf(out, "#EXT-X-MAP:URI=\"%s\"\n", hls->fmp4_init_filename);
-    }
     av_log(hls, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);
 }
 
@@ -1015,7 +1017,7 @@  static int hls_window(AVFormatContext *s, int last)
     char *iv_string = NULL;
     AVDictionary *options = NULL;
     double prog_date_time = hls->initial_prog_date_time;
-    int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
+    int byterange_mode = ((hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0));
 
     if (byterange_mode) {
         version = 4;
@@ -1066,13 +1068,21 @@  static int hls_window(AVFormatContext *s, int last)
             avio_printf(out, "#EXT-X-DISCONTINUITY\n");
         }
 
-        if (hls->flags & HLS_ROUND_DURATIONS)
-            avio_printf(out, "#EXTINF:%ld,\n",  lrint(en->duration));
-        else
-            avio_printf(out, "#EXTINF:%f,\n", en->duration);
-        if (byterange_mode)
-             avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
-                         en->size, en->pos);
+        if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == hls->segments)) {
+            avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", hls->fmp4_init_filename);
+            if (hls->flags & HLS_SINGLE_FILE) {
+                avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", en->size, en->pos);
+            }
+            avio_printf(out, "\n");
+        } else {
+            if (hls->flags & HLS_ROUND_DURATIONS)
+                avio_printf(out, "#EXTINF:%ld,\n",  lrint(en->duration));
+            else
+                avio_printf(out, "#EXTINF:%f,\n", en->duration);
+            if (byterange_mode)
+                avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n",
+                            en->size, en->pos);
+        }
         if (hls->flags & HLS_PROGRAM_DATE_TIME) {
             time_t tt, wrongsecs;
             int milli;
@@ -1097,9 +1107,11 @@  static int hls_window(AVFormatContext *s, int last)
             avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1);
             prog_date_time += en->duration;
         }
-        if (hls->baseurl)
-            avio_printf(out, "%s", hls->baseurl);
-        avio_printf(out, "%s\n", en->filename);
+        if (!((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == hls->segments))) {
+            if (hls->baseurl)
+                avio_printf(out, "%s", hls->baseurl);
+            avio_printf(out, "%s\n", en->filename);
+        }
     }
 
     if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
@@ -1262,7 +1274,7 @@  static int hls_start(AVFormatContext *s)
     }
     av_dict_free(&options);
 
-    if (c->segment_type == SEGMENT_TYPE_FMP4) {
+    if (c->segment_type == SEGMENT_TYPE_FMP4 && !(c->flags & HLS_SINGLE_FILE)) {
             write_styp(oc->pb);
     } else {
         /* We only require one PAT/PMT per segment. */
@@ -1315,15 +1327,10 @@  static int hls_write_header(AVFormatContext *s)
     const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s);
     const char *vtt_pattern = "%d.vtt";
     AVDictionary *options = NULL;
-    int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
     int basename_size;
     int vtt_basename_size;
 
     if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-        if (byterange_mode) {
-            av_log(s, AV_LOG_WARNING, "Have not support fmp4 byterange mode yet now\n");
-            return AVERROR_PATCHWELCOME;
-        }
         pattern = "%d.m4s";
     }
     if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) ||
@@ -1400,8 +1407,13 @@  static int hls_write_header(AVFormatContext *s)
             goto fail;
         }
     } else {
-        if (hls->flags & HLS_SINGLE_FILE)
-            pattern = ".ts";
+        if (hls->flags & HLS_SINGLE_FILE) {
+            if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+                pattern = ".m4s";
+            } else {
+                pattern = ".ts";
+            }
+        }
 
         if (hls->use_localtime) {
             basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
@@ -1490,6 +1502,14 @@  static int hls_write_header(AVFormatContext *s)
         av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size);
     }
 
+    if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) {
+        hls->fmp4_init_filename  = av_strdup(hls->basename);
+        if (!hls->fmp4_init_filename) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }
+
     if ((ret = hls_mux_init(s)) < 0)
         goto fail;
 
@@ -1504,7 +1524,7 @@  static int hls_write_header(AVFormatContext *s)
         }
     }
 
-    if (hls->segment_type != SEGMENT_TYPE_FMP4) {
+    if (hls->segment_type != SEGMENT_TYPE_FMP4 || hls->flags & HLS_SINGLE_FILE) {
         if ((ret = hls_start(s)) < 0)
             goto fail;
     }
@@ -1545,6 +1565,7 @@  fail:
 
     av_dict_free(&options);
     if (ret < 0) {
+        av_freep(&hls->fmp4_init_filename);
         av_freep(&hls->basename);
         av_freep(&hls->vtt_basename);
         av_freep(&hls->key_basename);
@@ -1615,7 +1636,7 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
                                    end_pts, AV_TIME_BASE_Q) >= 0) {
         int64_t new_start_pos;
         char *old_filename = av_strdup(hls->avf->filename);
-        int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
+        int byterange_mode = ((hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0));
 
         if (!old_filename) {
             return AVERROR(ENOMEM);
@@ -1643,7 +1664,7 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
             hls->number--;
         }
 
-        if (!hls->fmp4_init_mode)
+        if (!hls->fmp4_init_mode || byterange_mode)
             ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
 
         hls->start_pos = new_start_pos;
@@ -1679,9 +1700,10 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
             return ret;
         }
 
-        if ((ret = hls_window(s, 0)) < 0) {
-            return ret;
-        }
+        if (!hls->fmp4_init_mode || byterange_mode)
+            if ((ret = hls_window(s, 0)) < 0) {
+                return ret;
+            }
     }
 
     ret = ff_write_chained(oc, stream_index, pkt, s, 0);
@@ -1722,6 +1744,7 @@  static int hls_write_trailer(struct AVFormatContext *s)
         hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos;
         ff_format_io_close(s, &vtt_oc->pb);
     }
+    av_freep(&hls->fmp4_init_filename);
     av_freep(&hls->basename);
     av_freep(&hls->base_output_dirname);
     av_freep(&hls->key_basename);