胡斌

support save total.m3u8 for hls,unfinished

@@ -72,6 +72,8 @@ const char* _srs_version = "XCORE-"RTMP_SIG_SRS_SERVER; @@ -72,6 +72,8 @@ const char* _srs_version = "XCORE-"RTMP_SIG_SRS_SERVER;
72 #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000 72 #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000
73 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" 73 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
74 #define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8" 74 #define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8"
  75 +#define SRS_CONF_DEFAULT_HLS_TOTAL_M3U8_FILE "[app]/[stream]_total.m3u8"
  76 +#define SRS_CONF_DEFAULT_HLS_TOTAL_FILE "[app]/[stream]_total"
75 #define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts" 77 #define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts"
76 #define SRS_CONF_DEFAULT_HLS_TS_FLOOR false 78 #define SRS_CONF_DEFAULT_HLS_TS_FLOOR false
77 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 79 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
@@ -1898,7 +1900,7 @@ int SrsConfig::check_config() @@ -1898,7 +1900,7 @@ int SrsConfig::check_config()
1898 if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" 1900 if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
1899 && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" 1901 && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
1900 && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" 1902 && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
1901 - && m != "hls_wait_keyframe" && m != "hls_dispose" 1903 + && m != "hls_wait_keyframe" && m != "hls_dispose" && m != "hls_total_m3u8_file" && m != "hls_total_file"
1902 ) { 1904 ) {
1903 ret = ERROR_SYSTEM_CONFIG_INVALID; 1905 ret = ERROR_SYSTEM_CONFIG_INVALID;
1904 srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); 1906 srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
@@ -3677,6 +3679,40 @@ string SrsConfig::get_hls_m3u8_file(string vhost) @@ -3677,6 +3679,40 @@ string SrsConfig::get_hls_m3u8_file(string vhost)
3677 return conf->arg0(); 3679 return conf->arg0();
3678 } 3680 }
3679 3681
  3682 +string SrsConfig::get_hls_total_m3u8_file(string vhost)
  3683 +{
  3684 + SrsConfDirective* hls = get_hls(vhost);
  3685 +
  3686 + if (!hls) {
  3687 + return SRS_CONF_DEFAULT_HLS_TOTAL_M3U8_FILE;
  3688 + }
  3689 +
  3690 + SrsConfDirective* conf = hls->get("hls_total_m3u8_file");
  3691 +
  3692 + if (!conf) {
  3693 + return SRS_CONF_DEFAULT_HLS_TOTAL_M3U8_FILE;
  3694 + }
  3695 +
  3696 + return conf->arg0();
  3697 +}
  3698 +
  3699 +string SrsConfig::get_hls_total_file(string vhost)
  3700 +{
  3701 + SrsConfDirective* hls = get_hls(vhost);
  3702 +
  3703 + if (!hls) {
  3704 + return SRS_CONF_DEFAULT_HLS_TOTAL_FILE;
  3705 + }
  3706 +
  3707 + SrsConfDirective* conf = hls->get("hls_total_file");
  3708 +
  3709 + if (!conf) {
  3710 + return SRS_CONF_DEFAULT_HLS_TOTAL_FILE;
  3711 + }
  3712 +
  3713 + return conf->arg0();
  3714 +}
  3715 +
