winlin

support dvr to hss. change to 0.9.74

@@ -47,6 +47,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -47,6 +47,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47 #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html" 47 #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html"
48 #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session" 48 #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session"
49 #define SRS_CONF_DEFAULT_DVR_PLAN_SEGMENT "segment" 49 #define SRS_CONF_DEFAULT_DVR_PLAN_SEGMENT "segment"
  50 +// chnvideo hss
  51 +#define SRS_CONF_DEFAULT_DVR_PLAN_HSS "hss"
50 #define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION 52 #define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
51 #define SRS_CONF_DEFAULT_DVR_DURATION 30 53 #define SRS_CONF_DEFAULT_DVR_DURATION 30
52 // in ms, for HLS aac sync time. 54 // in ms, for HLS aac sync time.
@@ -299,18 +299,20 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s @@ -299,18 +299,20 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s
299 299
300 SrsFlvSegment::SrsFlvSegment() 300 SrsFlvSegment::SrsFlvSegment()
301 { 301 {
302 - current_flv_path = "";  
303 - segment_has_keyframe = false; 302 + path = "";
  303 + has_keyframe = false;
304 duration = 0; 304 duration = 0;
305 starttime = -1; 305 starttime = -1;
306 stream_starttime = 0; 306 stream_starttime = 0;
  307 + stream_previous_pkt_time = -1;
  308 + stream_duration = 0;
307 } 309 }
308 310
309 void SrsFlvSegment::reset() 311 void SrsFlvSegment::reset()
310 { 312 {
311 - segment_has_keyframe = false;  
312 - duration = 0; 313 + has_keyframe = false;
313 starttime = -1; 314 starttime = -1;
  315 + duration = 0;
314 } 316 }
315 317
316 SrsDvrPlan::SrsDvrPlan() 318 SrsDvrPlan::SrsDvrPlan()
@@ -357,7 +359,7 @@ int SrsDvrPlan::on_publish() @@ -357,7 +359,7 @@ int SrsDvrPlan::on_publish()
357 return ret; 359 return ret;
358 } 360 }
359 361
360 - // jitter. 362 + // jitter when publish, ensure whole stream start from 0.
361 srs_freep(jitter); 363 srs_freep(jitter);
362 jitter = new SrsRtmpJitter(); 364 jitter = new SrsRtmpJitter();
363 365
@@ -365,7 +367,9 @@ int SrsDvrPlan::on_publish() @@ -365,7 +367,9 @@ int SrsDvrPlan::on_publish()
365 srs_update_system_time_ms(); 367 srs_update_system_time_ms();
366 368
367 // when republish, stream starting. 369 // when republish, stream starting.
  370 + segment->stream_previous_pkt_time = -1;
368 segment->stream_starttime = srs_get_system_time_ms(); 371 segment->stream_starttime = srs_get_system_time_ms();
  372 + segment->stream_duration = 0;
