正在显示
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 | }; |
-
请 注册 或 登录 后发表评论