Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
e872befd
Commit
e872befd
authored
Jan 02, 2018
by
Vishwanath Dixit
Committed by
Steven Liu
Jan 02, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avformat/hlsenc: configurable variant stream index position in filenames
parent
26e1efb0
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
126 additions
and
58 deletions
+126
-58
muxers.texi
doc/muxers.texi
+25
-6
hlsenc.c
libavformat/hlsenc.c
+101
-52
No files found.
doc/muxers.texi
View file @
e872befd
...
...
@@ -577,6 +577,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.
...
...
@@ -703,6 +714,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:
...
...
@@ -816,32 +831,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
...
...
libavformat/hlsenc.c
View file @
e872befd
...
...
@@ -1528,7 +1528,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'
};
...
...
@@ -1547,6 +1547,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
)
...
...
@@ -1690,7 +1737,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
);
...
...
@@ -2052,7 +2099,7 @@ static int hls_init(AVFormatContext *s)
const
char
*
pattern_localtime_fmt
=
get_default_pattern_localtime_fmt
(
s
);
const
char
*
vtt_pattern
=
"%d.vtt"
;
char
*
p
=
NULL
;
int
vtt_basename_size
=
0
,
m3u8_name_size
=
0
;
int
vtt_basename_size
=
0
;
int
fmp4_init_filename_len
=
strlen
(
hls
->
fmp4_init_filename
)
+
1
;
ret
=
update_variant_stream_info
(
s
);
...
...
@@ -2068,6 +2115,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
)
{
...
...
@@ -2100,6 +2169,16 @@ 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
];
vs
->
m3u8_name
=
av_strdup
(
s
->
filename
);
if
(
!
vs
->
m3u8_name
)
{
ret
=
AVERROR
(
ENOMEM
);
goto
fail
;
}
ret
=
format_name
(
vs
->
m3u8_name
,
strlen
(
s
->
filename
)
+
1
,
i
);
if
(
ret
<
0
)
goto
fail
;
vs
->
sequence
=
hls
->
start_sequence
;
vs
->
start_pts
=
AV_NOPTS_VALUE
;
vs
->
end_pts
=
AV_NOPTS_VALUE
;
...
...
@@ -2153,9 +2232,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
);
...
...
@@ -2163,6 +2239,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
)
{
...
...
@@ -2173,13 +2252,9 @@ static int hls_init(AVFormatContext *s)
}
if
(
hls
->
use_localtime
)
{
basename_size
=
strlen
(
s
->
file
name
)
+
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
);
...
...
@@ -2188,7 +2263,7 @@ static int hls_init(AVFormatContext *s)
goto
fail
;
}
av_strlcpy
(
vs
->
basename
,
s
->
file
name
,
basename_size
);
av_strlcpy
(
vs
->
basename
,
vs
->
m3u8_
name
,
basename_size
);
p
=
strrchr
(
vs
->
basename
,
'.'
);
if
(
p
)
...
...
@@ -2200,28 +2275,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
);
...
...
@@ -2232,13 +2285,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
)
{
...
...
@@ -2248,6 +2300,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
;
...
...
@@ -2286,10 +2344,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
)
{
...
...
@@ -2301,27 +2356,21 @@ static int hls_init(AVFormatContext *s)
ret
=
AVERROR
(
ENOMEM
);
goto
fail
;
}
av_strlcpy
(
vs
->
vtt_basename
,
s
->
file
name
,
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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment