winlin

refine plan, add stream start time for atc

@@ -325,6 +325,56 @@ class RESTSessions(object): @@ -325,6 +325,56 @@ class RESTSessions(object):
325 # TODO: process the on_stop event 325 # TODO: process the on_stop event
326 326
327 return code 327 return code
  328 +
  329 +# the rest dvrs, when dvr got keyframe, call this api.
  330 +class RESTDvrs(object):
  331 + exposed = True
  332 + def __init__(self):
  333 + pass
  334 + # the dvrs POST api specified in following.
  335 + #
  336 + # when dvr got an keyframe, call the hook,
  337 + # the request in the POST data string is a object encode by json:
  338 + # {
  339 + # "action": "on_dvr_keyframe",
  340 + # "vhost": "video.test.com", "app": "live",
  341 + # "stream": "livestream"
  342 + # }
  343 + #
  344 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  345 + # an int value specifies the error code(0 corresponding to success):
  346 + # 0
  347 + def POST(self):
  348 + enable_crossdomain()
  349 +
  350 + req = cherrypy.request.body.read()
  351 + trace("post to sessions, req=%s"%(req))
  352 + try:
  353 + json_req = json.loads(req)
  354 + except Exception, ex:
  355 + code = Error.system_parse_json
  356 + trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
  357 + return str(code)
  358 +
  359 + action = json_req["action"]
  360 + if action == "on_dvr_keyframe":
  361 + code = self.__on_dvr_keyframe(json_req)
  362 + else:
  363 + code = Errors.request_invalid_action
  364 + trace("invalid request action: %s, code=%s"%(json_req["action"], code))
  365 +
  366 + return str(code)
  367 +
  368 + def __on_dvr_keyframe(self, req):
  369 + code = Error.success
  370 +
  371 + trace("srs %s: vhost=%s, app=%s, stream=%s"%(
  372 + req["action"], req["vhost"], req["app"], req["stream"]
  373 + ))
  374 +
  375 + # TODO: process the on_dvr_keyframe event
  376 +
  377 + return code
328 378
329 global_arm_server_id = os.getpid(); 379 global_arm_server_id = os.getpid();
330 class ArmServer: 380 class ArmServer:
@@ -930,6 +980,7 @@ class V1(object): @@ -930,6 +980,7 @@ class V1(object):
930 self.clients = RESTClients() 980 self.clients = RESTClients()
931 self.streams = RESTStreams() 981 self.streams = RESTStreams()
932 self.sessions = RESTSessions() 982 self.sessions = RESTSessions()
  983 + self.dvrs = RESTDvrs()
933 self.chats = RESTChats() 984 self.chats = RESTChats()
934 self.servers = RESTServers() 985 self.servers = RESTServers()
935 self.nodes = RESTNodes() 986 self.nodes = RESTNodes()
@@ -303,10 +303,12 @@ SrsFlvSegment::SrsFlvSegment() @@ -303,10 +303,12 @@ SrsFlvSegment::SrsFlvSegment()
303 segment_has_keyframe = false; 303 segment_has_keyframe = false;
304 duration = 0; 304 duration = 0;
305 starttime = -1; 305 starttime = -1;
  306 + stream_starttime = 0;
