winlin

for #351, support config the m3u8/ts path for hls. 2.0.149.

@@ -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-30, for [#351](https://github.com/winlinvip/simple-rtmp-server/issues/351), support config the m3u8/ts path for hls. 2.0.149.
565 * 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. 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.
566 * v2.0, 2015-03-15, start [2.0release branch](https://github.com/winlinvip/simple-rtmp-server/tree/2.0release), 80773 lines. 567 * v2.0, 2015-03-15, start [2.0release branch](https://github.com/winlinvip/simple-rtmp-server/tree/2.0release), 80773 lines.
567 * v2.0, 2015-03-14, fix [#324](https://github.com/winlinvip/simple-rtmp-server/issues/324), support hstrs(http stream trigger rtmp source) edge mode. 2.0.140. 568 * v2.0, 2015-03-14, fix [#324](https://github.com/winlinvip/simple-rtmp-server/issues/324), support hstrs(http stream trigger rtmp source) edge mode. 2.0.140.
@@ -528,17 +528,38 @@ vhost with-hls.srs.com { @@ -528,17 +528,38 @@ vhost with-hls.srs.com {
528 # default: disk 528 # default: disk
529 hls_storage disk; 529 hls_storage disk;
530 # the hls output path. 530 # the hls output path.
531 - # the app dir is auto created under the hls_path.  
532 - # for example, for rtmp stream:  
533 - # rtmp://127.0.0.1/live/livestream  
534 - # http://127.0.0.1/live/livestream.m3u8  
535 - # where hls_path is /hls, srs will create the following files:  
536 - # /hls/live the app dir for all streams.  
537 - # /hls/live/livestream.m3u8 the HLS m3u8 file.  
538 - # /hls/live/livestream-1.ts the HLS media/ts file.  
539 - # in a word, the hls_path is for vhost. 531 + # the m3u8 file is configed by hls_path/hls_m3u8_file, the default is:
  532 + # ./objs/nginx/html/[app]/[stream].m3u8
  533 + # the ts file is configed by hls_path/hls_ts_file, the default is:
  534 + # ./objs/nginx/html/[app]/[stream]-[seq].ts
  535 + # @remark the hls_path is compatible with srs v1 config.
540 # default: ./objs/nginx/html 536 # default: ./objs/nginx/html
541 hls_path ./objs/nginx/html; 537 hls_path ./objs/nginx/html;
  538 + # the hls m3u8 file name.
  539 + # we supports some variables to generate the filename.
  540 + # [vhost], the vhost of stream.
  541 + # [app], the app of stream.
  542 + # [stream], the stream name of stream.
  543 + # default: [app]/[stream].m3u8
  544 + hls_m3u8_file [app]/[stream].m3u8;
  545 + # the hls ts file name.
  546 + # we supports some variables to generate the filename.
  547 + # [vhost], the vhost of stream.
  548 + # [app], the app of stream.
  549 + # [stream], the stream name of stream.
  550 + # [2006], replace this const to current year.
  551 + # [01], replace this const to current month.
  552 + # [02], replace this const to current date.
  553 + # [15], replace this const to current hour.
  554 + # [04], repleace this const to current minute.
  555 + # [05], repleace this const to current second.
  556 + # [999], repleace this const to current millisecond.
  557 + # [timestamp],replace this const to current UNIX timestamp in ms.
  558 + # [seq], the sequence number of ts.
  559 + # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
  560 + # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#hls-config
  561 + # default: [app]/[stream]-[seq].ts
  562 + hls_ts_file [app]/[stream]-[seq].ts;
542 # the hls entry prefix, which is base url of ts url. 563 # the hls entry prefix, which is base url of ts url.
543 # if specified, the ts path in m3u8 will be like: 564 # if specified, the ts path in m3u8 will be like:
544 # http://your-server/live/livestream-0.ts 565 # http://your-server/live/livestream-0.ts
@@ -10,5 +10,7 @@ vhost __defaultVhost__ { @@ -10,5 +10,7 @@ vhost __defaultVhost__ {
10 hls_fragment 10; 10 hls_fragment 10;
11 hls_window 60; 11 hls_window 60;
12 hls_path ./objs/nginx/html; 12 hls_path ./objs/nginx/html;
  13 + hls_m3u8_file [app]/[stream].m3u8;
  14 + hls_ts_file [app]/[stream]-[seq].ts;
13 } 15 }
14 } 16 }
@@ -12,8 +12,10 @@ http_server { @@ -12,8 +12,10 @@ http_server {
12 vhost __defaultVhost__ { 12 vhost __defaultVhost__ {
13 hls { 13 hls {
14 enabled on; 14 enabled on;
15 - hls_path ./objs/nginx/html;  
16 hls_fragment 10; 15 hls_fragment 10;
17 hls_window 60; 16 hls_window 60;
  17 + hls_path ./objs/nginx/html;
  18 + hls_m3u8_file [app]/[stream].m3u8;
  19 + hls_ts_file [app]/[stream]-[seq].ts;
18 } 20 }
19 } 21 }
@@ -7,9 +7,11 @@ max_connections 1000; @@ -7,9 +7,11 @@ max_connections 1000;
7 vhost __defaultVhost__ { 7 vhost __defaultVhost__ {
8 hls { 8 hls {
9 enabled on; 9 enabled on;
10 - hls_path ./objs/nginx/html;  
11 hls_fragment 10; 10 hls_fragment 10;
12 hls_window 60; 11 hls_window 60;
  12 + hls_path ./objs/nginx/html;
  13 + hls_m3u8_file [app]/[stream].m3u8;
  14 + hls_ts_file [app]/[stream]-[seq].ts;
13 } 15 }
14 transcode { 16 transcode {
15 enabled on; 17 enabled on;
@@ -1482,6 +1482,7 @@ int SrsConfig::check_config() @@ -1482,6 +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 ) { 1486 ) {
1486 ret = ERROR_SYSTEM_CONFIG_INVALID; 1487 ret = ERROR_SYSTEM_CONFIG_INVALID;
1487 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);
@@ -3172,6 +3173,40 @@ string SrsConfig::get_hls_path(string vhost) @@ -3172,6 +3173,40 @@ string SrsConfig::get_hls_path(string vhost)
3172 return conf->arg0(); 3173 return conf->arg0();
3173 } 3174 }
3174 3175
  3176 +string SrsConfig::get_hls_m3u8_file(string vhost)
  3177 +{
  3178 + SrsConfDirective* hls = get_hls(vhost);
  3179 +
  3180 + if (!hls) {
  3181 + return SRS_CONF_DEFAULT_HLS_M3U8_FILE;
  3182 + }
  3183 +
  3184 + SrsConfDirective* conf = hls->get("hls_m3u8_file");
  3185 +
  3186 + if (!conf) {
  3187 + return SRS_CONF_DEFAULT_HLS_M3U8_FILE;
  3188 + }
  3189 +
  3190 + return conf->arg0();
  3191 +}
  3192 +
  3193 +string SrsConfig::get_hls_ts_file(string vhost)
  3194 +{
  3195 + SrsConfDirective* hls = get_hls(vhost);
  3196 +
  3197 + if (!hls) {
  3198 + return SRS_CONF_DEFAULT_HLS_TS_FILE;
  3199 + }
  3200 +
  3201 + SrsConfDirective* conf = hls->get("hls_ts_file");
  3202 +
  3203 + if (!conf) {
  3204 + return SRS_CONF_DEFAULT_HLS_TS_FILE;
  3205 + }
  3206 +
  3207 + return conf->arg0();
  3208 +}
  3209 +
3175 double SrsConfig::get_hls_fragment(string vhost) 3210 double SrsConfig::get_hls_fragment(string vhost)
3176 { 3211 {
3177 SrsConfDirective* hls = get_hls(vhost); 3212 SrsConfDirective* hls = get_hls(vhost);
@@ -46,6 +46,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -46,6 +46,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 46
47 #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000 47 #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000
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"
  50 +#define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts"
49 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 51 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
50 #define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5 52 #define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5
51 #define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0 53 #define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0
@@ -875,6 +877,14 @@ public: @@ -875,6 +877,14 @@ public:
875 */ 877 */
876 virtual std::string get_hls_path(std::string vhost); 878 virtual std::string get_hls_path(std::string vhost);
877 /** 879 /**
  880 + * get the HLS m3u8 file path template.
  881 + */
  882 + virtual std::string get_hls_m3u8_file(std::string vhost);
  883 + /**
  884 + * get the HLS ts file path template.
  885 + */
  886 + virtual std::string get_hls_ts_file(std::string vhost);
  887 + /**
878 * get the hls fragment time, in seconds. 888 * get the hls fragment time, in seconds.
879 */ 889 */
880 virtual double get_hls_fragment(std::string vhost); 890 virtual double get_hls_fragment(std::string vhost);
@@ -27,7 +27,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -27,7 +27,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 27
28 #include <fcntl.h> 28 #include <fcntl.h>
29 #include <sstream> 29 #include <sstream>
30 -#include <sys/time.h>  
31 #include <algorithm> 30 #include <algorithm>
32 using namespace std; 31 using namespace std;
33 32
@@ -42,6 +41,7 @@ using namespace std; @@ -42,6 +41,7 @@ using namespace std;
42 #include <srs_rtmp_amf0.hpp> 41 #include <srs_rtmp_amf0.hpp>
43 #include <srs_kernel_stream.hpp> 42 #include <srs_kernel_stream.hpp>
44 #include <srs_app_json.hpp> 43 #include <srs_app_json.hpp>
  44 +#include <srs_app_utility.hpp>
45 45
46 // update the flv duration and filesize every this interval in ms. 46 // update the flv duration and filesize every this interval in ms.
47 #define SRS_DVR_UPDATE_DURATION_INTERVAL 60000 47 #define SRS_DVR_UPDATE_DURATION_INTERVAL 60000
@@ -422,76 +422,8 @@ string SrsFlvSegment::generate_path() @@ -422,76 +422,8 @@ string SrsFlvSegment::generate_path()
422 422
423 // the flv file path 423 // the flv file path
424 std::string flv_path = path_config; 424 std::string flv_path = path_config;
425 -  
426 - // variable [vhost]  
427 - flv_path = srs_string_replace(flv_path, "[vhost]", req->vhost);  
428 - // variable [app]  
429 - flv_path = srs_string_replace(flv_path, "[app]", req->app);  
430 - // variable [stream]  
431 - flv_path = srs_string_replace(flv_path, "[stream]", req->stream);  
432 -  
433 - // date and time substitude  
434 - // clock time  
435 - timeval tv;  
436 - if (gettimeofday(&tv, NULL) == -1) {  
437 - return flv_path;  
438 - }  
439 -  
440 - // to calendar time  
441 - struct tm* tm;  
442 - if ((tm = localtime(&tv.tv_sec)) == NULL) {  
443 - return flv_path;  
444 - }  
445 -  
446 - // the buffer to format the date and time.  
447 - char buf[64];  
448 -  
449 - // [2006], replace with current year.  
450 - if (true) {  
451 - snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);  
452 - flv_path = srs_string_replace(flv_path, "[2006]", buf);  
453 - }  
454 - // [2006], replace with current year.  
455 - if (true) {  
456 - snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);  
457 - flv_path = srs_string_replace(flv_path, "[2006]", buf);  
458 - }  
459 - // [01], replace this const to current month.  
460 - if (true) {  
461 - snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);  
462 - flv_path = srs_string_replace(flv_path, "[01]", buf);  
463 - }  
464 - // [02], replace this const to current date.  
465 - if (true) {  
466 - snprintf(buf, sizeof(buf), "%d", tm->tm_mday);  
467 - flv_path = srs_string_replace(flv_path, "[02]", buf);  
468 - }  
469 - // [15], replace this const to current hour.  
470 - if (true) {  
471 - snprintf(buf, sizeof(buf), "%d", tm->tm_hour);  
472 - flv_path = srs_string_replace(flv_path, "[15]", buf);  
473 - }  
474 - // [04], repleace this const to current minute.  
475 - if (true) {  
476 - snprintf(buf, sizeof(buf), "%d", tm->tm_min);  
477 - flv_path = srs_string_replace(flv_path, "[04]", buf);  
478 - }  
479 - // [05], repleace this const to current second.  
480 - if (true) {  
481 - snprintf(buf, sizeof(buf), "%d", tm->tm_sec);  
482 - flv_path = srs_string_replace(flv_path, "[05]", buf);  
483 - }  
484 - // [999], repleace this const to current millisecond.  
485 - if (true) {  
486 - snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));  
487 - flv_path = srs_string_replace(flv_path, "[999]", buf);  
488 - }  
489 - // [timestamp],replace this const to current UNIX timestamp in ms.  
490 - if (true) {  
491 - int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;  
492 - snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);  
493 - flv_path = srs_string_replace(flv_path, "[timestamp]", buf);  
494 - } 425 + flv_path = srs_path_build_stream(flv_path, req->vhost, req->app, req->stream);
  426 + flv_path = srs_path_build_timestamp(flv_path);
495 427
496 return flv_path; 428 return flv_path;
497 } 429 }
@@ -53,6 +53,7 @@ using namespace std; @@ -53,6 +53,7 @@ using namespace std;
53 #include <srs_kernel_file.hpp> 53 #include <srs_kernel_file.hpp>
54 #include <srs_rtmp_buffer.hpp> 54 #include <srs_rtmp_buffer.hpp>
55 #include <srs_kernel_ts.hpp> 55 #include <srs_kernel_ts.hpp>
  56 +#include <srs_app_utility.hpp>