3680 string SrsConfig::get_hls_ts_file(string vhost) 3716 string SrsConfig::get_hls_ts_file(string vhost)
3681 { 3717 {
3682 SrsConfDirective* hls = get_hls(vhost); 3718 SrsConfDirective* hls = get_hls(vhost);
@@ -882,6 +882,14 @@ public: @@ -882,6 +882,14 @@ public:
882 */ 882 */
883 virtual std::string get_hls_m3u8_file(std::string vhost); 883 virtual std::string get_hls_m3u8_file(std::string vhost);
884 /** 884 /**
  885 + * get the HLS total m3u8 file path template.
  886 + */
  887 + virtual std::string get_hls_total_m3u8_file(std::string vhost);
  888 + /**
  889 + * get the HLS total file path template.
  890 + */
  891 + virtual std::string get_hls_total_file(std::string vhost);
  892 + /**
885 * get the HLS ts file path template. 893 * get the HLS ts file path template.
886 */ 894 */
887 virtual std::string get_hls_ts_file(std::string vhost); 895 virtual std::string get_hls_ts_file(std::string vhost);
@@ -387,7 +387,7 @@ int SrsHlsMuxer::initialize() @@ -387,7 +387,7 @@ int SrsHlsMuxer::initialize()
387 } 387 }
388 388
389 int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, 389 int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
390 - string path, string m3u8_file, string ts_file, double fragment, double window, 390 + string path, string m3u8_file, string total_m3u8_file, string total_file, string ts_file, double fragment, double window,
391 bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe 391 bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe
392 ) { 392 ) {
393 int ret = ERROR_SUCCESS; 393 int ret = ERROR_SUCCESS;
@@ -412,6 +412,14 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, @@ -412,6 +412,14 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
412 m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream); 412 m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
413 m3u8 = path + "/" + m3u8_url; 413 m3u8 = path + "/" + m3u8_url;
414 414
  415 + // generate the total m3u8 dir and path.
  416 + total_m3u8_url = srs_path_build_stream(total_m3u8_file, req->vhost, req->app, req->stream);
  417 + total_m3u8 = path + "/" + total_m3u8_url;
  418 +
  419 + // generate the m3u8 dir and path.
  420 + total_url = srs_path_build_stream(total_file, req->vhost, req->app, req->stream);
  421 + total = path + "/" + total_url;
  422 +
415 // when update config, reset the history target duration. 423 // when update config, reset the history target duration.
416 max_td = (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost)); 424 max_td = (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost));
417 425
@@ -735,6 +743,8 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -735,6 +743,8 @@ int SrsHlsMuxer::segment_close(string log_desc)
735 srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64, 743 srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
736 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration, 744 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration,
737 current->segment_start_dts); 745 current->segment_start_dts);
  746 +
  747 + SrsHlsSegment* currentSeg = current;
738 748
739 // close the muxer of finished segment. 749 // close the muxer of finished segment.
740 srs_freep(current->muxer); 750 srs_freep(current->muxer);
@@ -749,6 +759,63 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -749,6 +759,63 @@ int SrsHlsMuxer::segment_close(string log_desc)
749 tmp_file.c_str(), full_path.c_str(), ret); 759 tmp_file.c_str(), full_path.c_str(), ret);
750 return ret; 760 return ret;
751 } 761 }
  762 +
  763 +
  764 + SrsFileWriter total_m3u8_writer;
  765 + //add segment to total.m3u8
  766 + std::stringstream ss;
  767 +
  768 + if(currentSeg->sequence_no == 0){
  769 + ret = total_m3u8_writer.open(total_m3u8);
  770 + if(ret != ERROR_SUCCESS){
  771 + srs_error("open total file %s error:%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
  772 + total_m3u8.c_str(), log_desc.c_str(), currentSeg->sequence_no, currentSeg->uri.c_str(), currentSeg->duration,
  773 + currentSeg->segment_start_dts);
  774 + return ret;
  775 + }
  776 + //write total m3u8 header
  777 +
  778 + ss << "#EXTM3U" << SRS_CONSTS_LF
  779 + << "#EXT-X-VERSION:3" << SRS_CONSTS_LF
  780 + << "#EXT-X-ALLOW-CACHE:YES" << SRS_CONSTS_LF;
  781 + srs_verbose("write m3u8 header success.");
  782 +
  783 + }
  784 + else{
  785 + ret = total_m3u8_writer.open_append(total_m3u8);
  786 + if(ret != ERROR_SUCCESS){
  787 + srs_error("open total file %s error:%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
  788 + total_m3u8.c_str(), log_desc.c_str(), currentSeg->sequence_no, currentSeg->uri.c_str(), currentSeg->duration,
  789 + currentSeg->segment_start_dts);
  790 + return ret;
  791 + }
  792 + }
  793 +
  794 +
  795 + if (currentSeg->is_sequence_header) {
  796 + // #EXT-X-DISCONTINUITY\n
  797 + ss << "#EXT-X-DISCONTINUITY" << SRS_CONSTS_LF;
  798 + srs_verbose("write m3u8 segment discontinuity success.");
  799 + }
  800 +
  801 + // "#EXTINF:4294967295.208,\n"
  802 + ss.precision(3);
  803 + ss.setf(std::ios::fixed, std::ios::floatfield);
  804 + ss << "#EXTINF:" << currentSeg->duration << ", no desc" << SRS_CONSTS_LF;
  805 + srs_verbose("write m3u8 segment info success.");
  806 +
  807 + // {file name}\n
  808 + ss << currentSeg->uri << SRS_CONSTS_LF;
  809 + srs_verbose("write m3u8 segment uri success.");
  810 +
  811 + // write m3u8 to writer.
  812 + std::string m3u8 = ss.str();
  813 + if ((ret = total_m3u8_writer.write((char*)m3u8.c_str(), (int)m3u8.length(), NULL)) != ERROR_SUCCESS) {
  814 + srs_error("write m3u8 failed. ret=%d", ret);
  815 + return ret;
  816 + }
  817 + srs_info("write total m3u8 %s success.", m3u8_total_file.c_str());
  818 +
