winlin

refine the hls muxer module

@@ -42,6 +42,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -42,6 +42,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 #include <srs_core_autofree.hpp> 42 #include <srs_core_autofree.hpp>
43 #include <srs_core_rtmp.hpp> 43 #include <srs_core_rtmp.hpp>
44 44
  45 +// max PES packets size to flush the video.
  46 +#define SRS_HLS_AUDIO_CACHE_SIZE 512 * 1024
  47 +
45 // @see: NGX_RTMP_HLS_DELAY, 48 // @see: NGX_RTMP_HLS_DELAY,
46 // 63000: 700ms, ts_tbn=90000 49 // 63000: 700ms, ts_tbn=90000
47 #define SRS_HLS_DELAY 63000 50 #define SRS_HLS_DELAY 63000
@@ -399,40 +402,9 @@ void SrsHlsAacJitter::on_buffer_continue() @@ -399,40 +402,9 @@ void SrsHlsAacJitter::on_buffer_continue()
399 nb_samples++; 402 nb_samples++;
400 } 403 }
401 404
402 -SrsM3u8Segment::SrsM3u8Segment()  
403 -{  
404 - duration = 0;  
405 - sequence_no = 0;  
406 - muxer = new SrsTSMuxer();  
407 - segment_start_dts = 0;  
408 -}  
409 -  
410 -SrsM3u8Segment::~SrsM3u8Segment()  
411 -{  
412 - srs_freep(muxer);  
413 -}  
414 -  
415 -double SrsM3u8Segment::update_duration(int64_t video_stream_dts)  
416 -{  
417 - duration = (video_stream_dts - segment_start_dts) / 90000.0;  
418 - srs_assert(duration > 0);  
419 -  
420 - return duration;  
421 -}  
422 -  
423 -SrsHlsAacJitter::SrsHlsAacJitter()  
424 -{  
425 - base_pts = 0;  
426 - nb_samples = 0;  
427 -  
428 - // TODO: config it, 0 means no adjust  
429 - sync_ms = SRS_CONF_DEFAULT_AAC_SYNC;  
430 -}  
431 -  
432 SrsTSMuxer::SrsTSMuxer() 405 SrsTSMuxer::SrsTSMuxer()
433 { 406 {
434 fd = -1; 407 fd = -1;
435 - _fresh = false;  
436 } 408 }
437 409
438 SrsTSMuxer::~SrsTSMuxer() 410 SrsTSMuxer::~SrsTSMuxer()
@@ -461,29 +433,25 @@ int SrsTSMuxer::open(std::string _path) @@ -461,29 +433,25 @@ int SrsTSMuxer::open(std::string _path)
461 return ret; 433 return ret;
462 } 434 }
463 435
464 - _fresh = true;  
465 -  
466 return ret; 436 return ret;
467 } 437 }
468 438
469 -int SrsTSMuxer::write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer) 439 +int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
470 { 440 {
471 int ret = ERROR_SUCCESS; 441 int ret = ERROR_SUCCESS;
472 442
473 - if ((ret = SrsMpegtsWriter::write_frame(fd, audio_frame, audio_buffer)) != ERROR_SUCCESS) { 443 + if ((ret = SrsMpegtsWriter::write_frame(fd, af, ab)) != ERROR_SUCCESS) {
474 return ret; 444 return ret;
475 } 445 }
476 446
477 - _fresh = false;  
478 -  
479 return ret; 447 return ret;
480 } 448 }
481 449
482 -int SrsTSMuxer::write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer) 450 +int SrsTSMuxer::write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb)
483 { 451 {
484 int ret = ERROR_SUCCESS; 452 int ret = ERROR_SUCCESS;
485 453
486 - if ((ret = SrsMpegtsWriter::write_frame(fd, video_frame, video_buffer)) != ERROR_SUCCESS) { 454 + if ((ret = SrsMpegtsWriter::write_frame(fd, vf, vb)) != ERROR_SUCCESS) {
487 return ret; 455 return ret;
488 } 456 }
489 457
@@ -495,44 +463,49 @@ void SrsTSMuxer::close() @@ -495,44 +463,49 @@ void SrsTSMuxer::close()
495 if (fd > 0) { 463 if (fd > 0) {
496 ::close(fd); 464 ::close(fd);
497 fd = -1; 465 fd = -1;
498 - _fresh = false;  
499 } 466 }
500 } 467 }
501 468
502 -bool SrsTSMuxer::fresh() 469 +SrsM3u8Segment::SrsM3u8Segment()
503 { 470 {
504 - return _fresh; 471 + duration = 0;
  472 + sequence_no = 0;
  473 + muxer = new SrsTSMuxer();
  474 + segment_start_dts = 0;
505 } 475 }
506 476
507 -SrsHls::SrsHls() 477 +SrsM3u8Segment::~SrsM3u8Segment()
508 { 478 {
509 - hls_enabled = false;  
510 - codec = new SrsCodec();  
511 - sample = new SrsCodecSample();  
512 - current = NULL;  
513 - jitter = new SrsRtmpJitter();  
514 - aac_jitter = new SrsHlsAacJitter();  
515 - file_index = 0;  
516 - audio_buffer_start_pts = video_stream_dts = 0;  
517 - hls_fragment = hls_window = 0; 479 + srs_freep(muxer);
  480 +}
518 481
519 - // TODO: config it.  
520 - audio_delay = SRS_CONF_DEFAULT_AAC_DELAY; 482 +double SrsM3u8Segment::update_duration(int64_t video_stream_dts)
  483 +{
  484 + duration = (video_stream_dts - segment_start_dts) / 90000.0;
  485 + srs_assert(duration >= 0);
  486 +
  487 + return duration;
  488 +}
521 489
522 - audio_buffer = new SrsCodecBuffer();  
523 - video_buffer = new SrsCodecBuffer(); 490 +SrsHlsAacJitter::SrsHlsAacJitter()
  491 +{
  492 + base_pts = 0;
  493 + nb_samples = 0;
524 494
525 - audio_frame = new SrsMpegtsFrame();  
526 - video_frame = new SrsMpegtsFrame(); 495 + // TODO: config it, 0 means no adjust
  496 + sync_ms = SRS_CONF_DEFAULT_AAC_SYNC;
527 } 497 }
528 498
529 -SrsHls::~SrsHls() 499 +SrsM3u8Muxer::SrsM3u8Muxer()
530 { 500 {
531 - srs_freep(codec);  
532 - srs_freep(sample);  
533 - srs_freep(jitter);  
534 - srs_freep(aac_jitter); 501 + hls_fragment = hls_window = 0;
  502 + video_stream_dts = 0;
  503 + file_index = 0;
  504 + current = NULL;
  505 +}
535 506
  507 +SrsM3u8Muxer::~SrsM3u8Muxer()
  508 +{
536 std::vector<SrsM3u8Segment*>::iterator it; 509 std::vector<SrsM3u8Segment*>::iterator it;
537 for (it = segments.begin(); it != segments.end(); ++it) { 510 for (it = segments.begin(); it != segments.end(); ++it) {
538 SrsM3u8Segment* segment = *it; 511 SrsM3u8Segment* segment = *it;
@@ -541,274 +514,154 @@ SrsHls::~SrsHls() @@ -541,274 +514,154 @@ SrsHls::~SrsHls()
541 segments.clear(); 514 segments.clear();
542 515
543 srs_freep(current); 516 srs_freep(current);
544 -  
545 - audio_buffer->free();  
546 - video_buffer->free();  
547 -  
548 - srs_freep(audio_buffer);  
549 - srs_freep(video_buffer);  
550 -  
551 - srs_freep(audio_frame);  
552 - srs_freep(video_frame);  
553 } 517 }
554 518
555 -int SrsHls::on_publish(SrsRequest* req)  
556 -{ 519 +int SrsM3u8Muxer::update_config(
  520 + std::string _app, std::string _stream,
  521 + std::string path, int fragment, int window
  522 +) {
557 int ret = ERROR_SUCCESS; 523 int ret = ERROR_SUCCESS;
558 524
559 - vhost = req->vhost;  
560 - stream = req->stream;  
561 - app = req->app;  
562 -  
563 - // TODO: subscribe the reload event.  
564 -  
565 - SrsConfDirective* conf = NULL;  
566 - if ((conf = config->get_hls_fragment(vhost)) != NULL && !conf->arg0().empty()) {  
567 - hls_fragment = ::atoi(conf->arg0().c_str());  
568 - }  
569 - if (hls_fragment <= 0) {  
570 - hls_fragment = SRS_CONF_DEFAULT_HLS_FRAGMENT;  
571 - }  
572 -  
573 - if ((conf = config->get_hls_window(vhost)) != NULL && !conf->arg0().empty()) {  
574 - hls_window = ::atoi(conf->arg0().c_str());  
575 - }  
576 - if (hls_window <= 0) {  
577 - hls_window = SRS_CONF_DEFAULT_HLS_WINDOW;  
578 - }  
579 -  
580 - if ((ret = reopen()) != ERROR_SUCCESS) {  
581 - return ret;  
582 - } 525 + app = _app;
  526 + stream = _stream;
  527 + hls_path = path;
  528 + hls_fragment = fragment;
  529 + hls_window = window;
583 530
584 return ret; 531 return ret;
585 } 532 }
586 533
587 -void SrsHls::on_unpublish()  
588 -{  
589 - hls_enabled = false;  
590 -}  
591 -  
592 -int SrsHls::on_meta_data(SrsOnMetaDataPacket* metadata) 534 +int SrsM3u8Muxer::segment_open()
593 { 535 {
594 int ret = ERROR_SUCCESS; 536 int ret = ERROR_SUCCESS;
595 537
596 - if (!metadata || !metadata->metadata) {  
597 - srs_trace("no metadata persent, hls ignored it.");  
598 - return ret;  
599 - }  
600 -  
601 - SrsAmf0Object* obj = metadata->metadata;  
602 - if (obj->size() <= 0) {  
603 - srs_trace("no metadata persent, hls ignored it."); 538 + // TODO: create all parents dirs.
  539 + // create dir for app.
  540 + if ((ret = create_dir()) != ERROR_SUCCESS) {
604 return ret; 541 return ret;
605 } 542 }
606 543
607 - // finger out the codec info from metadata if possible.  
608 - SrsAmf0Any* prop = NULL;  
609 -  
610 - if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) {  
611 - codec->duration = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
612 - }  
613 - if ((prop = obj->get_property("width")) != NULL && prop->is_number()) {  
614 - codec->width = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
615 - }  
616 - if ((prop = obj->get_property("height")) != NULL && prop->is_number()) {  
617 - codec->height = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
618 - }  
619 - if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) {  
620 - codec->frame_rate = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
621 - }  
622 - if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) {  
623 - codec->video_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
624 - }  
625 - if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) {  
626 - codec->video_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);  
627 - }  
628 -  
629 - if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) {  
630 - codec->audio_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;  
631 - }  
632 - if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) {  
633 - codec->audio_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);  
634 - }  
635 -  
636 - // ignore the following, for each flv/rtmp packet contains them:  
637 - // audiosamplerate, sample->sound_rate  
638 - // audiosamplesize, sample->sound_size  
639 - // stereo, sample->sound_type  
640 -  
641 - return ret;  
642 -} 544 + // when segment open, the current segment must be NULL.
  545 + srs_assert(!current);