56 57
57 // drop the segment when duration of ts too small. 58 // drop the segment when duration of ts too small.
58 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 59 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
@@ -204,8 +205,9 @@ int SrsHlsMuxer::sequence_no() @@ -204,8 +205,9 @@ int SrsHlsMuxer::sequence_no()
204 return _sequence_no; 205 return _sequence_no;
205 } 206 }
206 207
207 -int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, string path, int fragment, int window, double aof_ratio)  
208 -{ 208 +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
  210 +) {
209 int ret = ERROR_SUCCESS; 211 int ret = ERROR_SUCCESS;
210 212
211 srs_freep(req); 213 srs_freep(req);
@@ -213,6 +215,8 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, string path, @@ -213,6 +215,8 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, string path,
213 215
214 hls_entry_prefix = entry_prefix; 216 hls_entry_prefix = entry_prefix;
215 hls_path = path; 217 hls_path = path;
  218 + hls_m3u8_file = m3u8_file;
  219 + hls_ts_file = ts_file;
216 hls_fragment = fragment; 220 hls_fragment = fragment;
217 hls_aof_ratio = aof_ratio; 221 hls_aof_ratio = aof_ratio;
218 hls_window = window; 222 hls_window = window;
@@ -249,7 +253,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -249,7 +253,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
249 253
250 // TODO: create all parents dirs. 254 // TODO: create all parents dirs.
251 // create dir for app. 255 // create dir for app.
252 - if (should_write_file && (ret = create_dir()) != ERROR_SUCCESS) { 256 + if (should_write_file && (ret = create_dir(current->full_path)) != ERROR_SUCCESS) {
253 return ret; 257 return ret;
254 } 258 }
255 259
@@ -292,22 +296,23 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -292,22 +296,23 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
292 current->segment_start_dts = segment_start_dts; 296 current->segment_start_dts = segment_start_dts;
293 297
294 // generate filename. 298 // generate filename.
295 - char filename[128];  
296 - snprintf(filename, sizeof(filename),  
297 - "%s-%d.ts", req->stream.c_str(), current->sequence_no); 299 + std::string ts_file = hls_ts_file;
  300 + ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream);
  301 + ts_file = srs_path_build_timestamp(ts_file);
  302 + if (true) {
  303 + std::stringstream ss;
  304 + ss << current->sequence_no;
  305 + ts_file = srs_string_replace(ts_file, "[seq]", ss.str());
  306 + }
