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-02-21 23:09:21 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
849e59b05d6718458d3dadc20e028e27c88bb972
849e59b0
1 parent
c67a4fdf
for #179, support http api to start dvr.
隐藏空白字符变更
内嵌
并排对比
正在显示
9 个修改的文件
包含
320 行增加
和
21 行删除
trunk/conf/full.conf
trunk/src/app/srs_app_config.cpp
trunk/src/app/srs_app_config.hpp
trunk/src/app/srs_app_dvr.cpp
trunk/src/app/srs_app_dvr.hpp
trunk/src/app/srs_app_http_api.cpp
trunk/src/app/srs_app_json.cpp
trunk/src/app/srs_app_json.hpp
trunk/src/kernel/srs_kernel_error.hpp
trunk/conf/full.conf
查看文件 @
849e59b
...
...
@@ -296,15 +296,14 @@ vhost dvr.srs.com {
# request params, for example ?vhost=__defaultVhost__, where:
# vhost, query all dvr of this vhost.
# response in json, where:
# {code:0, dvrs: [{plan:"api", path:"./objs/nginx/html",
# autostart:true, wait_keyframe:true, jitter:"full"
# {code:0, dvrs: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv",
# wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback"
# }]}
# method=POST
# to start dvr of specified vhost.
# request should encode in json, specifies the dvr to create, where:
# {plan:"api", path:"./objs/nginx/html",
# autostart:true, wait_keyframe:true, jitter:"full",
# vhost:"__defaultVhost", callback:"http://dvr/callback"
# {path_tmpl:"./[15].[04].[05].[999].flv",
# wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback"
# }
# response in json, where:
# {code:0}
...
...
@@ -329,7 +328,7 @@ vhost dvr.srs.com {
# [05], repleace this const to current second.
# [999], repleace this const to current millisecond.
# [timestamp],replace this const to current UNIX timestamp in ms.
# @remark we use golang time format "2006-01-02 15:04:05.999"
# @remark we use golang time format "2006-01-02 15:04:05.999"
as "[2006]-[01]-[02]_[15].[04].[05]_[999]"
# for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776
# 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename):
# dvr_path ./objs/nginx/html;
...
...
trunk/src/app/srs_app_config.cpp
查看文件 @
849e59b
...
...
@@ -1977,6 +1977,38 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc)
return
::
atoi
(
conf
->
arg0
().
c_str
());
}
SrsConfDirective
*
SrsConfig
::
create_directive
(
string
vhost
,
string
directive
,
string
sub_directive
)
{
SrsConfDirective
*
vhost_conf
=
get_vhost
(
vhost
);
if
(
!
vhost_conf
)
{
vhost_conf
=
new
SrsConfDirective
();
root
->
directives
.
push_back
(
vhost_conf
);
}
if
(
directive
.
empty
())
{
return
vhost_conf
;
}
SrsConfDirective
*
dir
=
vhost_conf
->
get
(
directive
);
if
(
!
dir
)
{
dir
=
new
SrsConfDirective
();
vhost_conf
->
directives
.
push_back
(
dir
);
}
if
(
sub_directive
.
empty
())
{
return
dir
;
}
SrsConfDirective
*
sdir
=
dir
->
get
(
sub_directive
);
if
(
!
sdir
)
{
sdir
=
new
SrsConfDirective
();
dir
->
directives
.
push_back
(
sdir
);
}
return
sdir
;
}
SrsConfDirective
*
SrsConfig
::
get_vhost
(
string
vhost
)
{
srs_assert
(
root
);
...
...
@@ -3327,6 +3359,13 @@ string SrsConfig::get_dvr_path(string vhost)
return
conf
->
arg0
();
}
void
SrsConfig
::
set_dvr_path
(
string
vhost
,
string
path
)
{
SrsConfDirective
*
conf
=
create_directive
(
vhost
,
"dvr"
,
"dvr_path"
);
conf
->
args
.
clear
();
conf
->
args
.
push_back
(
path
);
}
string
SrsConfig
::
get_dvr_plan
(
string
vhost
)
{
SrsConfDirective
*
dvr
=
get_dvr
(
vhost
);
...
...
@@ -3378,6 +3417,13 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost)
return
false
;
}
void
SrsConfig
::
set_dvr_wait_keyframe
(
string
vhost
,
bool
wait_keyframe
)
{
SrsConfDirective
*
conf
=
create_directive
(
vhost
,
"dvr"
,
"dvr_wait_keyframe"
);
conf
->
args
.
clear
();
conf
->
args
.
push_back
(
wait_keyframe
?
"on"
:
"off"
);
}
bool
SrsConfig
::
get_dvr_autostart
(
string
vhost
)
{
SrsConfDirective
*
dvr
=
get_dvr
(
vhost
);
...
...
trunk/src/app/srs_app_config.hpp
查看文件 @
849e59b
...
...
@@ -452,6 +452,14 @@ public:
* get the max udp port for rtp of stream caster rtsp.
*/
virtual
int
get_stream_caster_rtp_port_max
(
SrsConfDirective
*
sc
);
private
:
/**
* create directive under vhost.
* @param directive, get the directive of vhost. get vhost if directive is empty.
* @param sub_directive, get the sub directive of vhost. get directive if sub-directive is empty.
* @return the vhost(empty directive and sub-directive); the directive(empty sub-directive); the sub-directive.
*/
virtual
SrsConfDirective
*
create_directive
(
std
::
string
vhost
,
std
::
string
directive
,
std
::
string
sub_directive
);
// vhost specified section
public:
/**
...
...
@@ -919,6 +927,7 @@ public:
* get the dvr path, the flv file to save in.
*/
virtual
std
::
string
get_dvr_path
(
std
::
string
vhost
);
virtual
void
set_dvr_path
(
std
::
string
vhost
,
std
::
string
path
);
/**
* get the plan of dvr, how to reap the flv file.
*/
...
...
@@ -931,6 +940,7 @@ public:
* whether wait keyframe to reap segment.
*/
virtual
bool
get_dvr_wait_keyframe
(
std
::
string
vhost
);
virtual
void
set_dvr_wait_keyframe
(
std
::
string
vhost
,
bool
wait_keyframe
);
/**
* whether autostart for dvr. wait api to start dvr if false.
*/
...
...
trunk/src/app/srs_app_dvr.cpp
查看文件 @
849e59b
...
...
@@ -194,6 +194,11 @@ int SrsFlvSegment::close()
return
ret
;
}
}
if
((
ret
=
plan
->
on_reap_segment
())
!=
ERROR_SUCCESS
)
{
srs_error
(
"dvr: notify plan to reap segment failed. ret=%d"
,
ret
);
return
ret
;
}
#ifdef SRS_AUTO_HTTP_CALLBACK
if
(
_srs_config
->
get_vhost_http_hooks_enabled
(
req
->
vhost
))
{
...
...
@@ -405,6 +410,11 @@ int SrsFlvSegment::update_flv_metadata()
return
ret
;
}
string
SrsFlvSegment
::
get_path
()
{
return
path
;
}
string
SrsFlvSegment
::
generate_path
()
{
// the path in config, for example,
...
...
@@ -657,6 +667,11 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video)
return
ret
;
}
int
SrsDvrPlan
::
on_reap_segment
()
{
return
ERROR_SUCCESS
;
}
SrsDvrPlan
*
SrsDvrPlan
::
create_plan
(
string
vhost
)
{
std
::
string
plan
=
_srs_config
->
get_dvr_plan
(
vhost
);
...
...
@@ -726,12 +741,32 @@ void SrsDvrSessionPlan::on_unpublish()
SrsDvrApiPlan
::
SrsDvrApiPlan
()
{
autostart
=
false
;
started
=
false
;
}
SrsDvrApiPlan
::~
SrsDvrApiPlan
()
{
}
int
SrsDvrApiPlan
::
initialize
(
SrsSource
*
s
,
SrsRequest
*
r
)
{
int
ret
=
ERROR_SUCCESS
;
if
((
ret
=
SrsDvrPlan
::
initialize
(
s
,
r
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsApiDvrPool
*
pool
=
SrsApiDvrPool
::
instance
();
if
((
ret
=
pool
->
add_dvr
(
this
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
autostart
=
_srs_config
->
get_dvr_autostart
(
r
->
vhost
);
return
ret
;
}
int
SrsDvrApiPlan
::
on_publish
()
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -745,6 +780,13 @@ int SrsDvrApiPlan::on_publish()
return
ret
;
}
// api disabled dvr when not autostart.
bool
autostart
=
_srs_config
->
get_dvr_autostart
(
req
->
vhost
);
if
(
!
autostart
&&
!
started
)
{
srs_warn
(
"dvr: api not start and disabled for not autostart."
);
return
ret
;
}
if
((
ret
=
segment
->
close
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
...
...
@@ -760,18 +802,76 @@ int SrsDvrApiPlan::on_publish()
void
SrsDvrApiPlan
::
on_unpublish
()
{
// support multiple publish.
if
(
!
dvr_enabled
)
{
return
;
}
int
SrsDvrApiPlan
::
set_path_tmpl
(
string
path_tmpl
)
{
_srs_config
->
set_dvr_path
(
req
->
vhost
,
path_tmpl
);
return
ERROR_SUCCESS
;
}
int
SrsDvrApiPlan
::
set_callback
(
string
value
)
{
callback
=
value
;
return
ERROR_SUCCESS
;
}
int
SrsDvrApiPlan
::
set_wait_keyframe
(
bool
wait_keyframe
)
{
_srs_config
->
set_dvr_wait_keyframe
(
req
->
vhost
,
wait_keyframe
);
return
ERROR_SUCCESS
;
}
int
SrsDvrApiPlan
::
start
()
{
int
ret
=
ERROR_SUCCESS
;
if
(
started
)
{
return
ret
;
}
// stop dvr
if
(
dvr_enabled
)
{
// ignore error.
int
ret
=
segment
->
close
();
if
(
ret
!=
ERROR_SUCCESS
)
{
srs_warn
(
"ignore flv close error. ret=%d"
,
ret
);
}
// ignore error.
int
ret
=
segment
->
close
();
if
(
ret
!=
ERROR_SUCCESS
)
{
srs_warn
(
"ignore flv close error. ret=%d"
,
ret
);
dvr_enabled
=
false
;
}
dvr_enabled
=
false
;
// start dvr
if
((
ret
=
on_publish
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
started
=
true
;
return
ret
;
}
int
SrsDvrApiPlan
::
dumps
(
stringstream
&
ss
)
{
int
ret
=
ERROR_SUCCESS
;
bool
wait_keyframe
=
_srs_config
->
get_dvr_wait_keyframe
(
req
->
vhost
);
std
::
string
path_template
=
_srs_config
->
get_dvr_path
(
req
->
vhost
);
ss
<<
__SRS_JOBJECT_START
<<
__SRS_JFIELD_STR
(
"path_tmpl"
,
path_template
)
<<
__SRS_JFIELD_CONT
<<
__SRS_JFIELD_STR
(
"path_dvr"
,
segment
->
get_path
())
<<
__SRS_JFIELD_CONT
<<
__SRS_JFIELD_BOOL
(
"wait_keyframe"
,
wait_keyframe
)
<<
__SRS_JFIELD_CONT
<<
__SRS_JFIELD_STR
(
"vhost"
,
req
->
vhost
)
<<
__SRS_JFIELD_CONT
<<
__SRS_JFIELD_STR
(
"callback"
,
callback
)
<<
__SRS_JOBJECT_END
;
return
ret
;
}
int
SrsDvrApiPlan
::
on_reap_segment
()
{
// TODO: FIXME: implements it.
return
ERROR_SUCCESS
;
}
SrsDvrAppendPlan
::
SrsDvrAppendPlan
()
...
...
@@ -1043,16 +1143,103 @@ SrsApiDvrPool::SrsApiDvrPool()
SrsApiDvrPool
::~
SrsApiDvrPool
()
{
dvrs
.
clear
();
}
int
SrsApiDvrPool
::
dumps
(
stringstream
&
ss
)
int
SrsApiDvrPool
::
add_dvr
(
SrsDvrApiPlan
*
dvr
)
{
dvrs
.
push_back
(
dvr
);
return
ERROR_SUCCESS
;
}
int
SrsApiDvrPool
::
dumps
(
string
vhost
,
stringstream
&
ss
)
{
int
ret
=
ERROR_SUCCESS
;
ss
<<
__SRS_JARRAY_START
<<
__SRS_JARRAY_END
;
ss
<<
__SRS_JARRAY_START
;
std
::
vector
<
SrsDvrApiPlan
*>
plans
;
for
(
int
i
=
0
;
i
<
(
int
)
dvrs
.
size
();
i
++
)
{
SrsDvrApiPlan
*
plan
=
dvrs
.
at
(
i
);
if
(
!
vhost
.
empty
()
&&
plan
->
req
->
vhost
!=
vhost
)
{
continue
;
}
plans
.
push_back
(
plan
);
}
for
(
int
i
=
0
;
i
<
(
int
)
plans
.
size
();
i
++
)
{
SrsDvrApiPlan
*
plan
=
plans
.
at
(
i
);
if
((
ret
=
plan
->
dumps
(
ss
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
i
<
(
int
)
dvrs
.
size
()
-
1
)
{
ss
<<
__SRS_JFIELD_CONT
;
}
}
ss
<<
__SRS_JARRAY_END
;
return
ret
;
}
int
SrsApiDvrPool
::
create
(
SrsJsonAny
*
json
)
{
int
ret
=
ERROR_SUCCESS
;
srs_assert
(
json
);
if
(
!
json
->
is_object
())
{
ret
=
ERROR_HTTP_DVR_CREATE_REQUEST
;
srs_error
(
"dvr: api create dvr request requires json object. ret=%d"
,
ret
);
return
ret
;
}
SrsJsonObject
*
obj
=
json
->
to_object
();
SrsJsonAny
*
prop
=
NULL
;
if
((
prop
=
obj
->
ensure_property_string
(
"vhost"
))
==
NULL
)
{
ret
=
ERROR_HTTP_DVR_CREATE_REQUEST
;
srs_error
(
"dvr: api create dvr request requires vhost. ret=%d"
,
ret
);
return
ret
;
}
std
::
string
vhost
=
prop
->
to_str
();
SrsDvrApiPlan
*
dvr
=
NULL
;
for
(
int
i
=
0
;
i
<
(
int
)
dvrs
.
size
();
i
++
)
{
SrsDvrApiPlan
*
plan
=
dvrs
.
at
(
i
);
if
(
!
vhost
.
empty
()
&&
plan
->
req
->
vhost
!=
vhost
)
{
continue
;
}
dvr
=
plan
;
break
;
}
if
(
!
dvr
)
{
ret
=
ERROR_HTTP_DVR_CREATE_REQUEST
;
srs_error
(
"dvr: api create dvr request vhost invalid. vhost=%s. ret=%d"
,
vhost
.
c_str
(),
ret
);
return
ret
;
}
// update optional parameters for plan.
if
((
prop
=
obj
->
ensure_property_string
(
"path_tmpl"
))
!=
NULL
)
{
if
((
ret
=
dvr
->
set_path_tmpl
(
prop
->
to_str
()))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
if
((
prop
=
obj
->
ensure_property_boolean
(
"wait_keyframe"
))
!=
NULL
)
{
if
((
ret
=
dvr
->
set_wait_keyframe
(
prop
->
to_boolean
()))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
if
((
prop
=
obj
->
ensure_property_string
(
"callback"
))
!=
NULL
)
{
if
((
ret
=
dvr
->
set_callback
(
prop
->
to_str
()))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
}
return
dvr
->
start
();
}
SrsDvr
::
SrsDvr
(
SrsSource
*
s
)
{
source
=
s
;
...
...
trunk/src/app/srs_app_dvr.hpp
查看文件 @
849e59b
...
...
@@ -43,6 +43,7 @@ class SrsSharedPtrMessage;
class
SrsFileWriter
;
class
SrsFlvEncoder
;
class
SrsDvrPlan
;
class
SrsJsonAny
;
#include <srs_app_source.hpp>
#include <srs_app_reload.hpp>
...
...
@@ -149,6 +150,10 @@ public:
* update the flv metadata.
*/
virtual
int
update_flv_metadata
();
/**
* get the current dvr path.
*/
virtual
std
::
string
get_path
();
private
:
/**
* generate the flv segment path.
...
...
@@ -179,9 +184,10 @@ class SrsDvrPlan
{
public
:
friend
class
SrsFlvSegment
;
public
:
SrsRequest
*
req
;
protected
:
SrsSource
*
source
;
SrsRequest
*
req
;
SrsFlvSegment
*
segment
;
bool
dvr_enabled
;
public
:
...
...
@@ -204,6 +210,7 @@ public:
*/
virtual
int
on_video
(
SrsSharedPtrMessage
*
__video
);
protected
:
virtual
int
on_reap_segment
();
virtual
int
on_dvr_request_sh
();
virtual
int
on_video_keyframe
();
virtual
int64_t
filter_timestamp
(
int64_t
timestamp
);
...
...
@@ -229,12 +236,25 @@ public:
*/
class
SrsDvrApiPlan
:
public
SrsDvrPlan
{
private
:
std
::
string
callback
;
bool
autostart
;
bool
started
;
public
:
SrsDvrApiPlan
();
virtual
~
SrsDvrApiPlan
();
public
:
virtual
int
initialize
(
SrsSource
*
s
,
SrsRequest
*
r
);
virtual
int
on_publish
();
virtual
void
on_unpublish
();
public
:
virtual
int
set_path_tmpl
(
std
::
string
path_tmpl
);
virtual
int
set_callback
(
std
::
string
value
);
virtual
int
set_wait_keyframe
(
bool
wait_keyframe
);
virtual
int
start
();
virtual
int
dumps
(
std
::
stringstream
&
ss
);
protected
:
virtual
int
on_reap_segment
();
};
/**
...
...
@@ -302,6 +322,7 @@ private:
class
SrsApiDvrPool
{
private
:
std
::
vector
<
SrsDvrApiPlan
*>
dvrs
;
static
SrsApiDvrPool
*
_instance
;
private
:
SrsApiDvrPool
();
...
...
@@ -309,7 +330,10 @@ public:
static
SrsApiDvrPool
*
instance
();
virtual
~
SrsApiDvrPool
();
public
:
virtual
int
dumps
(
std
::
stringstream
&
ss
);
virtual
int
add_dvr
(
SrsDvrApiPlan
*
dvr
);
public
:
virtual
int
dumps
(
std
::
string
vhost
,
std
::
stringstream
&
ss
);
virtual
int
create
(
SrsJsonAny
*
json
);
};
/**
...
...
trunk/src/app/srs_app_http_api.cpp
查看文件 @
849e59b
...
...
@@ -494,12 +494,25 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
SrsApiDvrPool
*
pool
=
SrsApiDvrPool
::
instance
();
if
(
r
->
is_http_get
())
{
std
::
stringstream
data
;
int
ret
=
pool
->
dumps
(
data
);
int
ret
=
pool
->
dumps
(
r
->
query_get
(
"vhost"
),
data
);
ss
<<
__SRS_JOBJECT_START
<<
__SRS_JFIELD_ERROR
(
ret
)
<<
__SRS_JFIELD_CONT
<<
__SRS_JFIELD_ORG
(
"dvrs"
,
data
.
str
())
<<
__SRS_JOBJECT_END
;
}
else
if
(
r
->
is_http_post
())
{
char
*
body
=
(
char
*
)
r
->
body
().
c_str
();
SrsJsonAny
*
json
=
SrsJsonAny
::
loads
(
body
);
int
ret
=
ERROR_SUCCESS
;
if
(
!
json
)
{
ret
=
ERROR_HTTP_JSON_REQUIRED
;
}
else
{
SrsAutoFree
(
SrsJsonAny
,
json
);
ret
=
pool
->
create
(
json
);
}
ss
<<
__SRS_JOBJECT_START
<<
__SRS_JFIELD_ERROR
(
ret
)
<<
__SRS_JOBJECT_END
;
}
else
{
ss
<<
__SRS_JOBJECT_START
<<
__SRS_JFIELD_ERROR
(
ERROR_HTTP_DVR_REQUEST
)
...
...
trunk/src/app/srs_app_json.cpp
查看文件 @
849e59b
...
...
@@ -457,6 +457,21 @@ SrsJsonAny* SrsJsonObject::ensure_property_string(string name)
return
prop
;
}
SrsJsonAny
*
SrsJsonObject
::
ensure_property_boolean
(
string
name
)
{
SrsJsonAny
*
prop
=
get_property
(
name
);
if
(
!
prop
)
{
return
NULL
;
}
if
(
!
prop
->
is_boolean
())
{
return
NULL
;
}
return
prop
;
}
SrsJsonArray
::
SrsJsonArray
()
{
marker
=
SRS_JSON_Array
;
...
...
trunk/src/app/srs_app_json.hpp
查看文件 @
849e59b
...
...
@@ -123,6 +123,7 @@ public:
public
:
/**
* read json tree from str:char*
* @return json object. NULL if error.
*/
static
SrsJsonAny
*
loads
(
char
*
str
);
};
...
...
@@ -148,6 +149,7 @@ public:
virtual
void
set
(
std
::
string
key
,
SrsJsonAny
*
value
);
virtual
SrsJsonAny
*
get_property
(
std
::
string
name
);
virtual
SrsJsonAny
*
ensure_property_string
(
std
::
string
name
);
virtual
SrsJsonAny
*
ensure_property_boolean
(
std
::
string
name
);
};
class
SrsJsonArray
:
public
SrsJsonAny
...
...
@@ -214,6 +216,7 @@ that is:
#define __SRS_JFIELD_NAME(k) "\"" << k << "\":"
#define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\""
#define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v
#define __SRS_JFIELD_BOOL(k, v) __SRS_JFIELD_ORG(k, (v? "true":"false"))
#define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret
#define __SRS_JFIELD_CONT ","
#define __SRS_JOBJECT_END "}"
...
...
trunk/src/kernel/srs_kernel_error.hpp
查看文件 @
849e59b
...
...
@@ -211,6 +211,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_HLS_TRY_MP3 3049
#define ERROR_HTTP_DVR_DISABLED 3050
#define ERROR_HTTP_DVR_REQUEST 3051
#define ERROR_HTTP_JSON_REQUIRED 3052
#define ERROR_HTTP_DVR_CREATE_REQUEST 3053
///////////////////////////////////////////////////////
// HTTP/StreamCaster protocol error.
...
...
请
注册
或
登录
后发表评论