diff --git a/README.md b/README.md
index f9ec9c7f8..7103aa146 100755
--- a/README.md
+++ b/README.md
@@ -62,8 +62,8 @@ m3u8 url: http://127.0.0.1:1935/live/livestream.m3u8
* nginx v1.5.0: 139524 lines
### History
-* v0.5, 2013-11-24, support HLS(m3u8).
-* v0.5, 2013-11-24, support write ts file.
+* v0.5, 2013-11-24, support HLS(m3u8), fragment and window.
+* v0.5, 2013-11-24, support record to ts file for HLS.
* v0.5, 2013-11-21, add ts_info tool to demux ts file.
* v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6).
* v0.4, 2013-11-10, v0.4 released. 12500 lines.
diff --git a/trunk/src/core/srs_core_config.cpp b/trunk/src/core/srs_core_config.cpp
index 50d809654..e8dde1853 100644
--- a/trunk/src/core/srs_core_config.cpp
+++ b/trunk/src/core/srs_core_config.cpp
@@ -595,6 +595,28 @@ SrsConfDirective* SrsConfig::get_hls_path(std::string vhost)
return conf->get("hls_path");
}
+SrsConfDirective* SrsConfig::get_hls_fragment(std::string vhost)
+{
+ SrsConfDirective* conf = get_vhost(vhost);
+
+ if (!conf) {
+ return NULL;
+ }
+
+ return conf->get("hls_fragment");
+}
+
+SrsConfDirective* SrsConfig::get_hls_window(std::string vhost)
+{
+ SrsConfDirective* conf = get_vhost(vhost);
+
+ if (!conf) {
+ return NULL;
+ }
+
+ return conf->get("hls_window");
+}
+
SrsConfDirective* SrsConfig::get_refer(std::string vhost)
{
SrsConfDirective* conf = get_vhost(vhost);
diff --git a/trunk/src/core/srs_core_config.hpp b/trunk/src/core/srs_core_config.hpp
index 32d7d910a..2c0adeb88 100644
--- a/trunk/src/core/srs_core_config.hpp
+++ b/trunk/src/core/srs_core_config.hpp
@@ -38,6 +38,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define RTMP_VHOST_DEFAULT "__defaultVhost__"
#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
+#define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
+#define SRS_CONF_DEFAULT_HLS_WINDOW 60
class SrsFileBuffer
{
@@ -111,6 +113,8 @@ public:
virtual SrsConfDirective* get_gop_cache(std::string vhost);
virtual SrsConfDirective* get_hls(std::string vhost);
virtual SrsConfDirective* get_hls_path(std::string vhost);
+ virtual SrsConfDirective* get_hls_fragment(std::string vhost);
+ virtual SrsConfDirective* get_hls_window(std::string vhost);
virtual SrsConfDirective* get_refer(std::string vhost);
virtual SrsConfDirective* get_refer_play(std::string vhost);
virtual SrsConfDirective* get_refer_publish(std::string vhost);
diff --git a/trunk/src/core/srs_core_hls.cpp b/trunk/src/core/srs_core_hls.cpp
index b8020dc20..b34a3022f 100644
--- a/trunk/src/core/srs_core_hls.cpp
+++ b/trunk/src/core/srs_core_hls.cpp
@@ -370,6 +370,7 @@ SrsHLS::SrsHLS()
jitter = new SrsRtmpJitter();
file_index = 0;
m3u8_dts = stream_dts = 0;
+ hls_fragment = hls_window = 0;
audio_buffer = new SrsCodecBuffer();
video_buffer = new SrsCodecBuffer();
@@ -411,6 +412,23 @@ int SrsHLS::on_publish(std::string _vhost, std::string _app, std::string _stream
stream = _stream;
app = _app;
+ // TODO: subscribe the reload event.
+
+ SrsConfDirective* conf = NULL;
+ if ((conf = config->get_hls_fragment(vhost)) != NULL && !conf->arg0().empty()) {
+ hls_fragment = ::atoi(conf->arg0().c_str());
+ }
+ if (hls_fragment <= 0) {
+ hls_fragment = SRS_CONF_DEFAULT_HLS_FRAGMENT;
+ }
+
+ if ((conf = config->get_hls_window(vhost)) != NULL && !conf->arg0().empty()) {
+ hls_window = ::atoi(conf->arg0().c_str());
+ }
+ if (hls_window <= 0) {
+ hls_window = SRS_CONF_DEFAULT_HLS_WINDOW;
+ }
+
if ((ret = reopen()) != ERROR_SUCCESS) {
return ret;
}
@@ -555,9 +573,7 @@ int SrsHLS::on_video(SrsSharedPtrMessage* video)
// reopen the muxer for a gop
if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) {
int64_t diff = stream_dts - m3u8_dts;
- // 10s.
- // TODO: config it.
- if (diff / 90000 >= 10) {
+ if (diff / 90000 >= hls_fragment) {
if ((ret = reopen()) != ERROR_SUCCESS) {
return ret;
}
@@ -603,12 +619,39 @@ int SrsHLS::reopen()
segments.push_back(current);
current = NULL;
+ // the segments to remove
+ std::vector segment_to_remove;
+
+ // shrink the segments.
+ double duration = 0;
+ std::vector::reverse_iterator it;
+ for (it = segments.rbegin(); it != segments.rend(); ++it) {
+ SrsM3u8Segment* segment = *it;
+ duration += segment->duration;
+
+ if ((int)duration > hls_window) {
+ segment_to_remove.push_back(segment);
+ }
+ }
+ if (!segment_to_remove.empty()) {
+ segments.erase(segments.begin(), segments.begin() + segment_to_remove.size());
+ }
+
+ // refresh the m3u8, donot contains the removed ts
if ((ret = refresh_m3u8()) != ERROR_SUCCESS) {
return ret;
}
+
+ // remove the ts file.
+ for (it = segment_to_remove.rbegin(); it != segment_to_remove.rend(); ++it) {
+ SrsM3u8Segment* segment = *it;
+ unlink(segment->full_path.c_str());
+ srs_freep(segment);
+ }
}
// new segment.
current = new SrsM3u8Segment();
+ current->sequence_no = file_index;
m3u8_dts = current->segment_start_dts = stream_dts;
// generate filename.
diff --git a/trunk/src/core/srs_core_hls.hpp b/trunk/src/core/srs_core_hls.hpp
index aed348871..e75b7198e 100644
--- a/trunk/src/core/srs_core_hls.hpp
+++ b/trunk/src/core/srs_core_hls.hpp
@@ -74,6 +74,8 @@ private:
std::string stream;
std::string app;
std::string hls_path;
+ int hls_fragment;
+ int hls_window;
private:
int file_index;
std::string m3u8;