diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index c26ab4cd0..cde87f82f 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -13,6 +13,8 @@ vhost __defaultVhost__ { gop_cache on; hls on; hls_path ./objs/nginx/html; + hls_fragment 10; + hls_window 60; } # the vhost disabled. vhost removed.vhost.com { @@ -39,6 +41,12 @@ vhost no-hls.vhost.com { # in a word, the hls_path is for vhost. # default: ./objs/nginx/html hls_path /data/nginx/html; + # the hls fragment in seconds, the duration of a piece of ts. + # default: 10 + hls_fragment 10; + # the hls window in seconds, the number of ts in m3u8. + # default: 60 + hls_window 60; } # the vhost with hls disabled. vhost no-hls.vhost.com { diff --git a/trunk/src/core/srs_core_client.cpp b/trunk/src/core/srs_core_client.cpp index 4df02c14c..ee10425c1 100644 --- a/trunk/src/core/srs_core_client.cpp +++ b/trunk/src/core/srs_core_client.cpp @@ -332,7 +332,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); // notify the hls to prepare when publish start. - if ((ret = source->on_publish(req->vhost, req->stream)) != ERROR_SUCCESS) { + if ((ret = source->on_publish(req->vhost, req->app, req->stream)) != ERROR_SUCCESS) { srs_error("hls on_publish failed. ret=%d", ret); return ret; } diff --git a/trunk/src/core/srs_core_error.hpp b/trunk/src/core/srs_core_error.hpp index ccb8f1540..dc421a64d 100644 --- a/trunk/src/core/srs_core_error.hpp +++ b/trunk/src/core/srs_core_error.hpp @@ -109,7 +109,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_HLS_METADATA 600 #define ERROR_HLS_DECODE_ERROR 601 -//#define ERROR_HLS_BUSY 602 +#define ERROR_HLS_CREATE_DIR 602 #define ERROR_HLS_OPEN_FAILED 603 #define ERROR_HLS_WRITE_FAILED 604 #define ERROR_HLS_AAC_FRAME_LENGTH 605 diff --git a/trunk/src/core/srs_core_hls.cpp b/trunk/src/core/srs_core_hls.cpp index 522226dc6..b8020dc20 100644 --- a/trunk/src/core/srs_core_hls.cpp +++ b/trunk/src/core/srs_core_hls.cpp @@ -403,12 +403,13 @@ SrsHLS::~SrsHLS() srs_freep(video_frame); } -int SrsHLS::on_publish(std::string _vhost, std::string _stream) +int SrsHLS::on_publish(std::string _vhost, std::string _app, std::string _stream) { int ret = ERROR_SUCCESS; vhost = _vhost; stream = _stream; + app = _app; if ((ret = reopen()) != ERROR_SUCCESS) { return ret; @@ -555,6 +556,7 @@ int SrsHLS::on_video(SrsSharedPtrMessage* video) if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) { int64_t diff = stream_dts - m3u8_dts; // 10s. + // TODO: config it. if (diff / 90000 >= 10) { if ((ret = reopen()) != ERROR_SUCCESS) { return ret; @@ -590,6 +592,11 @@ int SrsHLS::reopen() hls_path = conf->arg0(); } + // create dir for app. + if ((ret = create_dir()) != ERROR_SUCCESS) { + return ret; + } + // start new segment. if (current) { current->duration = (stream_dts - current->segment_start_dts) / 90000.0; @@ -610,6 +617,8 @@ int SrsHLS::reopen() current->full_path = hls_path; current->full_path += "/"; + current->full_path += app; + current->full_path += "/"; current->full_path += filename; // TODO: support base url, and so on. @@ -619,7 +628,7 @@ int SrsHLS::reopen() srs_error("open hls muxer failed. ret=%d", ret); return ret; } - srs_trace("open HLS muxer success. vhost=%s, path=%s", vhost.c_str(), current->full_path.c_str()); + srs_info("open HLS muxer success. vhost=%s, path=%s", vhost.c_str(), current->full_path.c_str()); return ret; } @@ -628,16 +637,33 @@ int SrsHLS::refresh_m3u8() { int ret = ERROR_SUCCESS; + std::string m3u8_file = hls_path; + m3u8_file += "/"; + m3u8_file += app; + m3u8_file += "/"; + m3u8_file += stream; + m3u8_file += ".m3u8"; + + m3u8 = m3u8_file; + m3u8_file += ".temp"; + int fd = -1; - ret = _refresh_m3u8(fd); + ret = _refresh_m3u8(fd, m3u8_file); if (fd >= 0) { close(fd); + if (rename(m3u8_file.c_str(), m3u8.c_str()) < 0) { + ret = ERROR_HLS_WRITE_FAILED; + srs_error("rename m3u8 file failed. ret=%d", ret); + } } + // remove the temp file. + unlink(m3u8_file.c_str()); + return ret; } -int SrsHLS::_refresh_m3u8(int& fd) +int SrsHLS::_refresh_m3u8(int& fd, std::string m3u8_file) { int ret = ERROR_SUCCESS; @@ -646,19 +672,14 @@ int SrsHLS::_refresh_m3u8(int& fd) return ret; } - m3u8 = hls_path; - m3u8 += "/"; - m3u8 += stream; - m3u8 += ".m3u8"; - int flags = O_CREAT|O_WRONLY|O_TRUNC; mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; - if ((fd = ::open(m3u8.c_str(), flags, mode)) < 0) { + if ((fd = ::open(m3u8_file.c_str(), flags, mode)) < 0) { ret = ERROR_HLS_OPEN_FAILED; - srs_error("open m3u8 file %s failed. ret=%d", m3u8.c_str(), ret); + srs_error("open m3u8 file %s failed. ret=%d", m3u8_file.c_str(), ret); return ret; } - srs_info("open m3u8 file %s success.", m3u8.c_str()); + srs_info("open m3u8 file %s success.", m3u8_file.c_str()); // #EXTM3U\n#EXT-X-VERSION:3\n char header[] = { @@ -728,11 +749,34 @@ int SrsHLS::_refresh_m3u8(int& fd) } srs_verbose("write m3u8 segment uri success."); } - srs_info("write m3u8 %s success.", m3u8.c_str()); + srs_info("write m3u8 %s success.", m3u8_file.c_str()); return ret; } +int SrsHLS::create_dir() +{ + int ret = ERROR_SUCCESS; + + std::string app_dir = hls_path; + app_dir += "/"; + app_dir += app; + + // TODO: cleanup the dir when startup. + + mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH; + if (::mkdir(app_dir.c_str(), mode) < 0) { + if (errno != EEXIST) { + ret = ERROR_HLS_CREATE_DIR; + srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret); + return ret; + } + } + srs_info("create app dir %s success.", app_dir.c_str()); + + return ret; +} + SrsTSMuxer::SrsTSMuxer() { fd = -1; diff --git a/trunk/src/core/srs_core_hls.hpp b/trunk/src/core/srs_core_hls.hpp index 6ff684e1d..aed348871 100644 --- a/trunk/src/core/srs_core_hls.hpp +++ b/trunk/src/core/srs_core_hls.hpp @@ -72,6 +72,7 @@ class SrsHLS private: std::string vhost; std::string stream; + std::string app; std::string hls_path; private: int file_index; @@ -103,7 +104,7 @@ public: SrsHLS(); virtual ~SrsHLS(); public: - virtual int on_publish(std::string _vhost, std::string _stream); + virtual int on_publish(std::string _vhost, std::string _app, std::string _stream); virtual void on_unpublish(); virtual int on_meta_data(SrsOnMetaDataPacket* metadata); virtual int on_audio(SrsSharedPtrMessage* audio); @@ -111,7 +112,8 @@ public: private: virtual int reopen(); virtual int refresh_m3u8(); - virtual int _refresh_m3u8(int& fd); + virtual int _refresh_m3u8(int& fd, std::string m3u8_file); + virtual int create_dir(); }; class SrsTSMuxer diff --git a/trunk/src/core/srs_core_source.cpp b/trunk/src/core/srs_core_source.cpp index 16dc10263..560969eb2 100644 --- a/trunk/src/core/srs_core_source.cpp +++ b/trunk/src/core/srs_core_source.cpp @@ -452,9 +452,9 @@ int SrsSource::on_video(SrsCommonMessage* video) return ret; } -int SrsSource::on_publish(std::string vhost, std::string stream) +int SrsSource::on_publish(std::string vhost, std::string app, std::string stream) { - return hls->on_publish(vhost, stream); + return hls->on_publish(vhost, app, stream); } void SrsSource::on_unpublish() diff --git a/trunk/src/core/srs_core_source.hpp b/trunk/src/core/srs_core_source.hpp index 62f0bdc1f..b988b140a 100644 --- a/trunk/src/core/srs_core_source.hpp +++ b/trunk/src/core/srs_core_source.hpp @@ -166,7 +166,7 @@ public: virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); virtual int on_audio(SrsCommonMessage* audio); virtual int on_video(SrsCommonMessage* video); - virtual int on_publish(std::string vhost, std::string stream); + virtual int on_publish(std::string vhost, std::string app, std::string stream); virtual void on_unpublish(); public: virtual int create_consumer(SrsConsumer*& consumer);