winlin

fix #179: dvr support custom filepath by variables. 2.0.87

@@ -501,7 +501,8 @@ Supported operating systems and hardware: @@ -501,7 +501,8 @@ Supported operating systems and hardware:
501 * 2013-10-17, Created.<br/> 501 * 2013-10-17, Created.<br/>
502 502
503 ## History 503 ## History
504 -* v2.0, 2015-01-02, hotfix [#211](https://github.com/winlinvip/simple-rtmp-server/issues/211), support security allow/deny publish/play all/ip. 2.0.86 504 +* v2.0, 2015-01-03, fix [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), dvr support custom filepath by variables. 2.0.87
  505 +* v2.0, 2015-01-02, fix [#211](https://github.com/winlinvip/simple-rtmp-server/issues/211), support security allow/deny publish/play all/ip. 2.0.86
505 * v2.0, 2015-01-02, hotfix [#207](https://github.com/winlinvip/simple-rtmp-server/issues/207), trim the last 0 of log. 2.0.85 506 * v2.0, 2015-01-02, hotfix [#207](https://github.com/winlinvip/simple-rtmp-server/issues/207), trim the last 0 of log. 2.0.85
506 * v2.0, 2014-01-02, fix [#158](https://github.com/winlinvip/simple-rtmp-server/issues/158), http-callback check http status code ok(200). 2.0.84 507 * v2.0, 2014-01-02, fix [#158](https://github.com/winlinvip/simple-rtmp-server/issues/158), http-callback check http status code ok(200). 2.0.84
507 * v2.0, 2015-01-02, hotfix [#216](https://github.com/winlinvip/simple-rtmp-server/issues/216), http-callback post in application/json content-type. 2.0.83 508 * v2.0, 2015-01-02, hotfix [#216](https://github.com/winlinvip/simple-rtmp-server/issues/216), http-callback post in application/json content-type. 2.0.83
  1 +# the config for srs to dvr in custom path.
  2 +# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
  3 +# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
  4 +# @see full.conf for detail config.
  5 +
  6 +listen 1935;
  7 +max_connections 1000;
  8 +vhost __defaultVhost__ {
  9 + dvr {
  10 + enabled on;
  11 + dvr_path ./objs/nginx/html/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv;
  12 + dvr_plan segment;
  13 + dvr_duration 30;
  14 + dvr_wait_keyframe on;
  15 + }
  16 +}
@@ -236,15 +236,38 @@ vhost dvr.srs.com { @@ -236,15 +236,38 @@ vhost dvr.srs.com {
236 # default: off 236 # default: off
237 enabled on; 237 enabled on;
238 # the dvr output path. 238 # the dvr output path.
239 - # the app dir is auto created under the dvr_path.  
240 - # for example, for rtmp stream:  
241 - # rtmp://127.0.0.1/live/livestream  
242 - # http://127.0.0.1/live/livestream.m3u8  
243 - # where dvr_path is /dvr, srs will create the following files:  
244 - # /dvr/live the app dir for all streams.  
245 - # /dvr/live/livestream.{time}.flv the dvr flv file.  
246 - # @remark, the time use system timestamp in ms, user can use http callback to rename it.  
247 - # in a word, the dvr_path is for vhost. 239 + # we supports some variables to generate the filename.
  240 + # [vhost], the vhost of stream.
  241 + # [app], the app of stream.
  242 + # [stream], the stream name of stream.
  243 + # [2006], replace this const to current year.
  244 + # [01], replace this const to current month.
  245 + # [02], replace this const to current date.
  246 + # [15], replace this const to current hour.
  247 + # [04], repleace this const to current minute.
  248 + # [05], repleace this const to current second.
  249 + # [999], repleace this const to current millisecond.
  250 + # [timestamp],replace this const to current UNIX timestamp in ms.
  251 + # @remark we use golang time format "2006-01-02 15:04:05.999"
  252 + # for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776
  253 + # 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename):
  254 + # dvr_path ./objs/nginx/html;
  255 + # =>
  256 + # dvr_path ./objs/nginx/html/live/livestream.1420254068776.flv;
  257 + # 2. Use stream and date as dir name, time as filename:
  258 + # dvr_path /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv;
  259 + # =>
  260 + # dvr_path /data/ossrs.net/live/livestream/2015/01/03/10.57.30.776.flv;
  261 + # 3. Use stream and year/month as dir name, date and time as filename:
  262 + # dvr_path /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]-[15].[04].[05].[999].flv;
  263 + # =>
  264 + # dvr_path /data/ossrs.net/live/livestream/2015/01/03-10.57.30.776.flv;
  265 + # 4. Use vhost/app and year/month as dir name, stream/date/time as filename:
  266 + # dvr_path /data/[vhost]/[app]/[2006]/[01]/[stream]-[02]-[15].[04].[05].[999].flv;
  267 + # =>
  268 + # dvr_path /data/ossrs.net/live/2015/01/livestream-03-10.57.30.776.flv;
  269 + # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
  270 + # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
248 # default: ./objs/nginx/html 271 # default: ./objs/nginx/html
249 dvr_path ./objs/nginx/html; 272 dvr_path ./objs/nginx/html;
250 # the dvr plan. canbe: 273 # the dvr plan. canbe:
@@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -27,6 +27,7 @@ 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>
30 using namespace std; 31 using namespace std;
31 32
32 #include <srs_app_config.hpp> 33 #include <srs_app_config.hpp>
@@ -136,14 +137,97 @@ int SrsDvrPlan::open_new_segment() @@ -136,14 +137,97 @@ int SrsDvrPlan::open_new_segment()
136 137
137 SrsRequest* req = _req; 138 SrsRequest* req = _req;
138 139
139 - // new flv file  
140 - std::stringstream path; 140 + // the path in config, for example,
  141 + // /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv
  142 + std::string path_config = _srs_config->get_dvr_path(req->vhost);
141 143
142 - path << _srs_config->get_dvr_path(req->vhost)  
143 - << "/" << req->app << "/"  
144 - << req->stream << "." << srs_get_system_time_ms() << ".flv"; 144 + // add [stream].[timestamp].flv as filename for dir
  145 + if (path_config.find(".flv") != path_config.length() - 4) {
  146 + path_config += "/[stream].[timestamp].flv";
  147 + }
  148 +
  149 + // the flv file path
  150 + std::string path = path_config;
  151 +
  152 + // variable [vhost]
  153 + path = srs_string_replace(path, "[vhost]", req->vhost);
  154 + // variable [app]
  155 + path = srs_string_replace(path, "[app]", req->app);
  156 + // variable [stream]
  157 + path = srs_string_replace(path, "[stream]", req->stream);
  158 +
  159 + // date and time substitude
  160 + // clock time
  161 + timeval tv;
  162 + if (gettimeofday(&tv, NULL) == -1) {
  163 + return ERROR_SYSTEM_TIME;
  164 + }
  165 +
  166 + // to calendar time
  167 + struct tm* tm;
  168 + if ((tm = localtime(&tv.tv_sec)) == NULL) {
  169 + return ERROR_SYSTEM_TIME;
  170 + }
  171 +
  172 + // the buffer to format the date and time.
  173 + char buf[64];
  174 +
  175 + // [2006], replace with current year.
  176 + if (true) {
  177 + snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
  178 + path = srs_string_replace(path, "[2006]", buf);
  179 + }
  180 + // [2006], replace with current year.
  181 + if (true) {
  182 + snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
  183 + path = srs_string_replace(path, "[2006]", buf);
  184 + }
  185 + // [01], replace this const to current month.
  186 + if (true) {
  187 + snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);
  188 + path = srs_string_replace(path, "[01]", buf);
  189 + }
  190 + // [02], replace this const to current date.
  191 + if (true) {
  192 + snprintf(buf, sizeof(buf), "%d", tm->tm_mday);
  193 + path = srs_string_replace(path, "[02]", buf);
  194 + }
  195 + // [15], replace this const to current hour.
  196 + if (true) {
  197 + snprintf(buf, sizeof(buf), "%d", tm->tm_hour);
  198 + path = srs_string_replace(path, "[15]", buf);
  199 + }
  200 + // [04], repleace this const to current minute.
  201 + if (true) {
  202 + snprintf(buf, sizeof(buf), "%d", tm->tm_min);
  203 + path = srs_string_replace(path, "[04]", buf);
  204 + }
  205 + // [05], repleace this const to current second.
  206 + if (true) {
  207 + snprintf(buf, sizeof(buf), "%d", tm->tm_sec);
  208 + path = srs_string_replace(path, "[05]", buf);
  209 + }
  210 + // [999], repleace this const to current millisecond.
  211 + if (true) {
  212 + snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));
  213 + path = srs_string_replace(path, "[999]", buf);
  214 + }
  215 + // [timestamp],replace this const to current UNIX timestamp in ms.
  216 + if (true) {
  217 + int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;
  218 + snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);
  219 + path = srs_string_replace(path, "[timestamp]", buf);
  220 + }
  221 +
  222 + // create dir first.
  223 + std::string dir = path.substr(0, path.rfind("/"));
  224 + if ((ret = srs_create_dir_recursively(dir)) != ERROR_SUCCESS) {
  225 + srs_error("create dir=%s failed. ret=%d", dir.c_str(), ret);
  226 + return ret;
  227 + }
  228 + srs_info("create dir=%s ok", dir.c_str());
145 229
146 - if ((ret = flv_open(req->get_stream_url(), path.str())) != ERROR_SUCCESS) { 230 + if ((ret = flv_open(req->get_stream_url(), path)) != ERROR_SUCCESS) {
147 return ret; 231 return ret;
148 } 232 }
149 dvr_enabled = true; 233 dvr_enabled = true;
@@ -951,16 +951,12 @@ int SrsHlsMuxer::create_dir() @@ -951,16 +951,12 @@ int SrsHlsMuxer::create_dir()
951 app_dir += app; 951 app_dir += app;
952 952
953 // TODO: cleanup the dir when startup. 953 // TODO: cleanup the dir when startup.
954 -  
955 - mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH;  
956 - if (::mkdir(app_dir.c_str(), mode) < 0) {  
957 - if (errno != EEXIST) {  
958 - ret = ERROR_HLS_CREATE_DIR;  
959 - srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret);  
960 - return ret;  
961 - } 954 +
  955 + if ((ret = srs_create_dir_recursively(app_dir)) != ERROR_SUCCESS) {
  956 + srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret);
  957 + return ret;
962 } 958 }
963 - srs_info("create app dir %s success.", app_dir.c_str()); 959 + srs_info("create app dir %s ok", app_dir.c_str());
964 960
965 return ret; 961 return ret;
966 } 962 }
@@ -98,6 +98,9 @@ int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std: @@ -98,6 +98,9 @@ int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std:
98 break; 98 break;
99 } 99 }
100 break; 100 break;
  101 + case SrsRtmpConnUnknown:
  102 + default:
  103 + break;