643 546
644 -int SrsHls::on_audio(SrsSharedPtrMessage* audio)  
645 -{  
646 - int ret = ERROR_SUCCESS; 547 + // new segment.
  548 + current = new SrsM3u8Segment();
  549 + current->sequence_no = file_index++;
  550 + current->segment_start_dts = video_stream_dts;
647 551
648 - SrsAutoFree(SrsSharedPtrMessage, audio, false); 552 + // generate filename.
  553 + char filename[128];
  554 + snprintf(filename, sizeof(filename),
  555 + "%s-%d.ts", stream.c_str(), current->sequence_no);
649 556
650 - // TODO: maybe donot need to demux the aac?  
651 - if (!hls_enabled) {  
652 - return ret;  
653 - } 557 + // TODO: use temp file and rename it.
  558 + current->full_path = hls_path;
  559 + current->full_path += "/";
  560 + current->full_path += app;
  561 + current->full_path += "/";
  562 + current->full_path += filename;
654 563
655 - sample->clear();  
656 - if ((ret = codec->audio_aac_demux(audio->payload, audio->size, sample)) != ERROR_SUCCESS) {  
657 - return ret;  
658 - } 564 + // TODO: support base url, and so on.
  565 + current->uri = filename;
659 566
660 - if (codec->audio_codec_id != SrsCodecAudioAAC) { 567 + if ((ret = current->muxer->open(current->full_path)) != ERROR_SUCCESS) {
  568 + srs_error("open hls muxer failed. ret=%d", ret);
661 return ret; 569 return ret;
662 } 570 }
  571 + srs_info("open HLS muxer success. vhost=%s, path=%s",
  572 + vhost.c_str(), current->full_path.c_str());
663 573
664 - // ignore sequence header  
665 - if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {  
666 return ret; 574 return ret;
667 - } 575 +}
668 576
669 - int64_t corrected_time = 0;  
670 - if ((ret = jitter->correct(audio, 0, 0, &corrected_time)) != ERROR_SUCCESS) {  
671 - return ret;  
672 - } 577 +int SrsM3u8Muxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
  578 +{
  579 + int ret = ERROR_SUCCESS;
673 580
674 srs_assert(current); 581 srs_assert(current);
675 582
676 - // the pts calc from rtmp/flv header.  
677 - int64_t pts = corrected_time * 90;  
678 -  
679 - // flush if audio delay exceed  
680 - if (pts - audio_buffer_start_pts > audio_delay * 90) {  
681 - if ((ret = flush_audio()) != ERROR_SUCCESS) { 583 + if (ab->size <= 0) {
682 return ret; 584 return ret;
683 } 585 }
684 - }  
685 -  
686 - // start buffer, set the audio_frame  
687 - if (audio_buffer->size == 0) {  
688 - pts = aac_jitter->on_buffer_start(pts, sample->sound_rate);  
689 -  
690 - audio_frame->dts = audio_frame->pts = audio_buffer_start_pts = pts;  
691 - audio_frame->pid = TS_AUDIO_PID;  
692 - audio_frame->sid = TS_AUDIO_AAC;  
693 - } else {  
694 - aac_jitter->on_buffer_continue();  
695 - }  
696 586
697 - // write audio to cache.  
698 - if ((ret = write_audio()) != ERROR_SUCCESS) { 587 + if ((ret = current->muxer->write_audio(af, ab)) != ERROR_SUCCESS) {
699 return ret; 588 return ret;
700 } 589 }
701 590
702 - // write cache to file.  
703 - if (audio_buffer->size > 1024 * 1024) {  
704 - if ((ret = flush_audio()) != ERROR_SUCCESS) {  
705 - return ret;  
706 - }  
707 - } 591 + // write success, clear and free the buffer
  592 + ab->free();
708 593
709 return ret; 594 return ret;
710 } 595 }
711 596
712 -int SrsHls::on_video(SrsSharedPtrMessage* video) 597 +int SrsM3u8Muxer::flush_video(
  598 + SrsMpegtsFrame* af, SrsCodecBuffer* ab,
  599 + SrsMpegtsFrame* vf, SrsCodecBuffer* vb)
