diff mbox

[FFmpeg-devel,v3] avformat/hlsenc: add hls_flag option to write segments to temporary file until complete

Message ID 20170204175506.74792-1-ffmpeg@tmm1.net
State Accepted
Commit 606eac7b07133b0904c2b8b4eb1dc70e1bd0c9a6
Headers show

Commit Message

Aman Karmani Feb. 4, 2017, 5:55 p.m. UTC
From: Aman Gupta <aman@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.

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.
---
 doc/muxers.texi      |  5 +++++
 libavformat/hlsenc.c | 25 +++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

Comments

Hendrik Leppkes Feb. 4, 2017, 7:45 p.m. UTC | #1
On Sat, Feb 4, 2017 at 6:55 PM, Aman Gupta <ffmpeg@tmm1.net> wrote:
> From: Aman Gupta <aman@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.
>
> 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.

Wouldnt a segment only show up in the playlist when its finished? How
can they be served accidentally?

- Hendrik
Bodecs Bela Feb. 4, 2017, 8:38 p.m. UTC | #2
2017.02.04. 20:45 keltezéssel, Hendrik Leppkes írta:
> On Sat, Feb 4, 2017 at 6:55 PM, Aman Gupta <ffmpeg@tmm1.net> wrote:
>> From: Aman Gupta <aman@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.
>>
>> 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.
> Wouldnt a segment only show up in the playlist when its finished? How
> can they be served accidentally?
the segment file names are predictable.
In live streaming enviroment somebody predicting the segment name may 
see the program some seconds earlier than any other viewer by 
downloading continously the unpublished segment. (with one segment 
duration seconds earlier)
if the currently writed segment name is constant you may prohibit to 
acces it in web server config
> - Hendrik
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Steven Liu Feb. 5, 2017, 3:09 p.m. UTC | #3
2017-02-05 4:38 GMT+08:00 Bodecs Bela <bodecsb@vivanet.hu>:

>
>
> 2017.02.04. 20:45 keltezéssel, Hendrik Leppkes írta:
>
>> On Sat, Feb 4, 2017 at 6:55 PM, Aman Gupta <ffmpeg@tmm1.net> wrote:
>>
>>> From: Aman Gupta <aman@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.
>>>
>>> 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.
>>>
>> Wouldnt a segment only show up in the playlist when its finished? How
>> can they be served accidentally?
>>
> the segment file names are predictable.
> In live streaming enviroment somebody predicting the segment name may see
> the program some seconds earlier than any other viewer by downloading
> continously the unpublished segment. (with one segment duration seconds
> earlier)
> if the currently writed segment name is constant you may prohibit to acces
> it in web server config
>
> - Hendrik
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>


will push after 24 hours
Steven Liu Feb. 7, 2017, 5:51 a.m. UTC | #4
2017-02-05 23:09 GMT+08:00 Steven Liu <lingjiujianke@gmail.com>:

>
>
> 2017-02-05 4:38 GMT+08:00 Bodecs Bela <bodecsb@vivanet.hu>:
>
>>
>>
>> 2017.02.04. 20:45 keltezéssel, Hendrik Leppkes írta:
>>
>>> On Sat, Feb 4, 2017 at 6:55 PM, Aman Gupta <ffmpeg@tmm1.net> wrote:
>>>
>>>> From: Aman Gupta <aman@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.
>>>>
>>>> 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.
>>>>
>>> Wouldnt a segment only show up in the playlist when its finished? How
>>> can they be served accidentally?
>>>
>> the segment file names are predictable.
>> In live streaming enviroment somebody predicting the segment name may see
>> the program some seconds earlier than any other viewer by downloading
>> continously the unpublished segment. (with one segment duration seconds
>> earlier)
>> if the currently writed segment name is constant you may prohibit to
>> acces it in web server config
>>
>> - Hendrik
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>
>
> will push after 24 hours
>

Pushed!



Thanks
diff mbox

Patch

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 4372078..0d98805 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -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.
 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
 ffmpeg -i sample.mpeg \
    -f hls -hls_time 3 -hls_list_size 5 \
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index bd1e684..17d4fe4 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 {
@@ -416,6 +417,7 @@  static int hls_mux_init(AVFormatContext *s)
         return ret;
     oc = hls->avf;
 
+    oc->filename[0]        = '\0';
     oc->oformat            = hls->oformat;
     oc->interrupt_callback = s->interrupt_callback;
     oc->max_delay          = s->max_delay;
@@ -815,6 +817,15 @@  static int hls_start(AVFormatContext *s)
     char *filename, iv_string[KEYSIZE*2 + 1];
     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) {
         av_strlcpy(oc->filename, c->basename,
                    sizeof(oc->filename));
@@ -915,6 +926,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;
@@ -1364,6 +1379,15 @@  static int hls_write_trailer(struct AVFormatContext *s)
          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->pb)
             av_write_trailer(vtt_oc);
@@ -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_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"},