101 } 104 }
102 105
103 // when matched, donot search more. 106 // when matched, donot search more.
@@ -140,6 +143,9 @@ int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std:: @@ -140,6 +143,9 @@ int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::
140 break; 143 break;
141 } 144 }
142 break; 145 break;
  146 + case SrsRtmpConnUnknown:
  147 + default:
  148 + break;
143 } 149 }
144 150
145 // when matched, donot search more. 151 // when matched, donot search more.
@@ -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 86 34 +#define VERSION_REVISION 87
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -93,6 +93,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -93,6 +93,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
93 #define ERROR_SYSTEM_SECURITY 1052 93 #define ERROR_SYSTEM_SECURITY 1052
94 #define ERROR_SYSTEM_SECURITY_DENY 1053 94 #define ERROR_SYSTEM_SECURITY_DENY 1053
95 #define ERROR_SYSTEM_SECURITY_ALLOW 1054 95 #define ERROR_SYSTEM_SECURITY_ALLOW 1054
  96 +#define ERROR_SYSTEM_TIME 1055
  97 +#define ERROR_SYSTEM_DIR_EXISTS 1056
  98 +#define ERROR_SYSTEM_CREATE_DIR 1057
96 99
97 /////////////////////////////////////////////////////// 100 ///////////////////////////////////////////////////////
98 // RTMP protocol error. 101 // RTMP protocol error.
@@ -152,7 +155,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -152,7 +155,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
152 /////////////////////////////////////////////////////// 155 ///////////////////////////////////////////////////////
153 #define ERROR_HLS_METADATA 3000 156 #define ERROR_HLS_METADATA 3000
154 #define ERROR_HLS_DECODE_ERROR 3001 157 #define ERROR_HLS_DECODE_ERROR 3001
155 -#define ERROR_HLS_CREATE_DIR 3002 158 +//#define ERROR_HLS_CREATE_DIR 3002
156 #define ERROR_HLS_OPEN_FAILED 3003 159 #define ERROR_HLS_OPEN_FAILED 3003
157 #define ERROR_HLS_WRITE_FAILED 3004 160 #define ERROR_HLS_WRITE_FAILED 3004
158 #define ERROR_HLS_AAC_FRAME_LENGTH 3005 161 #define ERROR_HLS_AAC_FRAME_LENGTH 3005
@@ -32,10 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -32,10 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #endif 32 #endif
33 33
34 #include <string.h> 34 #include <string.h>
  35 +#include <sys/stat.h>
  36 +#include <fcntl.h>
