winlin

refine dvr, append file when dvr file exists. 2.0.122.

@@ -530,7 +530,8 @@ Supported operating systems and hardware: @@ -530,7 +530,8 @@ Supported operating systems and hardware:
530 530
531 ### SRS 2.0 history 531 ### SRS 2.0 history
532 532
533 -* v2.0, 2015-02-19, refine pithy print to more easyer to use 2.0.121. 533 +* v2.0, 2015-02-19, refine dvr, append file when dvr file exists. 2.0.122.
  534 +* v2.0, 2015-02-19, refine pithy print to more easyer to use. 2.0.121.
534 * v2.0, 2015-02-18, fix [#133](https://github.com/winlinvip/simple-rtmp-server/issues/133), support push rtsp to srs. 2.0.120. 535 * v2.0, 2015-02-18, fix [#133](https://github.com/winlinvip/simple-rtmp-server/issues/133), support push rtsp to srs. 2.0.120.
535 * v2.0, 2015-02-17, the join maybe failed, should use a variable to ensure thread terminated. 2.0.119. 536 * v2.0, 2015-02-17, the join maybe failed, should use a variable to ensure thread terminated. 2.0.119.
536 * v2.0, 2015-02-15, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), support config default acodec/vcodec. 2.0.118. 537 * v2.0, 2015-02-15, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), support config default acodec/vcodec. 2.0.118.
@@ -1227,4 +1227,5 @@ vhost removed.srs.com { @@ -1227,4 +1227,5 @@ vhost removed.srs.com {
1227 # config for the pithy print, 1227 # config for the pithy print,
1228 # which always print constant message specified by interval, 1228 # which always print constant message specified by interval,
1229 # whatever the clients in concurrency. 1229 # whatever the clients in concurrency.
  1230 +# default: 10000
1230 pithy_print_ms 10000; 1231 pithy_print_ms 10000;
@@ -369,11 +369,27 @@ int SrsDvrPlan::flv_open(string stream, string path) @@ -369,11 +369,27 @@ int SrsDvrPlan::flv_open(string stream, string path)
369 369
370 segment->reset(); 370 segment->reset();
371 371
372 - std::string tmp_file = path + ".tmp";  
373 - if ((ret = fs->open(tmp_file)) != ERROR_SUCCESS) { 372 + if (srs_path_exists(path)) {
  373 + // when path exists, always append to it.
  374 + // so we must use the target flv path as output flv.
  375 + tmp_flv_file = path;
  376 + } else {
  377 + // when path not exists, dvr to tmp file.
  378 + tmp_flv_file = path + ".tmp";
  379 + }
  380 +
  381 + if (srs_path_exists(path)) {
  382 + if ((ret = fs->open_append(tmp_flv_file)) != ERROR_SUCCESS) {
  383 + srs_error("append file stream for file %s failed. ret=%d", path.c_str(), ret);
  384 + return ret;
  385 + }
  386 + srs_warn("dvr: always append to when exists, file=%s.", path.c_str());
  387 + } else {
  388 + if ((ret = fs->open(tmp_flv_file)) != ERROR_SUCCESS) {
374 srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret); 389 srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
375 return ret; 390 return ret;
376 } 391 }
  392 + }
377 393
378 if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) { 394 if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {
379 srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret); 395 srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret);
@@ -396,13 +412,15 @@ int SrsDvrPlan::flv_close() @@ -396,13 +412,15 @@ int SrsDvrPlan::flv_close()
396 412
397 fs->close(); 413 fs->close();
398 414
399 - std::string tmp_file = segment->path + ".tmp";  
400 - if (rename(tmp_file.c_str(), segment->path.c_str()) < 0) { 415 + // when tmp flv file exists, reap it.
  416 + if (tmp_flv_file != segment->path) {
  417 + if (rename(tmp_flv_file.c_str(), segment->path.c_str()) < 0) {
401 ret = ERROR_SYSTEM_FILE_RENAME; 418 ret = ERROR_SYSTEM_FILE_RENAME;
402 srs_error("rename flv file failed, %s => %s. ret=%d", 419 srs_error("rename flv file failed, %s => %s. ret=%d",
403 - tmp_file.c_str(), segment->path.c_str(), ret); 420 + tmp_flv_file.c_str(), segment->path.c_str(), ret);
404 return ret; 421 return ret;
405 } 422 }
  423 + }
406 424
407 #ifdef SRS_AUTO_HTTP_CALLBACK 425 #ifdef SRS_AUTO_HTTP_CALLBACK
408 SrsRequest* req = _req; 426 SrsRequest* req = _req;
@@ -111,6 +111,8 @@ protected: @@ -111,6 +111,8 @@ protected:
111 SrsRequest* _req; 111 SrsRequest* _req;
112 bool dvr_enabled; 112 bool dvr_enabled;
113 SrsFileWriter* fs; 113 SrsFileWriter* fs;
  114 +private:
  115 + std::string tmp_flv_file;