298 307
299 - // TODO: use temp file and rename it.  
300 - current->full_path = hls_path;  
301 - current->full_path += "/";  
302 - current->full_path += req->app;  
303 - current->full_path += "/";  
304 - current->full_path += filename; 308 + // replace variables
  309 + current->full_path = hls_path + "/" + ts_file;
305 310
306 current->uri += hls_entry_prefix; 311 current->uri += hls_entry_prefix;
307 if (!hls_entry_prefix.empty() && !srs_string_ends_with(hls_entry_prefix, "/")) { 312 if (!hls_entry_prefix.empty() && !srs_string_ends_with(hls_entry_prefix, "/")) {
308 current->uri += "/"; 313 current->uri += "/";
309 } 314 }
310 - current->uri += filename; 315 + current->uri += ts_file;
311 316
312 std::string tmp_file = current->full_path + ".tmp"; 317 std::string tmp_file = current->full_path + ".tmp";
313 if ((ret = current->muxer->open(tmp_file.c_str())) != ERROR_SUCCESS) { 318 if ((ret = current->muxer->open(tmp_file.c_str())) != ERROR_SUCCESS) {
@@ -524,10 +529,8 @@ int SrsHlsMuxer::refresh_m3u8() @@ -524,10 +529,8 @@ int SrsHlsMuxer::refresh_m3u8()
524 529
525 std::string m3u8_file = hls_path; 530 std::string m3u8_file = hls_path;
526 m3u8_file += "/"; 531 m3u8_file += "/";
527 - m3u8_file += req->app;  
528 - m3u8_file += "/";  
529 - m3u8_file += req->stream;  
530 - m3u8_file += ".m3u8"; 532 + m3u8_file += hls_m3u8_file;
  533 + m3u8_file = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
531 534
532 m3u8 = m3u8_file; 535 m3u8 = m3u8_file;
533 m3u8_file += ".temp"; 536 m3u8_file += ".temp";
@@ -631,7 +634,7 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file) @@ -631,7 +634,7 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
631 return ret; 634 return ret;
632 } 635 }
633 636
634 -int SrsHlsMuxer::create_dir() 637 +int SrsHlsMuxer::create_dir(string filepath)
635 { 638 {
636 int ret = ERROR_SUCCESS; 639 int ret = ERROR_SUCCESS;
637 640
@@ -639,9 +642,11 @@ int SrsHlsMuxer::create_dir() @@ -639,9 +642,11 @@ int SrsHlsMuxer::create_dir()
639 return ret; 642 return ret;
640 } 643 }
641 644
642 - std::string app_dir = hls_path;  
643 - app_dir += "/";  
644 - app_dir += req->app; 645 + std::string app_dir = filepath;
  646 + size_t pos = string::npos;
  647 + if ((pos = app_dir.rfind("/")) != string::npos) {
  648 + app_dir = app_dir.substr(0, pos);
  649 + }