35 37
36 using namespace std; 38 using namespace std;
37 39
38 #include <srs_kernel_log.hpp> 40 #include <srs_kernel_log.hpp>
  41 +#include <srs_kernel_error.hpp>
39 42
40 // this value must: 43 // this value must:
41 // equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000 44 // equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000
@@ -222,3 +225,56 @@ bool srs_string_ends_with(string str, string flag) @@ -222,3 +225,56 @@ bool srs_string_ends_with(string str, string flag)
222 return str.rfind(flag) == str.length() - flag.length(); 225 return str.rfind(flag) == str.length() - flag.length();
223 } 226 }
224 227
  228 +int __srs_create_dir_recursively(string dir)
  229 +{
  230 + int ret = ERROR_SUCCESS;
  231 +
  232 + struct stat st;
  233 +
  234 + // stat current dir, if exists, return error.
  235 + if (stat(dir.c_str(), &st) == 0) {
  236 + return ERROR_SYSTEM_DIR_EXISTS;
  237 + }
  238 +
  239 + // create parent first.
  240 + size_t pos;
  241 + if ((pos = dir.rfind("/")) != std::string::npos) {
  242 + std::string parent = dir.substr(0, pos);
  243 + ret = __srs_create_dir_recursively(parent);
  244 + // return for error.
  245 + if (ret != ERROR_SUCCESS && ret != ERROR_SYSTEM_DIR_EXISTS) {
  246 + return ret;
  247 + }
  248 + // parent exists, set to ok.
  249 + ret = ERROR_SUCCESS;
  250 + }
  251 +
  252 + // create curren dir.
  253 + mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH;
  254 + if (::mkdir(dir.c_str(), mode) < 0) {
  255 + if (errno == EEXIST) {
  256 + return ERROR_SYSTEM_DIR_EXISTS;
  257 + }
  258 +
  259 + ret = ERROR_SYSTEM_CREATE_DIR;
  260 + srs_error("create dir %s failed. ret=%d", dir.c_str(), ret);
  261 + return ret;
  262 + }
  263 + srs_info("create dir %s success.", dir.c_str());
  264 +
  265 + return ret;
  266 +}
  267 +
  268 +int srs_create_dir_recursively(string dir)
  269 +{
  270 + int ret = ERROR_SUCCESS;
  271 +
  272 + ret = __srs_create_dir_recursively(dir);
  273 +
  274 + if (ret == ERROR_SYSTEM_DIR_EXISTS) {
  275 + return ERROR_SUCCESS;
  276 + }
  277 +
  278 + return ret;
  279 +}
  280 +
@@ -59,5 +59,8 @@ extern std::string srs_string_remove(std::string str, std::string remove_chars); @@ -59,5 +59,8 @@ extern std::string srs_string_remove(std::string str, std::string remove_chars);
59 // whether string end with 59 // whether string end with
60 extern bool srs_string_ends_with(std::string str, std::string flag); 60 extern bool srs_string_ends_with(std::string str, std::string flag);
61 61
  62 +// create dir recursively
  63 +extern int srs_create_dir_recursively(std::string dir);
  64 +
62 #endif 65 #endif
63 66