From 25af6c6847c8b7a9e071361684159aa3a63533a2 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 12 Feb 2015 13:34:59 +0800 Subject: [PATCH] for #304, use stringstream to generate m3u8, add hls_td_ratio. 2.0.116. --- README.md | 1 + trunk/conf/full.conf | 6 +++ trunk/src/app/srs_app_config.cpp | 19 +++++++- trunk/src/app/srs_app_config.hpp | 6 +++ trunk/src/app/srs_app_hls.cpp | 77 +++++++++++--------------------- trunk/src/app/srs_app_hls.hpp | 1 + trunk/src/core/srs_core.hpp | 2 +- 7 files changed, 60 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 9dab7ff25..6187b8f5a 100755 --- a/README.md +++ b/README.md @@ -525,6 +525,7 @@ Supported operating systems and hardware: ### SRS 2.0 history +* v2.0, 2015-02-12, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), use stringstream to generate m3u8, add hls_td_ratio. 2.0.116. * v2.0, 2015-02-11, dev code ZhouGuowen for 2.0.115. * v2.0, 2015-02-10, for [#311](https://github.com/winlinvip/simple-rtmp-server/issues/311), set pcr_base to dts. 2.0.114. * v2.0, 2015-02-10, fix [the bug](https://github.com/winlinvip/simple-rtmp-server/commit/87519aaae835199e5adb60c0ae2c1cd24939448c) of ibmf format which decoded in annexb. diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index fb2675545..0b4d964c0 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -451,6 +451,12 @@ vhost with-hls.srs.com { # the hls fragment in seconds, the duration of a piece of ts. # default: 10 hls_fragment 10; + # the hls m3u8 target duration ratio, + # EXT-X-TARGETDURATION = hls_td_ratio * hls_fragment // init + # EXT-X-TARGETDURATION = max(ts_duration, EXT-X-TARGETDURATION) // for each ts + # @see https://github.com/winlinvip/simple-rtmp-server/issues/304#issuecomment-74000081 + # default: 1.5 + hls_td_ratio 1.5; # the hls window in seconds, the number of ts in m3u8. # default: 60 hls_window 60; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 38c20cedc..56d44f7ef 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -1480,7 +1480,7 @@ int SrsConfig::check_config() for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name.c_str(); if (m != "enabled" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" - && m != "hls_storage" && m != "hls_mount" + && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" ) { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); @@ -3247,6 +3247,23 @@ double SrsConfig::get_hls_fragment(string vhost) return ::atof(conf->arg0().c_str()); } +double SrsConfig::get_hls_td_ratio(string vhost) +{ + SrsConfDirective* hls = get_hls(vhost); + + if (!hls) { + return SRS_CONF_DEFAULT_HLS_TD_RATIO; + } + + SrsConfDirective* conf = hls->get("hls_td_ratio"); + + if (!conf) { + return SRS_CONF_DEFAULT_HLS_TD_RATIO; + } + + return ::atof(conf->arg0().c_str()); +} + double SrsConfig::get_hls_window(string vhost) { SrsConfDirective* hls = get_hls(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index b988f98d0..3534c3126 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -47,6 +47,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 +#define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5 #define SRS_CONF_DEFAULT_HLS_WINDOW 60 #define SRS_CONF_DEFAULT_HLS_ON_ERROR_IGNORE "ignore" #define SRS_CONF_DEFAULT_HLS_ON_ERROR_DISCONNECT "disconnect" @@ -896,6 +897,11 @@ public: */ virtual double get_hls_fragment(std::string vhost); /** + * get the hls td(target duration) ratio. + * a fragment is a ts file. + */ + virtual double get_hls_td_ratio(std::string vhost); + /** * get the hls window time, in seconds. * a window is a set of ts, the ts collection in m3u8. * @remark SRS will delete the ts exceed the window. diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 9290d1f37..07ffb9b32 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -33,8 +33,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #include +#include using namespace std; #include @@ -166,6 +168,7 @@ SrsHlsMuxer::SrsHlsMuxer(ISrsHlsHandler* h) req = NULL; handler = h; hls_fragment = hls_window = 0; + target_duration = 0; _sequence_no = 0; current = NULL; acodec = SrsCodecAudioReserved1; @@ -201,6 +204,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string path, int fragment, int win hls_path = path; hls_fragment = fragment; hls_window = window; + target_duration = (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost)); std::string storage = _srs_config->get_hls_storage(r->vhost); if (storage == "ram") { @@ -503,35 +507,21 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) } srs_info("open m3u8 file %s success.", m3u8_file.c_str()); - // #EXTM3U\n#EXT-X-VERSION:3\n - char header[] = { - // #EXTM3U\n - 0x23, 0x45, 0x58, 0x54, 0x4d, 0x33, 0x55, SRS_CONSTS_LF, - // #EXT-X-VERSION:3\n - 0x23, 0x45, 0x58, 0x54, 0x2d, 0x58, 0x2d, 0x56, 0x45, 0x52, - 0x53, 0x49, 0x4f, 0x4e, 0x3a, 0x33, SRS_CONSTS_LF, - // #EXT-X-ALLOW-CACHE:NO\n - 0x23, 0x45, 0x58, 0x54, 0x2d, 0x58, 0x2d, 0x41, 0x4c, 0x4c, - 0x4f, 0x57, 0x2d, 0x43, 0x41, 0x43, 0x48, 0x45, 0x3a, 0x4e, 0x4f, SRS_CONSTS_LF - }; - if ((ret = writer.write(header, sizeof(header), NULL)) != ERROR_SUCCESS) { - srs_error("write m3u8 header failed. ret=%d", ret); - return ret; - } + // #EXTM3U\n + // #EXT-X-VERSION:3\n + // #EXT-X-ALLOW-CACHE:NO\n + std::stringstream ss; + ss << "#EXTM3U" << SRS_CONSTS_LF + << "#EXT-X-VERSION:3" << SRS_CONSTS_LF + << "#EXT-X-ALLOW-CACHE:NO" << SRS_CONSTS_LF; srs_verbose("write m3u8 header success."); // #EXT-X-MEDIA-SEQUENCE:4294967295\n SrsHlsSegment* first = *segments.begin(); - char sequence[34] = {}; - int len = snprintf(sequence, sizeof(sequence), "#EXT-X-MEDIA-SEQUENCE:%d%c", first->sequence_no, SRS_CONSTS_LF); - if ((ret = writer.write(sequence, len, NULL)) != ERROR_SUCCESS) { - srs_error("write m3u8 sequence failed. ret=%d", ret); - return ret; - } + ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF; srs_verbose("write m3u8 sequence success."); // #EXT-X-TARGETDURATION:4294967295\n - int target_duration = 0; /** * @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 25 * The Media Playlist file MUST contain an EXT-X-TARGETDURATION tag. @@ -540,20 +530,13 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) * rounded to the nearest integer. Its value MUST NOT change. A * typical target duration is 10 seconds. */ - // TODO: FIXME: finger it out whether it should not changed. + // @see https://github.com/winlinvip/simple-rtmp-server/issues/304#issuecomment-74000081 std::vector::iterator it; for (it = segments.begin(); it != segments.end(); ++it) { SrsHlsSegment* segment = *it; - target_duration = srs_max(target_duration, (int)segment->duration); - } - // TODO: maybe need to take an around value - target_duration += 1; - char duration[34]; // 23+10+1 - len = snprintf(duration, sizeof(duration), "#EXT-X-TARGETDURATION:%d%c", target_duration, SRS_CONSTS_LF); - if ((ret = writer.write(duration, len, NULL)) != ERROR_SUCCESS) { - srs_error("write m3u8 duration failed. ret=%d", ret); - return ret; + target_duration = srs_max(target_duration, (int)ceil(segment->duration)); } + ss << "#EXT-X-TARGETDURATION:" << target_duration << SRS_CONSTS_LF; srs_verbose("write m3u8 duration success."); // write all segments @@ -562,33 +545,27 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) if (segment->is_sequence_header) { // #EXT-X-DISCONTINUITY\n - char ext_discon[22]; // 21+1 - len = snprintf(ext_discon, sizeof(ext_discon), "#EXT-X-DISCONTINUITY%c", SRS_CONSTS_LF); - if ((ret = writer.write(ext_discon, len, NULL)) != ERROR_SUCCESS) { - srs_error("write m3u8 segment discontinuity failed. ret=%d", ret); - return ret; - } + ss << "#EXT-X-DISCONTINUITY" << SRS_CONSTS_LF; srs_verbose("write m3u8 segment discontinuity success."); } // "#EXTINF:4294967295.208,\n" - char ext_info[25]; // 14+10+1 - len = snprintf(ext_info, sizeof(ext_info), "#EXTINF:%.3f,%c", segment->duration, SRS_CONSTS_LF); - if ((ret = writer.write(ext_info, len, NULL)) != ERROR_SUCCESS) { - srs_error("write m3u8 segment info failed. ret=%d", ret); - return ret; - } + ss.precision(3); + ss.setf(std::ios::fixed, std::ios::floatfield); + ss << "#EXTINF:" << segment->duration << "," << SRS_CONSTS_LF; srs_verbose("write m3u8 segment info success."); // {file name}\n - std::string filename = segment->uri; - filename += SRS_CONSTS_LF; - if ((ret = writer.write((char*)filename.c_str(), (int)filename.length(), NULL)) != ERROR_SUCCESS) { - srs_error("write m3u8 segment uri failed. ret=%d", ret); - return ret; - } + ss << segment->uri << SRS_CONSTS_LF; srs_verbose("write m3u8 segment uri success."); } + + // write m3u8 to writer. + std::string m3u8 = ss.str(); + if ((ret = writer.write((char*)m3u8.c_str(), (int)m3u8.length(), NULL)) != ERROR_SUCCESS) { + srs_error("write m3u8 failed. ret=%d", ret); + return ret; + } srs_info("write m3u8 %s success.", m3u8_file.c_str()); // notify handler for update m3u8. diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index c3a169630..8edfe7ee7 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -172,6 +172,7 @@ private: int hls_window; private: int _sequence_no; + int target_duration; std::string m3u8; private: ISrsHlsHandler* handler; diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index df7118d05..ce2e07a8e 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 115 +#define VERSION_REVISION 116 // server info. #define RTMP_SIG_SRS_KEY "SRS"