[FFmpeg-devel] [PATCH] avformat/hlsenc: add hls_flag option to create segments atomically

Aman Gupta ffmpeg at tmm1.net
Thu Feb 2 01:49:54 EET 2017


On Wed, Feb 1, 2017 at 1:23 AM, Steven Liu <lingjiujianke at gmail.com> wrote:

>
>
> 2017-02-01 4:29 GMT+08:00 Aman Gupta <ffmpeg at tmm1.net>:
>
>> From: Aman Gupta <aman at 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"},
>> --
>> 2.10.1 (Apple Git-78)
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel at ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>
>
> Why use temp filename?
> There have no info in m3u8 list before the segment complete.
>

Plex and other "on-the-fly" transcoding webservers will create a fake m3u8
with all the segments listed. When segment2.ts is requested but not yet
available, it will wait for the file to show up on the disk and then serve
it to the client.


More information about the ffmpeg-devel mailing list