提交 606eac7b 编写于 作者: A Aman Gupta 提交者: Steven Liu

avformat/hlsenc: add hls_flag option to write segments to temporary file until complete

Adds a `-hls_flags +temp_file` which will write segment data to
filename.tmp, and then rename to filename when the segment is complete.

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.
Reviewed-by: NHendrik Leppkes <h.leppkes@gmail.com>
Reviewed-by: NBodecs Bela <bodecsb@vivanet.hu>
Signed-off-by: NAman Gupta <aman@tmm1.net>
Signed-off-by: NSteven Liu <lq@chinaffmpeg.org>
上级 a6cee50f
...@@ -656,6 +656,11 @@ Makes it possible to use segment duration (calculated in microseconds) as %%t i ...@@ -656,6 +656,11 @@ Makes it possible to use segment duration (calculated in microseconds) as %%t i
expression besides date/time values when use_localtime is on. expression besides date/time values when use_localtime is on.
To get fixed width numbers with trailing zeroes, %%0xt format is available where x is the required width. To get fixed width numbers with trailing zeroes, %%0xt format is available where x is the required width.
@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.
@example @example
ffmpeg -i sample.mpeg \ ffmpeg -i sample.mpeg \
-f hls -hls_time 3 -hls_list_size 5 \ -f hls -hls_time 3 -hls_list_size 5 \
......
...@@ -76,6 +76,7 @@ typedef enum HLSFlags { ...@@ -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_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_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_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; } HLSFlags;
typedef enum { typedef enum {
...@@ -416,6 +417,7 @@ static int hls_mux_init(AVFormatContext *s) ...@@ -416,6 +417,7 @@ static int hls_mux_init(AVFormatContext *s)
return ret; return ret;
oc = hls->avf; oc = hls->avf;
oc->filename[0] = '\0';
oc->oformat = hls->oformat; oc->oformat = hls->oformat;
oc->interrupt_callback = s->interrupt_callback; oc->interrupt_callback = s->interrupt_callback;
oc->max_delay = s->max_delay; oc->max_delay = s->max_delay;
...@@ -815,6 +817,15 @@ static int hls_start(AVFormatContext *s) ...@@ -815,6 +817,15 @@ static int hls_start(AVFormatContext *s)
char *filename, iv_string[KEYSIZE*2 + 1]; char *filename, iv_string[KEYSIZE*2 + 1];
int err = 0; int err = 0;
if ((c->flags & HLS_TEMP_FILE) && oc->filename[0] != 0) {
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';
}
if (c->flags & HLS_SINGLE_FILE) { if (c->flags & HLS_SINGLE_FILE) {
av_strlcpy(oc->filename, c->basename, av_strlcpy(oc->filename, c->basename,
sizeof(oc->filename)); sizeof(oc->filename));
...@@ -915,6 +926,10 @@ static int hls_start(AVFormatContext *s) ...@@ -915,6 +926,10 @@ static int hls_start(AVFormatContext *s)
set_http_options(&options, c); 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 (c->key_info_file) {
if ((err = hls_encryption_start(s)) < 0) if ((err = hls_encryption_start(s)) < 0)
goto fail; goto fail;
...@@ -1364,6 +1379,15 @@ static int hls_write_trailer(struct AVFormatContext *s) ...@@ -1364,6 +1379,15 @@ static int hls_write_trailer(struct AVFormatContext *s)
ff_rename(old_filename, hls->avf->filename, hls); ff_rename(old_filename, hls->avf->filename, hls);
} }
if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0] != 0) {
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';
}
if (vtt_oc) { if (vtt_oc) {
if (vtt_oc->pb) if (vtt_oc->pb)
av_write_trailer(vtt_oc); av_write_trailer(vtt_oc);
...@@ -1406,6 +1430,7 @@ static const AVOption options[] = { ...@@ -1406,6 +1430,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_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_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"}, {"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"}, {"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"}, {"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"}, {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册