mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
for #179, support http api to start dvr.
This commit is contained in:
parent
c67a4fdf97
commit
849e59b05d
9 changed files with 320 additions and 21 deletions
|
@ -296,15 +296,14 @@ vhost dvr.srs.com {
|
||||||
# request params, for example ?vhost=__defaultVhost__, where:
|
# request params, for example ?vhost=__defaultVhost__, where:
|
||||||
# vhost, query all dvr of this vhost.
|
# vhost, query all dvr of this vhost.
|
||||||
# response in json, where:
|
# response in json, where:
|
||||||
# {code:0, dvrs: [{plan:"api", path:"./objs/nginx/html",
|
# {code:0, dvrs: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv",
|
||||||
# autostart:true, wait_keyframe:true, jitter:"full"
|
# wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback"
|
||||||
# }]}
|
# }]}
|
||||||
# method=POST
|
# method=POST
|
||||||
# to start dvr of specified vhost.
|
# to start dvr of specified vhost.
|
||||||
# request should encode in json, specifies the dvr to create, where:
|
# request should encode in json, specifies the dvr to create, where:
|
||||||
# {plan:"api", path:"./objs/nginx/html",
|
# {path_tmpl:"./[15].[04].[05].[999].flv",
|
||||||
# autostart:true, wait_keyframe:true, jitter:"full",
|
# wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback"
|
||||||
# vhost:"__defaultVhost", callback:"http://dvr/callback"
|
|
||||||
# }
|
# }
|
||||||
# response in json, where:
|
# response in json, where:
|
||||||
# {code:0}
|
# {code:0}
|
||||||
|
@ -329,7 +328,7 @@ vhost dvr.srs.com {
|
||||||
# [05], repleace this const to current second.
|
# [05], repleace this const to current second.
|
||||||
# [999], repleace this const to current millisecond.
|
# [999], repleace this const to current millisecond.
|
||||||
# [timestamp],replace this const to current UNIX timestamp in ms.
|
# [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
|
# 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):
|
# 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename):
|
||||||
# dvr_path ./objs/nginx/html;
|
# dvr_path ./objs/nginx/html;
|
||||||
|
|
|
@ -1977,6 +1977,38 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc)
|
||||||
return ::atoi(conf->arg0().c_str());
|
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)
|
SrsConfDirective* SrsConfig::get_vhost(string vhost)
|
||||||
{
|
{
|
||||||
srs_assert(root);
|
srs_assert(root);
|
||||||
|
@ -3327,6 +3359,13 @@ string SrsConfig::get_dvr_path(string vhost)
|
||||||
return conf->arg0();
|
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)
|
string SrsConfig::get_dvr_plan(string vhost)
|
||||||
{
|
{
|
||||||
SrsConfDirective* dvr = get_dvr(vhost);
|
SrsConfDirective* dvr = get_dvr(vhost);
|
||||||
|
@ -3378,6 +3417,13 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost)
|
||||||
return false;
|
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)
|
bool SrsConfig::get_dvr_autostart(string vhost)
|
||||||
{
|
{
|
||||||
SrsConfDirective* dvr = get_dvr(vhost);
|
SrsConfDirective* dvr = get_dvr(vhost);
|
||||||
|
|
|
@ -452,6 +452,14 @@ public:
|
||||||
* get the max udp port for rtp of stream caster rtsp.
|
* get the max udp port for rtp of stream caster rtsp.
|
||||||
*/
|
*/
|
||||||
virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc);
|
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
|
// vhost specified section
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -919,6 +927,7 @@ public:
|
||||||
* get the dvr path, the flv file to save in.
|
* get the dvr path, the flv file to save in.
|
||||||
*/
|
*/
|
||||||
virtual std::string get_dvr_path(std::string vhost);
|
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.
|
* get the plan of dvr, how to reap the flv file.
|
||||||
*/
|
*/
|
||||||
|
@ -931,6 +940,7 @@ public:
|
||||||
* whether wait keyframe to reap segment.
|
* whether wait keyframe to reap segment.
|
||||||
*/
|
*/
|
||||||
virtual bool get_dvr_wait_keyframe(std::string vhost);
|
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.
|
* whether autostart for dvr. wait api to start dvr if false.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -194,6 +194,11 @@ int SrsFlvSegment::close()
|
||||||
return ret;
|
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
|
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||||
if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
|
if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
|
||||||
|
@ -405,6 +410,11 @@ int SrsFlvSegment::update_flv_metadata()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string SrsFlvSegment::get_path()
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
string SrsFlvSegment::generate_path()
|
string SrsFlvSegment::generate_path()
|
||||||
{
|
{
|
||||||
// the path in config, for example,
|
// the path in config, for example,
|
||||||
|
@ -657,6 +667,11 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsDvrPlan::on_reap_segment()
|
||||||
|
{
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
|
SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
|
||||||
{
|
{
|
||||||
std::string plan = _srs_config->get_dvr_plan(vhost);
|
std::string plan = _srs_config->get_dvr_plan(vhost);
|
||||||
|
@ -726,12 +741,32 @@ void SrsDvrSessionPlan::on_unpublish()
|
||||||
|
|
||||||
SrsDvrApiPlan::SrsDvrApiPlan()
|
SrsDvrApiPlan::SrsDvrApiPlan()
|
||||||
{
|
{
|
||||||
|
autostart = false;
|
||||||
|
started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDvrApiPlan::~SrsDvrApiPlan()
|
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 SrsDvrApiPlan::on_publish()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -745,6 +780,13 @@ int SrsDvrApiPlan::on_publish()
|
||||||
return ret;
|
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) {
|
if ((ret = segment->close()) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -760,18 +802,76 @@ int SrsDvrApiPlan::on_publish()
|
||||||
|
|
||||||
void SrsDvrApiPlan::on_unpublish()
|
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.
|
dvr_enabled = false;
|
||||||
int ret = segment->close();
|
|
||||||
if (ret != ERROR_SUCCESS) {
|
|
||||||
srs_warn("ignore flv close error. ret=%d", ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
SrsDvrAppendPlan::SrsDvrAppendPlan()
|
||||||
|
@ -1043,16 +1143,103 @@ SrsApiDvrPool::SrsApiDvrPool()
|
||||||
|
|
||||||
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;
|
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;
|
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)
|
SrsDvr::SrsDvr(SrsSource* s)
|
||||||
{
|
{
|
||||||
source = s;
|
source = s;
|
||||||
|
|
|
@ -43,6 +43,7 @@ class SrsSharedPtrMessage;
|
||||||
class SrsFileWriter;
|
class SrsFileWriter;
|
||||||
class SrsFlvEncoder;
|
class SrsFlvEncoder;
|
||||||
class SrsDvrPlan;
|
class SrsDvrPlan;
|
||||||
|
class SrsJsonAny;
|
||||||
|
|
||||||
#include <srs_app_source.hpp>
|
#include <srs_app_source.hpp>
|
||||||
#include <srs_app_reload.hpp>
|
#include <srs_app_reload.hpp>
|
||||||
|
@ -149,6 +150,10 @@ public:
|
||||||
* update the flv metadata.
|
* update the flv metadata.
|
||||||
*/
|
*/
|
||||||
virtual int update_flv_metadata();
|
virtual int update_flv_metadata();
|
||||||
|
/**
|
||||||
|
* get the current dvr path.
|
||||||
|
*/
|
||||||
|
virtual std::string get_path();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* generate the flv segment path.
|
* generate the flv segment path.
|
||||||
|
@ -179,9 +184,10 @@ class SrsDvrPlan
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class SrsFlvSegment;
|
friend class SrsFlvSegment;
|
||||||
|
public:
|
||||||
|
SrsRequest* req;
|
||||||
protected:
|
protected:
|
||||||
SrsSource* source;
|
SrsSource* source;
|
||||||
SrsRequest* req;
|
|
||||||
SrsFlvSegment* segment;
|
SrsFlvSegment* segment;
|
||||||
bool dvr_enabled;
|
bool dvr_enabled;
|
||||||
public:
|
public:
|
||||||
|
@ -204,6 +210,7 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual int on_video(SrsSharedPtrMessage* __video);
|
virtual int on_video(SrsSharedPtrMessage* __video);
|
||||||
protected:
|
protected:
|
||||||
|
virtual int on_reap_segment();
|
||||||
virtual int on_dvr_request_sh();
|
virtual int on_dvr_request_sh();
|
||||||
virtual int on_video_keyframe();
|
virtual int on_video_keyframe();
|
||||||
virtual int64_t filter_timestamp(int64_t timestamp);
|
virtual int64_t filter_timestamp(int64_t timestamp);
|
||||||
|
@ -229,12 +236,25 @@ public:
|
||||||
*/
|
*/
|
||||||
class SrsDvrApiPlan : public SrsDvrPlan
|
class SrsDvrApiPlan : public SrsDvrPlan
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
std::string callback;
|
||||||
|
bool autostart;
|
||||||
|
bool started;
|
||||||
public:
|
public:
|
||||||
SrsDvrApiPlan();
|
SrsDvrApiPlan();
|
||||||
virtual ~SrsDvrApiPlan();
|
virtual ~SrsDvrApiPlan();
|
||||||
public:
|
public:
|
||||||
|
virtual int initialize(SrsSource* s, SrsRequest* r);
|
||||||
virtual int on_publish();
|
virtual int on_publish();
|
||||||
virtual void on_unpublish();
|
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
|
class SrsApiDvrPool
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
std::vector<SrsDvrApiPlan*> dvrs;
|
||||||
static SrsApiDvrPool* _instance;
|
static SrsApiDvrPool* _instance;
|
||||||
private:
|
private:
|
||||||
SrsApiDvrPool();
|
SrsApiDvrPool();
|
||||||
|
@ -309,7 +330,10 @@ public:
|
||||||
static SrsApiDvrPool* instance();
|
static SrsApiDvrPool* instance();
|
||||||
virtual ~SrsApiDvrPool();
|
virtual ~SrsApiDvrPool();
|
||||||
public:
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -494,12 +494,25 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||||
if (r->is_http_get()) {
|
if (r->is_http_get()) {
|
||||||
std::stringstream data;
|
std::stringstream data;
|
||||||
int ret = pool->dumps(data);
|
int ret = pool->dumps(r->query_get("vhost"), data);
|
||||||
|
|
||||||
ss << __SRS_JOBJECT_START
|
ss << __SRS_JOBJECT_START
|
||||||
<< __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
|
<< __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
|
||||||
<< __SRS_JFIELD_ORG("dvrs", data.str())
|
<< __SRS_JFIELD_ORG("dvrs", data.str())
|
||||||
<< __SRS_JOBJECT_END;
|
<< __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 {
|
} else {
|
||||||
ss << __SRS_JOBJECT_START
|
ss << __SRS_JOBJECT_START
|
||||||
<< __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST)
|
<< __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST)
|
||||||
|
|
|
@ -457,6 +457,21 @@ SrsJsonAny* SrsJsonObject::ensure_property_string(string name)
|
||||||
return prop;
|
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()
|
SrsJsonArray::SrsJsonArray()
|
||||||
{
|
{
|
||||||
marker = SRS_JSON_Array;
|
marker = SRS_JSON_Array;
|
||||||
|
|
|
@ -123,6 +123,7 @@ public:
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* read json tree from str:char*
|
* read json tree from str:char*
|
||||||
|
* @return json object. NULL if error.
|
||||||
*/
|
*/
|
||||||
static SrsJsonAny* loads(char* str);
|
static SrsJsonAny* loads(char* str);
|
||||||
};
|
};
|
||||||
|
@ -148,6 +149,7 @@ public:
|
||||||
virtual void set(std::string key, SrsJsonAny* value);
|
virtual void set(std::string key, SrsJsonAny* value);
|
||||||
virtual SrsJsonAny* get_property(std::string name);
|
virtual SrsJsonAny* get_property(std::string name);
|
||||||
virtual SrsJsonAny* ensure_property_string(std::string name);
|
virtual SrsJsonAny* ensure_property_string(std::string name);
|
||||||
|
virtual SrsJsonAny* ensure_property_boolean(std::string name);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsJsonArray : public SrsJsonAny
|
class SrsJsonArray : public SrsJsonAny
|
||||||
|
@ -214,6 +216,7 @@ that is:
|
||||||
#define __SRS_JFIELD_NAME(k) "\"" << k << "\":"
|
#define __SRS_JFIELD_NAME(k) "\"" << k << "\":"
|
||||||
#define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\""
|
#define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\""
|
||||||
#define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << 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_ERROR(ret) "\"" << "code" << "\":" << ret
|
||||||
#define __SRS_JFIELD_CONT ","
|
#define __SRS_JFIELD_CONT ","
|
||||||
#define __SRS_JOBJECT_END "}"
|
#define __SRS_JOBJECT_END "}"
|
||||||
|
|
|
@ -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_HLS_TRY_MP3 3049
|
||||||
#define ERROR_HTTP_DVR_DISABLED 3050
|
#define ERROR_HTTP_DVR_DISABLED 3050
|
||||||
#define ERROR_HTTP_DVR_REQUEST 3051
|
#define ERROR_HTTP_DVR_REQUEST 3051
|
||||||
|
#define ERROR_HTTP_JSON_REQUIRED 3052
|
||||||
|
#define ERROR_HTTP_DVR_CREATE_REQUEST 3053
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// HTTP/StreamCaster protocol error.
|
// HTTP/StreamCaster protocol error.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue