]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/hlsenc.c
Merge commit 'c0a49077ea4ff3a0ad30b9e33f1bb06ba9112aaa'
[ffmpeg] / libavformat / hlsenc.c
index 2c0c6f0697889a6aad64df50c0c3850712723960..d7bb0c1031706a992cfdbef3f00913bf0034f162 100644 (file)
@@ -32,6 +32,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
+#include "libavutil/time_internal.h"
 
 #include "avformat.h"
 #include "internal.h"
@@ -79,6 +80,7 @@ typedef struct HLSContext {
     uint32_t flags;        // enum HLSFlags
     char *segment_filename;
 
+    int use_localtime;      ///< flag to expand filename with localtime
     int allowcache;
     int64_t recording_time;
     int has_video;
@@ -118,7 +120,8 @@ static int hls_delete_old_segments(HLSContext *hls) {
     HLSSegment *segment, *previous_segment = NULL;
     float playlist_duration = 0.0f;
     int ret = 0, path_size, sub_path_size;
-    char *dirname = NULL, *p, *path, *sub_path;
+    char *dirname = NULL, *p, *sub_path;
+    char *path = NULL;
 
     segment = hls->segments;
     while (segment) {
@@ -180,7 +183,7 @@ static int hls_delete_old_segments(HLSContext *hls) {
             av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
                                      sub_path, strerror(errno));
         }
-        av_free(path);
+        av_freep(&path);
         av_free(sub_path);
         previous_segment = segment;
         segment = previous_segment->next;
@@ -188,6 +191,7 @@ static int hls_delete_old_segments(HLSContext *hls) {
     }
 
 fail:
+    av_free(path);
     av_free(dirname);
 
     return ret;
@@ -251,7 +255,7 @@ static int hls_mux_init(AVFormatContext *s)
 {
     HLSContext *hls = s->priv_data;
     AVFormatContext *oc;
-    AVFormatContext *vtt_oc;
+    AVFormatContext *vtt_oc = NULL;
     int i, ret;
 
     ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL);
@@ -479,9 +483,18 @@ static int hls_start(AVFormatContext *s)
             av_strlcpy(vtt_oc->filename, c->vtt_basename,
                   sizeof(vtt_oc->filename));
     } else {
-        if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
+        if (c->use_localtime) {
+            time_t now0;
+            struct tm *tm, tmpbuf;
+            time(&now0);
+            tm = localtime_r(&now0, &tmpbuf);
+            if (!strftime(oc->filename, sizeof(oc->filename), c->basename, tm)) {
+                av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n");
+                return AVERROR(EINVAL);
+            }
+       } else if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
                                   c->basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) {
-            av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename);
+            av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try use -use_localtime 1 with it\n", c->basename);
             return AVERROR(EINVAL);
         }
         if( c->vtt_basename) {
@@ -542,6 +555,7 @@ static int hls_write_header(AVFormatContext *s)
     int ret, i;
     char *p;
     const char *pattern = "%d.ts";
+    const char *pattern_localtime_fmt = "-%s.ts";
     const char *vtt_pattern = "%d.vtt";
     AVDictionary *options = NULL;
     int basename_size;
@@ -596,7 +610,11 @@ static int hls_write_header(AVFormatContext *s)
         if (hls->flags & HLS_SINGLE_FILE)
             pattern = ".ts";
 
-        basename_size = strlen(s->filename) + strlen(pattern) + 1;
+        if (hls->use_localtime) {
+            basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
+        } else {
+            basename_size = strlen(s->filename) + strlen(pattern) + 1;
+        }
         hls->basename = av_malloc(basename_size);
         if (!hls->basename) {
             ret = AVERROR(ENOMEM);
@@ -608,7 +626,11 @@ static int hls_write_header(AVFormatContext *s)
         p = strrchr(hls->basename, '.');
         if (p)
             *p = '\0';
-        av_strlcat(hls->basename, pattern, basename_size);
+        if (hls->use_localtime) {
+            av_strlcat(hls->basename, pattern_localtime_fmt, basename_size);
+        } else {
+            av_strlcat(hls->basename, pattern, basename_size);
+        }
     }
 
     if(hls->has_subtitle) {
@@ -817,6 +839,7 @@ static const AVOption options[] = {
     {"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"},
     {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX,   E, "flags"},
+    { "use_localtime",          "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, E },
 
     { NULL },
 };