306 } 307 }
307 308
308 void SrsFlvSegment::reset() 309 void SrsFlvSegment::reset()
309 { 310 {
  311 + segment_has_keyframe = false;
310 duration = 0; 312 duration = 0;
311 starttime = -1; 313 starttime = -1;
312 } 314 }
@@ -319,7 +321,7 @@ SrsDvrPlan::SrsDvrPlan() @@ -319,7 +321,7 @@ SrsDvrPlan::SrsDvrPlan()
319 dvr_enabled = false; 321 dvr_enabled = false;
320 fs = new SrsFileStream(); 322 fs = new SrsFileStream();
321 enc = new SrsFlvEncoder(); 323 enc = new SrsFlvEncoder();
322 - segment = NULL; 324 + segment = new SrsFlvSegment();
323 } 325 }
324 326
325 SrsDvrPlan::~SrsDvrPlan() 327 SrsDvrPlan::~SrsDvrPlan()
@@ -362,6 +364,22 @@ int SrsDvrPlan::on_publish() @@ -362,6 +364,22 @@ int SrsDvrPlan::on_publish()
362 // always update time cache. 364 // always update time cache.
363 srs_update_system_time_ms(); 365 srs_update_system_time_ms();
364 366
  367 + // when republish, stream starting.
  368 + segment->stream_starttime = srs_get_system_time_ms();
  369 +
  370 + if ((ret = open_new_segment()) != ERROR_SUCCESS) {
  371 + return ret;
  372 + }
  373 +
  374 + return ret;
  375 +}
  376 +
  377 +int SrsDvrPlan::open_new_segment()
  378 +{
  379 + int ret = ERROR_SUCCESS;
  380 +
  381 + SrsRequest* req = _req;
  382 +
365 // new flv file 383 // new flv file
366 std::stringstream path; 384 std::stringstream path;
367 385
@@ -468,8 +486,7 @@ int SrsDvrPlan::flv_open(string stream, string path) @@ -468,8 +486,7 @@ int SrsDvrPlan::flv_open(string stream, string path)
468 { 486 {
469 int ret = ERROR_SUCCESS; 487 int ret = ERROR_SUCCESS;
470 488
471 - srs_freep(segment);  
472 - segment = new SrsFlvSegment(); 489 + segment->reset();
473 490
474 std::string tmp_file = path + ".tmp"; 491 std::string tmp_file = path + ".tmp";
475 if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) { 492 if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) {
@@ -548,7 +565,7 @@ int SrsDvrPlan::on_dvr_keyframe() @@ -548,7 +565,7 @@ int SrsDvrPlan::on_dvr_keyframe()
548 565
549 for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) { 566 for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) {
550 std::string url = on_dvr_keyframe->args.at(i); 567 std::string url = on_dvr_keyframe->args.at(i);
551 - SrsHttpHooks::on_dvr_keyframe(url, _req); 568 + SrsHttpHooks::on_dvr_keyframe(url, _req, segment);
552 } 569 }
553 #endif 570 #endif
554 571
@@ -620,6 +637,9 @@ int SrsDvrSegmentPlan::on_publish() @@ -620,6 +637,9 @@ int SrsDvrSegmentPlan::on_publish()
620 int ret = ERROR_SUCCESS; 637 int ret = ERROR_SUCCESS;
621 638
622 // if already opened, continue to dvr. 639 // if already opened, continue to dvr.
  640 + // the segment plan maybe keep running longer than the encoder.
  641 + // for example, segment running, encoder restart,
  642 + // the segment plan will just continue going and donot open new segment.
623 if (fs->is_open()) { 643 if (fs->is_open()) {
624 dvr_enabled = true; 644 dvr_enabled = true;
625 return ret; 645 return ret;
@@ -648,15 +668,14 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) @@ -648,15 +668,14 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
648 srs_assert(segment); 668 srs_assert(segment);
649 669
650 // reap if exceed duration. 670 // reap if exceed duration.
651 - if (segment->duration > 0 && segment_duration > 0 && segment->duration > segment_duration) {  
652 - segment->reset();  
653 - 671 + if (segment_duration > 0 && segment->duration > segment_duration) {
654 if ((ret = flv_close()) != ERROR_SUCCESS) { 672 if ((ret = flv_close()) != ERROR_SUCCESS) {
  673 + segment->reset();
655 return ret; 674 return ret;
656 } 675 }
657 on_unpublish(); 676 on_unpublish();
658 677
659 - if ((ret = on_publish()) != ERROR_SUCCESS) { 678 + if ((ret = open_new_segment()) != ERROR_SUCCESS) {
660 return ret; 679 return ret;
661 } 680 }
662 } 681 }
@@ -121,11 +121,15 @@ public: @@ -121,11 +121,15 @@ public:
121 * whether current segment has keyframe. 121 * whether current segment has keyframe.
122 */ 122 */
123 bool segment_has_keyframe; 123 bool segment_has_keyframe;
124 - /**  
125 - * current segment duration and starttime.  
126 - */ 124 + /**
  125 + * current segment duration and starttime.
  126 + */
127 int64_t duration; 127 int64_t duration;
128 int64_t starttime; 128 int64_t starttime;
  129 + /**
  130 + * stream start time, to generate atc pts.
  131 + */
  132 + int64_t stream_starttime;
129 public: 133 public:
130 SrsFlvSegment(); 134 SrsFlvSegment();
131 virtual void reset(); 135 virtual void reset();
@@ -137,6 +141,7 @@ public: @@ -137,6 +141,7 @@ public:
137 * 1. filename: the filename for record file. 141 * 1. filename: the filename for record file.
138 * 2. reap flv: when to reap the flv and start new piece. 142 * 2. reap flv: when to reap the flv and start new piece.
139 */ 143 */
  144 +// TODO: FIXME: the plan is too fat, refine me.
140 class SrsDvrPlan 145 class SrsDvrPlan
141 { 146 {
142 protected: 147 protected:
@@ -165,12 +170,13 @@ public: @@ -165,12 +170,13 @@ public:
165 protected: 170 protected:
166 virtual int flv_open(std::string stream, std::string path); 171 virtual int flv_open(std::string stream, std::string path);
167 virtual int flv_close(); 172 virtual int flv_close();
  173 + virtual int open_new_segment();
168 virtual int update_duration(SrsSharedPtrMessage* msg); 174 virtual int update_duration(SrsSharedPtrMessage* msg);
169 private: 175 private:
170 - /**  
171 - * when srs reap the flv(close the segment),  
172 - * if has keyframe, notice the api.  
173 - */ 176 + /**
  177 + * when srs reap the flv(close the segment),
  178 + * if has keyframe, notice the api.
  179 + */
174 virtual int on_dvr_keyframe(); 180 virtual int on_dvr_keyframe();
175 public: 181 public:
176 static SrsDvrPlan* create_plan(std::string vhost); 182 static SrsDvrPlan* create_plan(std::string vhost);
@@ -36,6 +36,7 @@ using namespace std; @@ -36,6 +36,7 @@ using namespace std;
36 #include <srs_app_socket.hpp> 36 #include <srs_app_socket.hpp>
37 #include <srs_app_http.hpp> 37 #include <srs_app_http.hpp>
38 #include <srs_app_json.hpp> 38 #include <srs_app_json.hpp>
  39 +#include <srs_app_dvr.hpp>
39 40
40 #define SRS_HTTP_RESPONSE_OK "0" 41 #define SRS_HTTP_RESPONSE_OK "0"
41 42
@@ -194,14 +195,6 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r @@ -194,14 +195,6 @@ int SrsHttpHooks::on_connect(string url, int client_id, string ip, SrsRequest* r
194 return ret; 195 return ret;
195 } 196 }
196 197
197 - /**  
198 - {  
199 - "action": "on_connect",  
200 - "client_id": 1985,  
201 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
202 - "pageUrl": "http://www.test.com/live.html"  
203 - }  
204 - */  
205 std::stringstream ss; 198 std::stringstream ss;
206 ss << JOBJECT_START 199 ss << JOBJECT_START
207 << JFIELD_STR("action", "on_connect") << JFIELD_CONT 200 << JFIELD_STR("action", "on_connect") << JFIELD_CONT
@@ -247,14 +240,6 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re @@ -247,14 +240,6 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re
247 return; 240 return;
248 } 241 }
249 242
250 - /**  
251 - {  
252 - "action": "on_close",  
253 - "client_id": 1985,  
254 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
255 - "stream": "livestream"  
256 - }  
257 - */  
258 std::stringstream ss; 243 std::stringstream ss;
259 ss << JOBJECT_START 244 ss << JOBJECT_START
260 << JFIELD_STR("action", "on_close") << JFIELD_CONT 245 << JFIELD_STR("action", "on_close") << JFIELD_CONT
@@ -300,14 +285,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r @@ -300,14 +285,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r
300 return ret; 285 return ret;
301 } 286 }
302 287
303 - /**  
304 - {  
305 - "action": "on_publish",  
306 - "client_id": 1985,  
307 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
308 - "stream": "livestream"  
309 - }  
310 - */  
311 std::stringstream ss; 288 std::stringstream ss;
312 ss << JOBJECT_START 289 ss << JOBJECT_START
313 << JFIELD_STR("action", "on_publish") << JFIELD_CONT 290 << JFIELD_STR("action", "on_publish") << JFIELD_CONT
@@ -354,14 +331,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest @@ -354,14 +331,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest
354 return; 331 return;
355 } 332 }
356 333
357 - /**  
358 - {  
359 - "action": "on_unpublish",  
360 - "client_id": 1985,  
361 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
362 - "stream": "livestream"  
363 - }  
364 - */  
365 std::stringstream ss; 334 std::stringstream ss;
366 ss << JOBJECT_START 335 ss << JOBJECT_START
367 << JFIELD_STR("action", "on_unpublish") << JFIELD_CONT 336 << JFIELD_STR("action", "on_unpublish") << JFIELD_CONT
@@ -408,14 +377,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req) @@ -408,14 +377,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req)
408 return ret; 377 return ret;
409 } 378 }
410 379
411 - /**  
412 - {  
413 - "action": "on_play",  
414 - "client_id": 1985,  
415 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
416 - "stream": "livestream"  
417 - }  
418 - */  
419 std::stringstream ss; 380 std::stringstream ss;
420 ss << JOBJECT_START 381 ss << JOBJECT_START
421 << JFIELD_STR("action", "on_play") << JFIELD_CONT 382 << JFIELD_STR("action", "on_play") << JFIELD_CONT
@@ -462,14 +423,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req @@ -462,14 +423,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
462 return; 423 return;
463 } 424 }
464 425
465 - /**  
466 - {  
467 - "action": "on_stop",  
468 - "client_id": 1985,  
469 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
470 - "stream": "livestream"  
471 - }  
472 - */  
473 std::stringstream ss; 426 std::stringstream ss;
474 ss << JOBJECT_START 427 ss << JOBJECT_START
475 << JFIELD_STR("action", "on_stop") << JFIELD_CONT 428 << JFIELD_STR("action", "on_stop") << JFIELD_CONT
@@ -505,10 +458,15 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req @@ -505,10 +458,15 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
505 return; 458 return;
506 } 459 }
507 460
508 -void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req) 461 +void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* segment)
509 { 462 {
510 int ret = ERROR_SUCCESS; 463 int ret = ERROR_SUCCESS;
511 464
  465 + srs_trace("flv segment %s, atc_start=%"PRId64", "
  466 + "has_key=%d, starttime=%"PRId64", duration=%d",
  467 + segment->current_flv_path.c_str(), segment->stream_starttime,
  468 + segment->segment_has_keyframe, segment->starttime, (int)segment->duration);
  469 +
512 SrsHttpUri uri; 470 SrsHttpUri uri;
513 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { 471 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
514 srs_warn("http uri parse on_dvr_keyframe url failed, ignored. " 472 srs_warn("http uri parse on_dvr_keyframe url failed, ignored. "
@@ -516,13 +474,6 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req) @@ -516,13 +474,6 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req)
516 return; 474 return;
517 } 475 }
518 476
519 - /**  
520 - {  
521 - "action": "on_dvr_keyframe",  
522 - "vhost": "video.test.com", "app": "live",  
523 - "stream": "livestream"  
524 - }  
525 - */  
526 std::stringstream ss; 477 std::stringstream ss;
527 ss << JOBJECT_START 478 ss << JOBJECT_START
528 << JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT 479 << JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT
@@ -37,6 +37,7 @@ class SrsHttpUri; @@ -37,6 +37,7 @@ class SrsHttpUri;
37 class SrsSocket; 37 class SrsSocket;
38 class SrsRequest; 38 class SrsRequest;
39 class SrsHttpParser; 39 class SrsHttpParser;
  40 +class SrsFlvSegment;
40 41
41 #include <srs_app_st.hpp> 42 #include <srs_app_st.hpp>
42 43
@@ -126,8 +127,9 @@ public: @@ -126,8 +127,9 @@ public:
126 * on_dvr_keyframe hook, when dvr get keyframe. 127 * on_dvr_keyframe hook, when dvr get keyframe.
127 * @param url the api server url, to process the event. 128 * @param url the api server url, to process the event.
128 * ignore if empty. 129 * ignore if empty.
  130 + * @param segment the current flv segment.
129 */ 131 */
130 - static void on_dvr_keyframe(std::string url, SrsRequest* req); 132 + static void on_dvr_keyframe(std::string url, SrsRequest* req, SrsFlvSegment* segment);
131 }; 133 };
132 134
133 #endif 135 #endif