369 373
370 if ((ret = open_new_segment()) != ERROR_SUCCESS) { 374 if ((ret = open_new_segment()) != ERROR_SUCCESS) {
371 return ret; 375 return ret;
@@ -470,7 +474,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video) @@ -470,7 +474,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
470 #ifdef SRS_AUTO_HTTP_CALLBACK 474 #ifdef SRS_AUTO_HTTP_CALLBACK
471 bool is_key_frame = SrsCodec::video_is_keyframe((int8_t*)payload, size); 475 bool is_key_frame = SrsCodec::video_is_keyframe((int8_t*)payload, size);
472 if (is_key_frame) { 476 if (is_key_frame) {
473 - segment->segment_has_keyframe = true; 477 + segment->has_keyframe = true;
474 } 478 }
475 srs_verbose("dvr video is key: %d", is_key_frame); 479 srs_verbose("dvr video is key: %d", is_key_frame);
476 #endif 480 #endif
@@ -504,7 +508,7 @@ int SrsDvrPlan::flv_open(string stream, string path) @@ -504,7 +508,7 @@ int SrsDvrPlan::flv_open(string stream, string path)
504 return ret; 508 return ret;
505 } 509 }
506 510
507 - segment->current_flv_path = path; 511 + segment->path = path;
508 512
509 srs_trace("dvr stream %s to file %s", stream.c_str(), path.c_str()); 513 srs_trace("dvr stream %s to file %s", stream.c_str(), path.c_str());
510 return ret; 514 return ret;
@@ -518,16 +522,16 @@ int SrsDvrPlan::flv_close() @@ -518,16 +522,16 @@ int SrsDvrPlan::flv_close()
518 return ret; 522 return ret;
519 } 523 }
520 524
521 - std::string tmp_file = segment->current_flv_path + ".tmp";  
522 - if (rename(tmp_file.c_str(), segment->current_flv_path.c_str()) < 0) { 525 + std::string tmp_file = segment->path + ".tmp";
  526 + if (rename(tmp_file.c_str(), segment->path.c_str()) < 0) {
523 ret = ERROR_SYSTEM_FILE_RENAME; 527 ret = ERROR_SYSTEM_FILE_RENAME;
524 srs_error("rename flv file failed, %s => %s. ret=%d", 528 srs_error("rename flv file failed, %s => %s. ret=%d",
525 - tmp_file.c_str(), segment->current_flv_path.c_str(), ret); 529 + tmp_file.c_str(), segment->path.c_str(), ret);
526 return ret; 530 return ret;
527 } 531 }
528 532
529 #ifdef SRS_AUTO_HTTP_CALLBACK 533 #ifdef SRS_AUTO_HTTP_CALLBACK
530 - if (segment->segment_has_keyframe) { 534 + if (segment->has_keyframe) {
531 if ((ret = on_dvr_keyframe()) != ERROR_SUCCESS) { 535 if ((ret = on_dvr_keyframe()) != ERROR_SUCCESS) {
532 return ret; 536 return ret;
533 } 537 }
@@ -540,13 +544,26 @@ int SrsDvrPlan::flv_close() @@ -540,13 +544,26 @@ int SrsDvrPlan::flv_close()
540 int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg) 544 int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg)
541 { 545 {
542 int ret = ERROR_SUCCESS; 546 int ret = ERROR_SUCCESS;
  547 +
  548 + // we must assumpt that the stream timestamp is monotonically increase,
  549 + // that is, always use time jitter to correct the timestamp.
543 550
544 - // foreach msg, collect the duration.  
545 - if (segment->starttime < 0 || segment->starttime > msg->header.timestamp) { 551 + // set the segment starttime at first time
  552 + if (segment->starttime < 0) {
546 segment->starttime = msg->header.timestamp; 553 segment->starttime = msg->header.timestamp;
547 } 554 }
548 - segment->duration += msg->header.timestamp - segment->starttime;  
549 - segment->starttime = msg->header.timestamp; 555 +
  556 + // no previous packet or timestamp overflow.
  557 + if (segment->stream_previous_pkt_time < 0 || segment->stream_previous_pkt_time > msg->header.timestamp) {
  558 + segment->stream_previous_pkt_time = msg->header.timestamp;
  559 + }
  560 +
  561 + // collect segment and stream duration, timestamp overflow is ok.
  562 + segment->duration += msg->header.timestamp - segment->stream_previous_pkt_time;
  563 + segment->stream_duration += msg->header.timestamp - segment->stream_previous_pkt_time;
  564 +
  565 + // update previous packet time
  566 + segment->stream_previous_pkt_time = msg->header.timestamp;
550 567
551 return ret; 568 return ret;
552 } 569 }
@@ -579,6 +596,8 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost) @@ -579,6 +596,8 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
579 return new SrsDvrSegmentPlan(); 596 return new SrsDvrSegmentPlan();
580 } else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_SESSION) { 597 } else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_SESSION) {
581 return new SrsDvrSessionPlan(); 598 return new SrsDvrSessionPlan();
  599 + } else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_HSS) {
  600 + return new SrsDvrHssPlan();
582 } else { 601 } else {
583 return new SrsDvrSessionPlan(); 602 return new SrsDvrSessionPlan();
584 } 603 }
@@ -683,6 +702,111 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) @@ -683,6 +702,111 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
683 return ret; 702 return ret;
684 } 703 }
685 704
  705 +SrsDvrHssPlan::SrsDvrHssPlan()
  706 +{
  707 + segment_duration = -1;
  708 + start_deviation = 0;
  709 + expect_reap_time = 0;
  710 +}
  711 +
  712 +SrsDvrHssPlan::~SrsDvrHssPlan()
  713 +{
  714 +}
  715 +
  716 +int SrsDvrHssPlan::initialize(SrsSource* source, SrsRequest* req)
  717 +{
  718 + int ret = ERROR_SUCCESS;
  719 +
  720 + if ((ret = SrsDvrPlan::initialize(source, req)) != ERROR_SUCCESS) {
  721 + return ret;
  722 + }
  723 +
  724 + // TODO: FIXME: support reload
  725 + segment_duration = _srs_config->get_dvr_duration(req->vhost);
  726 + // to ms
  727 + segment_duration *= 1000;
  728 +
  729 + return ret;
  730 +}
  731 +
  732 +int SrsDvrHssPlan::on_publish()
  733 +{
  734 + int ret = ERROR_SUCCESS;
  735 +
  736 + // if already opened, continue to dvr.
  737 + // the segment plan maybe keep running longer than the encoder.
  738 + // for example, segment running, encoder restart,
  739 + // the segment plan will just continue going and donot open new segment.
  740 + if (fs->is_open()) {
  741 + dvr_enabled = true;
  742 + return ret;
  743 + }
  744 +
  745 + if ((ret = SrsDvrPlan::on_publish()) != ERROR_SUCCESS) {
  746 + return ret;
  747 + }
  748 +
  749 + // expect reap flv time
  750 + expect_reap_time = segment->stream_starttime + segment_duration;
  751 + // the start deviation used ensure the segment starttime in nature clock.
  752 + start_deviation = segment->stream_starttime % 1000;
  753 +
  754 + return ret;
  755 +}
  756 +
  757 +void SrsDvrHssPlan::on_unpublish()
  758 +{
  759 + // support multiple publish.
  760 + if (!dvr_enabled) {
  761 + return;
  762 + }
  763 + dvr_enabled = false;
  764 +}
  765 +
  766 +int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg)
  767 +{
  768 + int ret = ERROR_SUCCESS;
  769 +
  770 + if ((ret = SrsDvrPlan::update_duration(msg)) != ERROR_SUCCESS) {
  771 + return ret;
  772 + }
  773 +
  774 + srs_assert(segment);
  775 +
  776 + // if not initialized, ignore reap.
  777 + if (expect_reap_time <= 0
  778 + || segment->stream_starttime <= 0
  779 + || segment->stream_duration <= 0
  780 + ) {
  781 + return ret;
  782 + }
  783 +
  784 + // reap if exceed atc expect time.
  785 + if (segment->stream_starttime + segment->stream_duration > expect_reap_time) {
  786 + srs_warn("hss reap start=%"PRId64", duration=%"PRId64", expect=%"PRId64
  787 + ", segment(start=%"PRId64", adjust=%"PRId64", duration=%"PRId64", file=%s",
  788 + segment->stream_starttime, segment->stream_duration, expect_reap_time,
  789 + segment->stream_starttime + segment->starttime,
  790 + segment->stream_starttime + segment->starttime - start_deviation,
  791 + segment->duration, segment->path.c_str());
  792 +
  793 + // update expect reap time
  794 + expect_reap_time += segment_duration;
  795 +
  796 + if ((ret = flv_close()) != ERROR_SUCCESS) {
  797 + segment->reset();
  798 + return ret;
  799 + }
  800 + on_unpublish();
  801 +
  802 + if ((ret = open_new_segment()) != ERROR_SUCCESS) {
  803 + return ret;
  804 + }
  805 + }
  806 +
  807 + return ret;
  808 +}
  809 +
