From: Aman Gupta <a...@tmm1.net>
Adds a `-hls_flags +temp_file` which will write segment data to
filename.tmp, and then rename to filename when the segment is complete
and before the file is added to the m3u8 playlist.
This patch is similar in spirit to one used in Plex's ffmpeg fork, and
allows a transcoding webserver to ensure incomplete segment files are
never served up accidentally.
---
libavformat/hlsenc.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index bd1e684..23b9011 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -76,6 +76,7 @@ typedef enum HLSFlags {
HLS_SECOND_LEVEL_SEGMENT_INDEX = (1 << 8), // include segment index
in segment filenames when use_localtime e.g.: %%03d
HLS_SECOND_LEVEL_SEGMENT_DURATION = (1 << 9), // include segment
duration (microsec) in segment filenames when use_localtime e.g.: %%09t
HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size
(bytes) in segment filenames when use_localtime e.g.: %%014s
+ HLS_TEMP_FILE = (1 << 11),
} HLSFlags;
typedef enum {
@@ -915,6 +916,10 @@ static int hls_start(AVFormatContext *s)
set_http_options(&options, c);
+ if (c->flags & HLS_TEMP_FILE) {
+ av_strlcat(oc->filename, ".tmp", sizeof(oc->filename));
+ }
+
if (c->key_info_file) {
if ((err = hls_encryption_start(s)) < 0)
goto fail;
@@ -1276,6 +1281,15 @@ static int hls_write_packet(AVFormatContext *s,
AVPacket *pkt)
av_write_frame(oc, NULL); /* Flush any buffered data */
+ if (hls->flags & HLS_TEMP_FILE) {
+ size_t len = strlen(oc->filename);
+ char final_filename[sizeof(oc->filename)];
+ av_strlcpy(final_filename, oc->filename, len);
+ final_filename[len-4] = '\0';
+ ff_rename(oc->filename, final_filename, s);
+ oc->filename[len-4] = '\0';
+ }
+
new_start_pos = avio_tell(hls->avf->pb);
hls->size = new_start_pos - hls->start_pos;
ret = hls_append_segment(s, hls, hls->duration, hls->start_pos,
hls->size);
@@ -1406,6 +1420,7 @@ static const AVOption options[] = {
{"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"},
{"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"},
{"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"},