merge from 2.0release

pull/499/head
winlin 10 years ago
commit abbed8f66c

@ -566,6 +566,7 @@ Supported operating systems and hardware:
### SRS 2.0 history ### SRS 2.0 history
* 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.
* 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. * 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.
* v2.0, 2015-03-15, start [2.0release branch](https://github.com/winlinvip/simple-rtmp-server/tree/2.0release), 80773 lines. * v2.0, 2015-03-15, start [2.0release branch](https://github.com/winlinvip/simple-rtmp-server/tree/2.0release), 80773 lines.
* 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. * 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 {
# default: disk # default: disk
hls_storage disk; hls_storage disk;
# the hls output path. # the hls output path.
# the app dir is auto created under the hls_path. # the m3u8 file is configed by hls_path/hls_m3u8_file, the default is:
# for example, for rtmp stream: # ./objs/nginx/html/[app]/[stream].m3u8
# rtmp://127.0.0.1/live/livestream # the ts file is configed by hls_path/hls_ts_file, the default is:
# http://127.0.0.1/live/livestream.m3u8 # ./objs/nginx/html/[app]/[stream]-[seq].ts
# where hls_path is /hls, srs will create the following files: # @remark the hls_path is compatible with srs v1 config.
# /hls/live the app dir for all streams.
# /hls/live/livestream.m3u8 the HLS m3u8 file.
# /hls/live/livestream-1.ts the HLS media/ts file.
# in a word, the hls_path is for vhost.
# default: ./objs/nginx/html # default: ./objs/nginx/html
hls_path ./objs/nginx/html; hls_path ./objs/nginx/html;
# the hls m3u8 file name.
# we supports some variables to generate the filename.
# [vhost], the vhost of stream.
# [app], the app of stream.
# [stream], the stream name of stream.
# default: [app]/[stream].m3u8
hls_m3u8_file [app]/[stream].m3u8;
# the hls ts file name.
# we supports some variables to generate the filename.
# [vhost], the vhost of stream.
# [app], the app of stream.
# [stream], the stream name of stream.
# [2006], replace this const to current year.
# [01], replace this const to current month.
# [02], replace this const to current date.
# [15], replace this const to current hour.
# [04], repleace this const to current minute.
# [05], repleace this const to current second.
# [999], repleace this const to current millisecond.
# [timestamp],replace this const to current UNIX timestamp in ms.
# [seq], the sequence number of ts.
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#hls-config
# default: [app]/[stream]-[seq].ts
hls_ts_file [app]/[stream]-[seq].ts;
# the hls entry prefix, which is base url of ts url. # the hls entry prefix, which is base url of ts url.
# if specified, the ts path in m3u8 will be like: # if specified, the ts path in m3u8 will be like:
# http://your-server/live/livestream-0.ts # http://your-server/live/livestream-0.ts

@ -10,5 +10,7 @@ vhost __defaultVhost__ {
hls_fragment 10; hls_fragment 10;
hls_window 60; hls_window 60;
hls_path ./objs/nginx/html; hls_path ./objs/nginx/html;
hls_m3u8_file [app]/[stream].m3u8;
hls_ts_file [app]/[stream]-[seq].ts;
} }
} }