686 SrsDvr::SrsDvr(SrsSource* source) 810 SrsDvr::SrsDvr(SrsSource* source)
687 { 811 {
688 _source = source; 812 _source = source;
@@ -114,22 +114,34 @@ class SrsFlvSegment @@ -114,22 +114,34 @@ class SrsFlvSegment
114 { 114 {
115 public: 115 public:
116 /** 116 /**
117 - * current flv file path. 117 + * current segment flv file path.
118 */ 118 */
119 - std::string current_flv_path; 119 + std::string path;
120 /** 120 /**
121 * whether current segment has keyframe. 121 * whether current segment has keyframe.
122 */ 122 */
123 - bool segment_has_keyframe; 123 + bool has_keyframe;
124 /** 124 /**
125 - * current segment duration and starttime. 125 + * current segment starttime, RTMP pkt time.
126 */ 126 */
127 - int64_t duration;  
128 int64_t starttime; 127 int64_t starttime;
129 /** 128 /**
130 - * stream start time, to generate atc pts. 129 + * current segment duration
  130 + */
  131 + int64_t duration;
  132 + /**
  133 + * stream start time, to generate atc pts. abs time.
131 */ 134 */
132 int64_t stream_starttime; 135 int64_t stream_starttime;
  136 + /**
  137 + * stream duration, to generate atc segment.
  138 + */
  139 + int64_t stream_duration;
  140 + /**
  141 + * previous stream RTMP pkt time, used to calc the duration.
  142 + * for the RTMP timestamp will overflow.
  143 + */
  144 + int64_t stream_previous_pkt_time;
133 public: 145 public:
134 SrsFlvSegment(); 146 SrsFlvSegment();
135 virtual void reset(); 147 virtual void reset();
@@ -214,6 +226,28 @@ private: @@ -214,6 +226,28 @@ private:
214 }; 226 };
215 227
216 /** 228 /**
  229 +* hss plan: use atc time to reap flv segment
  230 +*/
  231 +class SrsDvrHssPlan : public SrsDvrPlan
  232 +{
  233 +private:
  234 + // in config, in ms
  235 + int segment_duration;
  236 + // the deviation of starttime of the nature clock time.
  237 + int start_deviation;
  238 + int64_t expect_reap_time;
  239 +public:
  240 + SrsDvrHssPlan();
  241 + virtual ~SrsDvrHssPlan();
  242 +public:
  243 + virtual int initialize(SrsSource* source, SrsRequest* req);
  244 + virtual int on_publish();
  245 + virtual void on_unpublish();
  246 +private:
  247 + virtual int update_duration(SrsSharedPtrMessage* msg);
  248 +};
  249 +
  250 +/**
217 * dvr(digital video recorder) to record RTMP stream to flv file. 251 * dvr(digital video recorder) to record RTMP stream to flv file.
218 * TODO: FIXME: add utest for it. 252 * TODO: FIXME: add utest for it.
219 */ 253 */
@@ -462,10 +462,11 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s @@ -462,10 +462,11 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
462 { 462 {
463 int ret = ERROR_SUCCESS; 463 int ret = ERROR_SUCCESS;
464 464
  465 + srs_assert(segment);
465 srs_trace("flv segment %s, atc_start=%"PRId64", " 466 srs_trace("flv segment %s, atc_start=%"PRId64", "
466 "has_key=%d, starttime=%"PRId64", duration=%d", 467 "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); 468 + segment->path.c_str(), segment->stream_starttime,
  469 + segment->has_keyframe, segment->starttime, (int)segment->duration);
469 470
470 SrsHttpUri uri; 471 SrsHttpUri uri;
471 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { 472 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "73" 34 +#define VERSION_REVISION "74"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "srs" 37 #define RTMP_SIG_SRS_KEY "srs"