645 650
646 // TODO: cleanup the dir when startup. 651 // TODO: cleanup the dir when startup.
647 652
@@ -678,7 +683,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -678,7 +683,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
678 // get the hls m3u8 ts list entry prefix config 683 // get the hls m3u8 ts list entry prefix config
679 std::string entry_prefix = _srs_config->get_hls_entry_prefix(vhost); 684 std::string entry_prefix = _srs_config->get_hls_entry_prefix(vhost);
680 // get the hls path config 685 // get the hls path config
681 - std::string hls_path = _srs_config->get_hls_path(vhost); 686 + std::string path = _srs_config->get_hls_path(vhost);
  687 + std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost);
  688 + std::string ts_file = _srs_config->get_hls_ts_file(vhost);
682 // the audio overflow, for pure audio to reap segment. 689 // the audio overflow, for pure audio to reap segment.
683 double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost); 690 double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost);
684 691
@@ -686,7 +693,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment @@ -686,7 +693,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
686 // for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase. 693 // for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase.
687 694
688 // open muxer 695 // open muxer
689 - if ((ret = muxer->update_config(req, entry_prefix, hls_path, hls_fragment, hls_window, hls_aof_ratio)) != ERROR_SUCCESS) { 696 + if ((ret = muxer->update_config(req, entry_prefix, path, m3u8_file, ts_file, hls_fragment, hls_window, hls_aof_ratio)) != ERROR_SUCCESS) {
690 srs_error("m3u8 muxer update config failed. ret=%d", ret); 697 srs_error("m3u8 muxer update config failed. ret=%d", ret);
691 return ret; 698 return ret;
692 } 699 }
@@ -169,6 +169,8 @@ private: @@ -169,6 +169,8 @@ private:
169 private: 169 private:
170 std::string hls_entry_prefix; 170 std::string hls_entry_prefix;
171 std::string hls_path; 171 std::string hls_path;
  172 + std::string hls_m3u8_file;
  173 + std::string hls_ts_file;