@ -12,8 +12,10 @@ http_server {
vhost __defaultVhost__ { vhost __defaultVhost__ {
hls { hls {
enabled on; enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10; hls_fragment 10;
hls_window 60; hls_window 60;
hls_path ./objs/nginx/html;
hls_m3u8_file [app]/[stream].m3u8;
hls_ts_file [app]/[stream]-[seq].ts;
} }
} }

@ -7,9 +7,11 @@ max_connections 1000;
vhost __defaultVhost__ { vhost __defaultVhost__ {
hls { hls {
enabled on; enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10; hls_fragment 10;
hls_window 60; hls_window 60;
hls_path ./objs/nginx/html;
hls_m3u8_file [app]/[stream].m3u8;
hls_ts_file [app]/[stream]-[seq].ts;
} }
transcode { transcode {
enabled on; enabled on;

@ -1482,6 +1482,7 @@ int SrsConfig::check_config()
string m = conf->at(j)->name.c_str(); string m = conf->at(j)->name.c_str();
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
&& m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
&& m != "hls_m3u8_file" && m != "hls_ts_file"
) { ) {
ret = ERROR_SYSTEM_CONFIG_INVALID; ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
@ -3168,7 +3169,41 @@ string SrsConfig::get_hls_path(string vhost)
if (!conf) { if (!conf) {
return SRS_CONF_DEFAULT_HLS_PATH; return SRS_CONF_DEFAULT_HLS_PATH;
} }
return conf->arg0();
}
string SrsConfig::get_hls_m3u8_file(string vhost)
{
SrsConfDirective* hls = get_hls(vhost);
if (!hls) {
return SRS_CONF_DEFAULT_HLS_M3U8_FILE;
}
SrsConfDirective* conf = hls->get("hls_m3u8_file");
if (!conf) {
return SRS_CONF_DEFAULT_HLS_M3U8_FILE;
}
return conf->arg0();
}
string SrsConfig::get_hls_ts_file(string vhost)
{
SrsConfDirective* hls = get_hls(vhost);
if (!hls) {
return SRS_CONF_DEFAULT_HLS_TS_FILE;
}
SrsConfDirective* conf = hls->get("hls_ts_file");
if (!conf) {
return SRS_CONF_DEFAULT_HLS_TS_FILE;
}
return conf->arg0(); return conf->arg0();
} }

@ -46,6 +46,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000 #define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000
#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
#define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8"
#define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts"
#define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
#define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5 #define SRS_CONF_DEFAULT_HLS_TD_RATIO 1.5
#define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0 #define SRS_CONF_DEFAULT_HLS_AOF_RATIO 2.0
@ -871,9 +873,17 @@ public:
*/ */
virtual std::string get_hls_entry_prefix(std::string vhost); virtual std::string get_hls_entry_prefix(std::string vhost);
/** /**
* get the HLS ts/m3u8 file store path. * get the HLS ts/m3u8 file store path.
*/ */
virtual std::string get_hls_path(std::string vhost); virtual std::string get_hls_path(std::string vhost);
/**
* get the HLS m3u8 file path template.
*/
virtual std::string get_hls_m3u8_file(std::string vhost);
/**
* get the HLS ts file path template.
*/
virtual std::string get_hls_ts_file(std::string vhost);
/** /**
* get the hls fragment time, in seconds. * get the hls fragment time, in seconds.
*/ */

@ -27,7 +27,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <fcntl.h> #include <fcntl.h>
#include <sstream> #include <sstream>
#include <sys/time.h>
#include <algorithm> #include <algorithm>
using namespace std; using namespace std;
@ -42,6 +41,7 @@ using namespace std;
#include <srs_rtmp_amf0.hpp> #include <srs_rtmp_amf0.hpp>
#include <srs_kernel_stream.hpp> #include <srs_kernel_stream.hpp>
#include <srs_app_json.hpp> #include <srs_app_json.hpp>
#include <srs_app_utility.hpp>
// update the flv duration and filesize every this interval in ms. // update the flv duration and filesize every this interval in ms.
#define SRS_DVR_UPDATE_DURATION_INTERVAL 60000 #define SRS_DVR_UPDATE_DURATION_INTERVAL 60000
@ -422,76 +422,8 @@ string SrsFlvSegment::generate_path()
// the flv file path // the flv file path
std::string flv_path = path_config; std::string flv_path = path_config;
flv_path = srs_path_build_stream(flv_path, req->vhost, req->app, req->stream);
// variable [vhost] flv_path = srs_path_build_timestamp(flv_path);
flv_path = srs_string_replace(flv_path, "[vhost]", req->vhost);
// variable [app]
flv_path = srs_string_replace(flv_path, "[app]", req->app);
// variable [stream]
flv_path = srs_string_replace(flv_path, "[stream]", req->stream);
// date and time substitude
// clock time
timeval tv;
if (gettimeofday(&tv, NULL) == -1) {
return flv_path;
}
// to calendar time
struct tm* tm;
if ((tm = localtime(&tv.tv_sec)) == NULL) {
return flv_path;
}
// the buffer to format the date and time.
char buf[64];
// [2006], replace with current year.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
flv_path = srs_string_replace(flv_path, "[2006]", buf);
}
// [2006], replace with current year.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
flv_path = srs_string_replace(flv_path, "[2006]", buf);
}
// [01], replace this const to current month.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);
flv_path = srs_string_replace(flv_path, "[01]", buf);
}
// [02], replace this const to current date.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_mday);
flv_path = srs_string_replace(flv_path, "[02]", buf);
}
// [15], replace this const to current hour.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_hour);
flv_path = srs_string_replace(flv_path, "[15]", buf);
}
// [04], repleace this const to current minute.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_min);
flv_path = srs_string_replace(flv_path, "[04]", buf);
}
// [05], repleace this const to current second.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_sec);
flv_path = srs_string_replace(flv_path, "[05]", buf);
}
// [999], repleace this const to current millisecond.
if (true) {
snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));
flv_path = srs_string_replace(flv_path, "[999]", buf);
}
// [timestamp],replace this const to current UNIX timestamp in ms.
if (true) {
int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;
snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);
flv_path = srs_string_replace(flv_path, "[timestamp]", buf);
}
return flv_path; return flv_path;
} }

