winlin

enhanced hls, support deviation for duration. 2.0.151.

@@ -562,6 +562,7 @@ Supported operating systems and hardware: @@ -562,6 +562,7 @@ Supported operating systems and hardware:
562 562
563 ### SRS 2.0 history 563 ### SRS 2.0 history
564 564
  565 +* v2.0, 2015-03-31, enhanced hls, support deviation for duration. 2.0.151.
565 * v2.0, 2015-03-30, for [#351](https://github.com/winlinvip/simple-rtmp-server/issues/351), support config the m3u8/ts path for hls. 2.0.149. 566 * v2.0, 2015-03-30, for [#351](https://github.com/winlinvip/simple-rtmp-server/issues/351), support config the m3u8/ts path for hls. 2.0.149.
566 * v2.0, 2015-03-17, for [#155](https://github.com/winlinvip/simple-rtmp-server/issues/155), osx(darwin) support demo with nginx and ffmpeg. 2.0.143. 567 * v2.0, 2015-03-17, for [#155](https://github.com/winlinvip/simple-rtmp-server/issues/155), osx(darwin) support demo with nginx and ffmpeg. 2.0.143.
567 * v2.0, 2015-03-15, start [2.0release branch](https://github.com/winlinvip/simple-rtmp-server/tree/2.0release), 80773 lines. 568 * v2.0, 2015-03-15, start [2.0release branch](https://github.com/winlinvip/simple-rtmp-server/tree/2.0release), 80773 lines.
@@ -560,6 +560,11 @@ vhost with-hls.srs.com { @@ -560,6 +560,11 @@ vhost with-hls.srs.com {
560 # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#hls-config 560 # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#hls-config
561 # default: [app]/[stream]-[seq].ts 561 # default: [app]/[stream]-[seq].ts
562 hls_ts_file [app]/[stream]-[seq].ts; 562 hls_ts_file [app]/[stream]-[seq].ts;
  563 + # whether use floor for the hls_ts_file path generation.
  564 + # if on, use floor(timestamp/hls_fragment) as the variable [timestamp],
  565 + # and use enahanced algorithm to calc deviation for segment.
  566 + # default: off
  567 + hls_ts_floor off;
563 # the hls entry prefix, which is base url of ts url. 568 # the hls entry prefix, which is base url of ts url.
564 # if specified, the ts path in m3u8 will be like: 569 # if specified, the ts path in m3u8 will be like:
565 # http://your-server/live/livestream-0.ts 570 # http://your-server/live/livestream-0.ts
@@ -588,6 +593,11 @@ vhost with-hls.srs.com { @@ -588,6 +593,11 @@ vhost with-hls.srs.com {
588 # h264, vn 593 # h264, vn
589 # default: h264 594 # default: h264
590 hls_vcodec h264; 595 hls_vcodec h264;
  596 +
  597 + # on_hls, never config in here, should config in http_hooks.
  598 + # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com
  599 + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#http-callback
  600 + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#http-callback
591 } 601 }
592 } 602 }
593 # the vhost with hls disabled. 603 # the vhost with hls disabled.
@@ -722,6 +732,20 @@ vhost hooks.callback.srs.com { @@ -722,6 +732,20 @@ vhost hooks.callback.srs.com {
722 # an int value specifies the error code(0 corresponding to success): 732 # an int value specifies the error code(0 corresponding to success):
723 # 0 733 # 0
724 on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs; 734 on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
  735 + # when srs reap a ts file of hls, call the hook,
  736 + # the request in the POST data string is a object encode by json:
  737 + # {
  738 + # "action": "on_hls",
  739 + # "client_id": 1985,
  740 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  741 + # "stream": "livestream",
  742 + # "cwd": "/usr/local/srs",
  743 + # "file": "./objs/nginx/html/live/livestream.1420254068776-100.ts"
  744 + # }
  745 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  746 + # an int value specifies the error code(0 corresponding to success):
  747 + # 0
  748 + on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls;
725 } 749 }
726 } 750 }
727 751
@@ -1482,7 +1482,7 @@ int SrsConfig::check_config() @@ -1482,7 +1482,7 @@ int SrsConfig::check_config()
1482 string m = conf->at(j)->name.c_str(); 1482 string m = conf->at(j)->name.c_str();
1483 if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" 1483 if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
1484 && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" 1484 && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
1485 - && m != "hls_m3u8_file" && m != "hls_ts_file" 1485 + && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor"
1486 ) { 1486 ) {
1487 ret = ERROR_SYSTEM_CONFIG_INVALID; 1487 ret = ERROR_SYSTEM_CONFIG_INVALID;
1488 srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); 1488 srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
@@ -3207,6 +3207,23 @@ string SrsConfig::get_hls_ts_file(string vhost) @@ -3207,6 +3207,23 @@ string SrsConfig::get_hls_ts_file(string vhost)
3207 return conf->arg0(); 3207 return conf->arg0();
3208 } 3208 }
3209 3209
  3210 +bool SrsConfig::get_hls_ts_floor(string vhost)
  3211 +{
  3212 + SrsConfDirective* hls = get_hls(vhost);
  3213 +
  3214 + if (!hls) {
  3215 + return SRS_CONF_DEFAULT_HLS_TS_FLOOR;
  3216 + }
  3217 +
  3218 + SrsConfDirective* conf = hls->get("hls_ts_floor");
  3219 +
  3220 + if (!conf || conf->arg0() != "on") {
  3221 + return SRS_CONF_DEFAULT_HLS_TS_FLOOR;
  3222 + }
  3223 +
  3224 + return true;
  3225 +}
  3226 +
3210 double SrsConfig::get_hls_fragment(string vhost) 3227 double SrsConfig::get_hls_fragment(string vhost)
3211 { 3228 {
3212 SrsConfDirective* hls = get_hls(vhost); 3229 SrsConfDirective* hls = get_hls(vhost);
@@ -48,6 +48,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -48,6 +48,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" 48 #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
49 #define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8" 49 #define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8"
50 #define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts" 50 #define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts"
  51 +#define SRS_CONF_DEFAULT_HLS_TS_FLOOR "off"
51 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 52 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
52 #define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5 53 #define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5
53 #define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0 54 #define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0
@@ -885,6 +886,10 @@ public: @@ -885,6 +886,10 @@ public:
885 */ 886 */
886 virtual std::string get_hls_ts_file(std::string vhost); 887 virtual std::string get_hls_ts_file(std::string vhost);
887 /** 888 /**
  889 + * whether enable the floor(timestamp/hls_fragment) for variable timestamp.
  890 + */
  891 + virtual bool get_hls_ts_floor(std::string vhost);
  892 + /**
888 * get the hls fragment time, in seconds. 893 * get the hls fragment time, in seconds.
889 */ 894 */
890 virtual double get_hls_fragment(std::string vhost); 895 virtual double get_hls_fragment(std::string vhost);
@@ -58,6 +58,11 @@ using namespace std; @@ -58,6 +58,11 @@ using namespace std;
58 // drop the segment when duration of ts too small. 58 // drop the segment when duration of ts too small.
59 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 59 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
60 60
  61 +// startup piece, the first piece, fragment percent to reap.
  62 +#define SRS_HLS_FLOOR_STARTUP_PERCENT 0.1
  63 +// fragment plus the deviation percent.
  64 +#define SRS_HLS_FLOOR_REAP_PERCENT 0.9
  65 +
61 ISrsHlsHandler::ISrsHlsHandler() 66 ISrsHlsHandler::ISrsHlsHandler()
62 { 67 {
63 } 68 }
@@ -170,6 +175,8 @@ SrsHlsMuxer::SrsHlsMuxer() @@ -170,6 +175,8 @@ SrsHlsMuxer::SrsHlsMuxer()
170 handler = NULL; 175 handler = NULL;
171 hls_fragment = hls_window = 0; 176 hls_fragment = hls_window = 0;
172 hls_aof_ratio = 1.0; 177 hls_aof_ratio = 1.0;
  178 + hls_fragment_deviation = 0;
  179 + hls_ts_floor = false;
173 target_duration = 0; 180 target_duration = 0;
174 _sequence_no = 0; 181 _sequence_no = 0;
175 current = NULL; 182 current = NULL;
@@ -205,8 +212,24 @@ int SrsHlsMuxer::sequence_no() @@ -205,8 +212,24 @@ int SrsHlsMuxer::sequence_no()
205 return _sequence_no; 212 return _sequence_no;
206 } 213 }
207 214
  215 +string SrsHlsMuxer::ts_url()
  216 +{
  217 + return current? current->uri:"";
  218 +}
  219 +
  220 +double SrsHlsMuxer::duration()
  221 +{
  222 + return current? current->duration:0;
  223 +}
  224 +
  225 +double SrsHlsMuxer::deviation()
  226 +{
  227 + return hls_fragment_deviation;
  228 +}
  229 +
208 int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, 230 int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
209 - string path, string m3u8_file, string ts_file, int fragment, int window, double aof_ratio 231 + string path, string m3u8_file, string ts_file, double fragment, double window,
  232 + bool ts_floor, double aof_ratio
210 ) { 233 ) {
211 int ret = ERROR_SUCCESS; 234 int ret = ERROR_SUCCESS;
212 235
@@ -218,7 +241,11 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, @@ -218,7 +241,11 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
218 hls_ts_file = ts_file; 241 hls_ts_file = ts_file;
219 hls_fragment = fragment; 242 hls_fragment = fragment;
220 hls_aof_ratio = aof_ratio; 243 hls_aof_ratio = aof_ratio;
  244 + hls_ts_floor = ts_floor;
221 hls_window = window; 245 hls_window = window;
  246 + // for the first time, we set to -N% of fragment,
  247 + // that is, the first piece always smaller.
  248 + hls_fragment_deviation = -1 * (fragment * SRS_HLS_FLOOR_STARTUP_PERCENT);
222 249
223 // generate the m3u8 dir and path. 250 // generate the m3u8 dir and path.
224 m3u8 = path + "/" + m3u8_file; 251 m3u8 = path + "/" + m3u8_file;
@@ -301,6 +328,11 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -301,6 +328,11 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
301 // generate filename. 328 // generate filename.
302 std::string ts_file = hls_ts_file; 329 std::string ts_file = hls_ts_file;
303 ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream); 330 ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream);
  331 + if (hls_ts_floor) {
  332 + std::stringstream ts_floor;
  333 + ts_floor << (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment));
  334 + ts_file = srs_string_replace(ts_file, "[timestamp]", ts_floor.str());
  335 + }
304 ts_file = srs_path_build_timestamp(ts_file); 336 ts_file = srs_path_build_timestamp(ts_file);
305 if (true) { 337 if (true) {
306 std::stringstream ss; 338 std::stringstream ss;
@@ -308,6 +340,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -308,6 +340,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
308 ts_file = srs_string_replace(ts_file, "[seq]", ss.str()); 340 ts_file = srs_string_replace(ts_file, "[seq]", ss.str());
309 } 341 }
310 current->full_path = hls_path + "/" + ts_file; 342 current->full_path = hls_path + "/" + ts_file;
  343 + srs_info("hls: generate ts path %s, tmpl=%s, floor=%d", ts_file.c_str(), hls_ts_file.c_str(), hls_ts_floor);
