avformat/hlsenc: creation of variant streams in subdirectories

Reviewed-by: Steven Liu <lq@chinaffmpeg.org>
pull/274/head
Vishwanath Dixit 7 years ago committed by Steven Liu
parent e872befdb5
commit 41e51fbcd9
  1. 33
      doc/muxers.texi
  2. 68
      libavformat/hlsenc.c

@ -589,6 +589,20 @@ This example will produce the playlists segment file sets:
@file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and @file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
@file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc. @file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
The string "%v" may be present in the filename or in the last directory name
containing the file. If the string is present in the directory name, then
sub-directories are created after expanding the directory name pattern. This
enables creation of segments corresponding to different variant streams in
subdirectories.
@example
ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
-map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \
-hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8
@end example
This example will produce the playlists segment file sets:
@file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. and
@file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc.
@item use_localtime @item use_localtime
Use strftime() on @var{filename} to expand the segment filename with localtime. Use strftime() on @var{filename} to expand the segment filename with localtime.
The segment number is also available in this mode, but to use it, you need to specify second_level_segment_index The segment number is also available in this mode, but to use it, you need to specify second_level_segment_index
@ -717,6 +731,11 @@ set filename to the fragment files header file, default filename is @file{init.m
When @code{var_stream_map} is set with two or more variant streams, the When @code{var_stream_map} is set with two or more variant streams, the
@var{filename} pattern must contain the string "%v", this string specifies @var{filename} pattern must contain the string "%v", this string specifies
the position of variant stream index in the generated init file names. the position of variant stream index in the generated init file names.
The string "%v" may be present in the filename or in the last directory name
containing the file. If the string is present in the directory name, then
sub-directories are created after expanding the directory name pattern. This
enables creation of init files corresponding to different variant streams in
subdirectories.
@item hls_flags @var{flags} @item hls_flags @var{flags}
Possible values: Possible values:
@ -833,7 +852,11 @@ Allowed values are 0 to 9 (limited just based on practical usage).
When there are two or more variant streams, the output filename pattern must When there are two or more variant streams, the output filename pattern must
contain the string "%v", this string specifies the position of variant stream contain the string "%v", this string specifies the position of variant stream
index in the output media playlist filenames. index in the output media playlist filenames. The string "%v" may be present in
the filename or in the last directory name containing the file. If the string is
present in the directory name, then sub-directories are created after expanding
the directory name pattern. This enables creation of variant streams in
subdirectories.
@example @example
ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
@ -856,6 +879,14 @@ be an audio only stream with bitrate 64k and the third variant stream will be a
video only stream with bitrate 256k. Here, three media playlist with file names video only stream with bitrate 256k. Here, three media playlist with file names
out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created. out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
@example @example
ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
-map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \
http://example.com/live/vs_%v/out.m3u8
@end example
This example creates the variant streams in subdirectories. Here, the first
media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and
the second one at @file{http://example.com/live/vs_1/out.m3u8}.
@example
ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k \ ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k \
-map 0:a -map 0:a -map 0:v -map 0:v -f hls \ -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
-var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low v:1,agroup:aud_high" \ -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low v:1,agroup:aud_high" \

@ -1549,7 +1549,8 @@ static int append_postfix(char *name, int name_buf_len, int i)
static int validate_name(int nb_vs, const char *fn) static int validate_name(int nb_vs, const char *fn)
{ {
const char *filename; const char *filename, *subdir_name;
char *fn_dup = NULL;
int ret = 0; int ret = 0;
if (!fn) { if (!fn) {
@ -1557,22 +1558,38 @@ static int validate_name(int nb_vs, const char *fn)
goto fail; goto fail;
} }
fn_dup = av_strdup(fn);
if (!fn_dup) {
ret = AVERROR(ENOMEM);
goto fail;
}
filename = av_basename(fn); filename = av_basename(fn);
subdir_name = av_dirname(fn_dup);
if (nb_vs > 1 && !av_stristr(filename, "%v")) { if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, "%v")) {
av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected in the filename %s\n", av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected in the filename %s\n",
fn); fn);
ret = AVERROR(EINVAL); ret = AVERROR(EINVAL);
goto fail; goto fail;
} }
if (av_stristr(filename, "%v") && av_stristr(subdir_name, "%v")) {
av_log(NULL, AV_LOG_ERROR, "%%v is expected either in filename or in the sub-directory name of file %s\n",
fn);
ret = AVERROR(EINVAL);
goto fail;
}
fail: fail:
av_freep(&fn_dup);
return ret; return ret;
} }
static int format_name(char *buf, int buf_len, int index) static int format_name(char *buf, int buf_len, int index)
{ {
char *orig_buf_dup = NULL; const char *proto, *dir;
char *orig_buf_dup = NULL, *mod_buf_dup = NULL;
int ret = 0; int ret = 0;
if (!av_stristr(buf, "%v")) if (!av_stristr(buf, "%v"))
@ -1589,8 +1606,27 @@ static int format_name(char *buf, int buf_len, int index)
goto fail; goto fail;
} }
proto = avio_find_protocol_name(orig_buf_dup);
dir = av_dirname(orig_buf_dup);
/* if %v is present in the file's directory, create sub-directory */
if (av_stristr(dir, "%v") && proto && !strcmp(proto, "file")) {
mod_buf_dup = av_strdup(buf);
if (!mod_buf_dup) {
ret = AVERROR(ENOMEM);
goto fail;
}
dir = av_dirname(mod_buf_dup);
if (mkdir_p(dir) == -1 && errno != EEXIST) {
ret = AVERROR(errno);
goto fail;
}
}
fail: fail:
av_freep(&orig_buf_dup); av_freep(&orig_buf_dup);
av_freep(&mod_buf_dup);
return ret; return ret;
} }
@ -1737,16 +1773,30 @@ static int update_variant_stream_info(AVFormatContext *s) {
static int update_master_pl_info(AVFormatContext *s) { static int update_master_pl_info(AVFormatContext *s) {
HLSContext *hls = s->priv_data; HLSContext *hls = s->priv_data;
const char *dir; const char *dir;
char *fn = NULL; char *fn1= NULL, *fn2 = NULL;
int ret = 0; int ret = 0;
fn = av_strdup(s->filename); fn1 = av_strdup(s->filename);
if (!fn) { if (!fn1) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail; goto fail;
} }
dir = av_dirname(fn); dir = av_dirname(fn1);
/**
* if output file's directory has %v, variants are created in sub-directories
* then master is created at the sub-directories level
*/
if (dir && av_stristr(av_basename(dir), "%v")) {
fn2 = av_strdup(dir);
if (!fn2) {
ret = AVERROR(ENOMEM);
goto fail;
}
dir = av_dirname(fn2);
}
if (dir && strcmp(dir, ".")) if (dir && strcmp(dir, "."))
hls->master_m3u8_url = av_append_path_component(dir, hls->master_pl_name); hls->master_m3u8_url = av_append_path_component(dir, hls->master_pl_name);
else else
@ -1758,7 +1808,9 @@ static int update_master_pl_info(AVFormatContext *s) {
} }
fail: fail:
av_freep(&fn); av_freep(&fn1);
av_freep(&fn2);
return ret; return ret;
} }

Loading…
Cancel
Save