[FFmpeg-cvslog] avformat/hlsenc: temp_file usage for master playlist and vtt playlist

Bela Bodecs git at videolan.org
Fri Jun 28 08:56:15 EEST 2019


ffmpeg | branch: master | Bela Bodecs <bodecsb at vivanet.hu> | Fri Jun 28 13:54:27 2019 +0800| [098ab932579ea6d81e0b928f09b425fdd00a2890] | committer: Steven Liu

avformat/hlsenc: temp_file usage for master playlist and vtt playlist

currently master playlist and subtitle playlist creation does not use
temporary files even when temp_file flag is set. Most of the use cases
it is not a problem because master playlist creation happens once on the
beginning of the whole process. But if master playlist is periodically
re-created because of master_pl_refresh_rate is set, non-atomic playlist
creation may cause problems in case of live streaming. This patch
correct this behavior by adding this functionality.

Reviewed-by: Steven Liu <lq at onvideo.cn>
Signed-off-by: Bela Bodecs <bodecsb at vivanet.hu>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=098ab932579ea6d81e0b928f09b425fdd00a2890
---

 doc/muxers.texi      |  6 +++++-
 libavformat/hlsenc.c | 30 +++++++++++++++++++++---------
 2 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 59c93bc687..dd64672b85 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -893,7 +893,11 @@ This will produce segments like this:
 @item temp_file
 Write segment data to filename.tmp and rename to filename only once the segment is complete. A webserver
 serving up segments can be configured to reject requests to *.tmp to prevent access to in-progress segments
-before they have been added to the m3u8 playlist.
+before they have been added to the m3u8 playlist. This flag also affects how m3u8 playlist files are created.
+If this flag is set, all playlist files will written into temporary file and renamed after they are complete, similarly as segments are handled.
+But playlists with @code{file} protocol and with type (@code{hls_playlist_type}) other than @code{vod}
+are always written into temporary file regardles of this flag. Master playlist files (@code{master_pl_name}), if any, with @code{file} protocol,
+are always written into temporary file regardles of this flag if @code{master_pl_publish_rate} value is other than zero.
 
 @end table
 
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 37ae128f4f..5b0121f016 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1263,8 +1263,12 @@ static int create_master_playlist(AVFormatContext *s,
     AVDictionary *options = NULL;
     unsigned int i, j;
     int m3u8_name_size, ret, bandwidth;
-    char *m3u8_rel_name, *ccgroup;
+    char *m3u8_rel_name = NULL, *ccgroup;
     ClosedCaptionsStream *ccs;
+    const char *proto = avio_find_protocol_name(hls->master_m3u8_url);
+    int is_file_proto = proto && !strcmp(proto, "file");
+    int use_temp_file = is_file_proto && ((hls->flags & HLS_TEMP_FILE) || hls->master_publish_rate);
+    char temp_filename[1024];
 
     input_vs->m3u8_created = 1;
     if (!hls->master_m3u8_created) {
@@ -1280,12 +1284,12 @@ static int create_master_playlist(AVFormatContext *s,
     }
 
     set_http_options(s, &options, hls);
-
-    ret = hlsenc_io_open(s, &hls->m3u8_out, hls->master_m3u8_url, &options);
+    snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", hls->master_m3u8_url);
+    ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options);
     av_dict_free(&options);
     if (ret < 0) {
         av_log(NULL, AV_LOG_ERROR, "Failed to open master play list file '%s'\n",
-                hls->master_m3u8_url);
+                temp_filename);
         goto fail;
     }
 
@@ -1416,7 +1420,10 @@ fail:
     if(ret >=0)
         hls->master_m3u8_created = 1;
     av_freep(&m3u8_rel_name);
-    hlsenc_io_close(s, &hls->m3u8_out, hls->master_m3u8_url);
+    hlsenc_io_close(s, &hls->m3u8_out, temp_filename);
+    if (use_temp_file)
+        ff_rename(temp_filename, hls->master_m3u8_url, s);
+
     return ret;
 }
 
@@ -1427,6 +1434,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
     int target_duration = 0;
     int ret = 0;
     char temp_filename[1024];
+    char temp_vtt_filename[1024];
     int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries);
     const char *proto = avio_find_protocol_name(vs->m3u8_name);
     int is_file_proto = proto && !strcmp(proto, "file");
@@ -1508,8 +1516,9 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
     if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
         ff_hls_write_end_list(hls->m3u8_out);
 
-    if( vs->vtt_m3u8_name ) {
-        if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name, &options)) < 0) {
+    if (vs->vtt_m3u8_name) {
+        snprintf(temp_vtt_filename, sizeof(temp_vtt_filename), use_temp_file ? "%s.tmp" : "%s", vs->vtt_m3u8_name);
+        if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, temp_vtt_filename, &options)) < 0) {
             if (hls->ignore_io_errors)
                 ret = 0;
             goto fail;
@@ -1534,8 +1543,11 @@ fail:
     av_dict_free(&options);
     hlsenc_io_close(s, &hls->m3u8_out, temp_filename);
     hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name);
-    if (use_temp_file)
+    if (use_temp_file) {
         ff_rename(temp_filename, vs->m3u8_name, s);
+        if (vs->vtt_m3u8_name)
+            ff_rename(temp_vtt_filename, vs->vtt_m3u8_name, s);
+    }
     if (ret >= 0 && hls->master_pl_name)
         if (create_master_playlist(s, vs) < 0)
             av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n");
@@ -2994,7 +3006,7 @@ static const AVOption options[] = {
     {"hls_fmp4_init_filename", "set fragment mp4 file init filename", OFFSET(fmp4_init_filename),   AV_OPT_TYPE_STRING, {.str = "init.mp4"},            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"},
     {"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"},
-    {"temp_file", "write segment to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_TEMP_FILE }, 0, UINT_MAX,   E, "flags"},
+    {"temp_file", "write segment and playlist to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_TEMP_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"},
     {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX,   E, "flags"},



More information about the ffmpeg-cvslog mailing list