713 { 600 {
714 int ret = ERROR_SUCCESS; 601 int ret = ERROR_SUCCESS;
715 602
716 - SrsAutoFree(SrsSharedPtrMessage, video, false);  
717 -  
718 - // TODO: maybe donot need to demux the avc?  
719 - if (!hls_enabled) {  
720 - return ret;  
721 - }  
722 -  
723 - sample->clear();  
724 - if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) {  
725 - return ret;  
726 - } 603 + srs_assert(current);
727 604
728 - if (codec->video_codec_id != SrsCodecVideoAVC) {  
729 - return ret;  
730 - } 605 + video_stream_dts = vf->dts;
731 606
732 - // ignore sequence header  
733 - if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { 607 + // reopen the muxer for a gop
  608 + if (vf->key && current->duration >= hls_fragment) {
  609 + // TODO: flush audio before or after segment?
  610 + /*
  611 + if ((ret = flush_audio(af, ab)) != ERROR_SUCCESS) {
  612 + srs_error("m3u8 muxer flush audio failed. ret=%d", ret);
734 return ret; 613 return ret;
735 } 614 }
  615 + */
736 616
737 - int64_t corrected_time = 0;  
738 - if ((ret = jitter->correct(video, 0, 0, &corrected_time)) != ERROR_SUCCESS) { 617 + if ((ret = segment_close()) != ERROR_SUCCESS) {
  618 + srs_error("m3u8 muxer close segment failed. ret=%d", ret);
739 return ret; 619 return ret;
740 } 620 }
741 621
742 - // write video to cache.  
743 - if ((ret = write_video()) != ERROR_SUCCESS) { 622 + if ((ret = segment_open()) != ERROR_SUCCESS) {
  623 + srs_error("m3u8 muxer open segment failed. ret=%d", ret);
744 return ret; 624 return ret;
745 } 625 }
746 626
747 - video_stream_dts = video_frame->dts = corrected_time * 90;  
748 - video_frame->pts = video_frame->dts + sample->cts * 90;  
749 - video_frame->pid = TS_VIDEO_PID;  
750 - video_frame->sid = TS_VIDEO_AVC;  
751 - video_frame->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;  
752 -  
753 - // reopen the muxer for a gop  
754 - srs_assert(current);  
755 - if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) {  
756 - if (current->duration >= hls_fragment) {  
757 - if ((ret = reopen()) != ERROR_SUCCESS) { 627 + // TODO: flush audio before or after segment?
  628 + // segment open, flush the audio.
  629 + // @see: ngx_rtmp_hls_open_fragment
  630 + /* start fragment with audio to make iPhone happy */
  631 + if ((ret = flush_audio(af, ab)) != ERROR_SUCCESS) {
  632 + srs_error("m3u8 muxer flush audio failed. ret=%d", ret);
758 return ret; 633 return ret;
759 } 634 }
760 } 635 }
761 - }  
762 636
763 srs_assert(current); 637 srs_assert(current);
764 // update the duration of segment. 638 // update the duration of segment.
765 current->update_duration(video_stream_dts); 639 current->update_duration(video_stream_dts);
766 640
767 - if ((ret = current->muxer->write_video(video_frame, video_buffer)) != ERROR_SUCCESS) { 641 + if ((ret = current->muxer->write_video(vf, vb)) != ERROR_SUCCESS) {
768 return ret; 642 return ret;
769 } 643 }
770 644
771 // write success, clear and free the buffer 645 // write success, clear and free the buffer
772 - video_buffer->free(); 646 + vb->free();
773 647
774 return ret; 648 return ret;
775 } 649 }
776 650
777 -int SrsHls::reopen() 651 +int SrsM3u8Muxer::segment_close()
778 { 652 {
779 int ret = ERROR_SUCCESS; 653 int ret = ERROR_SUCCESS;
780 654
781 - // try to open the HLS muxer  
782 - if (!config->get_hls_enabled(vhost)) {  
783 - return ret;  
784 - } 655 + // when close current segment, the current segment must not be NULL.
  656 + srs_assert(current);
785 657
786 - // TODO: check the audio and video, ensure both exsists.  
787 - // for use fixed mpegts header specifeid the audio and video pid. 658 + // assert segment duplicate.
  659 + std::vector<SrsM3u8Segment*>::iterator it;
  660 + it = std::find(segments.begin(), segments.end(), current);
  661 + srs_assert(it == segments.end());
788 662
789 - hls_enabled = true;  
790 -  
791 - SrsConfDirective* conf = NULL;  
792 - hls_path = SRS_CONF_DEFAULT_HLS_PATH;  
793 - if ((conf = config->get_hls_path(vhost)) != NULL) {  
794 - hls_path = conf->arg0();  
795 - }  
796 -  
797 - // TODO: create all parents dirs.  
798 - // create dir for app.  
799 - if ((ret = create_dir()) != ERROR_SUCCESS) {  
800 - return ret;  
801 - }  
802 -  
803 - // close current segment and update the m3u8 file.  
804 - if (current) {  
805 - // assert segment duplicate.  
806 - std::vector<SrsM3u8Segment*>::iterator it;  
807 - it = std::find(segments.begin(), segments.end(), current);  
808 - srs_assert(it == segments.end());  
809 -  
810 - // valid, add to segments.  
811 - segments.push_back(current); 663 + // valid, add to segments.
  664 + segments.push_back(current);
812 665
813 srs_trace("reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64"", 666 srs_trace("reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64"",
814 current->sequence_no, current->uri.c_str(), current->duration, 667 current->sequence_no, current->uri.c_str(), current->duration,
@@ -855,47 +708,11 @@ int SrsHls::reopen() @@ -855,47 +708,11 @@ int SrsHls::reopen()
855 srs_error("refresh m3u8 failed. ret=%d", ret); 708 srs_error("refresh m3u8 failed. ret=%d", ret);
856 return ret; 709 return ret;
857 } 710 }
858 - }  
859 - // new segment.  
860 - current = new SrsM3u8Segment();  
861 - current->sequence_no = file_index++;  
862 - current->segment_start_dts = video_stream_dts;  
863 -  
864 - // generate filename.  
865 - char filename[128];  
866 - snprintf(filename, sizeof(filename),  
867 - "%s-%d.ts", stream.c_str(), current->sequence_no);  
868 -  
869 - // TODO: use temp file and rename it.  
870 - current->full_path = hls_path;  
871 - current->full_path += "/";  
872 - current->full_path += app;  
873 - current->full_path += "/";  
874 - current->full_path += filename;  
875 -  
876 - // TODO: support base url, and so on.  
877 - current->uri = filename;  
878 -  
879 - if ((ret = current->muxer->open(current->full_path)) != ERROR_SUCCESS) {  
880 - srs_error("open hls muxer failed. ret=%d", ret);  
881 - return ret;  
882 - }  
883 - srs_info("open HLS muxer success. vhost=%s, path=%s",  
884 - vhost.c_str(), current->full_path.c_str());  
885 -  
886 - // segment open, flush the audio.  
887 - // @see: ngx_rtmp_hls_open_fragment  
888 - /* start fragment with audio to make iPhone happy */  
889 - if (current->muxer->fresh()) {  
890 - if ((ret = flush_audio()) != ERROR_SUCCESS) {  
891 - return ret;  
892 - }  
893 - }  
894 711
895 return ret; 712 return ret;
896 } 713 }
897 714
898 -int SrsHls::refresh_m3u8() 715 +int SrsM3u8Muxer::refresh_m3u8()
899 { 716 {
900 int ret = ERROR_SUCCESS; 717 int ret = ERROR_SUCCESS;
901 718
@@ -925,7 +742,7 @@ int SrsHls::refresh_m3u8() @@ -925,7 +742,7 @@ int SrsHls::refresh_m3u8()
925 return ret; 742 return ret;
926 } 743 }
927 744
928 -int SrsHls::_refresh_m3u8(int& fd, std::string m3u8_file) 745 +int SrsM3u8Muxer::_refresh_m3u8(int& fd, std::string m3u8_file)
929 { 746 {
930 int ret = ERROR_SUCCESS; 747 int ret = ERROR_SUCCESS;
931 748
@@ -1016,7 +833,7 @@ int SrsHls::_refresh_m3u8(int& fd, std::string m3u8_file) @@ -1016,7 +833,7 @@ int SrsHls::_refresh_m3u8(int& fd, std::string m3u8_file)
1016 return ret; 833 return ret;
1017 } 834 }
1018 835
1019 -int SrsHls::create_dir() 836 +int SrsM3u8Muxer::create_dir()
1020 { 837 {
1021 int ret = ERROR_SUCCESS; 838 int ret = ERROR_SUCCESS;
1022 839
@@ -1039,7 +856,284 @@ int SrsHls::create_dir() @@ -1039,7 +856,284 @@ int SrsHls::create_dir()
1039 return ret; 856 return ret;
1040 } 857 }
1041 858
1042 -int SrsHls::write_audio() 859 +SrsHls::SrsHls()
  860 +{
  861 + hls_enabled = false;
  862 +
  863 + codec = new SrsCodec();
  864 + sample = new SrsCodecSample();
  865 + jitter = new SrsRtmpJitter();
  866 + aac_jitter = new SrsHlsAacJitter();
  867 +
  868 + ab = new SrsCodecBuffer();
  869 + vb = new SrsCodecBuffer();
  870 +
  871 + af = new SrsMpegtsFrame();
  872 + vf = new SrsMpegtsFrame();
  873 +
  874 + muxer = new SrsM3u8Muxer();
  875 +}
  876 +
  877 +SrsHls::~SrsHls()
  878 +{
  879 + srs_freep(codec);
  880 + srs_freep(sample);
  881 + srs_freep(jitter);
  882 + srs_freep(aac_jitter);
  883 +
  884 + ab->free();
  885 + vb->free();
  886 +
  887 + srs_freep(ab);
  888 + srs_freep(vb);
  889 +
  890 + srs_freep(af);
  891 + srs_freep(vf);
  892 +
  893 + srs_freep(muxer);
  894 +}
  895 +
  896 +int SrsHls::on_publish(SrsRequest* req)
  897 +{
  898 + int ret = ERROR_SUCCESS;
  899 +
  900 + std::string vhost = req->vhost;
  901 + std::string stream = req->stream;
  902 + std::string app = req->app;
  903 +
  904 + // TODO: support reload.
  905 + if (!config->get_hls_enabled(vhost)) {
  906 + return ret;
  907 + }
  908 +
  909 + // if enabled, open the muxer.
  910 + hls_enabled = true;
  911 +
  912 + // TODO: subscribe the reload event.
  913 + int hls_fragment = 0;
  914 + int hls_window = 0;
  915 +
  916 + SrsConfDirective* conf = NULL;
  917 + if ((conf = config->get_hls_fragment(vhost)) != NULL && !conf->arg0().empty()) {
  918 + hls_fragment = ::atoi(conf->arg0().c_str());
  919 + }
  920 + if (hls_fragment <= 0) {
  921 + hls_fragment = SRS_CONF_DEFAULT_HLS_FRAGMENT;
  922 + }
  923 +
  924 + if ((conf = config->get_hls_window(vhost)) != NULL && !conf->arg0().empty()) {
  925 + hls_window = ::atoi(conf->arg0().c_str());
  926 + }
  927 + if (hls_window <= 0) {
  928 + hls_window = SRS_CONF_DEFAULT_HLS_WINDOW;
  929 + }
  930 +
  931 + // get the hls path config
  932 + std::string hls_path = SRS_CONF_DEFAULT_HLS_PATH;
  933 + if ((conf = config->get_hls_path(vhost)) != NULL) {
  934 + hls_path = conf->arg0();
  935 + }
  936 +
  937 + // open muxer
  938 + if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) {
  939 + srs_error("m3u8 muxer update config failed. ret=%d", ret);
  940 + return ret;
  941 + }
  942 +
  943 + if ((ret = muxer->segment_open()) != ERROR_SUCCESS) {
  944 + srs_error("m3u8 muxer open segment failed. ret=%d", ret);
  945 + return ret;
  946 + }
  947 +
  948 + return ret;
  949 +}
  950 +
  951 +void SrsHls::on_unpublish()
  952 +{
  953 + int ret = ERROR_SUCCESS;
  954 +
  955 + // close muxer when unpublish.
  956 + ret = muxer->flush_audio(af, ab);
  957 + ret += muxer->segment_close();
  958 + if (ret != ERROR_SUCCESS) {
  959 + srs_error("ignore m3u8 muxer flush/close audio failed. ret=%d", ret);
  960 + return;
  961 + }
  962 +
  963 + hls_enabled = false;
  964 +}
  965 +
  966 +int SrsHls::on_meta_data(SrsOnMetaDataPacket* metadata)
  967 +{
  968 + int ret = ERROR_SUCCESS;
  969 +
  970 + if (!metadata || !metadata->metadata) {
  971 + srs_trace("no metadata persent, hls ignored it.");
  972 + return ret;
  973 + }
  974 +
  975 + SrsAmf0Object* obj = metadata->metadata;
  976 + if (obj->size() <= 0) {
  977 + srs_trace("no metadata persent, hls ignored it.");
  978 + return ret;
  979 + }
  980 +
  981 + // finger out the codec info from metadata if possible.
  982 + SrsAmf0Any* prop = NULL;
  983 +
  984 + if ((prop = obj->get_property("duration")) != NULL && prop->is_number()) {
  985 + codec->duration = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  986 + }
  987 + if ((prop = obj->get_property("width")) != NULL && prop->is_number()) {
  988 + codec->width = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  989 + }
  990 + if ((prop = obj->get_property("height")) != NULL && prop->is_number()) {
  991 + codec->height = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  992 + }
  993 + if ((prop = obj->get_property("framerate")) != NULL && prop->is_number()) {
  994 + codec->frame_rate = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  995 + }
  996 + if ((prop = obj->get_property("videocodecid")) != NULL && prop->is_number()) {
  997 + codec->video_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  998 + }
  999 + if ((prop = obj->get_property("videodatarate")) != NULL && prop->is_number()) {
  1000 + codec->video_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);
  1001 + }
  1002 +
  1003 + if ((prop = obj->get_property("audiocodecid")) != NULL && prop->is_number()) {
  1004 + codec->audio_codec_id = (int)srs_amf0_convert<SrsAmf0Number>(prop)->value;
  1005 + }
  1006 + if ((prop = obj->get_property("audiodatarate")) != NULL && prop->is_number()) {
  1007 + codec->audio_data_rate = (int)(1000 * srs_amf0_convert<SrsAmf0Number>(prop)->value);
  1008 + }
  1009 +
  1010 + // ignore the following, for each flv/rtmp packet contains them:
  1011 + // audiosamplerate, sample->sound_rate
  1012 + // audiosamplesize, sample->sound_size
  1013 + // stereo, sample->sound_type
  1014 +
  1015 + return ret;
  1016 +}
  1017 +
  1018 +int SrsHls::on_audio(SrsSharedPtrMessage* audio)
  1019 +{
  1020 + int ret = ERROR_SUCCESS;
  1021 +
  1022 + SrsAutoFree(SrsSharedPtrMessage, audio, false);
  1023 +
  1024 + // TODO: maybe donot need to demux the aac?
  1025 + if (!hls_enabled) {
  1026 + return ret;
  1027 + }
  1028 +
  1029 + sample->clear();
  1030 + if ((ret = codec->audio_aac_demux(audio->payload, audio->size, sample)) != ERROR_SUCCESS) {
  1031 + return ret;
  1032 + }
  1033 +
  1034 + if (codec->audio_codec_id != SrsCodecAudioAAC) {
  1035 + return ret;
  1036 + }
  1037 +
  1038 + // ignore sequence header
  1039 + if (sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
  1040 + return ret;
  1041 + }
  1042 +
  1043 + int64_t corrected_time = 0;
  1044 + if ((ret = jitter->correct(audio, 0, 0, &corrected_time)) != ERROR_SUCCESS) {
  1045 + return ret;
  1046 + }
  1047 +
  1048 + // the pts calc from rtmp/flv header.
  1049 + int64_t pts = corrected_time * 90;
  1050 +
  1051 + // start buffer, set the af
  1052 + if (ab->size == 0) {
  1053 + pts = aac_jitter->on_buffer_start(pts, sample->sound_rate);
  1054 +
  1055 + af->dts = af->pts = audio_buffer_start_pts = pts;
  1056 + af->pid = TS_AUDIO_PID;
  1057 + af->sid = TS_AUDIO_AAC;
  1058 + } else {
  1059 + aac_jitter->on_buffer_continue();
  1060 + }
  1061 +
  1062 + // write audio to cache.
  1063 + if ((ret = cache_audio()) != ERROR_SUCCESS) {
  1064 + return ret;
  1065 + }
  1066 +
  1067 + // flush if buffer exceed max size.
  1068 + if (ab->size > SRS_HLS_AUDIO_CACHE_SIZE) {
  1069 + if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) {
  1070 + return ret;
  1071 + }
  1072 + }
  1073 + // TODO: config it.
  1074 + // in ms, audio delay to flush the audios.
  1075 + int64_t audio_delay = SRS_CONF_DEFAULT_AAC_DELAY;
  1076 + // flush if audio delay exceed
  1077 + if (pts - audio_buffer_start_pts > audio_delay * 90) {
  1078 + if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) {
  1079 + return ret;
  1080 + }
  1081 + }
  1082 +
  1083 + return ret;
  1084 +}
  1085 +
  1086 +int SrsHls::on_video(SrsSharedPtrMessage* video)
  1087 +{
  1088 + int ret = ERROR_SUCCESS;
  1089 +
  1090 + SrsAutoFree(SrsSharedPtrMessage, video, false);
  1091 +
  1092 + // TODO: maybe donot need to demux the avc?
  1093 + if (!hls_enabled) {
  1094 + return ret;
  1095 + }
  1096 +
  1097 + sample->clear();
  1098 + if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) {
  1099 + return ret;
  1100 + }
  1101 +
  1102 + if (codec->video_codec_id != SrsCodecVideoAVC) {
  1103 + return ret;
  1104 + }
  1105 +
  1106 + // ignore sequence header
  1107 + if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
  1108 + return ret;
  1109 + }
  1110 +
  1111 + int64_t corrected_time = 0;
  1112 + if ((ret = jitter->correct(video, 0, 0, &corrected_time)) != ERROR_SUCCESS) {
  1113 + return ret;
  1114 + }
  1115 +
  1116 + // write video to cache.
  1117 + if ((ret = cache_video()) != ERROR_SUCCESS) {
  1118 + return ret;
  1119 + }
  1120 +
  1121 + vf->dts = corrected_time * 90;
  1122 + vf->pts = vf->dts + sample->cts * 90;
  1123 + vf->pid = TS_VIDEO_PID;
  1124 + vf->sid = TS_VIDEO_AVC;
  1125 + vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;
  1126 +
  1127 + // flush video when got one
  1128 + if ((ret = muxer->flush_video(af, ab, vf, vb)) != ERROR_SUCCESS) {
  1129 + srs_error("m3u8 muxer flush video failed. ret=%d", ret);
  1130 + return ret;
  1131 + }
  1132 +
  1133 + return ret;
  1134 +}
  1135 +
  1136 +int SrsHls::cache_audio()
