正在显示
13 个修改的文件
包含
235 行增加
和
110 行删除
@@ -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); |
@@ -3168,7 +3169,41 @@ string SrsConfig::get_hls_path(string vhost) | @@ -3168,7 +3169,41 @@ string SrsConfig::get_hls_path(string vhost) | ||
3168 | if (!conf) { | 3169 | if (!conf) { |
3169 | return SRS_CONF_DEFAULT_HLS_PATH; | 3170 | return SRS_CONF_DEFAULT_HLS_PATH; |
3170 | } | 3171 | } |
3172 | + | ||
3173 | + return conf->arg0(); | ||
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 | +} | ||
3171 | 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 | + | ||
3172 | return conf->arg0(); | 3207 | return conf->arg0(); |
3173 | } | 3208 | } |
3174 | 3209 |
@@ -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 |
@@ -871,10 +873,18 @@ public: | @@ -871,10 +873,18 @@ public: | ||
871 | */ | 873 | */ |
872 | virtual std::string get_hls_entry_prefix(std::string vhost); | 874 | virtual std::string get_hls_entry_prefix(std::string vhost); |
873 | /** | 875 | /** |
874 | - * get the HLS ts/m3u8 file store path. | ||
875 | - */ | 876 | + * get the HLS ts/m3u8 file store path. |
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" |
-
请 注册 或 登录 后发表评论