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
2015-04-10 12:01:52 +0800
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
17c1423f4a743a5bf19bd7b6f126c82f066fd4f4
17c1423f
2 parents
425e69e0
e3c6e525
Merge branch '2.0release' into develop
显示空白字符变更
内嵌
并排对比
正在显示
9 个修改的文件
包含
209 行增加
和
49 行删除
README.md
trunk/conf/full.conf
trunk/research/api-server/server.py
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/app/srs_app_http_hooks.cpp
trunk/src/app/srs_app_http_hooks.hpp
README.md
查看文件 @
17c1423
...
...
@@ -566,6 +566,8 @@ Supported operating systems and hardware:
### SRS 2.0 history
*
v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts.
*
v2.0, 2015-04-10, refine the hls deviation for floor algorithm.
*
v2.0, 2015-04-08, for
[
#375
](
https://github.com/winlinvip/simple-rtmp-server/issues/375
)
, fix hls bug, keep cc continous between ts files. 2.0.159.
*
v2.0, 2015-04-04, for
[
#304
](
https://github.com/winlinvip/simple-rtmp-server/issues/304
)
, rewrite annexb mux for ts, refer to apple sample. 2.0.157.
*
v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156.
...
...
trunk/conf/full.conf
查看文件 @
17c1423
...
...
@@ -618,6 +618,15 @@ vhost with-hls.srs.com {
# 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
# on_hls_notify, never config in here, should config in http_hooks.
# we support the variables to generate the notify url:
# [app], replace with the app.
# [stream], replace with the stream.
# [ts_url], replace with the ts url.
# for the hls http callback, @see http_hooks.on_hls_notify of vhost hooks.callback.srs.com
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#on-hls-notify
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#on-hls-notify
}
}
# the vhost with hls disabled.
...
...
@@ -768,6 +777,14 @@ vhost hooks.callback.srs.com {
# 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
;
# when srs reap a ts file of hls, call this hook,
# used to push file to cdn network, by get the ts file from cdn network.
# so we use HTTP GET and use the variable following:
# [app], replace with the app.
# [stream], replace with the stream.
# [ts_url], replace with the ts url.
# ignore any return data of server.
on_hls_notify
http
://
127
.
0
.
0
.
1
:
8085
/
api
/
v1
/
hls
/[
app
]/[
stream
][
ts_url
];
}
}
...
...
trunk/research/api-server/server.py
查看文件 @
17c1423
...
...
@@ -314,10 +314,24 @@ handle the hls requests: hls stream.
class
RESTHls
(
object
):
exposed
=
True
def
GET
(
self
):
'''
for SRS hook: on_hls_notify
on_hls_notify:
when srs reap a ts file of hls, call this hook,
used to push file to cdn network, by get the ts file from cdn network.
so we use HTTP GET and use the variable following:
[app], replace with the app.
[stream], replace with the stream.
[ts_url], replace with the ts url.
ignore any return data of server.
'''
def
GET
(
self
,
*
args
,
**
kwargs
):
enable_crossdomain
()
hls
=
{}
hls
=
{
"args"
:
args
,
"kwargs"
:
kwargs
}
return
json
.
dumps
(
hls
)
'''
...
...
trunk/src/app/srs_app_config.cpp
查看文件 @
17c1423
...
...
@@ -1499,7 +1499,7 @@ int SrsConfig::check_config()
string
m
=
conf
->
at
(
j
)
->
name
.
c_str
();
if
(
m
!=
"enabled"
&&
m
!=
"on_connect"
&&
m
!=
"on_close"
&&
m
!=
"on_publish"
&&
m
!=
"on_unpublish"
&&
m
!=
"on_play"
&&
m
!=
"on_stop"
&&
m
!=
"on_dvr"
&&
m
!=
"on_hls"
&&
m
!=
"on_dvr"
&&
m
!=
"on_hls"
&&
m
!=
"on_hls_notify"
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"unsupported vhost http_hooks directive %s, ret=%d"
,
m
.
c_str
(),
ret
);
...
...
@@ -2429,6 +2429,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
return
conf
->
get
(
"on_hls"
);
}
SrsConfDirective
*
SrsConfig
::
get_vhost_on_hls_notify
(
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost_http_hooks
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"on_hls_notify"
);
}
bool
SrsConfig
::
get_bw_check_enabled
(
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
...
...
trunk/src/app/srs_app_config.hpp
查看文件 @
17c1423
...
...
@@ -646,6 +646,11 @@ public:
* @return the on_hls callback directive, the args is the url to callback.
*/
virtual
SrsConfDirective
*
get_vhost_on_hls
(
std
::
string
vhost
);
/**
* get the on_hls_notify callbacks of vhost.
* @return the on_hls_notify callback directive, the args is the url to callback.
*/
virtual
SrsConfDirective
*
get_vhost_on_hls_notify
(
std
::
string
vhost
);
// bwct(bandwidth check tool) section
public:
/**
...
...
trunk/src/app/srs_app_hls.cpp
查看文件 @
17c1423
...
...
@@ -59,10 +59,10 @@ 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.2
// reset the piece id when deviation overflow this.
#define SRS_JUMP_WHEN_PIECE_DEVIATION 10
ISrsHlsHandler
::
ISrsHlsHandler
()
{
...
...
@@ -213,9 +213,49 @@ int SrsDvrAsyncCallOnHls::call()
string
SrsDvrAsyncCallOnHls
::
to_string
()
{
std
::
stringstream
ss
;
ss
<<
"vhost="
<<
req
->
vhost
<<
", file="
<<
path
;
return
ss
.
str
();
return
"on_hls: "
+
path
;
}
SrsDvrAsyncCallOnHlsNotify
::
SrsDvrAsyncCallOnHlsNotify
(
SrsRequest
*
r
,
string
u
)
{
req
=
r
;
ts_url
=
u
;
}
SrsDvrAsyncCallOnHlsNotify
::~
SrsDvrAsyncCallOnHlsNotify
()
{
}
int
SrsDvrAsyncCallOnHlsNotify
::
call
()
{
int
ret
=
ERROR_SUCCESS
;
#ifdef SRS_AUTO_HTTP_CALLBACK
// http callback for on_hls_notify in config.
if
(
_srs_config
->
get_vhost_http_hooks_enabled
(
req
->
vhost
))
{
// HTTP: on_hls
SrsConfDirective
*
on_hls
=
_srs_config
->
get_vhost_on_hls_notify
(
req
->
vhost
);
if
(
!
on_hls
)
{
srs_info
(
"ignore the empty http callback: on_hls_notify"
);
return
ret
;
}
for
(
int
i
=
0
;
i
<
(
int
)
on_hls
->
args
.
size
();
i
++
)
{
std
::
string
url
=
on_hls
->
args
.
at
(
i
);
if
((
ret
=
SrsHttpHooks
::
on_hls_notify
(
url
,
req
,
ts_url
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"hook client on_hls_notify failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
}
}
#endif
return
ret
;
}
string
SrsDvrAsyncCallOnHlsNotify
::
to_string
()
{
return
"on_hls_notify: "
+
ts_url
;
}
SrsHlsMuxer
::
SrsHlsMuxer
()
...
...
@@ -224,7 +264,7 @@ SrsHlsMuxer::SrsHlsMuxer()
handler
=
NULL
;
hls_fragment
=
hls_window
=
0
;
hls_aof_ratio
=
1.0
;
hls_fragment_deviation
=
0
;
deviation_ts
=
0
;
hls_cleanup
=
true
;
previous_floor_ts
=
0
;
accept_floor_ts
=
0
;
...
...
@@ -269,26 +309,14 @@ double SrsHlsMuxer::duration()
return
current
?
current
->
duration
:
0
;
}
double
SrsHlsMuxer
::
deviation
()
int
SrsHlsMuxer
::
deviation
()
{
// no floor, no deviation.
if
(
!
hls_ts_floor
)
{
return
0
;
}
return
hls_fragment_deviation
;
}
int
SrsHlsMuxer
::
absolute_deviation
()
{
// no floor, no deviation.
if
(
!
hls_ts_floor
)
{
return
0
;
}
// accept the floor ts for the first piece.
int64_t
floor_ts
=
(
int64_t
)(
srs_get_system_time_ms
()
/
(
1000
*
hls_fragment
));
return
(
int
)(
accept_floor_ts
-
(
floor_ts
-
1
));
return
deviation_ts
;
}
int
SrsHlsMuxer
::
initialize
(
ISrsHlsHandler
*
h
)
...
...
@@ -323,9 +351,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
previous_floor_ts
=
0
;
accept_floor_ts
=
0
;
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
);
deviation_ts
=
0
;
// generate the m3u8 dir and path.
m3u8
=
path
+
"/"
+
m3u8_file
;
...
...
@@ -412,26 +438,39 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
ts_file
=
srs_path_build_stream
(
ts_file
,
req
->
vhost
,
req
->
app
,
req
->
stream
);
if
(
hls_ts_floor
)
{
// accept the floor ts for the first piece.
int64_t
floor_ts
=
(
int64_t
)(
srs_get_system_time_ms
()
/
(
1000
*
hls_fragment
));
int64_t
current_
floor_ts
=
(
int64_t
)(
srs_get_system_time_ms
()
/
(
1000
*
hls_fragment
));
if
(
!
accept_floor_ts
)
{
accept_floor_ts
=
floor_ts
-
1
;
accept_floor_ts
=
current_
floor_ts
-
1
;
}
else
{
accept_floor_ts
++
;
}
// jump when deviation more than 10p
if
(
accept_floor_ts
-
current_floor_ts
>
SRS_JUMP_WHEN_PIECE_DEVIATION
)
{
srs_warn
(
"hls: jmp for ts deviation, current=%"
PRId64
", accept=%"
PRId64
,
current_floor_ts
,
accept_floor_ts
);
accept_floor_ts
=
current_floor_ts
-
1
;
}
// when reap ts, adjust the deviation.
deviation_ts
=
(
int
)(
accept_floor_ts
-
current_floor_ts
);
// dup/jmp detect for ts in floor mode.
if
(
previous_floor_ts
&&
previous_floor_ts
!=
current_floor_ts
-
1
)
{
srs_warn
(
"hls: dup or jmp for floor ts, previous=%"
PRId64
", current=%"
PRId64
", accept=%"
PRId64
", deviation=%d"
,
previous_floor_ts
,
current_floor_ts
,
accept_floor_ts
,
deviation_ts
);
}
previous_floor_ts
=
current_floor_ts
;
// we always ensure the piece is increase one by one.
std
::
stringstream
ts_floor
;
ts_floor
<<
accept_floor_ts
;
ts_file
=
srs_string_replace
(
ts_file
,
"[timestamp]"
,
ts_floor
.
str
());
// dup/jmp detect for ts in floor mode.
if
(
previous_floor_ts
&&
previous_floor_ts
!=
floor_ts
-
1
)
{
srs_warn
(
"hls: dup or jmp for floor ts, previous=%"
PRId64
", current=%"
PRId64
", ts=%s, deviation=%.2f"
,
previous_floor_ts
,
floor_ts
,
ts_file
.
c_str
(),
hls_fragment_deviation
);
}
previous_floor_ts
=
floor_ts
;
}
// TODO: FIMXE: we must use the accept ts floor time to generate the hour variable.
ts_file
=
srs_path_build_timestamp
(
ts_file
);
}
else
{
ts_file
=
srs_path_build_timestamp
(
ts_file
);
}
if
(
true
)
{
std
::
stringstream
ss
;
ss
<<
current
->
sequence_no
;
...
...
@@ -497,7 +536,7 @@ bool SrsHlsMuxer::is_segment_overflow()
srs_assert
(
current
);
// use N% deviation, to smoother.
double
deviation
=
hls_ts_floor
?
SRS_HLS_FLOOR_REAP_PERCENT
*
hls_fragment_deviation
:
0.0
;
double
deviation
=
hls_ts_floor
?
SRS_HLS_FLOOR_REAP_PERCENT
*
deviation_ts
*
hls_fragment
:
0.0
;
return
current
->
duration
>=
hls_fragment
+
deviation
;
}
...
...
@@ -594,19 +633,19 @@ int SrsHlsMuxer::segment_close(string log_desc)
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
);
// use async to call the http hooks, for it will cause thread switch.
if
((
ret
=
async
->
call
(
new
SrsDvrAsyncCallOnHls
(
req
,
current
->
full_path
,
current
->
sequence_no
,
current
->
duration
)))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
// use async to call the http hooks, for it will cause thread switch.
if
((
ret
=
async
->
call
(
new
SrsDvrAsyncCallOnHls
(
req
,
current
->
full_path
,
current
->
sequence_no
,
current
->
duration
)))
!=
ERROR_SUCCESS
)
{
if
((
ret
=
async
->
call
(
new
SrsDvrAsyncCallOnHls
Notify
(
req
,
current
->
uri
)))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
srs_info
(
"%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"
PRId64
", deviation=%.2f"
,
srs_info
(
"%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"
PRId64
,
log_desc
.
c_str
(),
current
->
sequence_no
,
current
->
uri
.
c_str
(),
current
->
duration
,
current
->
segment_start_dts
,
hls_fragment_deviation
);
current
->
segment_start_dts
);
// notify handler for update ts.
srs_assert
(
current
->
writer
);
...
...
@@ -1222,9 +1261,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), sno=%d, ts=%s, dur=%.2f, dva=%
.2fs/%
dp"
,
srs_trace
(
"-> "
SRS_CONSTS_LOG_HLS
" time=%"
PRId64
", stream dts=%"
PRId64
"(%"
PRId64
"ms), sno=%d, ts=%s, dur=%.2f, dva=%dp"
,
pprint
->
age
(),
stream_dts
,
stream_dts
/
90
,
muxer
->
sequence_no
(),
muxer
->
ts_url
().
c_str
(),
muxer
->
duration
(),
muxer
->
deviation
()
,
muxer
->
absolute_deviation
()
);
muxer
->
duration
(),
muxer
->
deviation
());
}
}
...
...
trunk/src/app/srs_app_hls.hpp
查看文件 @
17c1423
...
...
@@ -157,7 +157,7 @@ public:
};
/**
* the
dvr async call.
* the
hls async call: on_hls
*/
class
SrsDvrAsyncCallOnHls
:
public
ISrsDvrAsyncCall
{
...
...
@@ -175,6 +175,22 @@ public:
};
/**
* the hls async call: on_hls_notify
*/
class
SrsDvrAsyncCallOnHlsNotify
:
public
ISrsDvrAsyncCall
{
private
:
std
::
string
ts_url
;
SrsRequest
*
req
;
public
:
SrsDvrAsyncCallOnHlsNotify
(
SrsRequest
*
r
,
std
::
string
u
);
virtual
~
SrsDvrAsyncCallOnHlsNotify
();
public
:
virtual
int
call
();
virtual
std
::
string
to_string
();
};
/**
* muxer the HLS stream(m3u8 and ts files).
* generally, the m3u8 muxer only provides methods to open/close segments,
* to flush video/audio, without any mechenisms.
...
...
@@ -199,9 +215,9 @@ private:
private
:
// whether use floor algorithm for timestamp.
bool
hls_ts_floor
;
// the deviation in
seconds
to adjust the fragment to be more
// the deviation in
piece
to adjust the fragment to be more
// bigger or smaller.
double
hls_fragment_deviation
;
int
deviation_ts
;
// the previous reap floor timestamp,
// used to detect the dup or jmp or ts.
int64_t
accept_floor_ts
;
...
...
@@ -242,8 +258,7 @@ public:
virtual
int
sequence_no
();
virtual
std
::
string
ts_url
();
virtual
double
duration
();
virtual
double
deviation
();
virtual
int
absolute_deviation
();
virtual
int
deviation
();
public
:
/**
* initialize the hls muxer.
...
...
trunk/src/app/srs_app_http_hooks.cpp
查看文件 @
17c1423
...
...
@@ -37,6 +37,7 @@ using namespace std;
#include <srs_app_http_client.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp>
#define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS)
...
...
@@ -325,6 +326,55 @@ int SrsHttpHooks::on_hls(string url, SrsRequest* req, string file, int sn, doubl
return
ret
;
}
int
SrsHttpHooks
::
on_hls_notify
(
std
::
string
url
,
SrsRequest
*
req
,
std
::
string
ts_url
)
{
int
ret
=
ERROR_SUCCESS
;
int
client_id
=
_srs_context
->
get_id
();
std
::
string
cwd
=
_srs_config
->
cwd
();
if
(
srs_string_starts_with
(
ts_url
,
"http://"
)
||
srs_string_starts_with
(
ts_url
,
"https://"
))
{
url
=
ts_url
;
}
url
=
srs_string_replace
(
url
,
"[app]"
,
req
->
app
);
url
=
srs_string_replace
(
url
,
"[stream]"
,
req
->
stream
);
url
=
srs_string_replace
(
url
,
"[ts_url]"
,
ts_url
);
SrsHttpUri
uri
;
if
((
ret
=
uri
.
initialize
(
url
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"http: post failed. url=%s, ret=%d"
,
url
.
c_str
(),
ret
);
return
ret
;
}
SrsHttpClient
http
;
if
((
ret
=
http
.
initialize
(
uri
.
get_host
(),
uri
.
get_port
()))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsHttpMessage
*
msg
=
NULL
;
if
((
ret
=
http
.
get
(
uri
.
get_path
(),
""
,
&
msg
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsAutoFree
(
SrsHttpMessage
,
msg
);
ISrsHttpResponseReader
*
br
=
msg
->
body_reader
();
while
(
!
br
->
eof
())
{
std
::
string
data
;
if
((
ret
=
br
->
read
(
data
))
!=
ERROR_SUCCESS
)
{
break
;
}
}
srs_trace
(
"http hook on_hls_notify success. client_id=%d, url=%s, code=%d, ret=%d"
,
client_id
,
url
.
c_str
(),
msg
->
status_code
(),
ret
);
// ignore any error for on_hls_notify.
ret
=
ERROR_SUCCESS
;
return
ret
;
}
int
SrsHttpHooks
::
do_post
(
std
::
string
url
,
std
::
string
req
,
int
&
code
,
string
&
res
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
trunk/src/app/srs_app_http_hooks.hpp
查看文件 @
17c1423
...
...
@@ -105,6 +105,13 @@ public:
* @param duration the segment duration in seconds.
*/
static
int
on_hls
(
std
::
string
url
,
SrsRequest
*
req
,
std
::
string
file
,
int
sn
,
double
duration
);
/**
* when hls reap segment, callback.
* @param url the api server url, to process the event.
* ignore if empty.
* @param ts_url the ts uri, used to replace the variable [ts_url] in url.
*/
static
int
on_hls_notify
(
std
::
string
url
,
SrsRequest
*
req
,
std
::
string
ts_url
);
private
:
static
int
do_post
(
std
::
string
url
,
std
::
string
req
,
int
&
code
,
std
::
string
&
res
);
};
...
...
请
注册
或
登录
后发表评论