114 public: 116 public:
115 SrsDvrPlan(); 117 SrsDvrPlan();
116 virtual ~SrsDvrPlan(); 118 virtual ~SrsDvrPlan();
@@ -294,8 +294,7 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* @@ -294,8 +294,7 @@ int SrsGoHttpFileServer::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage*
294 } 294 }
295 295
296 // stat current dir, if exists, return error. 296 // stat current dir, if exists, return error.
297 - struct stat st;  
298 - if (stat(fullpath.c_str(), &st) != 0) { 297 + if (!srs_path_exists(fullpath)) {
299 srs_warn("http miss file=%s, pattern=%s, upath=%s", 298 srs_warn("http miss file=%s, pattern=%s, upath=%s",
300 fullpath.c_str(), entry->pattern.c_str(), upath.c_str()); 299 fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
301 return SrsGoHttpNotFoundHandler().serve_http(w, r); 300 return SrsGoHttpNotFoundHandler().serve_http(w, r);
@@ -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 121 34 +#define VERSION_REVISION 122
35 35
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"
@@ -69,6 +69,30 @@ int SrsFileWriter::open(string file) @@ -69,6 +69,30 @@ int SrsFileWriter::open(string file)
69 return ret; 69 return ret;
70 } 70 }
71 71
  72 +int SrsFileWriter::open_append(string file)
  73 +{
  74 + int ret = ERROR_SUCCESS;
  75 +
  76 + if (fd > 0) {
  77 + ret = ERROR_SYSTEM_FILE_ALREADY_OPENED;
  78 + srs_error("file %s already opened. ret=%d", _file.c_str(), ret);
  79 + return ret;
  80 + }
  81 +
  82 + int flags = O_APPEND|O_WRONLY;
  83 + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
  84 +
  85 + if ((fd = ::open(file.c_str(), flags, mode)) < 0) {
  86 + ret = ERROR_SYSTEM_FILE_OPENE;
  87 + srs_error("open file %s failed. ret=%d", file.c_str(), ret);
  88 + return ret;
  89 + }
  90 +
  91 + _file = file;
  92 +
  93 + return ret;
  94 +}
  95 +
72 void SrsFileWriter::close() 96 void SrsFileWriter::close()
73 { 97 {
74 int ret = ERROR_SUCCESS; 98 int ret = ERROR_SUCCESS;
@@ -47,6 +47,10 @@ public: @@ -47,6 +47,10 @@ public:
47 * open file writer, can open then close then open... 47 * open file writer, can open then close then open...
48 */ 48 */
49 virtual int open(std::string file); 49 virtual int open(std::string file);
  50 + /**
  51 + * open file writer in append mode.
  52 + */
  53 + virtual int open_append(std::string file);
50 virtual void close(); 54 virtual void close();
51 public: 55 public:
52 virtual bool is_open(); 56 virtual bool is_open();
@@ -230,10 +230,8 @@ int __srs_create_dir_recursively(string dir) @@ -230,10 +230,8 @@ int __srs_create_dir_recursively(string dir)
230 { 230 {
231 int ret = ERROR_SUCCESS; 231 int ret = ERROR_SUCCESS;
232 232
233 - struct stat st;  
234 -  
235 // stat current dir, if exists, return error. 233 // stat current dir, if exists, return error.
236 - if (stat(dir.c_str(), &st) == 0) { 234 + if (srs_path_exists(dir)) {
237 return ERROR_SYSTEM_DIR_EXISTS; 235 return ERROR_SYSTEM_DIR_EXISTS;
238 } 236 }
239 237
@@ -279,6 +277,18 @@ int srs_create_dir_recursively(string dir) @@ -279,6 +277,18 @@ int srs_create_dir_recursively(string dir)
279 return ret; 277 return ret;
280 } 278 }
281 279
  280 +bool srs_path_exists(std::string path)
  281 +{
  282 + struct stat st;
  283 +
  284 + // stat current dir, if exists, return error.
  285 + if (stat(path.c_str(), &st) == 0) {
  286 + return true;
  287 + }
  288 +
  289 + return false;
  290 +}
  291 +
282 bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code) 292 bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code)
283 { 293 {
284 char* bytes = stream->data() + stream->pos(); 294 char* bytes = stream->data() + stream->pos();
@@ -64,6 +64,9 @@ extern bool srs_string_ends_with(std::string str, std::string flag); @@ -64,6 +64,9 @@ extern bool srs_string_ends_with(std::string str, std::string flag);
64 // create dir recursively 64 // create dir recursively
65 extern int srs_create_dir_recursively(std::string dir); 65 extern int srs_create_dir_recursively(std::string dir);
66 66
  67 +// whether path exists.
  68 +extern bool srs_path_exists(std::string path);
  69 +
67 /** 70 /**
68 * whether stream starts with the avc NALU in "AnnexB" 71 * whether stream starts with the avc NALU in "AnnexB"
69 * from H.264-AVC-ISO_IEC_14496-10.pdf, page 211. 72 * from H.264-AVC-ISO_IEC_14496-10.pdf, page 211.