正在显示
11 个修改的文件
包含
161 行增加
和
59 行删除
| @@ -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,11 +565,9 @@ int SrsDvrPlan::flv_close() | @@ -531,11 +565,9 @@ 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) { | 568 | + if ((ret = on_dvr_reap_flv()) != ERROR_SUCCESS) { |
| 536 | return ret; | 569 | return ret; |
| 537 | } | 570 | } |
| 538 | - } | ||
| 539 | #endif | 571 | #endif |
| 540 | 572 | ||
| 541 | return ret; | 573 | return ret; |
| @@ -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" |
-
请 注册 或 登录 后发表评论