Browse code

avformat/hlsenc: added segment filename option

This option allows segment filenames to be specified. Unless -hls_flags
single_file is set the filename is used as a string format with the
segment number.

Example:
ffmpeg -f lavfi -i testsrc -c:v h264 -map 0 -hls_segment_filename
bar%03d.ts foo.m3u8

Signed-off-by: Christian Suloway <csuloway@globaleagleent.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Christian Suloway authored on 2014/12/06 06:20:15
Showing 2 changed files
... ...
@@ -254,6 +254,15 @@ and it is not to be confused with the segment filename sequence number
254 254
 which can be cyclic, for example if the @option{wrap} option is
255 255
 specified.
256 256
 
257
+@item hls_segment_filename @var{filename}
258
+Set the segment filename. Unless hls_flags single_file is set @var{filename}
259
+is used as a string format with the segment number:
260
+@example
261
+ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
262
+@end example
263
+This example will produce the playlist, @file{out.m3u8}, and segment files:
264
+@file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
265
+
257 266
 @item hls_flags single_file
258 267
 If this flag is set, the muxer will store all segments in a single MPEG-TS
259 268
 file, and will use byte ranges in the playlist. HLS playlists generated with
... ...
@@ -59,6 +59,7 @@ typedef struct HLSContext {
59 59
     int max_nb_segments;   // Set by a private option.
60 60
     int  wrap;             // Set by a private option.
61 61
     uint32_t flags;        // enum HLSFlags
62
+    char *segment_filename;
62 63
 
63 64
     int allowcache;
64 65
     int64_t recording_time;
... ...
@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s)
237 237
     char *p;
238 238
     const char *pattern = "%d.ts";
239 239
     AVDictionary *options = NULL;
240
-    int basename_size = strlen(s->filename) + strlen(pattern) + 1;
240
+    int basename_size;
241 241
 
242 242
     hls->sequence       = hls->start_sequence;
243 243
     hls->recording_time = hls->time * AV_TIME_BASE;
244 244
     hls->start_pts      = AV_NOPTS_VALUE;
245 245
 
246
-    if (hls->flags & HLS_SINGLE_FILE)
247
-        pattern = ".ts";
248
-
249 246
     if (hls->format_options_str) {
250 247
         ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
251 248
         if (ret < 0) {
... ...
@@ -270,21 +268,30 @@ static int hls_write_header(AVFormatContext *s)
270 270
         goto fail;
271 271
     }
272 272
 
273
-    hls->basename = av_malloc(basename_size);
274
-
275
-    if (!hls->basename) {
276
-        ret = AVERROR(ENOMEM);
277
-        goto fail;
278
-    }
279
-
280
-    strcpy(hls->basename, s->filename);
273
+    if (hls->segment_filename) {
274
+        hls->basename = av_strdup(hls->segment_filename);
275
+        if (!hls->basename) {
276
+            ret = AVERROR(ENOMEM);
277
+            goto fail;
278
+        }
279
+    } else {
280
+        if (hls->flags & HLS_SINGLE_FILE)
281
+            pattern = ".ts";
281 282
 
282
-    p = strrchr(hls->basename, '.');
283
+        basename_size = strlen(s->filename) + strlen(pattern) + 1;
284
+        hls->basename = av_malloc(basename_size);
285
+        if (!hls->basename) {
286
+            ret = AVERROR(ENOMEM);
287
+            goto fail;
288
+        }
283 289
 
284
-    if (p)
285
-        *p = '\0';
290
+        av_strlcpy(hls->basename, s->filename, basename_size);
286 291
 
287
-    av_strlcat(hls->basename, pattern, basename_size);
292
+        p = strrchr(hls->basename, '.');
293
+        if (p)
294
+            *p = '\0';
295
+        av_strlcat(hls->basename, pattern, basename_size);
296
+    }
288 297
 
289 298
     if ((ret = hls_mux_init(s)) < 0)
290 299
         goto fail;
... ...
@@ -410,6 +417,7 @@ static const AVOption options[] = {
410 410
     {"hls_wrap",      "set number after which the index wraps",  OFFSET(wrap),    AV_OPT_TYPE_INT,    {.i64 = 0},     0, INT_MAX, E},
411 411
     {"hls_allow_cache", "explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments", OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, E},
412 412
     {"hls_base_url",  "url to prepend to each playlist entry",   OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E},
413
+    {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},            0,       0,         E},
413 414
     {"hls_flags",     "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"},
414 415
     {"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"},
415 416