> On 27 Dec 2017, at 11:43, Vishwanath Dixit <vdi...@akamai.com> wrote: > > > > On 12/26/17 4:29 PM, 刘歧 wrote: >> >>> 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); >> >> ? > Thanks for the suggestion. I have made the change in the similar lines and > have submitted the updated patch set with version v3. > (https://patchwork.ffmpeg.org/patch/6985/) I have seen them, just wait developers full review, if no objections, i will merge these patches.
Thanks. >>>>> + 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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel