> On 26 Dec 2017, at 18:38, Vishwanath Dixit <vdi...@akamai.com> wrote: > > > > On 12/26/17 3:37 PM, 刘歧 wrote: >>> On 26 Dec 2017, at 17:53, vdi...@akamai.com wrote: >>> >>> From: Vishwanath Dixit <vdi...@akamai.com> >>> >>> --- >>> doc/muxers.texi | 31 +++++++++-- >>> libavformat/hlsenc.c | 153 >>> ++++++++++++++++++++++++++++++++++----------------- >>> 2 files changed, 127 insertions(+), 57 deletions(-) >>> >>> diff --git a/doc/muxers.texi b/doc/muxers.texi >>> index 93db549..6af970d 100644 >>> --- a/doc/muxers.texi >>> +++ b/doc/muxers.texi >>> @@ -575,6 +575,17 @@ Should a relative path be specified, the path of the >>> created segment >>> files will be relative to the current working directory. >>> When use_localtime_mkdir is set, the whole expanded value of @var{filename} >>> will be written into the m3u8 segment list. >>> >>> +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 >>> +the position of variant stream index in the generated segment file names. >>> +@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 'file_%v_%03d.ts' out_%v.m3u8 >>> +@end example >>> +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_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc. >>> >>> @item use_localtime >>> Use strftime() on @var{filename} to expand the segment filename with >>> localtime. >>> @@ -701,6 +712,10 @@ the fmp4 files is used in hls after version 7. >>> @item hls_fmp4_init_filename @var{filename} >>> set filename to the fragment files header file, default filename is >>> @file{init.mp4}. >>> >>> +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 >>> +the position of variant stream index in the generated init file names. >>> + >>> @item hls_flags @var{flags} >>> Possible values: >>> >>> @@ -814,32 +829,36 @@ Expected string format is like this "a:0,v:0 a:1,v:1 >>> ....". Here a:, v:, s: are >>> the keys to specify audio, video and subtitle streams respectively. >>> 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 >>> +contain the string "%v", this string specifies the position of variant >>> stream >>> +index in the output media playlist filenames. >>> + >>> @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/out.m3u8 >>> + http://example.com/live/out_%v.m3u8 >>> @end example >>> This example creates two hls variant streams. The first variant stream will >>> contain video stream of bitrate 1000k and audio stream of bitrate 64k and >>> the >>> second variant stream will contain video stream of bitrate 256k and audio >>> -stream of bitrate 32k. Here, two media playlist with file names out_1.m3u8 >>> and >>> -out_2.m3u8 will be created. >>> +stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 >>> and >>> +out_1.m3u8 will be created. >>> @example >>> ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \ >>> -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \ >>> - http://example.com/live/out.m3u8 >>> + http://example.com/live/out_%v.m3u8 >>> @end example >>> This example creates three hls variant streams. The first variant stream >>> will >>> be a video only stream with video bitrate 1000k, the second variant stream >>> will >>> 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 >>> -out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created. >>> +out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created. >>> @example >>> 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 \ >>> -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high >>> v:0,agroup:aud_low v:1,agroup:aud_high" \ >>> -master_pl_name master.m3u8 \ >>> - http://example.com/live/out.m3u8 >>> + http://example.com/live/out_%v.m3u8 >>> @end example >>> This example creates two audio only and two video only variant streams. In >>> addition to the #EXT-X-STREAM-INF tag for each variant stream in the master >>> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c >>> index bd43336..76a4110 100644 >>> --- a/libavformat/hlsenc.c >>> +++ b/libavformat/hlsenc.c >>> @@ -1536,7 +1536,7 @@ static const char * >>> get_default_pattern_localtime_fmt(AVFormatContext *s) >>> return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || >>> !strcmp(b, "%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts"; >>> } >>> >>> -static int format_name(char *name, int name_buf_len, int i) >>> +static int append_postfix(char *name, int name_buf_len, int i) >>> { >>> char *p; >>> char extension[10] = {'\0'}; >>> @@ -1555,6 +1555,53 @@ static int format_name(char *name, int name_buf_len, >>> int i) >>> return 0; >>> } >>> >>> +static int validate_name(int nb_vs, const char *fn) >>> +{ >>> + const char *filename; >>> + int ret = 0; >>> + >>> + if (!fn) { >>> + ret = AVERROR(EINVAL); >>> + goto fail; >>> + } >>> + >>> + filename = av_basename(fn); >>> + >>> + if (nb_vs > 1 && !av_stristr(filename, "%v")) { >>> + av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are >>> present, %%v is expected in the filename %s\n", >>> + fn); >>> + ret = AVERROR(EINVAL); >>> + goto fail; >>> + } >>> + >>> +fail: >>> + return ret; >>> +} >>> + >>> +static int format_name(char *buf, int buf_len, int index) >>> +{ >>> + char *orig_buf_dup = NULL; >>> + int ret = 0; >>> + >>> + if (!av_stristr(buf, "%v")) >>> + return ret; >>> + >>> + orig_buf_dup = av_strdup(buf); >>> + if (!orig_buf_dup) { >>> + ret = AVERROR(ENOMEM); >>> + goto fail; >>> + } >>> + >>> + if (replace_int_data_in_filename(buf, buf_len, orig_buf_dup, 'v', >>> index) < 1) { >>> + ret = AVERROR(EINVAL); >>> + goto fail; >>> + } >>> + >>> +fail: >>> + av_freep(&orig_buf_dup); >>> + return ret; >>> +} >>> + >>> static int get_nth_codec_stream_index(AVFormatContext *s, >>> enum AVMediaType codec_type, >>> int stream_id) >>> @@ -1698,7 +1745,7 @@ static int update_variant_stream_info(AVFormatContext >>> *s) { >>> static int update_master_pl_info(AVFormatContext *s) { >>> HLSContext *hls = s->priv_data; >>> const char *dir; >>> - char *fn; >>> + char *fn = NULL; >>> int ret = 0; >>> >>> fn = av_strdup(s->filename); >>> @@ -2076,6 +2123,28 @@ static int hls_init(AVFormatContext *s) >>> goto fail; >>> } >>> >>> + ret = validate_name(hls->nb_varstreams, s->filename); >>> + if (ret < 0) >>> + goto fail; >>> + >>> + if (hls->segment_filename) { >>> + ret = validate_name(hls->nb_varstreams, hls->segment_filename); >>> + if (ret < 0) >>> + goto fail; >>> + } >>> + >>> + if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { >>> + ret = validate_name(hls->nb_varstreams, hls->fmp4_init_filename); >>> + if (ret < 0) >>> + goto fail; >>> + } >>> + >>> + if (hls->subtitle_filename) { >>> + ret = validate_name(hls->nb_varstreams, hls->subtitle_filename); >>> + if (ret < 0) >>> + goto fail; >>> + } >>> + >>> if (hls->master_pl_name) { >>> ret = update_master_pl_info(s); >>> if (ret < 0) { >>> @@ -2108,6 +2177,18 @@ static int hls_init(AVFormatContext *s) >>> hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * >>> AV_TIME_BASE; >>> for (i = 0; i < hls->nb_varstreams; i++) { >>> vs = &hls->var_streams[i]; >>> + >> from here >>> + m3u8_name_size = strlen(s->filename) + 1; >>> + vs->m3u8_name = av_malloc(m3u8_name_size); >>> + if (!vs->m3u8_name ) { >>> + ret = AVERROR(ENOMEM); >>> + goto fail; >>> + } >>> + av_strlcpy(vs->m3u8_name, s->filename, m3u8_name_size); >> to here. is this mean strdup? > Yes, it is doing the same operation as that of strdup. Since, the size of the > allocated memory was needed to be used in the below line (m3u8_name_size), > av_malloc was used instead of strdup. What about modify to :
m3u8_name_size = strlen(s->filename) + 1; vs_>m3u8_name = av_strdup(s->filename); if (!vs->m3u8_name) { ret = AVERROR(ENOMEM); goto fail; } ret = format_name(vs->m3u8_name, m3u8_name_size, i); ? >>> + ret = format_name(vs->m3u8_name, m3u8_name_size, i); >>> + if (ret < 0) >>> + goto fail; >>> + >>> vs->sequence = hls->start_sequence; >>> vs->start_pts = AV_NOPTS_VALUE; >>> vs->end_pts = AV_NOPTS_VALUE; >>> @@ -2161,9 +2242,6 @@ static int hls_init(AVFormatContext *s) >>> } >>> if (hls->segment_filename) { >>> basename_size = strlen(hls->segment_filename) + 1; >>> - if (hls->nb_varstreams > 1) { >>> - basename_size += strlen(POSTFIX_PATTERN); >>> - } >>> vs->basename = av_malloc(basename_size); >>> if (!vs->basename) { >>> ret = AVERROR(ENOMEM); >>> @@ -2171,6 +2249,9 @@ static int hls_init(AVFormatContext *s) >>> } >>> >>> av_strlcpy(vs->basename, hls->segment_filename, basename_size); >>> + ret = format_name(vs->basename, basename_size, i); >>> + if (ret < 0) >>> + goto fail; >>> } else { >>> if (hls->flags & HLS_SINGLE_FILE) { >>> if (hls->segment_type == SEGMENT_TYPE_FMP4) { >>> @@ -2181,13 +2262,9 @@ static int hls_init(AVFormatContext *s) >>> } >>> >>> if (hls->use_localtime) { >>> - basename_size = strlen(s->filename) + >>> strlen(pattern_localtime_fmt) + 1; >>> + basename_size = strlen(vs->m3u8_name) + >>> strlen(pattern_localtime_fmt) + 1; >>> } else { >>> - basename_size = strlen(s->filename) + strlen(pattern) + 1; >>> - } >>> - >>> - if (hls->nb_varstreams > 1) { >>> - basename_size += strlen(POSTFIX_PATTERN); >>> + basename_size = strlen(vs->m3u8_name) + strlen(pattern) + >>> 1; >>> } >>> >>> vs->basename = av_malloc(basename_size); >>> @@ -2196,7 +2273,7 @@ static int hls_init(AVFormatContext *s) >>> goto fail; >>> } >>> >>> - av_strlcpy(vs->basename, s->filename, basename_size); >>> + av_strlcpy(vs->basename, vs->m3u8_name, basename_size); >>> >>> p = strrchr(vs->basename, '.'); >>> if (p) >>> @@ -2208,28 +2285,6 @@ static int hls_init(AVFormatContext *s) >>> } >>> } >>> >>> - m3u8_name_size = strlen(s->filename) + 1; >>> - if (hls->nb_varstreams > 1) { >>> - m3u8_name_size += strlen(POSTFIX_PATTERN); >>> - } >>> - >>> - vs->m3u8_name = av_malloc(m3u8_name_size); >>> - if (!vs->m3u8_name ) { >>> - ret = AVERROR(ENOMEM); >>> - goto fail; >>> - } >>> - >>> - av_strlcpy(vs->m3u8_name, s->filename, m3u8_name_size); >>> - >>> - if (hls->nb_varstreams > 1) { >>> - ret = format_name(vs->basename, basename_size, i); >>> - if (ret < 0) >>> - goto fail; >>> - ret = format_name(vs->m3u8_name, m3u8_name_size, i); >>> - if (ret < 0) >>> - goto fail; >>> - } >>> - >>> if (hls->segment_type == SEGMENT_TYPE_FMP4) { >>> if (hls->nb_varstreams > 1) >>> fmp4_init_filename_len += strlen(POSTFIX_PATTERN); >>> @@ -2240,13 +2295,12 @@ static int hls_init(AVFormatContext *s) >>> } >>> av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename, >>> fmp4_init_filename_len); >>> - if (hls->nb_varstreams > 1) { >>> + >>> + if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { >>> ret = format_name(vs->fmp4_init_filename, >>> fmp4_init_filename_len, i); >>> if (ret < 0) >>> goto fail; >>> - } >>> >>> - if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { >>> fmp4_init_filename_len = strlen(vs->fmp4_init_filename) + 1; >>> vs->base_output_dirname = av_malloc(fmp4_init_filename_len); >>> if (!vs->base_output_dirname) { >>> @@ -2256,6 +2310,12 @@ static int hls_init(AVFormatContext *s) >>> av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename, >>> fmp4_init_filename_len); >>> } else { >>> + if (hls->nb_varstreams > 1) { >>> + ret = append_postfix(vs->fmp4_init_filename, >>> fmp4_init_filename_len, i); >>> + if (ret < 0) >>> + goto fail; >>> + } >>> + >>> fmp4_init_filename_len = strlen(vs->m3u8_name) + >>> strlen(vs->fmp4_init_filename) + 1; >>> >>> @@ -2294,10 +2354,7 @@ static int hls_init(AVFormatContext *s) >>> >>> if (hls->flags & HLS_SINGLE_FILE) >>> vtt_pattern = ".vtt"; >>> - vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) >>> + 1; >>> - if (hls->nb_varstreams > 1) { >>> - vtt_basename_size += strlen(POSTFIX_PATTERN); >>> - } >>> + vtt_basename_size = strlen(vs->m3u8_name) + >>> strlen(vtt_pattern) + 1; >>> >>> vs->vtt_basename = av_malloc(vtt_basename_size); >>> if (!vs->vtt_basename) { >>> @@ -2309,27 +2366,21 @@ static int hls_init(AVFormatContext *s) >>> ret = AVERROR(ENOMEM); >>> goto fail; >>> } >>> - av_strlcpy(vs->vtt_basename, s->filename, vtt_basename_size); >>> + av_strlcpy(vs->vtt_basename, vs->m3u8_name, vtt_basename_size); >>> p = strrchr(vs->vtt_basename, '.'); >>> if (p) >>> *p = '\0'; >>> >>> if ( hls->subtitle_filename ) { >>> strcpy(vs->vtt_m3u8_name, hls->subtitle_filename); >>> + ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i); >>> + if (ret < 0) >>> + goto fail; >>> } else { >>> strcpy(vs->vtt_m3u8_name, vs->vtt_basename); >>> av_strlcat(vs->vtt_m3u8_name, "_vtt.m3u8", >>> vtt_basename_size); >>> } >>> av_strlcat(vs->vtt_basename, vtt_pattern, vtt_basename_size); >>> - >>> - if (hls->nb_varstreams > 1) { >>> - ret= format_name(vs->vtt_basename, vtt_basename_size, i); >>> - if (ret < 0) >>> - goto fail; >>> - ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i); >>> - if (ret < 0) >>> - goto fail; >>> - } >>> } >>> >>> if (hls->baseurl) { >>> -- >>> 1.9.1 >>> >>> _______________________________________________ >>> 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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel