winlin

support live flashP2P(integrated by chnvideo VDN). 0.9.75

@@ -157,6 +157,7 @@ Supported operating systems and hardware: @@ -157,6 +157,7 @@ Supported operating systems and hardware:
157 1. Support stream ingester using ffmpeg. 157 1. Support stream ingester using ffmpeg.
158 1. Support ingest RTSP(RTP, SDP) stream to RTMP. 158 1. Support ingest RTSP(RTP, SDP) stream to RTMP.
159 1. Support dvr(record live to flv file for vod) 159 1. Support dvr(record live to flv file for vod)
  160 +1. Support live flashP2P(integrated by chnvideo VDN).
160 1. [plan] Support file to hls vod stream. 161 1. [plan] Support file to hls vod stream.
161 1. [plan] Support system full utest on gtest. 162 1. [plan] Support system full utest on gtest.
162 1. [plan] Support RTMP edge server, push/pull stream from any RTMP server 163 1. [plan] Support RTMP edge server, push/pull stream from any RTMP server
@@ -184,6 +185,7 @@ Supported operating systems and hardware: @@ -184,6 +185,7 @@ Supported operating systems and hardware:
184 * 2013-10-17, Created.<br/> 185 * 2013-10-17, Created.<br/>
185 186
186 ## History 187 ## History
  188 +* v1.0, 2014-04-24, support live flashP2P(integrated by chnvideo VDN). 0.9.75
187 * v1.0, 2014-04-21, support android app to start srs for internal edge. 0.9.72 189 * v1.0, 2014-04-21, support android app to start srs for internal edge. 0.9.72
188 * v1.0, 2014-04-19, support tool over srs-librtmp to ingest flv/rtmp. 0.9.71 190 * v1.0, 2014-04-19, support tool over srs-librtmp to ingest flv/rtmp. 0.9.71
189 * v1.0, 2014-04-17, support dvr(record live to flv file for vod). 0.9.69 191 * v1.0, 2014-04-17, support dvr(record live to flv file for vod). 0.9.69
@@ -97,7 +97,7 @@ vhost dvr.srs.com { @@ -97,7 +97,7 @@ vhost dvr.srs.com {
97 # start to record to file when encoder publish, 97 # start to record to file when encoder publish,
98 # reap flv according by specified dvr_plan. 98 # reap flv according by specified dvr_plan.
99 # http callbacks: 99 # http callbacks:
100 - # @see http callback on_dvr_keyframe on http_hooks section. 100 + # @see http callback on_dvr_reap_flv on http_hooks section.
101 dvr { 101 dvr {
102 # whether enabled dvr features 102 # whether enabled dvr features
103 # default: off 103 # default: off
@@ -325,16 +325,22 @@ vhost hooks.callback.srs.com { @@ -325,16 +325,22 @@ vhost hooks.callback.srs.com {
325 # when dvr got an keyframe, call the hook, 325 # when dvr got an keyframe, call the hook,
326 # the request in the POST data string is a object encode by json: 326 # the request in the POST data string is a object encode by json:
327 # { 327 # {
328 - # "action": "on_dvr_keyframe", 328 + # "action": "on_dvr_reap_flv",
329 # "vhost": "video.test.com", "app": "live", 329 # "vhost": "video.test.com", "app": "live",
330 - # "stream": "livestream" 330 + # "stream": "livestream",
  331 + # "segment": {
  332 + # "cwd": "/usr/local/srs",
  333 + # "path": "./objs/nginx/html/live/livestream.1398315892865.flv",
  334 + # "duration": 1001, "offset":0,
  335 + # "has_keyframe": true, "pts":1398315895958
  336 + # }
331 # } 337 # }
332 # if valid, the hook must return HTTP code 200(Stauts OK) and response 338 # if valid, the hook must return HTTP code 200(Stauts OK) and response
333 # an int value specifies the error code(0 corresponding to success): 339 # an int value specifies the error code(0 corresponding to success):
334 # 0 340 # 0
335 # support multiple api hooks, format: 341 # support multiple api hooks, format:
336 # on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN 342 # on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
337 - on_dvr_keyframe http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs; 343 + on_dvr_reap_flv http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
338 } 344 }
339 } 345 }
340 346
@@ -1560,7 +1560,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost) @@ -1560,7 +1560,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
1560 return conf->get("on_stop"); 1560 return conf->get("on_stop");
1561 } 1561 }
1562 1562
1563 -SrsConfDirective* SrsConfig::get_vhost_on_dvr_keyframe(string vhost) 1563 +SrsConfDirective* SrsConfig::get_vhost_on_dvr_reap_flv(string vhost)
1564 { 1564 {
1565 SrsConfDirective* conf = get_vhost(vhost); 1565 SrsConfDirective* conf = get_vhost(vhost);
1566 1566
@@ -1578,7 +1578,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_dvr_keyframe(string vhost) @@ -1578,7 +1578,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_dvr_keyframe(string vhost)
1578 return NULL; 1578 return NULL;
1579 } 1579 }
1580 1580
1581 - return conf->get("on_dvr_keyframe"); 1581 + return conf->get("on_dvr_reap_flv");
1582 } 1582 }
1583 1583
1584 bool SrsConfig::get_vhost_enabled(string vhost) 1584 bool SrsConfig::get_vhost_enabled(string vhost)
@@ -175,7 +175,7 @@ public: @@ -175,7 +175,7 @@ public:
175 virtual SrsConfDirective* get_vhost_on_unpublish(std::string vhost); 175 virtual SrsConfDirective* get_vhost_on_unpublish(std::string vhost);
176 virtual SrsConfDirective* get_vhost_on_play(std::string vhost); 176 virtual SrsConfDirective* get_vhost_on_play(std::string vhost);
177 virtual SrsConfDirective* get_vhost_on_stop(std::string vhost); 177 virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
178 - virtual SrsConfDirective* get_vhost_on_dvr_keyframe(std::string vhost); 178 + virtual SrsConfDirective* get_vhost_on_dvr_reap_flv(std::string vhost);
179 virtual bool get_gop_cache(std::string vhost); 179 virtual bool get_gop_cache(std::string vhost);
180 virtual bool get_atc(std::string vhost); 180 virtual bool get_atc(std::string vhost);
181 virtual double get_queue_length(std::string vhost); 181 virtual double get_queue_length(std::string vhost);
@@ -138,6 +138,11 @@ int SrsFileStream::write(void* buf, size_t count, ssize_t* pnwrite) @@ -138,6 +138,11 @@ int SrsFileStream::write(void* buf, size_t count, ssize_t* pnwrite)
138 return ret; 138 return ret;
139 } 139 }
140 140
  141 +int64_t SrsFileStream::tellg()
  142 +{
  143 + return (int64_t)::lseek(fd, 0, SEEK_CUR);
  144 +}
  145 +
141 SrsFlvEncoder::SrsFlvEncoder() 146 SrsFlvEncoder::SrsFlvEncoder()
142 { 147 {
143 _fs = NULL; 148 _fs = NULL;
@@ -209,10 +214,12 @@ int SrsFlvEncoder::write_metadata(char* data, int size) @@ -209,10 +214,12 @@ int SrsFlvEncoder::write_metadata(char* data, int size)
209 return ret; 214 return ret;
210 } 215 }
211 216
212 -int SrsFlvEncoder::write_audio(int32_t timestamp, char* data, int size) 217 +int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)
213 { 218 {
214 int ret = ERROR_SUCCESS; 219 int ret = ERROR_SUCCESS;
215 220
  221 + timestamp &= 0x7fffffff;
  222 +
216 static char tag_header[] = { 223 static char tag_header[] = {
217 (char)8, // TagType UB [5], 8 = audio 224 (char)8, // TagType UB [5], 8 = audio
218 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 225 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
@@ -238,10 +245,12 @@ int SrsFlvEncoder::write_audio(int32_t timestamp, char* data, int size) @@ -238,10 +245,12 @@ int SrsFlvEncoder::write_audio(int32_t timestamp, char* data, int size)
238 return ret; 245 return ret;
239 } 246 }
240 247
241 -int SrsFlvEncoder::write_video(int32_t timestamp, char* data, int size) 248 +int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
242 { 249 {
243 int ret = ERROR_SUCCESS; 250 int ret = ERROR_SUCCESS;
244 251
  252 + timestamp &= 0x7fffffff;
  253 +
245 static char tag_header[] = { 254 static char tag_header[] = {
246 (char)9, // TagType UB [5], 9 = video 255 (char)9, // TagType UB [5], 9 = video
247 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. 256 (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
@@ -303,6 +312,7 @@ SrsFlvSegment::SrsFlvSegment() @@ -303,6 +312,7 @@ SrsFlvSegment::SrsFlvSegment()
303 has_keyframe = false; 312 has_keyframe = false;
304 duration = 0; 313 duration = 0;
305 starttime = -1; 314 starttime = -1;
  315 + sequence_header_offset = 0;
306 stream_starttime = 0; 316 stream_starttime = 0;
307 stream_previous_pkt_time = -1; 317 stream_previous_pkt_time = -1;
308 stream_duration = 0; 318 stream_duration = 0;
@@ -313,6 +323,7 @@ void SrsFlvSegment::reset() @@ -313,6 +323,7 @@ void SrsFlvSegment::reset()
313 has_keyframe = false; 323 has_keyframe = false;
314 starttime = -1; 324 starttime = -1;
315 duration = 0; 325 duration = 0;
  326 + sequence_header_offset = 0;
316 } 327 }
317 328
318 SrsDvrPlan::SrsDvrPlan() 329 SrsDvrPlan::SrsDvrPlan()
@@ -396,14 +407,32 @@ int SrsDvrPlan::open_new_segment() @@ -396,14 +407,32 @@ int SrsDvrPlan::open_new_segment()
396 } 407 }
397 dvr_enabled = true; 408 dvr_enabled = true;
398 409
  410 + return ret;
  411 +}
  412 +
  413 +int SrsDvrPlan::on_dvr_request_sh()
  414 +{
  415 + int ret = ERROR_SUCCESS;
  416 +
399 // the dvr is enabled, notice the source to push the data. 417 // the dvr is enabled, notice the source to push the data.
400 - if ((ret = _source->on_dvr_start()) != ERROR_SUCCESS) { 418 + if ((ret = _source->on_dvr_request_sh()) != ERROR_SUCCESS) {
401 return ret; 419 return ret;
402 } 420 }
403 421
404 return ret; 422 return ret;
405 } 423 }
406 424
  425 +int SrsDvrPlan::on_video_keyframe()
  426 +{
  427 + int ret = ERROR_SUCCESS;
  428 + return ret;
  429 +}
  430 +
  431 +int64_t SrsDvrPlan::filter_timestamp(int64_t timestamp)
  432 +{
  433 + return timestamp;
  434 +}
  435 +
407 int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata) 436 int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata)
408 { 437 {
409 int ret = ERROR_SUCCESS; 438 int ret = ERROR_SUCCESS;
@@ -438,9 +467,9 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio) @@ -438,9 +467,9 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio)
438 return ret; 467 return ret;
439 } 468 }
440 469
441 - int32_t timestamp = audio->header.timestamp;  
442 char* payload = (char*)audio->payload; 470 char* payload = (char*)audio->payload;
443 int size = (int)audio->size; 471 int size = (int)audio->size;
  472 + int64_t timestamp = filter_timestamp(audio->header.timestamp);
444 if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) { 473 if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) {
445 return ret; 474 return ret;
446 } 475 }
@@ -460,25 +489,31 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video) @@ -460,25 +489,31 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
460 return ret; 489 return ret;
461 } 490 }
462 491
463 - if ((jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {  
464 - return ret;  
465 - }  
466 -  
467 - int32_t timestamp = video->header.timestamp;  
468 char* payload = (char*)video->payload; 492 char* payload = (char*)video->payload;
469 int size = (int)video->size; 493 int size = (int)video->size;
470 - if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) {  
471 - return ret;  
472 - }  
473 494
474 #ifdef SRS_AUTO_HTTP_CALLBACK 495 #ifdef SRS_AUTO_HTTP_CALLBACK
475 - bool is_key_frame = SrsCodec::video_is_keyframe((int8_t*)payload, size); 496 + bool is_key_frame = SrsCodec::video_is_h264((int8_t*)payload, size)
  497 + && SrsCodec::video_is_keyframe((int8_t*)payload, size)
  498 + && !SrsCodec::video_is_sequence_header((int8_t*)payload, size);
476 if (is_key_frame) { 499 if (is_key_frame) {
477 segment->has_keyframe = true; 500 segment->has_keyframe = true;
  501 + if ((ret = on_video_keyframe()) != ERROR_SUCCESS) {
  502 + return ret;
  503 + }
478 } 504 }
479 srs_verbose("dvr video is key: %d", is_key_frame); 505 srs_verbose("dvr video is key: %d", is_key_frame);
480 #endif 506 #endif
481 507
  508 + if ((jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
  509 + return ret;
  510 + }
  511 +
  512 + int32_t timestamp = filter_timestamp(video->header.timestamp);
  513 + if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) {
  514 + return ret;
  515 + }
  516 +
482 if ((ret = update_duration(video)) != ERROR_SUCCESS) { 517 if ((ret = update_duration(video)) != ERROR_SUCCESS) {
483 return ret; 518 return ret;
484 } 519 }
@@ -503,8 +538,7 @@ int SrsDvrPlan::flv_open(string stream, string path) @@ -503,8 +538,7 @@ int SrsDvrPlan::flv_open(string stream, string path)
503 return ret; 538 return ret;
504 } 539 }
505 540
506 - if ((ret = enc->write_header()) != ERROR_SUCCESS) {  
507 - srs_error("write flv header for file %s failed. ret=%d", path.c_str(), ret); 541 + if ((ret = write_flv_header()) != ERROR_SUCCESS) {
508 return ret; 542 return ret;
509 } 543 }
510 544
@@ -531,10 +565,8 @@ int SrsDvrPlan::flv_close() @@ -531,10 +565,8 @@ int SrsDvrPlan::flv_close()
531 } 565 }
532 566
533 #ifdef SRS_AUTO_HTTP_CALLBACK 567 #ifdef SRS_AUTO_HTTP_CALLBACK
534 - if (segment->has_keyframe) {  
535 - if ((ret = on_dvr_keyframe()) != ERROR_SUCCESS) {  
536 - return ret;  
537 - } 568 + if ((ret = on_dvr_reap_flv()) != ERROR_SUCCESS) {
  569 + return ret;
538 } 570 }
539 #endif 571 #endif
540 572
@@ -568,21 +600,33 @@ int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg) @@ -568,21 +600,33 @@ int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg)
568 return ret; 600 return ret;
569 } 601 }
570 602
571 -int SrsDvrPlan::on_dvr_keyframe() 603 +int SrsDvrPlan::write_flv_header()
  604 +{
  605 + int ret = ERROR_SUCCESS;
  606 +
  607 + if ((ret = enc->write_header()) != ERROR_SUCCESS) {
  608 + srs_error("write flv header failed. ret=%d", ret);
  609 + return ret;
  610 + }
  611 +
  612 + return ret;
  613 +}
  614 +
  615 +int SrsDvrPlan::on_dvr_reap_flv()
572 { 616 {
573 int ret = ERROR_SUCCESS; 617 int ret = ERROR_SUCCESS;
574 618
575 #ifdef SRS_AUTO_HTTP_CALLBACK 619 #ifdef SRS_AUTO_HTTP_CALLBACK
576 - // HTTP: on_dvr_keyframe  
577 - SrsConfDirective* on_dvr_keyframe = _srs_config->get_vhost_on_dvr_keyframe(_req->vhost);  
578 - if (!on_dvr_keyframe) {  
579 - srs_info("ignore the empty http callback: on_dvr_keyframe"); 620 + // HTTP: on_dvr_reap_flv
  621 + SrsConfDirective* on_dvr_reap_flv = _srs_config->get_vhost_on_dvr_reap_flv(_req->vhost);
  622 + if (!on_dvr_reap_flv) {
  623 + srs_info("ignore the empty http callback: on_dvr_reap_flv");
580 return ret; 624 return ret;
581 } 625 }
582 626
583 - for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) {  
584 - std::string url = on_dvr_keyframe->args.at(i);  
585 - SrsHttpHooks::on_dvr_keyframe(url, _req, segment); 627 + for (int i = 0; i < (int)on_dvr_reap_flv->args.size(); i++) {
  628 + std::string url = on_dvr_reap_flv->args.at(i);
  629 + SrsHttpHooks::on_dvr_reap_flv(url, _req, segment);
586 } 630 }
587 #endif 631 #endif
588 632
@@ -705,7 +749,6 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) @@ -705,7 +749,6 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
705 SrsDvrHssPlan::SrsDvrHssPlan() 749 SrsDvrHssPlan::SrsDvrHssPlan()
706 { 750 {
707 segment_duration = -1; 751 segment_duration = -1;
708 - start_deviation = 0;  
709 expect_reap_time = 0; 752 expect_reap_time = 0;
710 } 753 }
711 754
@@ -748,8 +791,6 @@ int SrsDvrHssPlan::on_publish() @@ -748,8 +791,6 @@ int SrsDvrHssPlan::on_publish()
748 791
749 // expect reap flv time 792 // expect reap flv time
750 expect_reap_time = segment->stream_starttime + segment_duration; 793 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 794
754 return ret; 795 return ret;
755 } 796 }
@@ -763,6 +804,44 @@ void SrsDvrHssPlan::on_unpublish() @@ -763,6 +804,44 @@ void SrsDvrHssPlan::on_unpublish()
763 dvr_enabled = false; 804 dvr_enabled = false;
764 } 805 }
765 806
  807 +int SrsDvrHssPlan::on_meta_data(SrsOnMetaDataPacket* /*metadata*/)
  808 +{
  809 + int ret = ERROR_SUCCESS;
  810 + return ret;
  811 +}
  812 +
  813 +int SrsDvrHssPlan::write_flv_header()
  814 +{
  815 + int ret = ERROR_SUCCESS;
  816 + return ret;
  817 +}
  818 +
  819 +int SrsDvrHssPlan::on_dvr_request_sh()
  820 +{
  821 + int ret = ERROR_SUCCESS;
  822 + return ret;
  823 +}
  824 +
  825 +int SrsDvrHssPlan::on_video_keyframe()
  826 +{
  827 + int ret = ERROR_SUCCESS;
  828 +
  829 + segment->sequence_header_offset = fs->tellg();
  830 + if ((ret = SrsDvrPlan::on_dvr_request_sh()) != ERROR_SUCCESS) {
  831 + return ret;
  832 + }
  833 +
  834 + return ret;
  835 +}
  836 +
  837 +int64_t SrsDvrHssPlan::filter_timestamp(int64_t timestamp)
  838 +{
  839 + //return timestamp;
  840 + srs_assert(segment);
  841 + srs_verbose("filter timestamp from %"PRId64" to %"PRId64, timestamp, segment->stream_starttime + timestamp);
  842 + return segment->stream_starttime + timestamp;
  843 +}
  844 +
766 int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg) 845 int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg)
767 { 846 {
768 int ret = ERROR_SUCCESS; 847 int ret = ERROR_SUCCESS;
@@ -784,10 +863,9 @@ int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg) @@ -784,10 +863,9 @@ int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg)
784 // reap if exceed atc expect time. 863 // reap if exceed atc expect time.
785 if (segment->stream_starttime + segment->stream_duration > expect_reap_time) { 864 if (segment->stream_starttime + segment->stream_duration > expect_reap_time) {
786 srs_verbose("hss reap start=%"PRId64", duration=%"PRId64", expect=%"PRId64 865 srs_verbose("hss reap start=%"PRId64", duration=%"PRId64", expect=%"PRId64
787 - ", segment(start=%"PRId64", adjust=%"PRId64", duration=%"PRId64", file=%s", 866 + ", segment(start=%"PRId64", duration=%"PRId64", file=%s",
788 segment->stream_starttime, segment->stream_duration, expect_reap_time, 867 segment->stream_starttime, segment->stream_duration, expect_reap_time,
789 segment->stream_starttime + segment->starttime, 868 segment->stream_starttime + segment->starttime,
790 - segment->stream_starttime + segment->starttime - start_deviation,  
791 segment->duration, segment->path.c_str()); 869 segment->duration, segment->path.c_str());
792 870
793 // update expect reap time 871 // update expect reap time
@@ -62,6 +62,10 @@ public: @@ -62,6 +62,10 @@ public:
62 * @param pnwrite, return the write size. NULL to ignore. 62 * @param pnwrite, return the write size. NULL to ignore.
63 */ 63 */
64 virtual int write(void* buf, size_t count, ssize_t* pnwrite); 64 virtual int write(void* buf, size_t count, ssize_t* pnwrite);
  65 + /**
  66 + * tell current offset of stream.
  67 + */
  68 + virtual int64_t tellg();
65 }; 69 };
66 70
67 /** 71 /**
@@ -101,8 +105,8 @@ public: @@ -101,8 +105,8 @@ public:
101 /** 105 /**
102 * write audio/video packet. 106 * write audio/video packet.
103 */ 107 */
104 - virtual int write_audio(int32_t timestamp, char* data, int size);  
105 - virtual int write_video(int32_t timestamp, char* data, int size); 108 + virtual int write_audio(int64_t timestamp, char* data, int size);
  109 + virtual int write_video(int64_t timestamp, char* data, int size);
106 private: 110 private:
107 virtual int write_tag(char* header, int header_size, char* tag, int tag_size); 111 virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
108 }; 112 };
@@ -122,6 +126,10 @@ public: @@ -122,6 +126,10 @@ public:
122 */ 126 */
123 bool has_keyframe; 127 bool has_keyframe;
124 /** 128 /**
  129 + * sequence header offset in file.
  130 + */
  131 + int64_t sequence_header_offset;
  132 + /**
125 * current segment starttime, RTMP pkt time. 133 * current segment starttime, RTMP pkt time.
126 */ 134 */
127 int64_t starttime; 135 int64_t starttime;
@@ -184,12 +192,15 @@ protected: @@ -184,12 +192,15 @@ protected:
184 virtual int flv_close(); 192 virtual int flv_close();
185 virtual int open_new_segment(); 193 virtual int open_new_segment();
186 virtual int update_duration(SrsSharedPtrMessage* msg); 194 virtual int update_duration(SrsSharedPtrMessage* msg);
  195 + virtual int write_flv_header();
  196 + virtual int on_dvr_request_sh();
  197 + virtual int on_video_keyframe();
  198 + virtual int64_t filter_timestamp(int64_t timestamp);
187 private: 199 private:
188 /** 200 /**
189 - * when srs reap the flv(close the segment),  
190 - * if has keyframe, notice the api. 201 + * when srs reap the flv(close the segment), notice the api.
191 */ 202 */
192 - virtual int on_dvr_keyframe(); 203 + virtual int on_dvr_reap_flv();
193 public: 204 public:
194 static SrsDvrPlan* create_plan(std::string vhost); 205 static SrsDvrPlan* create_plan(std::string vhost);
195 }; 206 };
@@ -233,8 +244,6 @@ class SrsDvrHssPlan : public SrsDvrPlan @@ -233,8 +244,6 @@ class SrsDvrHssPlan : public SrsDvrPlan
233 private: 244 private:
234 // in config, in ms 245 // in config, in ms
235 int segment_duration; 246 int segment_duration;
236 - // the deviation of starttime of the nature clock time.  
237 - int start_deviation;  
238 int64_t expect_reap_time; 247 int64_t expect_reap_time;
239 public: 248 public:
240 SrsDvrHssPlan(); 249 SrsDvrHssPlan();
@@ -243,6 +252,12 @@ public: @@ -243,6 +252,12 @@ public:
243 virtual int initialize(SrsSource* source, SrsRequest* req); 252 virtual int initialize(SrsSource* source, SrsRequest* req);
244 virtual int on_publish(); 253 virtual int on_publish();
245 virtual void on_unpublish(); 254 virtual void on_unpublish();
  255 + virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
  256 +protected:
  257 + virtual int write_flv_header();
  258 + virtual int on_dvr_request_sh();
  259 + virtual int on_video_keyframe();
  260 + virtual int64_t filter_timestamp(int64_t timestamp);
246 private: 261 private:
247 virtual int update_duration(SrsSharedPtrMessage* msg); 262 virtual int update_duration(SrsSharedPtrMessage* msg);
248 }; 263 };
@@ -459,7 +459,7 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req @@ -459,7 +459,7 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
459 return; 459 return;
460 } 460 }
461 461
462 -void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* segment) 462 +void SrsHttpHooks::on_dvr_reap_flv(string url, SrsRequest* req, SrsFlvSegment* segment)
463 { 463 {
464 int ret = ERROR_SUCCESS; 464 int ret = ERROR_SUCCESS;
465 465
@@ -471,23 +471,24 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s @@ -471,23 +471,24 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
471 471
472 SrsHttpUri uri; 472 SrsHttpUri uri;
473 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { 473 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
474 - srs_warn("http uri parse on_dvr_keyframe url failed, ignored. " 474 + srs_warn("http uri parse on_dvr_reap_flv url failed, ignored. "
475 "url=%s, ret=%d", url.c_str(), ret); 475 "url=%s, ret=%d", url.c_str(), ret);
476 return; 476 return;
477 } 477 }
478 478
479 std::stringstream ss; 479 std::stringstream ss;
480 ss << JOBJECT_START 480 ss << JOBJECT_START
481 - << JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT 481 + << JFIELD_STR("action", "on_dvr_reap_flv") << JFIELD_CONT
482 << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT 482 << JFIELD_STR("vhost", req->vhost) << JFIELD_CONT
483 << JFIELD_STR("app", req->app) << JFIELD_CONT 483 << JFIELD_STR("app", req->app) << JFIELD_CONT
484 << JFIELD_STR("stream", req->stream) << JFIELD_CONT 484 << JFIELD_STR("stream", req->stream) << JFIELD_CONT
485 << JFIELD_NAME("segment") << JOBJECT_START 485 << JFIELD_NAME("segment") << JOBJECT_START
486 << JFIELD_STR("cwd", _srs_config->get_cwd()) << JFIELD_CONT 486 << JFIELD_STR("cwd", _srs_config->get_cwd()) << JFIELD_CONT
487 << JFIELD_STR("path", segment->path) << JFIELD_CONT 487 << JFIELD_STR("path", segment->path) << JFIELD_CONT
488 - << JFIELD_ORG("pts", segment->stream_starttime + segment->starttime) << JFIELD_CONT  
489 << JFIELD_ORG("duration", segment->duration) << JFIELD_CONT 488 << JFIELD_ORG("duration", segment->duration) << JFIELD_CONT
490 - << JFIELD_ORG("offset", 0) 489 + << JFIELD_ORG("offset", segment->sequence_header_offset) << JFIELD_CONT
  490 + << JFIELD_ORG("has_keyframe", (segment->has_keyframe? "true":"false")) << JFIELD_CONT
  491 + << JFIELD_ORG("pts", segment->stream_starttime + segment->starttime)
491 << JOBJECT_END 492 << JOBJECT_END
492 << JOBJECT_END; 493 << JOBJECT_END;
493 std::string data = ss.str(); 494 std::string data = ss.str();
@@ -495,7 +496,7 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s @@ -495,7 +496,7 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
495 496
496 SrsHttpClient http; 497 SrsHttpClient http;
497 if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) { 498 if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
498 - srs_warn("http post on_dvr_keyframe uri failed, ignored. " 499 + srs_warn("http post on_dvr_reap_flv uri failed, ignored. "
499 "url=%s, request=%s, response=%s, ret=%d", 500 "url=%s, request=%s, response=%s, ret=%d",
500 url.c_str(), data.c_str(), res.c_str(), ret); 501 url.c_str(), data.c_str(), res.c_str(), ret);
501 return; 502 return;
@@ -503,12 +504,12 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s @@ -503,12 +504,12 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
503 504
504 if (res.empty() || res != SRS_HTTP_RESPONSE_OK) { 505 if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
505 ret = ERROR_HTTP_DATA_INVLIAD; 506 ret = ERROR_HTTP_DATA_INVLIAD;
506 - srs_warn("http hook on_dvr_keyframe validate failed, ignored. " 507 + srs_warn("http hook on_dvr_reap_flv validate failed, ignored. "
507 "res=%s, ret=%d", res.c_str(), ret); 508 "res=%s, ret=%d", res.c_str(), ret);
508 return; 509 return;
509 } 510 }
510 511
511 - srs_info("http hook on_dvr_keyframe success. " 512 + srs_info("http hook on_dvr_reap_flv success. "
512 "url=%s, request=%s, response=%s, ret=%d", 513 "url=%s, request=%s, response=%s, ret=%d",
513 url.c_str(), data.c_str(), res.c_str(), ret); 514 url.c_str(), data.c_str(), res.c_str(), ret);
514 515
@@ -124,12 +124,12 @@ public: @@ -124,12 +124,12 @@ public:
124 static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req); 124 static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
125 public: 125 public:
126 /** 126 /**
127 - * on_dvr_keyframe hook, when dvr get keyframe. 127 + * on_dvr_reap_flv hook, when dvr close flv file.
128 * @param url the api server url, to process the event. 128 * @param url the api server url, to process the event.
129 * ignore if empty. 129 * ignore if empty.
130 * @param segment the current flv segment. 130 * @param segment the current flv segment.
131 */ 131 */
132 - static void on_dvr_keyframe(std::string url, SrsRequest* req, SrsFlvSegment* segment); 132 + static void on_dvr_reap_flv(std::string url, SrsRequest* req, SrsFlvSegment* segment);
133 }; 133 };
134 134
135 #endif 135 #endif
@@ -721,14 +721,14 @@ int SrsSource::on_hls_start() @@ -721,14 +721,14 @@ int SrsSource::on_hls_start()
721 return ret; 721 return ret;
722 } 722 }
723 723
724 -int SrsSource::on_dvr_start() 724 +int SrsSource::on_dvr_request_sh()
725 { 725 {
726 int ret = ERROR_SUCCESS; 726 int ret = ERROR_SUCCESS;
727 727
728 #ifdef SRS_AUTO_DVR 728 #ifdef SRS_AUTO_DVR
729 // feed the dvr the metadata/sequence header, 729 // feed the dvr the metadata/sequence header,
730 // when reload to start dvr, dvr will never get the sequence header in stream, 730 // when reload to start dvr, dvr will never get the sequence header in stream,
731 - // use the SrsSource.on_dvr_start to push the sequence header to DVR. 731 + // use the SrsSource.on_dvr_request_sh to push the sequence header to DVR.
732 if (cache_metadata) { 732 if (cache_metadata) {
733 char* payload = (char*)cache_metadata->payload; 733 char* payload = (char*)cache_metadata->payload;
734 int size = (int)cache_metadata->size; 734 int size = (int)cache_metadata->size;
@@ -288,7 +288,7 @@ public: @@ -288,7 +288,7 @@ public:
288 // for the SrsHls to callback to request the sequence headers. 288 // for the SrsHls to callback to request the sequence headers.
289 virtual int on_hls_start(); 289 virtual int on_hls_start();
290 // for the SrsDvr to callback to request the sequence headers. 290 // for the SrsDvr to callback to request the sequence headers.
291 - virtual int on_dvr_start(); 291 + virtual int on_dvr_request_sh();
292 public: 292 public:
293 virtual bool can_publish(); 293 virtual bool can_publish();
294 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); 294 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
@@ -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 "74" 34 +#define VERSION_REVISION "75"
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"