@ -53,6 +53,7 @@ using namespace std;
#include <srs_kernel_file.hpp> #include <srs_kernel_file.hpp>
#include <srs_rtmp_buffer.hpp> #include <srs_rtmp_buffer.hpp>
#include <srs_kernel_ts.hpp> #include <srs_kernel_ts.hpp>
#include <srs_app_utility.hpp>
// drop the segment when duration of ts too small. // drop the segment when duration of ts too small.
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
@ -204,8 +205,9 @@ int SrsHlsMuxer::sequence_no()
return _sequence_no; return _sequence_no;
} }
int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, string path, int fragment, int window, double aof_ratio) int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
{ string path, string m3u8_file, string ts_file, int fragment, int window, double aof_ratio
) {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
srs_freep(req); srs_freep(req);
@ -213,6 +215,8 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, string path,
hls_entry_prefix = entry_prefix; hls_entry_prefix = entry_prefix;
hls_path = path; hls_path = path;
hls_m3u8_file = m3u8_file;
hls_ts_file = ts_file;
hls_fragment = fragment; hls_fragment = fragment;
hls_aof_ratio = aof_ratio; hls_aof_ratio = aof_ratio;
hls_window = window; hls_window = window;
@ -249,7 +253,7 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
// TODO: create all parents dirs. // TODO: create all parents dirs.
// create dir for app. // create dir for app.
if (should_write_file && (ret = create_dir()) != ERROR_SUCCESS) { if (should_write_file && (ret = create_dir(current->full_path)) != ERROR_SUCCESS) {
return ret; return ret;
} }
@ -292,22 +296,23 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
current->segment_start_dts = segment_start_dts; current->segment_start_dts = segment_start_dts;
// generate filename. // generate filename.
char filename[128]; std::string ts_file = hls_ts_file;
snprintf(filename, sizeof(filename), ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream);
"%s-%d.ts", req->stream.c_str(), current->sequence_no); ts_file = srs_path_build_timestamp(ts_file);
if (true) {
std::stringstream ss;
ss << current->sequence_no;
ts_file = srs_string_replace(ts_file, "[seq]", ss.str());
}
// TODO: use temp file and rename it. // replace variables
current->full_path = hls_path; current->full_path = hls_path + "/" + ts_file;
current->full_path += "/";
current->full_path += req->app;
current->full_path += "/";
current->full_path += filename;
current->uri += hls_entry_prefix; current->uri += hls_entry_prefix;
if (!hls_entry_prefix.empty() && !srs_string_ends_with(hls_entry_prefix, "/")) { if (!hls_entry_prefix.empty() && !srs_string_ends_with(hls_entry_prefix, "/")) {
current->uri += "/"; current->uri += "/";
} }
current->uri += filename; current->uri += ts_file;
std::string tmp_file = current->full_path + ".tmp"; std::string tmp_file = current->full_path + ".tmp";
if ((ret = current->muxer->open(tmp_file.c_str())) != ERROR_SUCCESS) { if ((ret = current->muxer->open(tmp_file.c_str())) != ERROR_SUCCESS) {
@ -524,10 +529,8 @@ int SrsHlsMuxer::refresh_m3u8()
std::string m3u8_file = hls_path; std::string m3u8_file = hls_path;
m3u8_file += "/"; m3u8_file += "/";
m3u8_file += req->app; m3u8_file += hls_m3u8_file;
m3u8_file += "/"; m3u8_file = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
m3u8_file += req->stream;
m3u8_file += ".m3u8";
m3u8 = m3u8_file; m3u8 = m3u8_file;
m3u8_file += ".temp"; m3u8_file += ".temp";
@ -631,7 +634,7 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
return ret; return ret;
} }
int SrsHlsMuxer::create_dir() int SrsHlsMuxer::create_dir(string filepath)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -639,9 +642,11 @@ int SrsHlsMuxer::create_dir()
return ret; return ret;
} }
std::string app_dir = hls_path; std::string app_dir = filepath;
app_dir += "/"; size_t pos = string::npos;
app_dir += req->app; if ((pos = app_dir.rfind("/")) != string::npos) {
app_dir = app_dir.substr(0, pos);
}
// TODO: cleanup the dir when startup. // TODO: cleanup the dir when startup.
@ -678,7 +683,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
// get the hls m3u8 ts list entry prefix config // get the hls m3u8 ts list entry prefix config
std::string entry_prefix = _srs_config->get_hls_entry_prefix(vhost); std::string entry_prefix = _srs_config->get_hls_entry_prefix(vhost);
// get the hls path config // get the hls path config
std::string hls_path = _srs_config->get_hls_path(vhost); std::string path = _srs_config->get_hls_path(vhost);
std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost);
std::string ts_file = _srs_config->get_hls_ts_file(vhost);
// the audio overflow, for pure audio to reap segment. // the audio overflow, for pure audio to reap segment.
double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost); double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost);
@ -686,7 +693,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
// for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase. // for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase.
// open muxer // open muxer
if ((ret = muxer->update_config(req, entry_prefix, hls_path, hls_fragment, hls_window, hls_aof_ratio)) != ERROR_SUCCESS) { if ((ret = muxer->update_config(req, entry_prefix, path, m3u8_file, ts_file, hls_fragment, hls_window, hls_aof_ratio)) != ERROR_SUCCESS) {
srs_error("m3u8 muxer update config failed. ret=%d", ret); srs_error("m3u8 muxer update config failed. ret=%d", ret);
return ret; return ret;
} }