172 double hls_aof_ratio; 174 double hls_aof_ratio;
173 int hls_fragment; 175 int hls_fragment;
174 int hls_window; 176 int hls_window;
@@ -209,7 +211,9 @@ public: @@ -209,7 +211,9 @@ public:
209 /** 211 /**
210 * when publish, update the config for muxer. 212 * when publish, update the config for muxer.
211 */ 213 */
212 - virtual int update_config(SrsRequest* r, std::string entry_prefix, std::string path, int fragment, int window, double aof_ratio); 214 + virtual int update_config(SrsRequest* r, std::string entry_prefix,
  215 + std::string path, std::string m3u8_file, std::string ts_file,
  216 + int fragment, int window, double aof_ratio);
213 /** 217 /**
214 * open a new segment(a new ts file), 218 * open a new segment(a new ts file),
215 * @param segment_start_dts use to calc the segment duration, 219 * @param segment_start_dts use to calc the segment duration,
@@ -240,7 +244,7 @@ public: @@ -240,7 +244,7 @@ public:
240 private: 244 private:
241 virtual int refresh_m3u8(); 245 virtual int refresh_m3u8();
242 virtual int _refresh_m3u8(std::string m3u8_file); 246 virtual int _refresh_m3u8(std::string m3u8_file);
243 - virtual int create_dir(); 247 + virtual int create_dir(std::string filepath);
244 }; 248 };
245 249
246 /** 250 /**
@@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #include <sys/sysctl.h> 32 #include <sys/sysctl.h>
33 #endif 33 #endif
34 #include <stdlib.h> 34 #include <stdlib.h>
  35 +#include <sys/time.h>
35 using namespace std; 36 using namespace std;
36 37
37 #include <srs_kernel_log.hpp> 38 #include <srs_kernel_log.hpp>
@@ -111,6 +112,91 @@ int srs_get_log_level(string level) @@ -111,6 +112,91 @@ int srs_get_log_level(string level)
111 } 112 }
112 } 113 }
113 114
  115 +string srs_path_build_stream(string template_path, string vhost, string app, string stream)
  116 +{
  117 + std::string path = template_path;
  118 +
  119 + // variable [vhost]
  120 + path = srs_string_replace(path, "[vhost]", vhost);
  121 + // variable [app]
  122 + path = srs_string_replace(path, "[app]", app);
  123 + // variable [stream]
  124 + path = srs_string_replace(path, "[stream]", stream);
  125 +
  126 + return path;
  127 +}
  128 +
  129 +string srs_path_build_timestamp(string template_path)
  130 +{
  131 + std::string path = template_path;
  132 +
  133 +
  134 + // date and time substitude
  135 + // clock time
  136 + timeval tv;
  137 + if (gettimeofday(&tv, NULL) == -1) {
  138 + return path;
  139 + }
  140 +
  141 + // to calendar time
  142 + struct tm* tm;
  143 + if ((tm = localtime(&tv.tv_sec)) == NULL) {
  144 + return path;
  145 + }
  146 +
  147 + // the buffer to format the date and time.
  148 + char buf[64];
  149 +
  150 + // [2006], replace with current year.
  151 + if (true) {
  152 + snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
  153 + path = srs_string_replace(path, "[2006]", buf);
  154 + }
  155 + // [2006], replace with current year.
  156 + if (true) {
  157 + snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
  158 + path = srs_string_replace(path, "[2006]", buf);
  159 + }
  160 + // [01], replace this const to current month.
  161 + if (true) {
  162 + snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);
  163 + path = srs_string_replace(path, "[01]", buf);
  164 + }
  165 + // [02], replace this const to current date.
  166 + if (true) {
  167 + snprintf(buf, sizeof(buf), "%d", tm->tm_mday);
  168 + path = srs_string_replace(path, "[02]", buf);
  169 + }
  170 + // [15], replace this const to current hour.
  171 + if (true) {
  172 + snprintf(buf, sizeof(buf), "%d", tm->tm_hour);
  173 + path = srs_string_replace(path, "[15]", buf);
  174 + }
  175 + // [04], repleace this const to current minute.
  176 + if (true) {
  177 + snprintf(buf, sizeof(buf), "%d", tm->tm_min);
  178 + path = srs_string_replace(path, "[04]", buf);
  179 + }
  180 + // [05], repleace this const to current second.
  181 + if (true) {
  182 + snprintf(buf, sizeof(buf), "%d", tm->tm_sec);
  183 + path = srs_string_replace(path, "[05]", buf);
  184 + }
  185 + // [999], repleace this const to current millisecond.
  186 + if (true) {
  187 + snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));
  188 + path = srs_string_replace(path, "[999]", buf);
  189 + }
  190 + // [timestamp],replace this const to current UNIX timestamp in ms.
  191 + if (true) {
  192 + int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;
  193 + snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);
  194 + path = srs_string_replace(path, "[timestamp]", buf);
  195 + }
  196 +
  197 + return path;
  198 +}
  199 +
114 void srs_parse_endpoint(string ip_port, string& ip, string& port) 200 void srs_parse_endpoint(string ip_port, string& ip, string& port)
115 { 201 {
116 ip = "0.0.0.0"; 202 ip = "0.0.0.0";
@@ -51,6 +51,29 @@ extern int srs_socket_connect(std::string server, int port, int64_t timeout, st_ @@ -51,6 +51,29 @@ extern int srs_socket_connect(std::string server, int port, int64_t timeout, st_
51 extern int srs_get_log_level(std::string level); 51 extern int srs_get_log_level(std::string level);
52 52
53 /** 53 /**
  54 +* build the path according to vhost/app/stream, where replace variables:
  55 +* [vhost], the vhost of stream.
  56 +* [app], the app of stream.
  57 +* [stream], the stream name of stream.
  58 +* @return the replaced path.
  59 +*/
  60 +extern std::string srs_path_build_stream(std::string template_path, std::string vhost, std::string app, std::string stream);
  61 +
  62 +/**
  63 +* build the path according to timestamp, where replace variables:
  64 +* [2006], replace this const to current year.
  65 +* [01], replace this const to current month.
  66 +* [02], replace this const to current date.
  67 +* [15], replace this const to current hour.
  68 +* [04], repleace this const to current minute.
  69 +* [05], repleace this const to current second.
  70 +* [999], repleace this const to current millisecond.
  71 +* [timestamp],replace this const to current UNIX timestamp in ms.
  72 +* @return the replaced path.
  73 +*/
  74 +extern std::string srs_path_build_timestamp(std::string template_path);
  75 +
  76 +/**
54 * parse the endpoint to ip and port. 77 * parse the endpoint to ip and port.
55 * @param ip_port the ip and port which formats in <[ip:]port> 78 * @param ip_port the ip and port which formats in <[ip:]port>
56 */ 79 */
@@ -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 148 34 +#define VERSION_REVISION 149
35 35
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"