1043 { 1137 {
1044 int ret = ERROR_SUCCESS; 1138 int ret = ERROR_SUCCESS;
1045 1139
@@ -1099,19 +1193,19 @@ int SrsHls::write_audio() @@ -1099,19 +1193,19 @@ int SrsHls::write_audio()
1099 adts_header[5] |= 0x1f; 1193 adts_header[5] |= 0x1f;
1100 1194
1101 // copy to audio buffer 1195 // copy to audio buffer
1102 - audio_buffer->append(adts_header, sizeof(adts_header));  
1103 - audio_buffer->append(buf->bytes, buf->size); 1196 + ab->append(adts_header, sizeof(adts_header));
  1197 + ab->append(buf->bytes, buf->size);
1104 } 1198 }
1105 1199
1106 return ret; 1200 return ret;
1107 } 1201 }
1108 1202
1109 -int SrsHls::write_video() 1203 +int SrsHls::cache_video()
1110 { 1204 {
1111 int ret = ERROR_SUCCESS; 1205 int ret = ERROR_SUCCESS;
1112 1206
1113 static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; 1207 static u_int8_t aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 };
1114 - video_buffer->append(aud_nal, sizeof(aud_nal)); 1208 + vb->append(aud_nal, sizeof(aud_nal));
1115 1209
1116 bool sps_pps_sent = false; 1210 bool sps_pps_sent = false;
1117 for (int i = 0; i < sample->nb_buffers; i++) { 1211 for (int i = 0; i < sample->nb_buffers; i++) {
@@ -1138,21 +1232,21 @@ int SrsHls::write_video() @@ -1138,21 +1232,21 @@ int SrsHls::write_video()
1138 // 5: Coded slice of an IDR picture. 1232 // 5: Coded slice of an IDR picture.
1139 // insert sps/pps before IDR or key frame is ok. 1233 // insert sps/pps before IDR or key frame is ok.
1140 if (nal_unit_type == 5 && !sps_pps_sent) { 1234 if (nal_unit_type == 5 && !sps_pps_sent) {
1141 - //if (video_frame->key && !sps_pps_sent) { 1235 + //if (vf->key && !sps_pps_sent) {
1142 sps_pps_sent = true; 1236 sps_pps_sent = true;
1143 1237
1144 // ngx_rtmp_hls_append_sps_pps 1238 // ngx_rtmp_hls_append_sps_pps
1145 if (codec->sequenceParameterSetLength > 0) { 1239 if (codec->sequenceParameterSetLength > 0) {
1146 // AnnexB prefix 1240 // AnnexB prefix
1147 - video_buffer->append(aud_nal, 4); 1241 + vb->append(aud_nal, 4);
1148 // sps 1242 // sps
1149 - video_buffer->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); 1243 + vb->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
1150 } 1244 }
1151 if (codec->pictureParameterSetLength > 0) { 1245 if (codec->pictureParameterSetLength > 0) {
1152 // AnnexB prefix 1246 // AnnexB prefix
1153 - video_buffer->append(aud_nal, 4); 1247 + vb->append(aud_nal, 4);
1154 // pps 1248 // pps
1155 - video_buffer->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); 1249 + vb->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength);
1156 } 1250 }
1157 } 1251 }
1158 1252
@@ -1164,30 +1258,12 @@ int SrsHls::write_video() @@ -1164,30 +1258,12 @@ int SrsHls::write_video()
1164 if (i == 0) { 1258 if (i == 0) {
1165 p = aud_nal; 1259 p = aud_nal;
1166 } 1260 }
1167 - video_buffer->append(p, end - p); 1261 + vb->append(p, end - p);
1168 1262
1169 // sample data 1263 // sample data
1170 - video_buffer->append(buf->bytes, buf->size);  
1171 - }  
1172 -  
1173 - return ret;  
1174 -}  
1175 -  
1176 -int SrsHls::flush_audio()  
1177 -{  
1178 - int ret = ERROR_SUCCESS;  
1179 -  
1180 - if (audio_buffer->size <= 0) {  
1181 - return ret; 1264 + vb->append(buf->bytes, buf->size);
1182 } 1265 }
1183 1266
1184 - if ((ret = current->muxer->write_audio(audio_frame, audio_buffer)) != ERROR_SUCCESS) {  
1185 - return ret;  
1186 - }  
1187 -  
1188 - // write success, clear and free the buffer  
1189 - audio_buffer->free();  
1190 -  
1191 return ret; 1267 return ret;
1192 } 1268 }
1193 1269
@@ -74,6 +74,22 @@ public: @@ -74,6 +74,22 @@ public:
74 virtual void on_buffer_continue(); 74 virtual void on_buffer_continue();
75 }; 75 };
76 76
  77 +//TODO: refine the ts muxer, do more jobs.
  78 +class SrsTSMuxer
  79 +{
  80 +private:
  81 + int fd;
  82 + std::string path;
  83 +public:
  84 + SrsTSMuxer();
  85 + virtual ~SrsTSMuxer();
  86 +public:
  87 + virtual int open(std::string _path);
  88 + virtual int write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab);
  89 + virtual int write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb);
  90 + virtual void close();
  91 +};
  92 +