752 } else { 819 } else {
753 // reuse current segment index. 820 // reuse current segment index.
754 _sequence_no--; 821 _sequence_no--;
@@ -953,6 +1020,8 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -953,6 +1020,8 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
953 // get the hls path config 1020 // get the hls path config
954 std::string path = _srs_config->get_hls_path(vhost); 1021 std::string path = _srs_config->get_hls_path(vhost);
955 std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost); 1022 std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost);
  1023 + std::string total_m3u8_file = _srs_config->get_hls_total_m3u8_file(vhost);
  1024 + std::string total_file = _srs_config->get_hls_total_file(vhost);
956 std::string ts_file = _srs_config->get_hls_ts_file(vhost); 1025 std::string ts_file = _srs_config->get_hls_ts_file(vhost);
957 bool cleanup = _srs_config->get_hls_cleanup(vhost); 1026 bool cleanup = _srs_config->get_hls_cleanup(vhost);
958 bool wait_keyframe = _srs_config->get_hls_wait_keyframe(vhost); 1027 bool wait_keyframe = _srs_config->get_hls_wait_keyframe(vhost);
@@ -968,7 +1037,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -968,7 +1037,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
968 1037
969 // open muxer 1038 // open muxer
970 if ((ret = muxer->update_config(req, entry_prefix, 1039 if ((ret = muxer->update_config(req, entry_prefix,
971 - path, m3u8_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio, 1040 + path, m3u8_file, total_m3u8_file, total_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio,
972 cleanup, wait_keyframe)) != ERROR_SUCCESS 1041 cleanup, wait_keyframe)) != ERROR_SUCCESS
973 ) { 1042 ) {
974 srs_error("m3u8 muxer update config failed. ret=%d", ret); 1043 srs_error("m3u8 muxer update config failed. ret=%d", ret);
@@ -205,6 +205,10 @@ private: @@ -205,6 +205,10 @@ private:
205 int max_td; 205 int max_td;
206 std::string m3u8; 206 std::string m3u8;
207 std::string m3u8_url; 207 std::string m3u8_url;
  208 + std::string total_m3u8;
  209 + std::string total_m3u8_url;
  210 + std::string total;
  211 + std::string total_url;
208 private: 212 private:
209 // TODO: FIXME: remove it. 213 // TODO: FIXME: remove it.
210 bool should_write_cache; 214 bool should_write_cache;
@@ -248,7 +252,7 @@ public: @@ -248,7 +252,7 @@ public:
248 * when publish, update the config for muxer. 252 * when publish, update the config for muxer.
249 */ 253 */
250 virtual int update_config(SrsRequest* r, std::string entry_prefix, 254 virtual int update_config(SrsRequest* r, std::string entry_prefix,
251 - std::string path, std::string m3u8_file, std::string ts_file, 255 + std::string path, std::string m3u8_file, std::string total_m3u8_file, std::string total_file, std::string ts_file,
252 double fragment, double window, bool ts_floor, double aof_ratio, 256 double fragment, double window, bool ts_floor, double aof_ratio,
253 bool cleanup, bool wait_keyframe); 257 bool cleanup, bool wait_keyframe);
254 /** 258 /**