mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
refine plan, add stream start time for atc
This commit is contained in:
parent
0c0010d529
commit
e271cb607f
5 changed files with 101 additions and 72 deletions
|
@ -325,6 +325,56 @@ class RESTSessions(object):
|
||||||
# TODO: process the on_stop event
|
# TODO: process the on_stop event
|
||||||
|
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
# the rest dvrs, when dvr got keyframe, call this api.
|
||||||
|
class RESTDvrs(object):
|
||||||
|
exposed = True
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
# the dvrs POST api specified in following.
|
||||||
|
#
|
||||||
|
# when dvr got an keyframe, call the hook,
|
||||||
|
# the request in the POST data string is a object encode by json:
|
||||||
|
# {
|
||||||
|
# "action": "on_dvr_keyframe",
|
||||||
|
# "vhost": "video.test.com", "app": "live",
|
||||||
|
# "stream": "livestream"
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# if valid, the hook must return HTTP code 200(Stauts OK) and response
|
||||||
|
# an int value specifies the error code(0 corresponding to success):
|
||||||
|
# 0
|
||||||
|
def POST(self):
|
||||||
|
enable_crossdomain()
|
||||||
|
|
||||||
|
req = cherrypy.request.body.read()
|
||||||
|
trace("post to sessions, req=%s"%(req))
|
||||||
|
try:
|
||||||
|
json_req = json.loads(req)
|
||||||
|
except Exception, ex:
|
||||||
|
code = Error.system_parse_json
|
||||||
|
trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
|
||||||
|
return str(code)
|
||||||
|
|
||||||
|
action = json_req["action"]
|
||||||
|
if action == "on_dvr_keyframe":
|
||||||
|
code = self.__on_dvr_keyframe(json_req)
|
||||||
|
else:
|
||||||
|
code = Errors.request_invalid_action
|
||||||
|
trace("invalid request action: %s, code=%s"%(json_req["action"], code))
|
||||||
|
|
||||||
|
return str(code)
|
||||||
|
|
||||||
|
def __on_dvr_keyframe(self, req):
|
||||||
|
code = Error.success
|
||||||
|
|
||||||
|
trace("srs %s: vhost=%s, app=%s, stream=%s"%(
|
||||||
|
req["action"], req["vhost"], req["app"], req["stream"]
|
||||||
|
))
|
||||||
|
|
||||||
|
# TODO: process the on_dvr_keyframe event
|
||||||
|
|
||||||
|
return code
|
||||||
|
|
||||||
global_arm_server_id = os.getpid();
|
global_arm_server_id = os.getpid();
|
||||||
class ArmServer:
|
class ArmServer:
|
||||||
|
@ -930,6 +980,7 @@ class V1(object):
|
||||||
self.clients = RESTClients()
|
self.clients = RESTClients()
|
||||||
self.streams = RESTStreams()
|
self.streams = RESTStreams()
|
||||||
self.sessions = RESTSessions()
|
self.sessions = RESTSessions()
|
||||||
|
self.dvrs = RESTDvrs()
|
||||||
self.chats = RESTChats()
|
self.chats = RESTChats()
|
||||||
self.servers = RESTServers()
|
self.servers = RESTServers()
|
||||||
self.nodes = RESTNodes()
|
self.nodes = RESTNodes()
|
||||||
|
|
|
@ -303,10 +303,12 @@ SrsFlvSegment::SrsFlvSegment()
|
||||||
segment_has_keyframe = false;
|
segment_has_keyframe = false;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
starttime = -1;
|
starttime = -1;
|
||||||
|
stream_starttime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsFlvSegment::reset()
|
void SrsFlvSegment::reset()
|
||||||
{
|
{
|
||||||
|
segment_has_keyframe = false;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
starttime = -1;
|
starttime = -1;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +321,7 @@ SrsDvrPlan::SrsDvrPlan()
|
||||||
dvr_enabled = false;
|
dvr_enabled = false;
|
||||||
fs = new SrsFileStream();
|
fs = new SrsFileStream();
|
||||||
enc = new SrsFlvEncoder();
|
enc = new SrsFlvEncoder();
|
||||||
segment = NULL;
|
segment = new SrsFlvSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDvrPlan::~SrsDvrPlan()
|
SrsDvrPlan::~SrsDvrPlan()
|
||||||
|
@ -362,6 +364,22 @@ int SrsDvrPlan::on_publish()
|
||||||
// always update time cache.
|
// always update time cache.
|
||||||
srs_update_system_time_ms();
|
srs_update_system_time_ms();
|
||||||
|
|
||||||
|
// when republish, stream starting.
|
||||||
|
segment->stream_starttime = srs_get_system_time_ms();
|
||||||
|
|
||||||
|
if ((ret = open_new_segment()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrPlan::open_new_segment()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsRequest* req = _req;
|
||||||
|
|
||||||
// new flv file
|
// new flv file
|
||||||
std::stringstream path;
|
std::stringstream path;
|
||||||
|
|
||||||
|
@ -468,8 +486,7 @@ int SrsDvrPlan::flv_open(string stream, string path)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
srs_freep(segment);
|
segment->reset();
|
||||||
segment = new SrsFlvSegment();
|
|
||||||
|
|
||||||
std::string tmp_file = path + ".tmp";
|
std::string tmp_file = path + ".tmp";
|
||||||
if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) {
|
if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) {
|
||||||
|
@ -548,7 +565,7 @@ int SrsDvrPlan::on_dvr_keyframe()
|
||||||
|
|
||||||
for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) {
|
for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) {
|
||||||
std::string url = on_dvr_keyframe->args.at(i);
|
std::string url = on_dvr_keyframe->args.at(i);
|
||||||
SrsHttpHooks::on_dvr_keyframe(url, _req);
|
SrsHttpHooks::on_dvr_keyframe(url, _req, segment);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -620,6 +637,9 @@ int SrsDvrSegmentPlan::on_publish()
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
// if already opened, continue to dvr.
|
// if already opened, continue to dvr.
|
||||||
|
// the segment plan maybe keep running longer than the encoder.
|
||||||
|
// for example, segment running, encoder restart,
|
||||||
|
// the segment plan will just continue going and donot open new segment.
|
||||||
if (fs->is_open()) {
|
if (fs->is_open()) {
|
||||||
dvr_enabled = true;
|
dvr_enabled = true;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -648,15 +668,14 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
|
||||||
srs_assert(segment);
|
srs_assert(segment);
|
||||||
|
|
||||||
// reap if exceed duration.
|
// reap if exceed duration.
|
||||||
if (segment->duration > 0 && segment_duration > 0 && segment->duration > segment_duration) {
|
if (segment_duration > 0 && segment->duration > segment_duration) {
|
||||||
segment->reset();
|
|
||||||
|
|
||||||
if ((ret = flv_close()) != ERROR_SUCCESS) {
|
if ((ret = flv_close()) != ERROR_SUCCESS) {
|
||||||
|
segment->reset();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
on_unpublish();
|
on_unpublish();
|
||||||
|
|
||||||
if ((ret = on_publish()) != ERROR_SUCCESS) {
|
if ((ret = open_new_segment()) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,11 +121,15 @@ public:
|
||||||
* whether current segment has keyframe.
|
* whether current segment has keyframe.
|
||||||
*/
|
*/
|
||||||
bool segment_has_keyframe;
|
bool segment_has_keyframe;
|
||||||
/**
|
/**
|
||||||
* current segment duration and starttime.
|
* current segment duration and starttime.
|
||||||
*/
|
*/
|
||||||
int64_t duration;
|
int64_t duration;
|
||||||
int64_t starttime;
|
int64_t starttime;
|
||||||
|
/**
|
||||||
|
* stream start time, to generate atc pts.
|
||||||
|
*/
|
||||||
|
int64_t stream_starttime;
|
||||||
public:
|
public:
|
||||||
SrsFlvSegment();
|
SrsFlvSegment();
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
@ -137,6 +141,7 @@ public:
|
||||||
* 1. filename: the filename for record file.
|
* 1. filename: the filename for record file.
|
||||||
* 2. reap flv: when to reap the flv and start new piece.
|
* 2. reap flv: when to reap the flv and start new piece.
|
||||||
*/
|
*/
|
||||||
|
// TODO: FIXME: the plan is too fat, refine me.
|
||||||
class SrsDvrPlan
|
class SrsDvrPlan
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -165,12 +170,13 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual int flv_open(std::string stream, std::string path);
|
virtual int flv_open(std::string stream, std::string path);
|
||||||
virtual int flv_close();
|
virtual int flv_close();
|
||||||
|
virtual int open_new_segment();
|
||||||
virtual int update_duration(SrsSharedPtrMessage* msg);
|
virtual int update_duration(SrsSharedPtrMessage* msg);
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* when srs reap the flv(close the segment),
|
* when srs reap the flv(close the segment),
|
||||||
* if has keyframe, notice the api.
|
* if has keyframe, notice the api.
|
||||||
*/
|
*/
|
||||||
virtual int on_dvr_keyframe();
|
virtual int on_dvr_keyframe();
|
||||||
public:
|
public:
|
||||||
static SrsDvrPlan* create_plan(std::string vhost);
|
static SrsDvrPlan* create_plan(std::string vhost);
|
||||||
|
|
|
@ -36,6 +36,7 @@ using namespace std;
|
||||||
#include <srs_app_socket.hpp>
|
#include <srs_app_socket.hpp>
|
||||||
#include <srs_app_http.hpp>
|
#include <srs_app_http.hpp>
|
||||||
#include <srs_app_json.hpp>
|
#include <srs_app_json.hpp>
|
||||||
|
#include <srs_app_dvr.hpp>
|
||||||
|
|
||||||
#define SRS_HTTP_RESPONSE_OK "0"
|
#define SRS_HTTP_RESPONSE_OK "0"
|
||||||
|
|
||||||
|
@ -194,14 +195,6 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_connect",
|
|
||||||
"client_id": 1985,
|
|
||||||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
|
||||||
"pageUrl": "http://www.test.com/live.html"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_connect") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_connect") << JFIELD_CONT
|
||||||
|
@ -247,14 +240,6 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_close",
|
|
||||||
"client_id": 1985,
|
|
||||||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
|
||||||
"stream": "livestream"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_close") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_close") << JFIELD_CONT
|
||||||
|
@ -300,14 +285,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_publish",
|
|
||||||
"client_id": 1985,
|
|
||||||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
|
||||||
"stream": "livestream"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_publish") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_publish") << JFIELD_CONT
|
||||||
|
@ -354,14 +331,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_unpublish",
|
|
||||||
"client_id": 1985,
|
|
||||||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
|
||||||
"stream": "livestream"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_unpublish") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_unpublish") << JFIELD_CONT
|
||||||
|
@ -408,14 +377,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_play",
|
|
||||||
"client_id": 1985,
|
|
||||||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
|
||||||
"stream": "livestream"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_play") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_play") << JFIELD_CONT
|
||||||
|
@ -462,14 +423,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_stop",
|
|
||||||
"client_id": 1985,
|
|
||||||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
|
||||||
"stream": "livestream"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_stop") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_stop") << JFIELD_CONT
|
||||||
|
@ -505,10 +458,15 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req)
|
void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* segment)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_trace("flv segment %s, atc_start=%"PRId64", "
|
||||||
|
"has_key=%d, starttime=%"PRId64", duration=%d",
|
||||||
|
segment->current_flv_path.c_str(), segment->stream_starttime,
|
||||||
|
segment->segment_has_keyframe, segment->starttime, (int)segment->duration);
|
||||||
|
|
||||||
SrsHttpUri uri;
|
SrsHttpUri uri;
|
||||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||||
srs_warn("http uri parse on_dvr_keyframe url failed, ignored. "
|
srs_warn("http uri parse on_dvr_keyframe url failed, ignored. "
|
||||||
|
@ -516,13 +474,6 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
{
|
|
||||||
"action": "on_dvr_keyframe",
|
|
||||||
"vhost": "video.test.com", "app": "live",
|
|
||||||
"stream": "livestream"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT
|
||||||
|
|
|
@ -37,6 +37,7 @@ class SrsHttpUri;
|
||||||
class SrsSocket;
|
class SrsSocket;
|
||||||
class SrsRequest;
|
class SrsRequest;
|
||||||
class SrsHttpParser;
|
class SrsHttpParser;
|
||||||
|
class SrsFlvSegment;
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
|
|
||||||
|
@ -126,8 +127,9 @@ public:
|
||||||
* on_dvr_keyframe hook, when dvr get keyframe.
|
* on_dvr_keyframe hook, when dvr get keyframe.
|
||||||
* @param url the api server url, to process the event.
|
* @param url the api server url, to process the event.
|
||||||
* ignore if empty.
|
* ignore if empty.
|
||||||
|
* @param segment the current flv segment.
|
||||||
*/
|
*/
|
||||||
static void on_dvr_keyframe(std::string url, SrsRequest* req);
|
static void on_dvr_keyframe(std::string url, SrsRequest* req, SrsFlvSegment* segment);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue