正在显示
3 个修改的文件
包含
232 行增加
和
78 行删除
| @@ -169,6 +169,23 @@ int SrsTsMessage::stream_number() | @@ -169,6 +169,23 @@ int SrsTsMessage::stream_number() | ||
| 169 | return -1; | 169 | return -1; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | +SrsTsMessage* SrsTsMessage::detach() | ||
| 173 | +{ | ||
| 174 | + // @remark the packet cannot be used, but channel is ok. | ||
| 175 | + SrsTsMessage* cp = new SrsTsMessage(channel, NULL); | ||
| 176 | + cp->start_pts = start_pts; | ||
| 177 | + cp->write_pcr = write_pcr; | ||
| 178 | + cp->is_discontinuity = is_discontinuity; | ||
| 179 | + cp->dts = dts; | ||
| 180 | + cp->pts = pts; | ||
| 181 | + cp->sid = sid; | ||
| 182 | + cp->PES_packet_length = PES_packet_length; | ||
| 183 | + cp->continuity_counter = continuity_counter; | ||
| 184 | + cp->payload = payload; | ||
| 185 | + payload = NULL; | ||
| 186 | + return cp; | ||
| 187 | +} | ||
| 188 | + | ||
| 172 | ISrsTsHandler::ISrsTsHandler() | 189 | ISrsTsHandler::ISrsTsHandler() |
| 173 | { | 190 | { |
| 174 | } | 191 | } |
| @@ -309,6 +309,13 @@ public: | @@ -309,6 +309,13 @@ public: | ||
| 309 | * @return the stream number for audio/video; otherwise, -1. | 309 | * @return the stream number for audio/video; otherwise, -1. |
| 310 | */ | 310 | */ |
| 311 | virtual int stream_number(); | 311 | virtual int stream_number(); |
| 312 | +public: | ||
| 313 | + /** | ||
| 314 | + * detach the ts message, | ||
| 315 | + * for user maybe need to parse the message by queue. | ||
| 316 | + * @remark we always use the payload of original message. | ||
| 317 | + */ | ||
| 318 | + virtual SrsTsMessage* detach(); | ||
| 312 | }; | 319 | }; |
| 313 | 320 | ||
| 314 | /** | 321 | /** |
| @@ -23,8 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,8 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | 23 | ||
| 24 | #include <srs_core.hpp> | 24 | #include <srs_core.hpp> |
| 25 | 25 | ||
| 26 | +#include <stdlib.h> | ||
| 26 | #include <string> | 27 | #include <string> |
| 27 | #include <vector> | 28 | #include <vector> |
| 29 | +#include <map> | ||
| 28 | using namespace std; | 30 | using namespace std; |
| 29 | 31 | ||
| 30 | #include <srs_kernel_error.hpp> | 32 | #include <srs_kernel_error.hpp> |
| @@ -148,7 +150,7 @@ private: | @@ -148,7 +150,7 @@ private: | ||
| 148 | dirty = false; | 150 | dirty = false; |
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | - int fetch(std::string m3u8, SrsHttpClient* client); | 153 | + int fetch(std::string m3u8); |
| 152 | }; | 154 | }; |
| 153 | private: | 155 | private: |
| 154 | SrsHttpUri* in_hls; | 156 | SrsHttpUri* in_hls; |
| @@ -196,7 +198,7 @@ private: | @@ -196,7 +198,7 @@ private: | ||
| 196 | /** | 198 | /** |
| 197 | * fetch all ts body. | 199 | * fetch all ts body. |
| 198 | */ | 200 | */ |
| 199 | - virtual void fetch_all_ts(bool fresh_m3u8, SrsHttpClient* client); | 201 | + virtual void fetch_all_ts(bool fresh_m3u8); |
| 200 | /** | 202 | /** |
| 201 | * remove all ts which is dirty. | 203 | * remove all ts which is dirty. |
| 202 | */ | 204 | */ |
| @@ -209,6 +211,7 @@ int SrsIngestSrsInput::connect() | @@ -209,6 +211,7 @@ int SrsIngestSrsInput::connect() | ||
| 209 | 211 | ||
| 210 | int64_t now = srs_update_system_time_ms(); | 212 | int64_t now = srs_update_system_time_ms(); |
| 211 | if (now < next_connect_time) { | 213 | if (now < next_connect_time) { |
| 214 | + srs_trace("input hls wait for %dms", next_connect_time - now); | ||
| 212 | st_usleep((next_connect_time - now) * 1000); | 215 | st_usleep((next_connect_time - now) * 1000); |
| 213 | } | 216 | } |
| 214 | 217 | ||
| @@ -328,7 +331,7 @@ int SrsIngestSrsInput::connect() | @@ -328,7 +331,7 @@ int SrsIngestSrsInput::connect() | ||
| 328 | } | 331 | } |
| 329 | 332 | ||
| 330 | // fetch all ts. | 333 | // fetch all ts. |
| 331 | - fetch_all_ts(fresh_m3u8, &client); | 334 | + fetch_all_ts(fresh_m3u8); |
| 332 | 335 | ||
| 333 | // remove all dirty ts. | 336 | // remove all dirty ts. |
| 334 | remove_dirty(); | 337 | remove_dirty(); |
| @@ -344,12 +347,19 @@ int SrsIngestSrsInput::parse(ISrsTsHandler* handler) | @@ -344,12 +347,19 @@ int SrsIngestSrsInput::parse(ISrsTsHandler* handler) | ||
| 344 | 347 | ||
| 345 | for (int i = 0; i < (int)pieces.size(); i++) { | 348 | for (int i = 0; i < (int)pieces.size(); i++) { |
| 346 | SrsTsPiece* tp = pieces.at(i); | 349 | SrsTsPiece* tp = pieces.at(i); |
| 350 | + | ||
| 351 | + // sent only once. | ||
| 352 | + if (tp->sent) { | ||
| 353 | + continue; | ||
| 354 | + } | ||
| 347 | tp->sent = true; | 355 | tp->sent = true; |
| 348 | 356 | ||
| 349 | if (tp->body.empty()) { | 357 | if (tp->body.empty()) { |
| 350 | continue; | 358 | continue; |
| 351 | } | 359 | } |
| 352 | 360 | ||
| 361 | + srs_trace("proxy the ts to rtmp, ts=%s, duration=%.2f", tp->url.c_str(), tp->duration); | ||
| 362 | + | ||
| 353 | // use stream to parse ts packet. | 363 | // use stream to parse ts packet. |
| 354 | int nb_packet = (int)tp->body.length() / SRS_TS_PACKET_SIZE; | 364 | int nb_packet = (int)tp->body.length() / SRS_TS_PACKET_SIZE; |
| 355 | for (int i = 0; i < nb_packet; i++) { | 365 | for (int i = 0; i < nb_packet; i++) { |
| @@ -360,6 +370,12 @@ int SrsIngestSrsInput::parse(ISrsTsHandler* handler) | @@ -360,6 +370,12 @@ int SrsIngestSrsInput::parse(ISrsTsHandler* handler) | ||
| 360 | 370 | ||
| 361 | // process each ts packet | 371 | // process each ts packet |
| 362 | if ((ret = context->decode(stream, handler)) != ERROR_SUCCESS) { | 372 | if ((ret = context->decode(stream, handler)) != ERROR_SUCCESS) { |
| 373 | + // when peer closed, must interrupt parse and reconnect. | ||
| 374 | + if (srs_is_client_gracefully_close(ret)) { | ||
| 375 | + srs_warn("interrupt parse for peer closed. ret=%d", ret); | ||
| 376 | + return ret; | ||
| 377 | + } | ||
| 378 | + | ||
| 363 | srs_warn("mpegts: ignore parse ts packet failed. ret=%d", ret); | 379 | srs_warn("mpegts: ignore parse ts packet failed. ret=%d", ret); |
| 364 | continue; | 380 | continue; |
| 365 | } | 381 | } |
| @@ -392,7 +408,7 @@ void SrsIngestSrsInput::dirty_all_ts() | @@ -392,7 +408,7 @@ void SrsIngestSrsInput::dirty_all_ts() | ||
| 392 | } | 408 | } |
| 393 | } | 409 | } |
| 394 | 410 | ||
| 395 | -void SrsIngestSrsInput::fetch_all_ts(bool fresh_m3u8, SrsHttpClient* client) | 411 | +void SrsIngestSrsInput::fetch_all_ts(bool fresh_m3u8) |
| 396 | { | 412 | { |
| 397 | int ret = ERROR_SUCCESS; | 413 | int ret = ERROR_SUCCESS; |
| 398 | 414 | ||
| @@ -410,17 +426,16 @@ void SrsIngestSrsInput::fetch_all_ts(bool fresh_m3u8, SrsHttpClient* client) | @@ -410,17 +426,16 @@ void SrsIngestSrsInput::fetch_all_ts(bool fresh_m3u8, SrsHttpClient* client) | ||
| 410 | continue; | 426 | continue; |
| 411 | } | 427 | } |
| 412 | 428 | ||
| 413 | - if ((ret = tp->fetch(in_hls->get_url(), client)) != ERROR_SUCCESS) { | 429 | + if ((ret = tp->fetch(in_hls->get_url())) != ERROR_SUCCESS) { |
| 414 | srs_warn("ignore ts %s for error. ret=%d", tp->url.c_str(), ret); | 430 | srs_warn("ignore ts %s for error. ret=%d", tp->url.c_str(), ret); |
| 415 | tp->skip = true; | 431 | tp->skip = true; |
| 416 | continue; | 432 | continue; |
| 417 | } | 433 | } |
| 418 | 434 | ||
| 419 | - // set the next connect time. | ||
| 420 | - if (next_connect_time <= 0) { | ||
| 421 | - next_connect_time = srs_update_system_time_ms(); | 435 | + // only wait for a duration of last piece. |
| 436 | + if (i == pieces.size() - 1) { | ||
| 437 | + next_connect_time = srs_update_system_time_ms() + (int)tp->duration * 1000; | ||
| 422 | } | 438 | } |
| 423 | - next_connect_time += (int)tp->duration * 1000; | ||
| 424 | } | 439 | } |
| 425 | } | 440 | } |
| 426 | 441 | ||
| @@ -432,6 +447,7 @@ void SrsIngestSrsInput::remove_dirty() | @@ -432,6 +447,7 @@ void SrsIngestSrsInput::remove_dirty() | ||
| 432 | SrsTsPiece* tp = *it; | 447 | SrsTsPiece* tp = *it; |
| 433 | 448 | ||
| 434 | if (tp->dirty) { | 449 | if (tp->dirty) { |
| 450 | + srs_trace("erase dirty ts, url=%s, duration=%.2f", tp->url.c_str(), tp->duration); | ||
| 435 | srs_freep(tp); | 451 | srs_freep(tp); |
| 436 | it = pieces.erase(it); | 452 | it = pieces.erase(it); |
| 437 | } else { | 453 | } else { |
| @@ -440,7 +456,7 @@ void SrsIngestSrsInput::remove_dirty() | @@ -440,7 +456,7 @@ void SrsIngestSrsInput::remove_dirty() | ||
| 440 | } | 456 | } |
| 441 | } | 457 | } |
| 442 | 458 | ||
| 443 | -int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | 459 | +int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8) |
| 444 | { | 460 | { |
| 445 | int ret = ERROR_SUCCESS; | 461 | int ret = ERROR_SUCCESS; |
| 446 | 462 | ||
| @@ -450,8 +466,7 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | @@ -450,8 +466,7 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | ||
| 450 | 466 | ||
| 451 | size_t pos = string::npos; | 467 | size_t pos = string::npos; |
| 452 | 468 | ||
| 453 | - bool use_abs_client = false; | ||
| 454 | - SrsHttpClient abs_client; | 469 | + SrsHttpClient client; |
| 455 | 470 | ||
| 456 | std::string ts_url = url; | 471 | std::string ts_url = url; |
| 457 | if (!srs_string_starts_with(ts_url, "http://")) { | 472 | if (!srs_string_starts_with(ts_url, "http://")) { |
| @@ -460,10 +475,6 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | @@ -460,10 +475,6 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | ||
| 460 | baseurl = m3u8.substr(0, pos); | 475 | baseurl = m3u8.substr(0, pos); |
| 461 | } | 476 | } |
| 462 | ts_url = baseurl + "/" + url; | 477 | ts_url = baseurl + "/" + url; |
| 463 | - | ||
| 464 | - // use fresh client for absolute url. | ||
| 465 | - client = &abs_client; | ||
| 466 | - use_abs_client = true; | ||
| 467 | } | 478 | } |
| 468 | 479 | ||
| 469 | SrsHttpUri uri; | 480 | SrsHttpUri uri; |
| @@ -472,12 +483,12 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | @@ -472,12 +483,12 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8, SrsHttpClient* client) | ||
| 472 | } | 483 | } |
| 473 | 484 | ||
| 474 | // initialize the fresh http client. | 485 | // initialize the fresh http client. |
| 475 | - if (use_abs_client && (ret = client->initialize(uri.get_host(), uri.get_port()) != ERROR_SUCCESS)) { | 486 | + if ((ret = client.initialize(uri.get_host(), uri.get_port()) != ERROR_SUCCESS)) { |
| 476 | return ret; | 487 | return ret; |
| 477 | } | 488 | } |
| 478 | 489 | ||
| 479 | SrsHttpMessage* msg = NULL; | 490 | SrsHttpMessage* msg = NULL; |
| 480 | - if ((ret = client->get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) { | 491 | + if ((ret = client.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) { |
| 481 | srs_error("HTTP GET %s failed. ret=%d", uri.get_url(), ret); | 492 | srs_error("HTTP GET %s failed. ret=%d", uri.get_url(), ret); |
| 482 | return ret; | 493 | return ret; |
| 483 | } | 494 | } |
| @@ -501,6 +512,9 @@ class SrsIngestSrsOutput : public ISrsTsHandler | @@ -501,6 +512,9 @@ class SrsIngestSrsOutput : public ISrsTsHandler | ||
| 501 | private: | 512 | private: |
| 502 | SrsHttpUri* out_rtmp; | 513 | SrsHttpUri* out_rtmp; |
| 503 | private: | 514 | private: |
| 515 | + bool disconnected; | ||
| 516 | + std::multimap<int64_t, SrsTsMessage*> queue; | ||
| 517 | +private: | ||
| 504 | SrsRequest* req; | 518 | SrsRequest* req; |
| 505 | st_netfd_t stfd; | 519 | st_netfd_t stfd; |
| 506 | SrsStSocket* io; | 520 | SrsStSocket* io; |
| @@ -519,6 +533,7 @@ private: | @@ -519,6 +533,7 @@ private: | ||
| 519 | public: | 533 | public: |
| 520 | SrsIngestSrsOutput(SrsHttpUri* rtmp) { | 534 | SrsIngestSrsOutput(SrsHttpUri* rtmp) { |
| 521 | out_rtmp = rtmp; | 535 | out_rtmp = rtmp; |
| 536 | + disconnected = false; | ||
| 522 | 537 | ||
| 523 | req = NULL; | 538 | req = NULL; |
| 524 | io = NULL; | 539 | io = NULL; |
| @@ -537,14 +552,22 @@ public: | @@ -537,14 +552,22 @@ public: | ||
| 537 | 552 | ||
| 538 | srs_freep(avc); | 553 | srs_freep(avc); |
| 539 | srs_freep(aac); | 554 | srs_freep(aac); |
| 555 | + | ||
| 556 | + std::multimap<int64_t, SrsTsMessage*>::iterator it; | ||
| 557 | + for (it = queue.begin(); it != queue.end(); ++it) { | ||
| 558 | + SrsTsMessage* msg = it->second; | ||
| 559 | + srs_freep(msg); | ||
| 560 | + } | ||
| 561 | + queue.clear(); | ||
| 540 | } | 562 | } |
| 541 | // interface ISrsTsHandler | 563 | // interface ISrsTsHandler |
| 542 | public: | 564 | public: |
| 543 | virtual int on_ts_message(SrsTsMessage* msg); | 565 | virtual int on_ts_message(SrsTsMessage* msg); |
| 544 | private: | 566 | private: |
| 567 | + virtual int parse_message_queue(); | ||
| 545 | virtual int on_ts_video(SrsTsMessage* msg, SrsStream* avs); | 568 | virtual int on_ts_video(SrsTsMessage* msg, SrsStream* avs); |
| 546 | virtual int write_h264_sps_pps(u_int32_t dts, u_int32_t pts); | 569 | virtual int write_h264_sps_pps(u_int32_t dts, u_int32_t pts); |
| 547 | - virtual int write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts); | 570 | + virtual int write_h264_ipb_frame(std::string ibps, SrsCodecVideoAVCFrame frame_type, u_int32_t dts, u_int32_t pts); |
| 548 | virtual int on_ts_audio(SrsTsMessage* msg, SrsStream* avs); | 571 | virtual int on_ts_audio(SrsTsMessage* msg, SrsStream* avs); |
| 549 | virtual int write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, u_int32_t dts); | 572 | virtual int write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, u_int32_t dts); |
| 550 | private: | 573 | private: |
| @@ -554,6 +577,10 @@ public: | @@ -554,6 +577,10 @@ public: | ||
| 554 | * connect to output rtmp server. | 577 | * connect to output rtmp server. |
| 555 | */ | 578 | */ |
| 556 | virtual int connect(); | 579 | virtual int connect(); |
| 580 | + /** | ||
| 581 | + * flush the message queue when all ts parsed. | ||
| 582 | + */ | ||
| 583 | + virtual int flush_message_queue(); | ||
| 557 | private: | 584 | private: |
| 558 | virtual int connect_app(std::string ep_server, std::string ep_port); | 585 | virtual int connect_app(std::string ep_server, std::string ep_port); |
| 559 | // close the connected io and rtmp to ready to be re-connect. | 586 | // close the connected io and rtmp to ready to be re-connect. |
| @@ -601,7 +628,7 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | @@ -601,7 +628,7 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | ||
| 601 | // 14496-2 video stream number xxxx | 628 | // 14496-2 video stream number xxxx |
| 602 | // ((stream_id >> 4) & 0x0f) == SrsTsPESStreamIdVideo | 629 | // ((stream_id >> 4) & 0x0f) == SrsTsPESStreamIdVideo |
| 603 | 630 | ||
| 604 | - srs_trace("<- "SRS_CONSTS_LOG_STREAM_CASTER" mpegts: got %s stream=%s, dts=%"PRId64", pts=%"PRId64", size=%d, us=%d, cc=%d, sid=%#x(%s-%d)", | 631 | + srs_info("<- "SRS_CONSTS_LOG_STREAM_CASTER" mpegts: got %s stream=%s, dts=%"PRId64", pts=%"PRId64", size=%d, us=%d, cc=%d, sid=%#x(%s-%d)", |
| 605 | (msg->channel->apply == SrsTsPidApplyVideo)? "Video":"Audio", srs_ts_stream2string(msg->channel->stream).c_str(), | 632 | (msg->channel->apply == SrsTsPidApplyVideo)? "Video":"Audio", srs_ts_stream2string(msg->channel->stream).c_str(), |
| 606 | msg->dts, msg->pts, msg->payload->length(), msg->packet->payload_unit_start_indicator, msg->continuity_counter, msg->sid, | 633 | msg->dts, msg->pts, msg->payload->length(), msg->packet->payload_unit_start_indicator, msg->continuity_counter, msg->sid, |
| 607 | msg->is_audio()? "A":msg->is_video()? "V":"N", msg->stream_number()); | 634 | msg->is_audio()? "A":msg->is_video()? "V":"N", msg->stream_number()); |
| @@ -621,41 +648,120 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | @@ -621,41 +648,120 @@ int SrsIngestSrsOutput::on_ts_message(SrsTsMessage* msg) | ||
| 621 | return ret; | 648 | return ret; |
| 622 | } | 649 | } |
| 623 | 650 | ||
| 624 | - // parse the stream. | ||
| 625 | - SrsStream avs; | ||
| 626 | - if ((ret = avs.initialize(msg->payload->bytes(), msg->payload->length())) != ERROR_SUCCESS) { | ||
| 627 | - srs_error("mpegts: initialize av stream failed. ret=%d", ret); | 651 | + // we must use queue to cache the msg, then parse it if possible. |
| 652 | + queue.insert(std::make_pair(msg->dts, msg->detach())); | ||
| 653 | + if ((ret = parse_message_queue()) != ERROR_SUCCESS) { | ||
| 654 | + // when peer closed, close the output and reconnect. | ||
| 655 | + if (srs_is_client_gracefully_close(ret)) { | ||
| 656 | + close(); | ||
| 657 | + } | ||
| 628 | return ret; | 658 | return ret; |
| 629 | } | 659 | } |
| 630 | 660 | ||
| 631 | - // publish audio or video. | ||
| 632 | - if (msg->channel->stream == SrsTsStreamVideoH264) { | ||
| 633 | - return on_ts_video(msg, &avs); | 661 | + return ret; |
| 662 | +} | ||
| 663 | + | ||
| 664 | +int SrsIngestSrsOutput::parse_message_queue() | ||
| 665 | +{ | ||
| 666 | + int ret = ERROR_SUCCESS; | ||
| 667 | + | ||
| 668 | + int nb_videos = 0; | ||
| 669 | + int nb_audios = 0; | ||
| 670 | + std::multimap<int64_t, SrsTsMessage*>::iterator it; | ||
| 671 | + for (it = queue.begin(); it != queue.end(); ++it) { | ||
| 672 | + SrsTsMessage* msg = it->second; | ||
| 673 | + | ||
| 674 | + // publish audio or video. | ||
| 675 | + if (msg->channel->stream == SrsTsStreamVideoH264) { | ||
| 676 | + nb_videos++; | ||
| 677 | + } else { | ||
| 678 | + nb_audios++; | ||
| 679 | + } | ||
| 680 | + } | ||
| 681 | + | ||
| 682 | + // always wait 2+ videos, to left one video in the queue. | ||
| 683 | + // TODO: FIXME: support pure audio hls. | ||
| 684 | + if (nb_videos <= 1) { | ||
| 685 | + return ret; | ||
| 634 | } | 686 | } |
| 635 | - if (msg->channel->stream == SrsTsStreamAudioAAC) { | ||
| 636 | - return on_ts_audio(msg, &avs); | 687 | + |
| 688 | + // parse messages util the last video. | ||
| 689 | + while (nb_videos > 1 && queue.size() > 0) { | ||
| 690 | + std::multimap<int64_t, SrsTsMessage*>::iterator it = queue.begin(); | ||
| 691 | + | ||
| 692 | + SrsTsMessage* msg = it->second; | ||
| 693 | + if (msg->channel->stream == SrsTsStreamVideoH264) { | ||
| 694 | + nb_videos--; | ||
| 695 | + } | ||
| 696 | + queue.erase(it); | ||
| 697 | + | ||
| 698 | + // parse the stream. | ||
| 699 | + SrsStream avs; | ||
| 700 | + if ((ret = avs.initialize(msg->payload->bytes(), msg->payload->length())) != ERROR_SUCCESS) { | ||
| 701 | + srs_error("mpegts: initialize av stream failed. ret=%d", ret); | ||
| 702 | + return ret; | ||
| 703 | + } | ||
| 704 | + | ||
| 705 | + // publish audio or video. | ||
| 706 | + if (msg->channel->stream == SrsTsStreamVideoH264) { | ||
| 707 | + if ((ret = on_ts_video(msg, &avs)) != ERROR_SUCCESS) { | ||
| 708 | + return ret; | ||
| 709 | + } | ||
| 710 | + } | ||
| 711 | + if (msg->channel->stream == SrsTsStreamAudioAAC) { | ||
| 712 | + if ((ret = on_ts_audio(msg, &avs)) != ERROR_SUCCESS) { | ||
| 713 | + return ret; | ||
| 714 | + } | ||
| 715 | + } | ||
| 637 | } | 716 | } |
| 638 | 717 | ||
| 639 | - // TODO: FIXME: implements it. | ||
| 640 | return ret; | 718 | return ret; |
| 641 | } | 719 | } |
| 642 | 720 | ||
| 643 | -int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | 721 | +int SrsIngestSrsOutput::flush_message_queue() |
| 644 | { | 722 | { |
| 645 | int ret = ERROR_SUCCESS; | 723 | int ret = ERROR_SUCCESS; |
| 646 | 724 | ||
| 647 | - // ensure rtmp connected. | ||
| 648 | - if ((ret = connect()) != ERROR_SUCCESS) { | ||
| 649 | - return ret; | 725 | + // parse messages util the last video. |
| 726 | + while (!queue.empty()) { | ||
| 727 | + std::multimap<int64_t, SrsTsMessage*>::iterator it = queue.begin(); | ||
| 728 | + | ||
| 729 | + SrsTsMessage* msg = it->second; | ||
| 730 | + queue.erase(it); | ||
| 731 | + | ||
| 732 | + // parse the stream. | ||
| 733 | + SrsStream avs; | ||
| 734 | + if ((ret = avs.initialize(msg->payload->bytes(), msg->payload->length())) != ERROR_SUCCESS) { | ||
| 735 | + srs_error("mpegts: initialize av stream failed. ret=%d", ret); | ||
| 736 | + return ret; | ||
| 737 | + } | ||
| 738 | + | ||
| 739 | + // publish audio or video. | ||
| 740 | + if (msg->channel->stream == SrsTsStreamVideoH264) { | ||
| 741 | + if ((ret = on_ts_video(msg, &avs)) != ERROR_SUCCESS) { | ||
| 742 | + return ret; | ||
| 743 | + } | ||
| 744 | + } | ||
| 745 | + if (msg->channel->stream == SrsTsStreamAudioAAC) { | ||
| 746 | + if ((ret = on_ts_audio(msg, &avs)) != ERROR_SUCCESS) { | ||
| 747 | + return ret; | ||
| 748 | + } | ||
| 749 | + } | ||
| 650 | } | 750 | } |
| 651 | 751 | ||
| 752 | + return ret; | ||
| 753 | +} | ||
| 754 | + | ||
| 755 | +int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
| 756 | +{ | ||
| 757 | + int ret = ERROR_SUCCESS; | ||
| 758 | + | ||
| 652 | // ts tbn to flv tbn. | 759 | // ts tbn to flv tbn. |
| 653 | u_int32_t dts = (u_int32_t)(msg->dts / 90); | 760 | u_int32_t dts = (u_int32_t)(msg->dts / 90); |
| 654 | u_int32_t pts = (u_int32_t)(msg->dts / 90); | 761 | u_int32_t pts = (u_int32_t)(msg->dts / 90); |
| 655 | 762 | ||
| 656 | - // the whole ts pes video packet must be a flv frame packet. | ||
| 657 | - char* ibpframe = avs->data() + avs->pos(); | ||
| 658 | - int ibpframe_size = avs->size() - avs->pos(); | 763 | + std::string ibps; |
| 764 | + SrsCodecVideoAVCFrame frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
| 659 | 765 | ||
| 660 | // send each frame. | 766 | // send each frame. |
| 661 | while (!avs->empty()) { | 767 | while (!avs->empty()) { |
| @@ -665,10 +771,18 @@ int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | @@ -665,10 +771,18 @@ int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
| 665 | return ret; | 771 | return ret; |
| 666 | } | 772 | } |
| 667 | 773 | ||
| 668 | - // ignore invalid frame, | ||
| 669 | - // * atleast 1bytes for SPS to decode the type | ||
| 670 | - // * ignore the auth bytes '09f0' | ||
| 671 | - if (frame_size <= 2) { | 774 | + // 5bits, 7.3.1 NAL unit syntax, |
| 775 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 776 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 777 | + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); | ||
| 778 | + | ||
| 779 | + // for IDR frame, the frame is keyframe. | ||
| 780 | + if (nal_unit_type == SrsAvcNaluTypeIDR) { | ||
| 781 | + frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 782 | + } | ||
| 783 | + | ||
| 784 | + // ignore the nalu type aud(9) | ||
| 785 | + if (nal_unit_type == SrsAvcNaluTypeAccessUnitDelimiter) { | ||
| 672 | continue; | 786 | continue; |
| 673 | } | 787 | } |
| 674 | 788 | ||
| @@ -684,10 +798,6 @@ int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | @@ -684,10 +798,6 @@ int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
| 684 | } | 798 | } |
| 685 | h264_sps_changed = true; | 799 | h264_sps_changed = true; |
| 686 | h264_sps = sps; | 800 | h264_sps = sps; |
| 687 | - | ||
| 688 | - if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) { | ||
| 689 | - return ret; | ||
| 690 | - } | ||
| 691 | continue; | 801 | continue; |
| 692 | } | 802 | } |
| 693 | 803 | ||
| @@ -703,27 +813,45 @@ int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | @@ -703,27 +813,45 @@ int SrsIngestSrsOutput::on_ts_video(SrsTsMessage* msg, SrsStream* avs) | ||
| 703 | } | 813 | } |
| 704 | h264_pps_changed = true; | 814 | h264_pps_changed = true; |
| 705 | h264_pps = pps; | 815 | h264_pps = pps; |
| 706 | - | ||
| 707 | - if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) { | ||
| 708 | - return ret; | ||
| 709 | - } | ||
| 710 | continue; | 816 | continue; |
| 711 | } | 817 | } |
| 712 | 818 | ||
| 713 | - break; | 819 | + // ibp frame. |
| 820 | + std::string ibp; | ||
| 821 | + if ((ret = avc->mux_ipb_frame(frame, frame_size, ibp)) != ERROR_SUCCESS) { | ||
| 822 | + return ret; | ||
| 823 | + } | ||
| 824 | + ibps.append(ibp); | ||
| 825 | + } | ||
| 826 | + | ||
| 827 | + if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) { | ||
| 828 | + return ret; | ||
| 714 | } | 829 | } |
| 715 | 830 | ||
| 716 | - // ibp frame. | ||
| 717 | - srs_info("mpegts: demux avc ibp frame size=%d, dts=%d", ibpframe_size, dts); | ||
| 718 | - return write_h264_ipb_frame(ibpframe, ibpframe_size, dts, pts); | 831 | + if ((ret = write_h264_ipb_frame(ibps, frame_type, dts, pts)) != ERROR_SUCCESS) { |
| 832 | + // drop the ts message. | ||
| 833 | + if (ret == ERROR_H264_DROP_BEFORE_SPS_PPS) { | ||
| 834 | + return ERROR_SUCCESS; | ||
| 835 | + } | ||
| 836 | + return ret; | ||
| 837 | + } | ||
| 838 | + | ||
| 839 | + return ret; | ||
| 719 | } | 840 | } |
| 720 | 841 | ||
| 721 | int SrsIngestSrsOutput::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | 842 | int SrsIngestSrsOutput::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) |
| 722 | { | 843 | { |
| 723 | int ret = ERROR_SUCCESS; | 844 | int ret = ERROR_SUCCESS; |
| 724 | 845 | ||
| 725 | - // only send when both sps and pps changed. | ||
| 726 | - if (!h264_sps_changed || !h264_pps_changed) { | 846 | + // when sps or pps changed, update the sequence header, |
| 847 | + // for the pps maybe not changed while sps changed. | ||
| 848 | + // so, we must check when each video ts message frame parsed. | ||
| 849 | + if (h264_sps_pps_sent && !h264_sps_changed && !h264_pps_changed) { | ||
| 850 | + return ret; | ||
| 851 | + } | ||
| 852 | + | ||
| 853 | + // when not got sps/pps, wait. | ||
| 854 | + if (h264_pps.empty() || h264_sps.empty()) { | ||
| 727 | return ret; | 855 | return ret; |
| 728 | } | 856 | } |
| 729 | 857 | ||
| @@ -752,11 +880,12 @@ int SrsIngestSrsOutput::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | @@ -752,11 +880,12 @@ int SrsIngestSrsOutput::write_h264_sps_pps(u_int32_t dts, u_int32_t pts) | ||
| 752 | h264_sps_changed = false; | 880 | h264_sps_changed = false; |
| 753 | h264_pps_changed = false; | 881 | h264_pps_changed = false; |
| 754 | h264_sps_pps_sent = true; | 882 | h264_sps_pps_sent = true; |
| 883 | + srs_trace("hls: h264 sps/pps sent, sps=%dB, pps=%dB", h264_sps.length(), h264_pps.length()); | ||
| 755 | 884 | ||
| 756 | return ret; | 885 | return ret; |
| 757 | } | 886 | } |
| 758 | 887 | ||
| 759 | -int SrsIngestSrsOutput::write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts) | 888 | +int SrsIngestSrsOutput::write_h264_ipb_frame(string ibps, SrsCodecVideoAVCFrame frame_type, u_int32_t dts, u_int32_t pts) |
| 760 | { | 889 | { |
| 761 | int ret = ERROR_SUCCESS; | 890 | int ret = ERROR_SUCCESS; |
| 762 | 891 | ||
| @@ -766,26 +895,10 @@ int SrsIngestSrsOutput::write_h264_ipb_frame(char* frame, int frame_size, u_int3 | @@ -766,26 +895,10 @@ int SrsIngestSrsOutput::write_h264_ipb_frame(char* frame, int frame_size, u_int3 | ||
| 766 | return ERROR_H264_DROP_BEFORE_SPS_PPS; | 895 | return ERROR_H264_DROP_BEFORE_SPS_PPS; |
| 767 | } | 896 | } |
| 768 | 897 | ||
| 769 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 770 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 771 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 772 | - SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); | ||
| 773 | - | ||
| 774 | - // for IDR frame, the frame is keyframe. | ||
| 775 | - SrsCodecVideoAVCFrame frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
| 776 | - if (nal_unit_type == SrsAvcNaluTypeIDR) { | ||
| 777 | - frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 778 | - } | ||
| 779 | - | ||
| 780 | - std::string ibp; | ||
| 781 | - if ((ret = avc->mux_ipb_frame(frame, frame_size, ibp)) != ERROR_SUCCESS) { | ||
| 782 | - return ret; | ||
| 783 | - } | ||
| 784 | - | ||
| 785 | int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | 898 | int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; |
| 786 | char* flv = NULL; | 899 | char* flv = NULL; |
| 787 | int nb_flv = 0; | 900 | int nb_flv = 0; |
| 788 | - if ((ret = avc->mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != ERROR_SUCCESS) { | 901 | + if ((ret = avc->mux_avc2flv(ibps, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != ERROR_SUCCESS) { |
| 789 | return ret; | 902 | return ret; |
| 790 | } | 903 | } |
| 791 | 904 | ||
| @@ -798,14 +911,17 @@ int SrsIngestSrsOutput::on_ts_audio(SrsTsMessage* msg, SrsStream* avs) | @@ -798,14 +911,17 @@ int SrsIngestSrsOutput::on_ts_audio(SrsTsMessage* msg, SrsStream* avs) | ||
| 798 | { | 911 | { |
| 799 | int ret = ERROR_SUCCESS; | 912 | int ret = ERROR_SUCCESS; |
| 800 | 913 | ||
| 801 | - // ensure rtmp connected. | ||
| 802 | - if ((ret = connect()) != ERROR_SUCCESS) { | ||
| 803 | - return ret; | ||
| 804 | - } | ||
| 805 | - | ||
| 806 | // ts tbn to flv tbn. | 914 | // ts tbn to flv tbn. |
| 807 | u_int32_t dts = (u_int32_t)(msg->dts / 90); | 915 | u_int32_t dts = (u_int32_t)(msg->dts / 90); |
| 808 | 916 | ||
| 917 | + // got the next video to calc the delta duration for each audio. | ||
| 918 | + u_int32_t duration = 0; | ||
| 919 | + if (!queue.empty()) { | ||
| 920 | + SrsTsMessage* nm = queue.begin()->second; | ||
| 921 | + duration = (u_int32_t)(srs_max(0, nm->dts - msg->dts) / 90); | ||
| 922 | + } | ||
| 923 | + u_int32_t max_dts = dts + duration; | ||
| 924 | + | ||
| 809 | // send each frame. | 925 | // send each frame. |
| 810 | while (!avs->empty()) { | 926 | while (!avs->empty()) { |
| 811 | char* frame = NULL; | 927 | char* frame = NULL; |
| @@ -842,6 +958,10 @@ int SrsIngestSrsOutput::on_ts_audio(SrsTsMessage* msg, SrsStream* avs) | @@ -842,6 +958,10 @@ int SrsIngestSrsOutput::on_ts_audio(SrsTsMessage* msg, SrsStream* avs) | ||
| 842 | if ((ret = write_audio_raw_frame(frame, frame_size, &codec, dts)) != ERROR_SUCCESS) { | 958 | if ((ret = write_audio_raw_frame(frame, frame_size, &codec, dts)) != ERROR_SUCCESS) { |
| 843 | return ret; | 959 | return ret; |
| 844 | } | 960 | } |
| 961 | + | ||
| 962 | + // calc the delta of dts, when previous frame output. | ||
| 963 | + u_int32_t delta = duration / (msg->payload->length() / frame_size); | ||
| 964 | + dts = (u_int32_t)(srs_min(max_dts, dts + delta)); | ||
| 845 | } | 965 | } |
| 846 | 966 | ||
| 847 | return ret; | 967 | return ret; |
| @@ -890,6 +1010,8 @@ int SrsIngestSrsOutput::connect() | @@ -890,6 +1010,8 @@ int SrsIngestSrsOutput::connect() | ||
| 890 | return ret; | 1010 | return ret; |
| 891 | } | 1011 | } |
| 892 | 1012 | ||
| 1013 | + srs_trace("connect output=%s", out_rtmp->get_url()); | ||
| 1014 | + | ||
| 893 | // parse uri | 1015 | // parse uri |
| 894 | if (!req) { | 1016 | if (!req) { |
| 895 | req = new SrsRequest(); | 1017 | req = new SrsRequest(); |
| @@ -996,6 +1118,9 @@ int SrsIngestSrsOutput::connect_app(string ep_server, string ep_port) | @@ -996,6 +1118,9 @@ int SrsIngestSrsOutput::connect_app(string ep_server, string ep_port) | ||
| 996 | 1118 | ||
| 997 | void SrsIngestSrsOutput::close() | 1119 | void SrsIngestSrsOutput::close() |
| 998 | { | 1120 | { |
| 1121 | + srs_trace("close output=%s", out_rtmp->get_url()); | ||
| 1122 | + h264_sps_pps_sent = false; | ||
| 1123 | + | ||
| 999 | srs_freep(client); | 1124 | srs_freep(client); |
| 1000 | srs_freep(io); | 1125 | srs_freep(io); |
| 1001 | srs_freep(req); | 1126 | srs_freep(req); |
| @@ -1035,6 +1160,11 @@ public: | @@ -1035,6 +1160,11 @@ public: | ||
| 1035 | return ret; | 1160 | return ret; |
| 1036 | } | 1161 | } |
| 1037 | 1162 | ||
| 1163 | + if ((ret = oc->flush_message_queue()) != ERROR_SUCCESS) { | ||
| 1164 | + srs_warn("flush oc message failed. ret=%d", ret); | ||
| 1165 | + return ret; | ||
| 1166 | + } | ||
| 1167 | + | ||
| 1038 | return ret; | 1168 | return ret; |
| 1039 | } | 1169 | } |
| 1040 | }; | 1170 | }; |
-
请 注册 或 登录 后发表评论