@ -169,6 +169,8 @@ private:
private: private:
std::string hls_entry_prefix; std::string hls_entry_prefix;
std::string hls_path; std::string hls_path;
std::string hls_m3u8_file;
std::string hls_ts_file;
double hls_aof_ratio; double hls_aof_ratio;
int hls_fragment; int hls_fragment;
int hls_window; int hls_window;
@ -209,7 +211,9 @@ public:
/** /**
* when publish, update the config for muxer. * when publish, update the config for muxer.
*/ */
virtual int update_config(SrsRequest* r, std::string entry_prefix, std::string path, int fragment, int window, double aof_ratio); virtual int update_config(SrsRequest* r, std::string entry_prefix,
std::string path, std::string m3u8_file, std::string ts_file,
int fragment, int window, double aof_ratio);
/** /**
* open a new segment(a new ts file), * open a new segment(a new ts file),
* @param segment_start_dts use to calc the segment duration, * @param segment_start_dts use to calc the segment duration,
@ -240,7 +244,7 @@ public:
private: private:
virtual int refresh_m3u8(); virtual int refresh_m3u8();
virtual int _refresh_m3u8(std::string m3u8_file); virtual int _refresh_m3u8(std::string m3u8_file);
virtual int create_dir(); virtual int create_dir(std::string filepath);
}; };
/** /**

@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
using namespace std; using namespace std;
#include <srs_kernel_log.hpp> #include <srs_kernel_log.hpp>
@ -111,6 +112,91 @@ int srs_get_log_level(string level)
} }
} }
string srs_path_build_stream(string template_path, string vhost, string app, string stream)
{
std::string path = template_path;
// variable [vhost]
path = srs_string_replace(path, "[vhost]", vhost);
// variable [app]
path = srs_string_replace(path, "[app]", app);
// variable [stream]
path = srs_string_replace(path, "[stream]", stream);
return path;
}
string srs_path_build_timestamp(string template_path)
{
std::string path = template_path;
// date and time substitude
// clock time
timeval tv;
if (gettimeofday(&tv, NULL) == -1) {
return path;
}
// to calendar time
struct tm* tm;
if ((tm = localtime(&tv.tv_sec)) == NULL) {
return path;
}
// the buffer to format the date and time.
char buf[64];
// [2006], replace with current year.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
path = srs_string_replace(path, "[2006]", buf);
}
// [2006], replace with current year.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
path = srs_string_replace(path, "[2006]", buf);
}
// [01], replace this const to current month.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);
path = srs_string_replace(path, "[01]", buf);
}
// [02], replace this const to current date.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_mday);
path = srs_string_replace(path, "[02]", buf);
}
// [15], replace this const to current hour.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_hour);
path = srs_string_replace(path, "[15]", buf);
}
// [04], repleace this const to current minute.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_min);
path = srs_string_replace(path, "[04]", buf);
}
// [05], repleace this const to current second.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_sec);
path = srs_string_replace(path, "[05]", buf);
}
// [999], repleace this const to current millisecond.
if (true) {
snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));
path = srs_string_replace(path, "[999]", buf);
}
// [timestamp],replace this const to current UNIX timestamp in ms.
if (true) {
int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;
snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);
path = srs_string_replace(path, "[timestamp]", buf);
}
return path;
}
void srs_parse_endpoint(string ip_port, string& ip, string& port) void srs_parse_endpoint(string ip_port, string& ip, string& port)
{ {
ip = "0.0.0.0"; ip = "0.0.0.0";

@ -50,6 +50,29 @@ extern int srs_socket_connect(std::string server, int port, int64_t timeout, st_
*/ */
extern int srs_get_log_level(std::string level); extern int srs_get_log_level(std::string level);
/**
* build the path according to vhost/app/stream, where replace variables:
* [vhost], the vhost of stream.
* [app], the app of stream.
* [stream], the stream name of stream.
* @return the replaced path.
*/
extern std::string srs_path_build_stream(std::string template_path, std::string vhost, std::string app, std::string stream);
/**
* build the path according to timestamp, where replace variables:
* [2006], replace this const to current year.
* [01], replace this const to current month.
* [02], replace this const to current date.
* [15], replace this const to current hour.
* [04], repleace this const to current minute.
* [05], repleace this const to current second.
* [999], repleace this const to current millisecond.
* [timestamp],replace this const to current UNIX timestamp in ms.
* @return the replaced path.
*/
extern std::string srs_path_build_timestamp(std::string template_path);
/** /**
* parse the endpoint to ip and port. * parse the endpoint to ip and port.
* @param ip_port the ip and port which formats in <[ip:]port> * @param ip_port the ip and port which formats in <[ip:]port>

Loading…
Cancel
Save