77 /** 93 /**
78 * 3.3.2. EXTINF 94 * 3.3.2. EXTINF
79 * The EXTINF tag specifies the duration of a media segment. 95 * The EXTINF tag specifies the duration of a media segment.
@@ -102,33 +118,15 @@ struct SrsM3u8Segment @@ -102,33 +118,15 @@ struct SrsM3u8Segment
102 virtual double update_duration(int64_t video_stream_dts); 118 virtual double update_duration(int64_t video_stream_dts);
103 }; 119 };
104 120
105 -//TODO: refine the ts muxer, do more jobs.  
106 -class SrsTSMuxer  
107 -{  
108 -private:  
109 - int fd;  
110 - std::string path;  
111 - bool _fresh;  
112 -public:  
113 - SrsTSMuxer();  
114 - virtual ~SrsTSMuxer();  
115 -public:  
116 - virtual int open(std::string _path);  
117 - virtual int write_audio(SrsMpegtsFrame* audio_frame, SrsCodecBuffer* audio_buffer);  
118 - virtual int write_video(SrsMpegtsFrame* video_frame, SrsCodecBuffer* video_buffer);  
119 - virtual void close();  
120 - virtual bool fresh();  
121 -};  
122 -  
123 /** 121 /**
124 -* write m3u8 hls. 122 +* muxer the m3u8 and ts files.
125 */ 123 */
126 -class SrsHls 124 +class SrsM3u8Muxer
127 { 125 {
128 private: 126 private:
129 - std::string vhost;  
130 - std::string stream;  
131 std::string app; 127 std::string app;
  128 + std::string stream;
  129 +private:
132 std::string hls_path; 130 std::string hls_path;
133 int hls_fragment; 131 int hls_fragment;
134 int hls_window; 132 int hls_window;
@@ -144,16 +142,37 @@ private: @@ -144,16 +142,37 @@ private:
144 * current writing segment. 142 * current writing segment.
145 */ 143 */
146 SrsM3u8Segment* current; 144 SrsM3u8Segment* current;
147 - // current frame and buffer  
148 - SrsMpegtsFrame* audio_frame;  
149 - SrsCodecBuffer* audio_buffer;  
150 - SrsMpegtsFrame* video_frame;  
151 - SrsCodecBuffer* video_buffer;  
152 // last known dts 145 // last known dts
153 int64_t video_stream_dts; 146 int64_t video_stream_dts;
  147 +public:
  148 + SrsM3u8Muxer();
  149 + virtual ~SrsM3u8Muxer();
  150 +public:
  151 + virtual int update_config(std::string _app, std::string _stream, std::string path, int fragment, int window);
  152 + virtual int segment_open();
  153 + virtual int flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab);
  154 + virtual int flush_video(SrsMpegtsFrame* af, SrsCodecBuffer* ab, SrsMpegtsFrame* vf, SrsCodecBuffer* vb);
  155 + virtual int segment_close();
  156 +private:
  157 + virtual int refresh_m3u8();
  158 + virtual int _refresh_m3u8(int& fd, std::string m3u8_file);
  159 + virtual int create_dir();
  160 +};
  161 +
  162 +/**
  163 +* write m3u8 hls.
  164 +*/
  165 +class SrsHls
  166 +{
  167 +private:
  168 + SrsM3u8Muxer* muxer;
  169 + // current frame and buffer
  170 + SrsMpegtsFrame* af;
  171 + SrsCodecBuffer* ab;
  172 + SrsMpegtsFrame* vf;
  173 + SrsCodecBuffer* vb;
  174 + // the audio cache buffer start pts, to flush audio if full.
154 int64_t audio_buffer_start_pts; 175 int64_t audio_buffer_start_pts;
155 - // in ms, audio delay to flush the audios.  
156 - int64_t audio_delay;  
157 private: 176 private:
158 bool hls_enabled; 177 bool hls_enabled;
159 SrsCodec* codec; 178 SrsCodec* codec;
@@ -170,14 +189,8 @@ public: @@ -170,14 +189,8 @@ public:
170 virtual int on_audio(SrsSharedPtrMessage* audio); 189 virtual int on_audio(SrsSharedPtrMessage* audio);
171 virtual int on_video(SrsSharedPtrMessage* video); 190 virtual int on_video(SrsSharedPtrMessage* video);
172 private: 191 private:
173 - virtual int reopen();  
174 - virtual int refresh_m3u8();  
175 - virtual int _refresh_m3u8(int& fd, std::string m3u8_file);  
176 - virtual int create_dir();  
177 -private:  
178 - virtual int write_audio();  
179 - virtual int write_video();  
180 - virtual int flush_audio(); 192 + virtual int cache_audio();
  193 + virtual int cache_video();
181 }; 194 };
182 195
183 #endif 196 #endif