311 344
312 // the ts url, relative or absolute url. 345 // the ts url, relative or absolute url.
313 std::string ts_url = current->full_path; 346 std::string ts_url = current->full_path;
@@ -336,7 +369,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -336,7 +369,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
336 srs_error("open hls muxer failed. ret=%d", ret); 369 srs_error("open hls muxer failed. ret=%d", ret);
337 return ret; 370 return ret;
338 } 371 }
339 - srs_info("open HLS muxer success. path=%s, tmp=%s", 372 + srs_info("open HLS muxer success. path=%s, tmp=%s",
340 current->full_path.c_str(), tmp_file.c_str()); 373 current->full_path.c_str(), tmp_file.c_str());
341 374
342 // set the segment muxer audio codec. 375 // set the segment muxer audio codec.
@@ -363,14 +396,22 @@ int SrsHlsMuxer::on_sequence_header() @@ -363,14 +396,22 @@ int SrsHlsMuxer::on_sequence_header()
363 bool SrsHlsMuxer::is_segment_overflow() 396 bool SrsHlsMuxer::is_segment_overflow()
364 { 397 {
365 srs_assert(current); 398 srs_assert(current);
366 - return current->duration >= hls_fragment; 399 +
  400 + // use N% deviation, to smoother.
  401 + double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * hls_fragment_deviation : 0.0;
  402 +
  403 + return current->duration >= hls_fragment + deviation;
367 } 404 }
368 405
369 bool SrsHlsMuxer::is_segment_absolutely_overflow() 406 bool SrsHlsMuxer::is_segment_absolutely_overflow()
370 { 407 {
371 // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950 408 // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950
372 srs_assert(current); 409 srs_assert(current);
373 - return current->duration >= hls_aof_ratio * hls_fragment; 410 +
  411 + // use N% deviation, to smoother.
  412 + double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * hls_fragment_deviation : 0.0;
  413 +
  414 + return current->duration >= hls_aof_ratio * (hls_fragment + deviation);
374 } 415 }
375 416
376 int SrsHlsMuxer::update_acodec(SrsCodecAudio ac) 417 int SrsHlsMuxer::update_acodec(SrsCodecAudio ac)
@@ -457,10 +498,15 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -457,10 +498,15 @@ int SrsHlsMuxer::segment_close(string log_desc)
457 // valid, add to segments if segment duration is ok 498 // valid, add to segments if segment duration is ok
458 if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { 499 if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) {
459 segments.push_back(current); 500 segments.push_back(current);
  501 +
  502 + // when reap ts, adjust the deviation.
  503 + if (hls_ts_floor) {
  504 + hls_fragment_deviation += (double)(hls_fragment - current->duration);
  505 + }
460 506
461 - srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64"", 507 + srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64", deviation=%.2f",
462 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration, 508 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration,
463 - current->segment_start_dts); 509 + current->segment_start_dts, hls_fragment_deviation);
464 510
465 // notify handler for update ts. 511 // notify handler for update ts.
466 srs_assert(current->writer); 512 srs_assert(current->writer);
@@ -505,7 +551,7 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -505,7 +551,7 @@ int SrsHlsMuxer::segment_close(string log_desc)
505 // shrink the segments. 551 // shrink the segments.
506 double duration = 0; 552 double duration = 0;
507 int remove_index = -1; 553 int remove_index = -1;
508 - for (int i = segments.size() - 1; i >= 0; i--) { 554 + for (int i = (int)segments.size() - 1; i >= 0; i--) {
509 SrsHlsSegment* segment = segments[i]; 555 SrsHlsSegment* segment = segments[i];
510 duration += segment->duration; 556 duration += segment->duration;
511 557
@@ -662,8 +708,8 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -662,8 +708,8 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
662 std::string stream = req->stream; 708 std::string stream = req->stream;
663 std::string app = req->app; 709 std::string app = req->app;
664 710
665 - int hls_fragment = (int)_srs_config->get_hls_fragment(vhost);  
666 - int hls_window = (int)_srs_config->get_hls_window(vhost); 711 + double hls_fragment = _srs_config->get_hls_fragment(vhost);
  712 + double hls_window = _srs_config->get_hls_window(vhost);
667 713
668 // get the hls m3u8 ts list entry prefix config 714 // get the hls m3u8 ts list entry prefix config
669 std::string entry_prefix = _srs_config->get_hls_entry_prefix(vhost); 715 std::string entry_prefix = _srs_config->get_hls_entry_prefix(vhost);
@@ -673,12 +719,16 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -673,12 +719,16 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
673 std::string ts_file = _srs_config->get_hls_ts_file(vhost); 719 std::string ts_file = _srs_config->get_hls_ts_file(vhost);
674 // the audio overflow, for pure audio to reap segment. 720 // the audio overflow, for pure audio to reap segment.
675 double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost); 721 double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost);
  722 + // whether use floor(timestamp/hls_fragment) for variable timestamp
  723 + bool ts_floor = _srs_config->get_hls_ts_floor(vhost);
676 724
677 // TODO: FIXME: support load exists m3u8, to continue publish stream. 725 // TODO: FIXME: support load exists m3u8, to continue publish stream.
678 // for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase. 726 // for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase.
679 727
680 // open muxer 728 // open muxer
681 - if ((ret = muxer->update_config(req, entry_prefix, path, m3u8_file, ts_file, hls_fragment, hls_window, hls_aof_ratio)) != ERROR_SUCCESS) { 729 + if ((ret = muxer->update_config(req, entry_prefix,
  730 + path, m3u8_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio)) != ERROR_SUCCESS
  731 + ) {
682 srs_error("m3u8 muxer update config failed. ret=%d", ret); 732 srs_error("m3u8 muxer update config failed. ret=%d", ret);
683 return ret; 733 return ret;
684 } 734 }
@@ -687,6 +737,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -687,6 +737,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
687 srs_error("m3u8 muxer open segment failed. ret=%d", ret); 737 srs_error("m3u8 muxer open segment failed. ret=%d", ret);
688 return ret; 738 return ret;
689 } 739 }
  740 + srs_trace("hls: win=%.2f, frag=%.2f, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d",
  741 + hls_window, hls_fragment, entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(),
  742 + ts_file.c_str(), hls_aof_ratio, ts_floor);
690 743
691 return ret; 744 return ret;
692 } 745 }
@@ -1057,9 +1110,9 @@ void SrsHls::hls_show_mux_log() @@ -1057,9 +1110,9 @@ void SrsHls::hls_show_mux_log()
1057 // the run time is not equals to stream time, 1110 // the run time is not equals to stream time,
1058 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994 1111 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994
1059 // it's ok. 1112 // it's ok.
1060 - srs_trace("-> "SRS_CONSTS_LOG_HLS  
1061 - " time=%"PRId64", stream dts=%"PRId64"(%"PRId64"ms), sequence_no=%d",  
1062 - pprint->age(), stream_dts, stream_dts / 90, muxer->sequence_no()); 1113 + srs_trace("-> "SRS_CONSTS_LOG_HLS" time=%"PRId64", stream dts=%"PRId64"(%"PRId64"ms), sequence_no=%d, ts=%s, duration=%.2f, deviation=%.2f",
  1114 + pprint->age(), stream_dts, stream_dts / 90, muxer->sequence_no(), muxer->ts_url().c_str(),
  1115 + muxer->duration(), muxer->deviation());
1063 } 1116 }
1064 } 1117 }
1065 1118
@@ -172,8 +172,14 @@ private: @@ -172,8 +172,14 @@ private:
172 std::string hls_ts_file; 172 std::string hls_ts_file;
173 std::string m3u8_dir; 173 std::string m3u8_dir;
174 double hls_aof_ratio; 174 double hls_aof_ratio;
175 - int hls_fragment;  
176 - int hls_window; 175 + double hls_fragment;
  176 + double hls_window;
  177 +private:
  178 + // whether use floor algorithm for timestamp.
  179 + bool hls_ts_floor;
  180 + // the deviation in seconds to adjust the fragment to be more
  181 + // bigger or smaller.
  182 + double hls_fragment_deviation;
177 private: 183 private:
178 int _sequence_no; 184 int _sequence_no;
179 int target_duration; 185 int target_duration;
@@ -203,6 +209,9 @@ public: @@ -203,6 +209,9 @@ public:
203 virtual ~SrsHlsMuxer(); 209 virtual ~SrsHlsMuxer();
204 public: 210 public:
205 virtual int sequence_no(); 211 virtual int sequence_no();
  212 + virtual std::string ts_url();
  213 + virtual double duration();
  214 + virtual double deviation();
206 public: 215 public:
207 /** 216 /**
208 * initialize the hls muxer. 217 * initialize the hls muxer.
@@ -213,7 +222,7 @@ public: @@ -213,7 +222,7 @@ public:
213 */ 222 */
214 virtual int update_config(SrsRequest* r, std::string entry_prefix, 223 virtual int update_config(SrsRequest* r, std::string entry_prefix,
215 std::string path, std::string m3u8_file, std::string ts_file, 224 std::string path, std::string m3u8_file, std::string ts_file,
216 - int fragment, int window, double aof_ratio); 225 + double fragment, double window, bool ts_floor, double aof_ratio);
217 /** 226 /**
218 * open a new segment(a new ts file), 227 * open a new segment(a new ts file),
219 * @param segment_start_dts use to calc the segment duration, 228 * @param segment_start_dts use to calc the segment duration,
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 149 34 +#define VERSION_REVISION 151
35 35
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"