mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 11:51:57 +00:00
dvr support plan and default session plan
This commit is contained in:
parent
4b82a4f510
commit
6f19a83114
5 changed files with 253 additions and 47 deletions
|
@ -288,39 +288,32 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDvr::SrsDvr(SrsSource* source)
|
SrsDvrPlan::SrsDvrPlan()
|
||||||
{
|
{
|
||||||
_source = source;
|
_source = NULL;
|
||||||
dvr_enabled = false;
|
dvr_enabled = false;
|
||||||
fs = new SrsFileStream();
|
fs = new SrsFileStream();
|
||||||
enc = new SrsFlvEncoder();
|
enc = new SrsFlvEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDvr::~SrsDvr()
|
SrsDvrPlan::~SrsDvrPlan()
|
||||||
{
|
{
|
||||||
srs_freep(fs);
|
srs_freep(fs);
|
||||||
srs_freep(enc);
|
srs_freep(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsDvr::on_publish(SrsRequest* req)
|
int SrsDvrPlan::initialize(SrsSource* source)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
// support multiple publish.
|
_source = source;
|
||||||
if (dvr_enabled) {
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_srs_config->get_dvr_enabled(req->vhost)) {
|
int SrsDvrPlan::flv_open(string stream, string path)
|
||||||
return ret;
|
{
|
||||||
}
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
std::string path = _srs_config->get_dvr_path(req->vhost);
|
|
||||||
path += "/";
|
|
||||||
path += req->app;
|
|
||||||
path += "/";
|
|
||||||
path += req->stream;
|
|
||||||
path += ".flv";
|
|
||||||
|
|
||||||
if ((ret = fs->open(path)) != ERROR_SUCCESS) {
|
if ((ret = fs->open(path)) != ERROR_SUCCESS) {
|
||||||
srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
|
srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
|
||||||
|
@ -341,26 +334,16 @@ int SrsDvr::on_publish(SrsRequest* req)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_trace("dvr stream %s to file %s", req->get_stream_url().c_str(), path.c_str());
|
srs_trace("dvr stream %s to file %s", stream.c_str(), path.c_str());
|
||||||
dvr_enabled = true;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsDvr::on_unpublish()
|
int SrsDvrPlan::flv_close()
|
||||||
{
|
{
|
||||||
// support multiple publish.
|
return fs->close();
|
||||||
if (!dvr_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore error.
|
int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata)
|
||||||
fs->close();
|
|
||||||
|
|
||||||
dvr_enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrsDvr::on_meta_data(SrsOnMetaDataPacket* metadata)
|
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -382,12 +365,10 @@ int SrsDvr::on_meta_data(SrsOnMetaDataPacket* metadata)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsDvr::on_audio(SrsSharedPtrMessage* audio)
|
int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
SrsAutoFree(SrsSharedPtrMessage, audio, false);
|
|
||||||
|
|
||||||
if (!dvr_enabled) {
|
if (!dvr_enabled) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -402,12 +383,10 @@ int SrsDvr::on_audio(SrsSharedPtrMessage* audio)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsDvr::on_video(SrsSharedPtrMessage* video)
|
int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
SrsAutoFree(SrsSharedPtrMessage, video, false);
|
|
||||||
|
|
||||||
if (!dvr_enabled) {
|
if (!dvr_enabled) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -422,5 +401,140 @@ int SrsDvr::on_video(SrsSharedPtrMessage* video)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsDvrPlan* SrsDvrPlan::create_plan()
|
||||||
|
{
|
||||||
|
return new SrsDvrSessionPlan();
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDvrSessionPlan::SrsDvrSessionPlan()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDvrSessionPlan::~SrsDvrSessionPlan()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrSessionPlan::on_publish(SrsRequest* req)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// support multiple publish.
|
||||||
|
if (dvr_enabled) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_srs_config->get_dvr_enabled(req->vhost)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path = _srs_config->get_dvr_path(req->vhost);
|
||||||
|
path += "/";
|
||||||
|
path += req->app;
|
||||||
|
path += "/";
|
||||||
|
path += req->stream;
|
||||||
|
path += ".flv";
|
||||||
|
|
||||||
|
if ((ret = flv_open(req->get_stream_url(), path)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
dvr_enabled = true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsDvrSessionPlan::on_unpublish()
|
||||||
|
{
|
||||||
|
// support multiple publish.
|
||||||
|
if (!dvr_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore error.
|
||||||
|
int ret = flv_close();
|
||||||
|
if (ret != ERROR_SUCCESS) {
|
||||||
|
srs_warn("ignore flv close error. ret=%d", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
dvr_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDvr::SrsDvr(SrsSource* source)
|
||||||
|
{
|
||||||
|
_source = source;
|
||||||
|
plan = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDvr::~SrsDvr()
|
||||||
|
{
|
||||||
|
srs_freep(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvr::initialize()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_freep(plan);
|
||||||
|
plan = SrsDvrPlan::create_plan();
|
||||||
|
|
||||||
|
if ((ret = plan->initialize(_source)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvr::on_publish(SrsRequest* req)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if ((ret = plan->on_publish(req)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsDvr::on_unpublish()
|
||||||
|
{
|
||||||
|
plan->on_unpublish();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvr::on_meta_data(SrsOnMetaDataPacket* metadata)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if ((ret = plan->on_meta_data(metadata)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvr::on_audio(SrsSharedPtrMessage* audio)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsAutoFree(SrsSharedPtrMessage, audio, false);
|
||||||
|
|
||||||
|
if ((ret = plan->on_audio(audio)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvr::on_video(SrsSharedPtrMessage* video)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsAutoFree(SrsSharedPtrMessage, video, false);
|
||||||
|
|
||||||
|
if ((ret = plan->on_video(video)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,57 @@ private:
|
||||||
virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
|
virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the plan for dvr.
|
||||||
|
* use to control the following dvr params:
|
||||||
|
* 1. filename: the filename for record file.
|
||||||
|
* 2. reap flv: when to reap the flv and start new piece.
|
||||||
|
*/
|
||||||
|
class SrsDvrPlan
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* the underlayer dvr stream.
|
||||||
|
* if close, the flv is reap and closed.
|
||||||
|
* if open, new flv file is crote.
|
||||||
|
*/
|
||||||
|
SrsFileStream* fs;
|
||||||
|
SrsFlvEncoder* enc;
|
||||||
|
bool dvr_enabled;
|
||||||
|
SrsSource* _source;
|
||||||
|
public:
|
||||||
|
SrsDvrPlan();
|
||||||
|
virtual ~SrsDvrPlan();
|
||||||
|
public:
|
||||||
|
virtual int initialize(SrsSource* source);
|
||||||
|
virtual int on_publish(SrsRequest* req) = 0;
|
||||||
|
virtual void on_unpublish() = 0;
|
||||||
|
virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
|
||||||
|
virtual int on_audio(SrsSharedPtrMessage* audio);
|
||||||
|
virtual int on_video(SrsSharedPtrMessage* video);
|
||||||
|
protected:
|
||||||
|
virtual int flv_open(std::string stream, std::string path);
|
||||||
|
virtual int flv_close();
|
||||||
|
public:
|
||||||
|
static SrsDvrPlan* create_plan();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default session plan:
|
||||||
|
* 1. start dvr when session start(publish).
|
||||||
|
* 2. stop dvr when session stop(unpublish).
|
||||||
|
* 3. always dvr to file: dvr_path/app/stream.flv
|
||||||
|
*/
|
||||||
|
class SrsDvrSessionPlan : public SrsDvrPlan
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsDvrSessionPlan();
|
||||||
|
virtual ~SrsDvrSessionPlan();
|
||||||
|
public:
|
||||||
|
virtual int on_publish(SrsRequest* req);
|
||||||
|
virtual void on_unpublish();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dvr(digital video recorder) to record RTMP stream to flv file.
|
* dvr(digital video recorder) to record RTMP stream to flv file.
|
||||||
* TODO: FIXME: add utest for it.
|
* TODO: FIXME: add utest for it.
|
||||||
|
@ -114,13 +165,17 @@ class SrsDvr
|
||||||
private:
|
private:
|
||||||
SrsSource* _source;
|
SrsSource* _source;
|
||||||
private:
|
private:
|
||||||
bool dvr_enabled;
|
SrsDvrPlan* plan;
|
||||||
SrsFileStream* fs;
|
|
||||||
SrsFlvEncoder* enc;
|
|
||||||
public:
|
public:
|
||||||
SrsDvr(SrsSource* source);
|
SrsDvr(SrsSource* source);
|
||||||
virtual ~SrsDvr();
|
virtual ~SrsDvr();
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* initialize dvr, create dvr plan.
|
||||||
|
* when system initialize(encoder publish at first time, or reload),
|
||||||
|
* initialize the dvr will reinitialize the plan, the whole dvr framework.
|
||||||
|
*/
|
||||||
|
virtual int initialize();
|
||||||
/**
|
/**
|
||||||
* publish stream event,
|
* publish stream event,
|
||||||
* when encoder start to publish RTMP stream.
|
* when encoder start to publish RTMP stream.
|
||||||
|
|
|
@ -276,7 +276,10 @@ int SrsRtmpConn::stream_service_cycle()
|
||||||
srs_trace("set chunk_size=%d success", chunk_size);
|
srs_trace("set chunk_size=%d success", chunk_size);
|
||||||
|
|
||||||
// find a source to serve.
|
// find a source to serve.
|
||||||
SrsSource* source = SrsSource::find(req);
|
SrsSource* source = NULL;
|
||||||
|
if ((ret = SrsSource::find(req, &source)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
srs_assert(source != NULL);
|
srs_assert(source != NULL);
|
||||||
|
|
||||||
// check publish available.
|
// check publish available.
|
||||||
|
|
|
@ -413,17 +413,27 @@ int64_t SrsGopCache::get_start_time()
|
||||||
|
|
||||||
std::map<std::string, SrsSource*> SrsSource::pool;
|
std::map<std::string, SrsSource*> SrsSource::pool;
|
||||||
|
|
||||||
SrsSource* SrsSource::find(SrsRequest* req)
|
int SrsSource::find(SrsRequest* req, SrsSource** ppsource)
|
||||||
{
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
string stream_url = req->get_stream_url();
|
string stream_url = req->get_stream_url();
|
||||||
string vhost = req->vhost;
|
string vhost = req->vhost;
|
||||||
|
|
||||||
if (pool.find(stream_url) == pool.end()) {
|
if (pool.find(stream_url) == pool.end()) {
|
||||||
pool[stream_url] = new SrsSource(req);
|
SrsSource* source = new SrsSource(req);
|
||||||
|
if ((ret = source->initialize()) != ERROR_SUCCESS) {
|
||||||
|
srs_freep(source);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool[stream_url] = source;
|
||||||
srs_info("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
|
srs_info("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool[stream_url];
|
*ppsource = pool[stream_url];
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsSource::SrsSource(SrsRequest* _req)
|
SrsSource::SrsSource(SrsRequest* _req)
|
||||||
|
@ -492,6 +502,19 @@ SrsSource::~SrsSource()
|
||||||
srs_freep(req);
|
srs_freep(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsSource::initialize()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
#ifdef SRS_AUTO_DVR
|
||||||
|
if ((ret = dvr->initialize()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int SrsSource::on_reload_vhost_atc(string vhost)
|
int SrsSource::on_reload_vhost_atc(string vhost)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -614,11 +637,20 @@ int SrsSource::on_reload_vhost_dvr(string vhost)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SRS_AUTO_DVR
|
#ifdef SRS_AUTO_DVR
|
||||||
|
// cleanup dvr
|
||||||
dvr->on_unpublish();
|
dvr->on_unpublish();
|
||||||
|
|
||||||
|
// reinitialize the dvr, update plan.
|
||||||
|
if ((ret = dvr->initialize()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start to publish by new plan.
|
||||||
if ((ret = dvr->on_publish(req)) != ERROR_SUCCESS) {
|
if ((ret = dvr->on_publish(req)) != ERROR_SUCCESS) {
|
||||||
srs_error("dvr publish failed. ret=%d", ret);
|
srs_error("dvr publish failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_trace("vhost %s dvr reload success", vhost.c_str());
|
srs_trace("vhost %s dvr reload success", vhost.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -213,10 +213,10 @@ public:
|
||||||
/**
|
/**
|
||||||
* find stream by vhost/app/stream.
|
* find stream by vhost/app/stream.
|
||||||
* @param req the client request.
|
* @param req the client request.
|
||||||
* @return the matched source, never be NULL.
|
* @param ppsource the matched source, if success never be NULL.
|
||||||
* @remark stream_url should without port and schema.
|
* @remark stream_url should without port and schema.
|
||||||
*/
|
*/
|
||||||
static SrsSource* find(SrsRequest* req);
|
static int find(SrsRequest* req, SrsSource** ppsource);
|
||||||
private:
|
private:
|
||||||
// deep copy of client request.
|
// deep copy of client request.
|
||||||
SrsRequest* req;
|
SrsRequest* req;
|
||||||
|
@ -271,6 +271,8 @@ public:
|
||||||
*/
|
*/
|
||||||
SrsSource(SrsRequest* _req);
|
SrsSource(SrsRequest* _req);
|
||||||
virtual ~SrsSource();
|
virtual ~SrsSource();
|
||||||
|
public:
|
||||||
|
virtual int initialize();
|
||||||
// interface ISrsReloadHandler
|
// interface ISrsReloadHandler
|
||||||
public:
|
public:
|
||||||
virtual int on_reload_vhost_atc(std::string vhost);
|
virtual int on_reload_vhost_atc(std::string vhost);
|
||||||
|
|
Loading…
Reference in a new issue