Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
10 years ago
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
f6e135943f8a817ff6cffe3c373ff6583c1df54d
f6e13594
1 parent
cd682ae4
enhanced hls, support deviation for duration. 2.0.151.
隐藏空白字符变更
内嵌
并排对比
正在显示
7 个修改的文件
包含
127 行增加
和
18 行删除
README.md
trunk/conf/full.conf
trunk/src/app/srs_app_config.cpp
trunk/src/app/srs_app_config.hpp
trunk/src/app/srs_app_hls.cpp
trunk/src/app/srs_app_hls.hpp
trunk/src/core/srs_core.hpp
README.md
查看文件 @
f6e1359
...
...
@@ -562,6 +562,7 @@ Supported operating systems and hardware:
### SRS 2.0 history
*
v2.0, 2015-03-31, enhanced hls, support deviation for duration. 2.0.151.
*
v2.0, 2015-03-30, for
[
#351
](
https://github.com/winlinvip/simple-rtmp-server/issues/351
)
, support config the m3u8/ts path for hls. 2.0.149.
*
v2.0, 2015-03-17, for
[
#155
](
https://github.com/winlinvip/simple-rtmp-server/issues/155
)
, osx(darwin) support demo with nginx and ffmpeg. 2.0.143.
*
v2.0, 2015-03-15, start
[
2.0release branch
](
https://github.com/winlinvip/simple-rtmp-server/tree/2.0release
)
, 80773 lines.
...
...
trunk/conf/full.conf
查看文件 @
f6e1359
...
...
@@ -560,6 +560,11 @@ vhost with-hls.srs.com {
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#hls-config
# default: [app]/[stream]-[seq].ts
hls_ts_file
[
app
]/[
stream
]-[
seq
].
ts
;
# whether use floor for the hls_ts_file path generation.
# if on, use floor(timestamp/hls_fragment) as the variable [timestamp],
# and use enahanced algorithm to calc deviation for segment.
# default: off
hls_ts_floor
off
;
# the hls entry prefix, which is base url of ts url.
# if specified, the ts path in m3u8 will be like:
# http://your-server/live/livestream-0.ts
...
...
@@ -588,6 +593,11 @@ vhost with-hls.srs.com {
# h264, vn
# default: h264
hls_vcodec
h264
;
# on_hls, never config in here, should config in http_hooks.
# for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#http-callback
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#http-callback
}
}
# the vhost with hls disabled.
...
...
@@ -722,6 +732,20 @@ vhost hooks.callback.srs.com {
# an int value specifies the error code(0 corresponding to success):
# 0
on_dvr
http
://
127
.
0
.
0
.
1
:
8085
/
api
/
v1
/
dvrs
http
://
localhost
:
8085
/
api
/
v1
/
dvrs
;
# when srs reap a ts file of hls, call the hook,
# the request in the POST data string is a object encode by json:
# {
# "action": "on_hls",
# "client_id": 1985,
# "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
# "stream": "livestream",
# "cwd": "/usr/local/srs",
# "file": "./objs/nginx/html/live/livestream.1420254068776-100.ts"
# }
# if valid, the hook must return HTTP code 200(Stauts OK) and response
# an int value specifies the error code(0 corresponding to success):
# 0
on_hls
http
://
127
.
0
.
0
.
1
:
8085
/
api
/
v1
/
hls
http
://
localhost
:
8085
/
api
/
v1
/
hls
;
}
}
...
...
trunk/src/app/srs_app_config.cpp
查看文件 @
f6e1359
...
...
@@ -1482,7 +1482,7 @@ int SrsConfig::check_config()
string
m
=
conf
->
at
(
j
)
->
name
.
c_str
();
if
(
m
!=
"enabled"
&&
m
!=
"hls_entry_prefix"
&&
m
!=
"hls_path"
&&
m
!=
"hls_fragment"
&&
m
!=
"hls_window"
&&
m
!=
"hls_on_error"
&&
m
!=
"hls_storage"
&&
m
!=
"hls_mount"
&&
m
!=
"hls_td_ratio"
&&
m
!=
"hls_aof_ratio"
&&
m
!=
"hls_acodec"
&&
m
!=
"hls_vcodec"
&&
m
!=
"hls_m3u8_file"
&&
m
!=
"hls_ts_file"
&&
m
!=
"hls_m3u8_file"
&&
m
!=
"hls_ts_file"
&&
m
!=
"hls_ts_floor"
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"unsupported vhost hls directive %s, ret=%d"
,
m
.
c_str
(),
ret
);
...
...
@@ -3207,6 +3207,23 @@ string SrsConfig::get_hls_ts_file(string vhost)
return
conf
->
arg0
();
}
bool
SrsConfig
::
get_hls_ts_floor
(
string
vhost
)
{
SrsConfDirective
*
hls
=
get_hls
(
vhost
);
if
(
!
hls
)
{
return
SRS_CONF_DEFAULT_HLS_TS_FLOOR
;
}
SrsConfDirective
*
conf
=
hls
->
get
(
"hls_ts_floor"
);
if
(
!
conf
||
conf
->
arg0
()
!=
"on"
)
{
return
SRS_CONF_DEFAULT_HLS_TS_FLOOR
;
}
return
true
;
}
double
SrsConfig
::
get_hls_fragment
(
string
vhost
)
{
SrsConfDirective
*
hls
=
get_hls
(
vhost
);
...
...
trunk/src/app/srs_app_config.hpp
查看文件 @
f6e1359
...
...
@@ -48,6 +48,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
#define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8"
#define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts"
#define SRS_CONF_DEFAULT_HLS_TS_FLOOR "off"
#define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
#define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5
#define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0
...
...
@@ -885,6 +886,10 @@ public:
*/
virtual
std
::
string
get_hls_ts_file
(
std
::
string
vhost
);
/**
* whether enable the floor(timestamp/hls_fragment) for variable timestamp.
*/
virtual
bool
get_hls_ts_floor
(
std
::
string
vhost
);
/**
* get the hls fragment time, in seconds.
*/
virtual
double
get_hls_fragment
(
std
::
string
vhost
);
...
...
trunk/src/app/srs_app_hls.cpp
查看文件 @
f6e1359
...
...
@@ -58,6 +58,11 @@ using namespace std;
// drop the segment when duration of ts too small.
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
// startup piece, the first piece, fragment percent to reap.
#define SRS_HLS_FLOOR_STARTUP_PERCENT 0.1
// fragment plus the deviation percent.
#define SRS_HLS_FLOOR_REAP_PERCENT 0.9
ISrsHlsHandler
::
ISrsHlsHandler
()
{
}
...
...
@@ -170,6 +175,8 @@ SrsHlsMuxer::SrsHlsMuxer()
handler
=
NULL
;
hls_fragment
=
hls_window
=
0
;
hls_aof_ratio
=
1.0
;
hls_fragment_deviation
=
0
;
hls_ts_floor
=
false
;
target_duration
=
0
;
_sequence_no
=
0
;
current
=
NULL
;
...
...
@@ -205,8 +212,24 @@ int SrsHlsMuxer::sequence_no()
return
_sequence_no
;
}
string
SrsHlsMuxer
::
ts_url
()
{
return
current
?
current
->
uri
:
""
;
}
double
SrsHlsMuxer
::
duration
()
{
return
current
?
current
->
duration
:
0
;
}
double
SrsHlsMuxer
::
deviation
()
{
return
hls_fragment_deviation
;
}
int
SrsHlsMuxer
::
update_config
(
SrsRequest
*
r
,
string
entry_prefix
,
string
path
,
string
m3u8_file
,
string
ts_file
,
int
fragment
,
int
window
,
double
aof_ratio
string
path
,
string
m3u8_file
,
string
ts_file
,
double
fragment
,
double
window
,
bool
ts_floor
,
double
aof_ratio
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -218,7 +241,11 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
hls_ts_file
=
ts_file
;
hls_fragment
=
fragment
;
hls_aof_ratio
=
aof_ratio
;
hls_ts_floor
=
ts_floor
;
hls_window
=
window
;
// for the first time, we set to -N% of fragment,
// that is, the first piece always smaller.
hls_fragment_deviation
=
-
1
*
(
fragment
*
SRS_HLS_FLOOR_STARTUP_PERCENT
);
// generate the m3u8 dir and path.
m3u8
=
path
+
"/"
+
m3u8_file
;
...
...
@@ -301,6 +328,11 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
// generate filename.
std
::
string
ts_file
=
hls_ts_file
;
ts_file
=
srs_path_build_stream
(
ts_file
,
req
->
vhost
,
req
->
app
,
req
->
stream
);
if
(
hls_ts_floor
)
{
std
::
stringstream
ts_floor
;
ts_floor
<<
(
int64_t
)(
srs_get_system_time_ms
()
/
(
1000
*
hls_fragment
));
ts_file
=
srs_string_replace
(
ts_file
,
"[timestamp]"
,
ts_floor
.
str
());
}
ts_file
=
srs_path_build_timestamp
(
ts_file
);
if
(
true
)
{
std
::
stringstream
ss
;
...
...
@@ -308,6 +340,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
ts_file
=
srs_string_replace
(
ts_file
,
"[seq]"
,
ss
.
str
());
}
current
->
full_path
=
hls_path
+
"/"
+
ts_file
;
srs_info
(
"hls: generate ts path %s, tmpl=%s, floor=%d"
,
ts_file
.
c_str
(),
hls_ts_file
.
c_str
(),
hls_ts_floor
);
// the ts url, relative or absolute url.
std
::
string
ts_url
=
current
->
full_path
;
...
...
@@ -336,7 +369,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
srs_error
(
"open hls muxer failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"open HLS muxer success. path=%s, tmp=%s"
,
srs_info
(
"open HLS muxer success. path=%s, tmp=%s"
,
current
->
full_path
.
c_str
(),
tmp_file
.
c_str
());
// set the segment muxer audio codec.
...
...
@@ -363,14 +396,22 @@ int SrsHlsMuxer::on_sequence_header()
bool
SrsHlsMuxer
::
is_segment_overflow
()
{
srs_assert
(
current
);
return
current
->
duration
>=
hls_fragment
;
// use N% deviation, to smoother.
double
deviation
=
hls_ts_floor
?
SRS_HLS_FLOOR_REAP_PERCENT
*
hls_fragment_deviation
:
0.0
;
return
current
->
duration
>=
hls_fragment
+
deviation
;
}
bool
SrsHlsMuxer
::
is_segment_absolutely_overflow
()
{
// @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950
srs_assert
(
current
);
return
current
->
duration
>=
hls_aof_ratio
*
hls_fragment
;
// use N% deviation, to smoother.
double
deviation
=
hls_ts_floor
?
SRS_HLS_FLOOR_REAP_PERCENT
*
hls_fragment_deviation
:
0.0
;
return
current
->
duration
>=
hls_aof_ratio
*
(
hls_fragment
+
deviation
);
}
int
SrsHlsMuxer
::
update_acodec
(
SrsCodecAudio
ac
)
...
...
@@ -457,10 +498,15 @@ int SrsHlsMuxer::segment_close(string log_desc)
// valid, add to segments if segment duration is ok
if
(
current
->
duration
*
1000
>=
SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS
)
{
segments
.
push_back
(
current
);
// when reap ts, adjust the deviation.
if
(
hls_ts_floor
)
{
hls_fragment_deviation
+=
(
double
)(
hls_fragment
-
current
->
duration
);
}
srs_info
(
"%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"
PRId64
""
,
srs_info
(
"%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"
PRId64
"
, deviation=%.2f
"
,
log_desc
.
c_str
(),
current
->
sequence_no
,
current
->
uri
.
c_str
(),
current
->
duration
,
current
->
segment_start_dts
);
current
->
segment_start_dts
,
hls_fragment_deviation
);
// notify handler for update ts.
srs_assert
(
current
->
writer
);
...
...
@@ -505,7 +551,7 @@ int SrsHlsMuxer::segment_close(string log_desc)
// shrink the segments.
double
duration
=
0
;
int
remove_index
=
-
1
;
for
(
int
i
=
segments
.
size
()
-
1
;
i
>=
0
;
i
--
)
{
for
(
int
i
=
(
int
)
segments
.
size
()
-
1
;
i
>=
0
;
i
--
)
{
SrsHlsSegment
*
segment
=
segments
[
i
];
duration
+=
segment
->
duration
;
...
...
@@ -662,8 +708,8 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
std
::
string
stream
=
req
->
stream
;
std
::
string
app
=
req
->
app
;
int
hls_fragment
=
(
int
)
_srs_config
->
get_hls_fragment
(
vhost
);
int
hls_window
=
(
int
)
_srs_config
->
get_hls_window
(
vhost
);
double
hls_fragment
=
_srs_config
->
get_hls_fragment
(
vhost
);
double
hls_window
=
_srs_config
->
get_hls_window
(
vhost
);
// get the hls m3u8 ts list entry prefix config
std
::
string
entry_prefix
=
_srs_config
->
get_hls_entry_prefix
(
vhost
);
...
...
@@ -673,12 +719,16 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
std
::
string
ts_file
=
_srs_config
->
get_hls_ts_file
(
vhost
);
// the audio overflow, for pure audio to reap segment.
double
hls_aof_ratio
=
_srs_config
->
get_hls_aof_ratio
(
vhost
);
// whether use floor(timestamp/hls_fragment) for variable timestamp
bool
ts_floor
=
_srs_config
->
get_hls_ts_floor
(
vhost
);
// TODO: FIXME: support load exists m3u8, to continue publish stream.
// for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase.
// open muxer
if
((
ret
=
muxer
->
update_config
(
req
,
entry_prefix
,
path
,
m3u8_file
,
ts_file
,
hls_fragment
,
hls_window
,
hls_aof_ratio
))
!=
ERROR_SUCCESS
)
{
if
((
ret
=
muxer
->
update_config
(
req
,
entry_prefix
,
path
,
m3u8_file
,
ts_file
,
hls_fragment
,
hls_window
,
ts_floor
,
hls_aof_ratio
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"m3u8 muxer update config failed. ret=%d"
,
ret
);
return
ret
;
}
...
...
@@ -687,6 +737,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
srs_error
(
"m3u8 muxer open segment failed. ret=%d"
,
ret
);
return
ret
;
}
srs_trace
(
"hls: win=%.2f, frag=%.2f, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d"
,
hls_window
,
hls_fragment
,
entry_prefix
.
c_str
(),
path
.
c_str
(),
m3u8_file
.
c_str
(),
ts_file
.
c_str
(),
hls_aof_ratio
,
ts_floor
);
return
ret
;
}
...
...
@@ -1057,9 +1110,9 @@ void SrsHls::hls_show_mux_log()
// the run time is not equals to stream time,
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994
// it's ok.
srs_trace
(
"-> "
SRS_CONSTS_LOG_HLS
" time=%"
PRId64
", stream dts=%"
PRId64
"(%"
PRId64
"ms), sequence_no=%d"
,
pprint
->
age
(),
stream_dts
,
stream_dts
/
90
,
muxer
->
sequence_no
());
srs_trace
(
"-> "
SRS_CONSTS_LOG_HLS
" time=%"
PRId64
", stream dts=%"
PRId64
"(%"
PRId64
"ms), sequence_no=%d, ts=%s, duration=%.2f, deviation=%.2f"
,
pprint
->
age
(),
stream_dts
,
stream_dts
/
90
,
muxer
->
sequence_no
(),
muxer
->
ts_url
().
c_str
(),
muxer
->
duration
(),
muxer
->
deviation
());
}
}
...
...
trunk/src/app/srs_app_hls.hpp
查看文件 @
f6e1359
...
...
@@ -172,8 +172,14 @@ private:
std
::
string
hls_ts_file
;
std
::
string
m3u8_dir
;
double
hls_aof_ratio
;
int
hls_fragment
;
int
hls_window
;
double
hls_fragment
;
double
hls_window
;
private
:
// whether use floor algorithm for timestamp.
bool
hls_ts_floor
;
// the deviation in seconds to adjust the fragment to be more
// bigger or smaller.
double
hls_fragment_deviation
;
private
:
int
_sequence_no
;
int
target_duration
;
...
...
@@ -203,6 +209,9 @@ public:
virtual
~
SrsHlsMuxer
();
public
:
virtual
int
sequence_no
();
virtual
std
::
string
ts_url
();
virtual
double
duration
();
virtual
double
deviation
();
public
:
/**
* initialize the hls muxer.
...
...
@@ -213,7 +222,7 @@ public:
*/
virtual
int
update_config
(
SrsRequest
*
r
,
std
::
string
entry_prefix
,
std
::
string
path
,
std
::
string
m3u8_file
,
std
::
string
ts_file
,
int
fragment
,
int
window
,
double
aof_ratio
);
double
fragment
,
double
window
,
bool
ts_floor
,
double
aof_ratio
);
/**
* open a new segment(a new ts file),
* @param segment_start_dts use to calc the segment duration,
...
...
trunk/src/core/srs_core.hpp
查看文件 @
f6e1359
...
...
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 1
49
#define VERSION_REVISION 1
51
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
...
...
请
注册
或
登录
后发表评论