1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

for #179, revert dvr http api. 2.0.128.

This commit is contained in:
winlin 2015-03-01 17:57:28 +08:00
parent 4505983944
commit fb3fced8d0
10 changed files with 7 additions and 932 deletions

View file

@ -785,17 +785,6 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
return new SrsDvrSessionPlan();
} else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND) {
return new SrsDvrAppendPlan();
} else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_API) {
/**
* @remark the api plan maybe create by publish event or http api post create dvr event.
* so when we got from pool first when create it.
*/
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
SrsDvrApiPlan* plan = pool->get_dvr(vhost);
if (plan) {
return plan;
}
return new SrsDvrApiPlan();
} else {
srs_error("invalid dvr plan=%s, vhost=%s", plan.c_str(), vhost.c_str());
srs_assert(false);
@ -852,318 +841,6 @@ void SrsDvrSessionPlan::on_unpublish()
dvr_enabled = false;
}
SrsDvrApiPlan::SrsDvrApiPlan()
{
autostart = false;
started = false;
metadata = sh_audio = sh_video = NULL;
}
SrsDvrApiPlan::~SrsDvrApiPlan()
{
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
pool->detach_dvr(this);
srs_freep(metadata);
srs_freep(sh_audio);
srs_freep(sh_video);
}
int SrsDvrApiPlan::initialize(SrsRequest* r)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsDvrPlan::initialize(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;
// support multiple publish.
if (dvr_enabled) {
return ret;
}
if (!_srs_config->get_dvr_enabled(req->vhost)) {
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;
}
dvr_enabled = true;
if ((ret = segment->close()) != ERROR_SUCCESS) {
return ret;
}
if ((ret = segment->open()) != ERROR_SUCCESS) {
return ret;
}
// update sequence header
if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
return ret;
}
if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
return ret;
}
if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
void SrsDvrApiPlan::on_unpublish()
{
}
int SrsDvrApiPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
{
int ret = ERROR_SUCCESS;
srs_freep(metadata);
metadata = __metadata->copy();
return ret;
}
int SrsDvrApiPlan::on_audio(SrsSharedPtrMessage* __audio)
{
int ret = ERROR_SUCCESS;
if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) {
srs_freep(sh_audio);
sh_audio = __audio->copy();
}
if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrApiPlan::on_video(SrsSharedPtrMessage* __video)
{
int ret = ERROR_SUCCESS;
if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) {
srs_freep(sh_video);
sh_video = __video->copy();
}
if ((ret = check_user_actions(__video)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsDvrApiPlan::set_plan()
{
_srs_config->set_dvr_plan(req->vhost, SRS_CONF_DEFAULT_DVR_PLAN_API);
return ERROR_SUCCESS;
}
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)
{
_srs_config->set_vhost_http_hooks_enabled(req->vhost, true);
_srs_config->set_vhost_on_dvr(req->vhost, 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;
}
// enable the config.
_srs_config->set_dvr_enabled(req->vhost, true);
// stop dvr
if (dvr_enabled) {
// ignore error.
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);
SrsConfDirective* callbacks = _srs_config->get_vhost_on_dvr(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("app", req->app) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("callback", callbacks->arg0()) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("status", (dvr_enabled? "start":"stop"))
<< __SRS_JOBJECT_END;
return ret;
}
int SrsDvrApiPlan::stop()
{
int ret = ERROR_SUCCESS;
_srs_config->set_dvr_enabled(req->vhost, false);
started = false;
// stop dvr
if (dvr_enabled) {
// ignore error.
int ret = segment->close();
if (ret != ERROR_SUCCESS) {
srs_warn("ignore flv close error. ret=%d", ret);
}
dvr_enabled = false;
}
srs_trace("dvr: stop dvr of vhost=%s", req->vhost.c_str());
return ret;
}
int SrsDvrApiPlan::rpc(SrsJsonObject* obj)
{
int ret = ERROR_SUCCESS;
SrsJsonAny* prop = NULL;
if ((prop = obj->ensure_property_string("action")) == NULL) {
ret = ERROR_HTTP_DVR_REQUEST;
srs_error("dvr: rpc required action request. ret=%d", ret);
return ret;
}
action = prop->to_str();
if (action == SRS_DVR_USER_ACTION_REAP_SEGMENT) {
if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) {
path_template = prop->to_str();
}
} else {
ret = ERROR_HTTP_DVR_REQUEST;
}
return ret;
}
int SrsDvrApiPlan::check_user_actions(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
srs_assert(segment);
if (action == SRS_DVR_USER_ACTION_REAP_SEGMENT) {
// when wait keyframe, ignore if no frame arrived.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/177
if (_srs_config->get_dvr_wait_keyframe(req->vhost)) {
if (!msg->is_video()) {
return ret;
}
char* payload = msg->payload;
int size = msg->size;
bool is_key_frame = SrsFlvCodec::video_is_h264(payload, size)
&& SrsFlvCodec::video_is_keyframe(payload, size)
&& !SrsFlvCodec::video_is_sequence_header(payload, size);
if (!is_key_frame) {
return ret;
}
}
// reap segment
if ((ret = segment->close()) != ERROR_SUCCESS) {
return ret;
}
// use new path template if user specified.
if (!path_template.empty() && (ret = set_path_tmpl(path_template)) != ERROR_SUCCESS) {
return ret;
}
// open new flv file
if ((ret = segment->open()) != ERROR_SUCCESS) {
return ret;
}
// update sequence header
if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
return ret;
}
if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
return ret;
}
if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
return ret;
}
}
// reset rcp params.
action = "";
path_template = "";
return ret;
}
SrsDvrAppendPlan::SrsDvrAppendPlan()
{
last_update_time = 0;
@ -1420,290 +1097,6 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
return ret;
}
SrsApiDvrPool* SrsApiDvrPool::_instance = new SrsApiDvrPool();
SrsApiDvrPool* SrsApiDvrPool::instance()
{
return SrsApiDvrPool::_instance;
}
SrsApiDvrPool::SrsApiDvrPool()
{
}
SrsApiDvrPool::~SrsApiDvrPool()
{
dvrs.clear();
}
SrsDvrApiPlan* SrsApiDvrPool::get_dvr(string vhost)
{
std::vector<SrsDvrApiPlan*>::iterator it;
for (it = dvrs.begin(); it != dvrs.end(); ++it) {
SrsDvrApiPlan* plan = *it;
if (plan->req->vhost == vhost) {
return plan;
}
}
return NULL;
}
int SrsApiDvrPool::add_dvr(SrsDvrApiPlan* dvr)
{
dvrs.push_back(dvr);
return ERROR_SUCCESS;
}
void SrsApiDvrPool::detach_dvr(SrsDvrApiPlan* dvr)
{
std::vector<SrsDvrApiPlan*>::iterator it;
it = ::find(dvrs.begin(), dvrs.end(), dvr);
if (it != dvrs.end()) {
dvrs.erase(it);
}
}
int SrsApiDvrPool::dumps(string vhost, string app, string stream, stringstream& ss)
{
int ret = ERROR_SUCCESS;
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;
}
if (!app.empty() && plan->req->app != app) {
continue;
}
if (!stream.empty() && plan->req->stream != stream) {
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)plans.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();
if ((prop = obj->ensure_property_string("app")) == NULL) {
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
srs_error("dvr: api create dvr request requires app. ret=%d", ret);
return ret;
}
std::string app = prop->to_str();
if ((prop = obj->ensure_property_string("stream")) == NULL) {
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
srs_error("dvr: api create dvr request requires stream. ret=%d", ret);
return ret;
}
std::string stream = prop->to_str();
if (vhost.empty() || app.empty() || stream.empty()) {
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
srs_error("dvr: api create dvr request requires vhost/app/stream. ret=%d", ret);
return ret;
}
SrsDvrApiPlan* dvr = NULL;
for (int i = 0; i < (int)dvrs.size(); i++) {
SrsDvrApiPlan* plan = dvrs.at(i);
if (plan->req->vhost != vhost || plan->req->app != app || plan->req->stream != stream) {
continue;
}
dvr = plan;
break;
}
// mock the client request for dvr.
SrsRequest* req = new SrsRequest();
SrsAutoFree(SrsRequest, req);
// should notice the source to reload dvr when already publishing.
SrsSource* source = NULL;
// create if not exists
if (!dvr) {
dvr = new SrsDvrApiPlan();
req->vhost = vhost;
req->app = app;
req->stream = stream;
req->tcUrl = "rtmp://" + vhost + "/" + app + "/" + stream;
// fetch source from pool.
// NULL, create without source, ignore.
// start dvr when already publishing.
source = SrsSource::fetch(req);
// initialize for dvr pool to create it.
if ((ret = dvr->initialize(req)) != ERROR_SUCCESS) {
return ret;
}
}
// update optional parameters for plan.
if ((ret = dvr->set_plan()) != ERROR_SUCCESS) {
return ret;
}
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;
}
}
if ((ret = dvr->start()) != ERROR_SUCCESS) {
return ret;
}
// do reload for source when already publishing.
// when reload, the source will use the request instead.
if (source) {
if ((ret = source->on_reload_vhost_dvr(vhost)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
int SrsApiDvrPool::stop(string vhost, string app, string stream)
{
int ret = ERROR_SUCCESS;
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;
}
if (!app.empty() && plan->req->app != app) {
continue;
}
if (!stream.empty() && plan->req->stream != stream) {
continue;
}
plans.push_back(plan);
}
if (plans.empty()) {
ret = ERROR_HTTP_DVR_NO_TAEGET;
srs_error("dvr: stop not found for url=%s/%s/%s, ret=%d", vhost.c_str(), app.c_str(), stream.c_str(), ret);
return ret;
}
for (int i = 0; i < (int)plans.size(); i++) {
SrsDvrApiPlan* plan = plans.at(i);
if ((ret = plan->stop()) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
int SrsApiDvrPool::rpc(SrsJsonAny* json)
{
int ret = ERROR_SUCCESS;
if (!json->is_object()) {
ret = ERROR_HTTP_DVR_REQUEST;
srs_error("dvr: rpc required object request. 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_REQUEST;
srs_error("dvr: rpc required vhost request. ret=%d", ret);
return ret;
}
std::string vhost = prop->to_str();
std::string app, stream;
if ((prop = obj->ensure_property_string("app")) != NULL) {
app = prop->to_str();
}
if ((prop = obj->ensure_property_string("stream")) != NULL) {
stream = prop->to_str();
}
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);
}
if (plans.empty()) {
ret = ERROR_HTTP_DVR_NO_TAEGET;
srs_error("dvr: rpc not found for url=%s/%s/%s, ret=%d", vhost.c_str(), app.c_str(), stream.c_str(), ret);
return ret;
}
for (int i = 0; i < (int)plans.size(); i++) {
SrsDvrApiPlan* plan = plans.at(i);
if ((ret = plan->rpc(obj)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
SrsDvr::SrsDvr()
{
source = NULL;