winlin

for #367: extract the process from ffmpeg to exec programs.

@@ -176,7 +176,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then @@ -176,7 +176,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
176 "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" 176 "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static"
177 "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" 177 "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds"
178 "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" 178 "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call"
179 - "srs_app_caster_flv") 179 + "srs_app_caster_flv" "srs_app_process")
180 DEFINES="" 180 DEFINES=""
181 # add each modules for app 181 # add each modules for app
182 for SRS_MODULE in ${SRS_MODULES[*]}; do 182 for SRS_MODULE in ${SRS_MODULES[*]}; do
@@ -117,6 +117,8 @@ file @@ -117,6 +117,8 @@ file
117 ../../src/app/srs_app_log.cpp, 117 ../../src/app/srs_app_log.cpp,
118 ../../src/app/srs_app_mpegts_udp.hpp, 118 ../../src/app/srs_app_mpegts_udp.hpp,
119 ../../src/app/srs_app_mpegts_udp.cpp, 119 ../../src/app/srs_app_mpegts_udp.cpp,
  120 + ../../src/app/srs_app_process.hpp,
  121 + ../../src/app/srs_app_process.cpp,
120 ../../src/app/srs_app_recv_thread.hpp, 122 ../../src/app/srs_app_recv_thread.hpp,
121 ../../src/app/srs_app_recv_thread.cpp, 123 ../../src/app/srs_app_recv_thread.cpp,
122 ../../src/app/srs_app_refer.hpp, 124 ../../src/app/srs_app_refer.hpp,
@@ -79,6 +79,7 @@ @@ -79,6 +79,7 @@
79 3C36DB5B1ABD1CB90066CCAF /* srs_lib_bandwidth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB551ABD1CB90066CCAF /* srs_lib_bandwidth.cpp */; }; 79 3C36DB5B1ABD1CB90066CCAF /* srs_lib_bandwidth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB551ABD1CB90066CCAF /* srs_lib_bandwidth.cpp */; };
80 3C36DB5C1ABD1CB90066CCAF /* srs_lib_simple_socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB571ABD1CB90066CCAF /* srs_lib_simple_socket.cpp */; }; 80 3C36DB5C1ABD1CB90066CCAF /* srs_lib_simple_socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB571ABD1CB90066CCAF /* srs_lib_simple_socket.cpp */; };
81 3C36DB5D1ABD1CB90066CCAF /* srs_librtmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */; }; 81 3C36DB5D1ABD1CB90066CCAF /* srs_librtmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */; };
  82 + 3C4F97121B8B466D00FF0E46 /* srs_app_process.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C4F97101B8B466D00FF0E46 /* srs_app_process.cpp */; };
82 3C5265B41B241BF0009CA186 /* srs_core_mem_watch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C5265B21B241BF0009CA186 /* srs_core_mem_watch.cpp */; }; 83 3C5265B41B241BF0009CA186 /* srs_core_mem_watch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C5265B21B241BF0009CA186 /* srs_core_mem_watch.cpp */; };
83 3C663F0F1AB0155100286D8B /* srs_aac_raw_publish.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C663F021AB0155100286D8B /* srs_aac_raw_publish.c */; }; 84 3C663F0F1AB0155100286D8B /* srs_aac_raw_publish.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C663F021AB0155100286D8B /* srs_aac_raw_publish.c */; };
84 3C663F101AB0155100286D8B /* srs_audio_raw_publish.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C663F031AB0155100286D8B /* srs_audio_raw_publish.c */; }; 85 3C663F101AB0155100286D8B /* srs_audio_raw_publish.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C663F031AB0155100286D8B /* srs_audio_raw_publish.c */; };
@@ -328,6 +329,8 @@ @@ -328,6 +329,8 @@
328 3C36DB581ABD1CB90066CCAF /* srs_lib_simple_socket.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_lib_simple_socket.hpp; path = ../../../src/libs/srs_lib_simple_socket.hpp; sourceTree = "<group>"; }; 329 3C36DB581ABD1CB90066CCAF /* srs_lib_simple_socket.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_lib_simple_socket.hpp; path = ../../../src/libs/srs_lib_simple_socket.hpp; sourceTree = "<group>"; };
329 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_librtmp.cpp; path = ../../../src/libs/srs_librtmp.cpp; sourceTree = "<group>"; }; 330 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_librtmp.cpp; path = ../../../src/libs/srs_librtmp.cpp; sourceTree = "<group>"; };
330 3C36DB5A1ABD1CB90066CCAF /* srs_librtmp.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_librtmp.hpp; path = ../../../src/libs/srs_librtmp.hpp; sourceTree = "<group>"; }; 331 3C36DB5A1ABD1CB90066CCAF /* srs_librtmp.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_librtmp.hpp; path = ../../../src/libs/srs_librtmp.hpp; sourceTree = "<group>"; };
  332 + 3C4F97101B8B466D00FF0E46 /* srs_app_process.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_process.cpp; path = ../../../src/app/srs_app_process.cpp; sourceTree = "<group>"; };
  333 + 3C4F97111B8B466D00FF0E46 /* srs_app_process.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_process.hpp; path = ../../../src/app/srs_app_process.hpp; sourceTree = "<group>"; };
331 3C5265B21B241BF0009CA186 /* srs_core_mem_watch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_core_mem_watch.cpp; path = ../../../src/core/srs_core_mem_watch.cpp; sourceTree = "<group>"; }; 334 3C5265B21B241BF0009CA186 /* srs_core_mem_watch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_core_mem_watch.cpp; path = ../../../src/core/srs_core_mem_watch.cpp; sourceTree = "<group>"; };
332 3C5265B31B241BF0009CA186 /* srs_core_mem_watch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_core_mem_watch.hpp; path = ../../../src/core/srs_core_mem_watch.hpp; sourceTree = "<group>"; }; 335 3C5265B31B241BF0009CA186 /* srs_core_mem_watch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_core_mem_watch.hpp; path = ../../../src/core/srs_core_mem_watch.hpp; sourceTree = "<group>"; };
333 3C663F021AB0155100286D8B /* srs_aac_raw_publish.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = srs_aac_raw_publish.c; path = ../../../research/librtmp/srs_aac_raw_publish.c; sourceTree = "<group>"; }; 336 3C663F021AB0155100286D8B /* srs_aac_raw_publish.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = srs_aac_raw_publish.c; path = ../../../research/librtmp/srs_aac_raw_publish.c; sourceTree = "<group>"; };
@@ -573,6 +576,8 @@ @@ -573,6 +576,8 @@
573 3C1232771AAE81D900CE8F6C /* srs_app_mpegts_udp.hpp */, 576 3C1232771AAE81D900CE8F6C /* srs_app_mpegts_udp.hpp */,
574 3C1232781AAE81D900CE8F6C /* srs_app_pithy_print.cpp */, 577 3C1232781AAE81D900CE8F6C /* srs_app_pithy_print.cpp */,
575 3C1232791AAE81D900CE8F6C /* srs_app_pithy_print.hpp */, 578 3C1232791AAE81D900CE8F6C /* srs_app_pithy_print.hpp */,
  579 + 3C4F97101B8B466D00FF0E46 /* srs_app_process.cpp */,
  580 + 3C4F97111B8B466D00FF0E46 /* srs_app_process.hpp */,
576 3C12327A1AAE81D900CE8F6C /* srs_app_recv_thread.cpp */, 581 3C12327A1AAE81D900CE8F6C /* srs_app_recv_thread.cpp */,
577 3C12327B1AAE81D900CE8F6C /* srs_app_recv_thread.hpp */, 582 3C12327B1AAE81D900CE8F6C /* srs_app_recv_thread.hpp */,
578 3C12327C1AAE81D900CE8F6C /* srs_app_refer.cpp */, 583 3C12327C1AAE81D900CE8F6C /* srs_app_refer.cpp */,
@@ -911,6 +916,7 @@ @@ -911,6 +916,7 @@
911 3C1232B21AAE81D900CE8F6C /* srs_app_source.cpp in Sources */, 916 3C1232B21AAE81D900CE8F6C /* srs_app_source.cpp in Sources */,
912 3C1231F71AAE652D00CE8F6C /* srs_core_performance.cpp in Sources */, 917 3C1231F71AAE652D00CE8F6C /* srs_core_performance.cpp in Sources */,
913 3CC52DD81ACE4023006FEB01 /* srs_utest_amf0.cpp in Sources */, 918 3CC52DD81ACE4023006FEB01 /* srs_utest_amf0.cpp in Sources */,
  919 + 3C4F97121B8B466D00FF0E46 /* srs_app_process.cpp in Sources */,
914 3C1232981AAE81D900CE8F6C /* srs_app_edge.cpp in Sources */, 920 3C1232981AAE81D900CE8F6C /* srs_app_edge.cpp in Sources */,
915 3CC52DDB1ACE4023006FEB01 /* srs_utest_kernel.cpp in Sources */, 921 3CC52DDB1ACE4023006FEB01 /* srs_utest_kernel.cpp in Sources */,
916 3C689F9E1AB6AAC800C9CEEE /* md.S in Sources */, 922 3C689F9E1AB6AAC800C9CEEE /* md.S in Sources */,
@@ -30,12 +30,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,12 +30,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <signal.h> 30 #include <signal.h>
31 #include <sys/types.h> 31 #include <sys/types.h>
32 32
  33 +#include <vector>
33 using namespace std; 34 using namespace std;
34 35
35 #include <srs_kernel_error.hpp> 36 #include <srs_kernel_error.hpp>
36 #include <srs_kernel_log.hpp> 37 #include <srs_kernel_log.hpp>
37 #include <srs_app_config.hpp> 38 #include <srs_app_config.hpp>
38 #include <srs_app_utility.hpp> 39 #include <srs_app_utility.hpp>
  40 +#include <srs_app_process.hpp>
  41 +#include <srs_core_autofree.hpp>
39 42
40 #ifdef SRS_AUTO_FFMPEG_STUB 43 #ifdef SRS_AUTO_FFMPEG_STUB
41 44
@@ -52,9 +55,6 @@ using namespace std; @@ -52,9 +55,6 @@ using namespace std;
52 55
53 SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin) 56 SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
54 { 57 {
55 - started = false;  
56 - fast_stopped = false;  
57 - pid = -1;  
58 ffmpeg = ffmpeg_bin; 58 ffmpeg = ffmpeg_bin;
59 59
60 vbitrate = 0; 60 vbitrate = 0;
@@ -65,11 +65,15 @@ SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin) @@ -65,11 +65,15 @@ SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
65 abitrate = 0; 65 abitrate = 0;
66 asample_rate = 0; 66 asample_rate = 0;
67 achannels = 0; 67 achannels = 0;
  68 +
  69 + process = new SrsProcess();
68 } 70 }
69 71
70 SrsFFMPEG::~SrsFFMPEG() 72 SrsFFMPEG::~SrsFFMPEG()
71 { 73 {
72 stop(); 74 stop();
  75 +
  76 + srs_freep(process);
73 } 77 }
74 78
75 void SrsFFMPEG::set_iparams(string iparams) 79 void SrsFFMPEG::set_iparams(string iparams)
@@ -236,17 +240,22 @@ int SrsFFMPEG::start() @@ -236,17 +240,22 @@ int SrsFFMPEG::start()
236 { 240 {
237 int ret = ERROR_SUCCESS; 241 int ret = ERROR_SUCCESS;
238 242
239 - if (started) { 243 + if (process->started()) {
240 return ret; 244 return ret;
241 } 245 }
242 246
243 // prepare exec params 247 // prepare exec params
244 - char tmp[256];  
245 - std::vector<std::string> params; 248 + // @remark we should never use stack variable, use heap to alloc to make lldb happy.
  249 + #define SRS_TMP_SIZE 512
  250 + char* tmp = new char[SRS_TMP_SIZE];
  251 + SrsAutoFree(char, tmp);
  252 +
  253 + // the argv for process.
  254 + params.clear();
246 255
247 // argv[0], set to ffmpeg bin. 256 // argv[0], set to ffmpeg bin.
248 // The execv() and execvp() functions .... 257 // The execv() and execvp() functions ....
249 - // The first argument, by convention, should point to 258 + // The first argument, by convention, should point to
250 // the filename associated with the file being executed. 259 // the filename associated with the file being executed.
251 params.push_back(ffmpeg); 260 params.push_back(ffmpeg);
252 261
@@ -287,32 +296,32 @@ int SrsFFMPEG::start() @@ -287,32 +296,32 @@ int SrsFFMPEG::start()
287 if (vcodec != SRS_RTMP_ENCODER_COPY && vcodec != SRS_RTMP_ENCODER_NO_VIDEO) { 296 if (vcodec != SRS_RTMP_ENCODER_COPY && vcodec != SRS_RTMP_ENCODER_NO_VIDEO) {
288 if (vbitrate > 0) { 297 if (vbitrate > 0) {
289 params.push_back("-b:v"); 298 params.push_back("-b:v");
290 - snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000); 299 + snprintf(tmp, SRS_TMP_SIZE, "%d", vbitrate * 1000);
291 params.push_back(tmp); 300 params.push_back(tmp);
292 } 301 }
293 302
294 if (vfps > 0) { 303 if (vfps > 0) {
295 params.push_back("-r"); 304 params.push_back("-r");
296 - snprintf(tmp, sizeof(tmp), "%.2f", vfps); 305 + snprintf(tmp, SRS_TMP_SIZE, "%.2f", vfps);
297 params.push_back(tmp); 306 params.push_back(tmp);
298 } 307 }
299 308
300 if (vwidth > 0 && vheight > 0) { 309 if (vwidth > 0 && vheight > 0) {
301 params.push_back("-s"); 310 params.push_back("-s");
302 - snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight); 311 + snprintf(tmp, SRS_TMP_SIZE, "%dx%d", vwidth, vheight);
303 params.push_back(tmp); 312 params.push_back(tmp);
304 } 313 }
305 314
306 // TODO: add aspect if needed. 315 // TODO: add aspect if needed.
307 if (vwidth > 0 && vheight > 0) { 316 if (vwidth > 0 && vheight > 0) {
308 params.push_back("-aspect"); 317 params.push_back("-aspect");
309 - snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight); 318 + snprintf(tmp, SRS_TMP_SIZE, "%d:%d", vwidth, vheight);
310 params.push_back(tmp); 319 params.push_back(tmp);
311 } 320 }
312 321
313 if (vthreads > 0) { 322 if (vthreads > 0) {
314 params.push_back("-threads"); 323 params.push_back("-threads");
315 - snprintf(tmp, sizeof(tmp), "%d", vthreads); 324 + snprintf(tmp, SRS_TMP_SIZE, "%d", vthreads);
316 params.push_back(tmp); 325 params.push_back(tmp);
317 } 326 }
318 327
@@ -347,19 +356,19 @@ int SrsFFMPEG::start() @@ -347,19 +356,19 @@ int SrsFFMPEG::start()
347 if (acodec != SRS_RTMP_ENCODER_COPY) { 356 if (acodec != SRS_RTMP_ENCODER_COPY) {
348 if (abitrate > 0) { 357 if (abitrate > 0) {
349 params.push_back("-b:a"); 358 params.push_back("-b:a");
350 - snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000); 359 + snprintf(tmp, SRS_TMP_SIZE, "%d", abitrate * 1000);
351 params.push_back(tmp); 360 params.push_back(tmp);
352 } 361 }
353 362
354 if (asample_rate > 0) { 363 if (asample_rate > 0) {
355 params.push_back("-ar"); 364 params.push_back("-ar");
356 - snprintf(tmp, sizeof(tmp), "%d", asample_rate); 365 + snprintf(tmp, SRS_TMP_SIZE, "%d", asample_rate);
357 params.push_back(tmp); 366 params.push_back(tmp);
358 } 367 }
359 368
360 if (achannels > 0) { 369 if (achannels > 0) {
361 params.push_back("-ac"); 370 params.push_back("-ac");
362 - snprintf(tmp, sizeof(tmp), "%d", achannels); 371 + snprintf(tmp, SRS_TMP_SIZE, "%d", achannels);
363 params.push_back(tmp); 372 params.push_back(tmp);
364 } 373 }
365 374
@@ -387,7 +396,7 @@ int SrsFFMPEG::start() @@ -387,7 +396,7 @@ int SrsFFMPEG::start()
387 } 396 }
388 } 397 }
389 } 398 }
390 - 399 +
391 // output 400 // output
392 if (oformat != "off" && !oformat.empty()) { 401 if (oformat != "off" && !oformat.empty()) {
393 params.push_back("-f"); 402 params.push_back("-f");
@@ -396,176 +405,40 @@ int SrsFFMPEG::start() @@ -396,176 +405,40 @@ int SrsFFMPEG::start()
396 405
397 params.push_back("-y"); 406 params.push_back("-y");
398 params.push_back(_output); 407 params.push_back(_output);
399 -  
400 - std::string cli;  
401 - if (true) {  
402 - for (int i = 0; i < (int)params.size(); i++) {  
403 - std::string ffp = params[i];  
404 - cli += ffp;  
405 - if (i < (int)params.size() - 1) {  
406 - cli += " ";  
407 - }  
408 - }  
409 - srs_trace("start ffmpeg, log: %s, params: %s", log_file.c_str(), cli.c_str());  
410 - }  
411 -  
412 - // for log  
413 - int cid = _srs_context->get_id();  
414 408
415 - // TODO: fork or vfork?  
416 - if ((pid = fork()) < 0) {  
417 - ret = ERROR_ENCODER_FORK;  
418 - srs_error("vfork process failed. ret=%d", ret);  
419 - return ret; 409 + // when specified the log file.
  410 + if (false && !log_file.empty()) {
  411 + // stdout
  412 + params.push_back("1");
  413 + params.push_back(">");
  414 + params.push_back(log_file);
  415 + // stderr
  416 + params.push_back("2");
  417 + params.push_back(">");
  418 + params.push_back(log_file);
420 } 419 }
421 420
422 - // child process: ffmpeg encoder engine.  
423 - if (pid == 0) {  
424 - // ignore the SIGINT and SIGTERM  
425 - signal(SIGINT, SIG_IGN);  
426 - signal(SIGTERM, SIG_IGN);  
427 -  
428 - // redirect logs to file.  
429 - int log_fd = -1;  
430 - int flags = O_CREAT|O_WRONLY|O_APPEND;  
431 - mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;  
432 - if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) {  
433 - ret = ERROR_ENCODER_OPEN;  
434 - srs_error("open encoder file %s failed. ret=%d", log_file.c_str(), ret);  
435 - return ret;  
436 - }  
437 -  
438 - // log basic info  
439 - if (true) {  
440 - char buf[4096];  
441 - int pos = 0;  
442 - pos += snprintf(buf + pos, sizeof(buf) - pos, "\n");  
443 - pos += snprintf(buf + pos, sizeof(buf) - pos, "ffmpeg cid=%d\n", cid);  
444 - pos += snprintf(buf + pos, sizeof(buf) - pos, "log=%s\n", log_file.c_str());  
445 - pos += snprintf(buf + pos, sizeof(buf) - pos, "params: %s\n", cli.c_str());  
446 - ::write(log_fd, buf, pos);  
447 - }  
448 -  
449 - // dup to stdout and stderr.  
450 - if (dup2(log_fd, STDOUT_FILENO) < 0) {  
451 - ret = ERROR_ENCODER_DUP2;  
452 - srs_error("dup2 encoder file failed. ret=%d", ret);  
453 - return ret;  
454 - }  
455 - if (dup2(log_fd, STDERR_FILENO) < 0) {  
456 - ret = ERROR_ENCODER_DUP2;  
457 - srs_error("dup2 encoder file failed. ret=%d", ret);  
458 - return ret;  
459 - }  
460 -  
461 - // close log fd  
462 - ::close(log_fd);  
463 - // close other fds  
464 - // TODO: do in right way.  
465 - for (int i = 3; i < 1024; i++) {  
466 - ::close(i);  
467 - }  
468 -  
469 - // memory leak in child process, it's ok.  
470 - char** charpv_params = new char*[params.size() + 1];  
471 - for (int i = 0; i < (int)params.size(); i++) {  
472 - std::string& p = params[i];  
473 - charpv_params[i] = (char*)p.data();  
474 - }  
475 - // EOF: NULL  
476 - charpv_params[params.size()] = NULL;  
477 -  
478 - // TODO: execv or execvp  
479 - ret = execv(ffmpeg.c_str(), charpv_params);  
480 - if (ret < 0) {  
481 - fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)",  
482 - errno, strerror(errno));  
483 - }  
484 - exit(ret);  
485 - }  
486 -  
487 - // parent.  
488 - if (pid > 0) {  
489 - started = true;  
490 - srs_trace("vfored ffmpeg encoder engine, pid=%d", pid); 421 + // initialize the process.
  422 + if ((ret = process->initialize(ffmpeg, params)) != ERROR_SUCCESS) {
491 return ret; 423 return ret;
492 } 424 }
493 425
494 - return ret; 426 + return process->start();
495 } 427 }
496 428
497 int SrsFFMPEG::cycle() 429 int SrsFFMPEG::cycle()
498 { 430 {
499 - int ret = ERROR_SUCCESS;  
500 -  
501 - if (!started) {  
502 - return ret;  
503 - }  
504 -  
505 - // ffmpeg is prepare to stop, donot cycle.  
506 - if (fast_stopped) {  
507 - return ret;  
508 - }  
509 -  
510 - int status = 0;  
511 - pid_t p = waitpid(pid, &status, WNOHANG);  
512 -  
513 - if (p < 0) {  
514 - ret = ERROR_SYSTEM_WAITPID;  
515 - srs_error("transcode waitpid failed, pid=%d, ret=%d", pid, ret);  
516 - return ret;  
517 - }  
518 -  
519 - if (p == 0) {  
520 - srs_info("transcode process pid=%d is running.", pid);  
521 - return ret;  
522 - }  
523 -  
524 - srs_trace("transcode process pid=%d terminate, restart it.", pid);  
525 - started = false;  
526 -  
527 - return ret; 431 + return process->cycle();
528 } 432 }
529 433
530 void SrsFFMPEG::stop() 434 void SrsFFMPEG::stop()
531 { 435 {
532 - if (!started) {  
533 - return;  
534 - }  
535 -  
536 - // kill the ffmpeg,  
537 - // when rewind, upstream will stop publish(unpublish),  
538 - // unpublish event will stop all ffmpeg encoders,  
539 - // then publish will start all ffmpeg encoders.  
540 - int ret = srs_kill_forced(pid);  
541 - if (ret != ERROR_SUCCESS) {  
542 - srs_warn("ignore kill the encoder failed, pid=%d. ret=%d", pid, ret);  
543 - return;  
544 - }  
545 -  
546 - // terminated, set started to false to stop the cycle.  
547 - started = false; 436 + process->stop();
548 } 437 }
549 438
550 void SrsFFMPEG::fast_stop() 439 void SrsFFMPEG::fast_stop()
551 { 440 {
552 - int ret = ERROR_SUCCESS;  
553 -  
554 - if (!started) {  
555 - return;  
556 - }  
557 -  
558 - if (pid <= 0) {  
559 - return;  
560 - }  
561 -  
562 - if (kill(pid, SIGTERM) < 0) {  
563 - ret = ERROR_SYSTEM_KILL;  
564 - srs_warn("ignore fast stop ffmpeg failed, pid=%d. ret=%d", pid, ret);  
565 - return;  
566 - }  
567 -  
568 - return; 441 + process->fast_stop();
569 } 442 }
570 443
571 #endif 444 #endif
@@ -31,11 +31,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,11 +31,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 31
32 #ifdef SRS_AUTO_FFMPEG_STUB 32 #ifdef SRS_AUTO_FFMPEG_STUB
33 33
34 -#include <string>  
35 #include <vector> 34 #include <vector>
  35 +#include <string>
36 36
37 class SrsConfDirective; 37 class SrsConfDirective;
38 class SrsPithyPrint; 38 class SrsPithyPrint;
  39 +class SrsProcess;
39 40
40 /** 41 /**
41 * a transcode engine: ffmepg, 42 * a transcode engine: ffmepg,
@@ -44,11 +45,8 @@ class SrsPithyPrint; @@ -44,11 +45,8 @@ class SrsPithyPrint;
44 class SrsFFMPEG 45 class SrsFFMPEG
45 { 46 {
46 private: 47 private:
47 - bool started;  
48 - // whether SIGTERM send but need to wait or SIGKILL.  
49 - bool fast_stopped;  
50 - pid_t pid;  
51 -private: 48 + SrsProcess* process;
  49 + std::vector<std::string> params;
52 std::string log_file; 50 std::string log_file;
53 private: 51 private:
54 std::string ffmpeg; 52 std::string ffmpeg;
@@ -83,26 +81,11 @@ public: @@ -83,26 +81,11 @@ public:
83 virtual int initialize(std::string in, std::string out, std::string log); 81 virtual int initialize(std::string in, std::string out, std::string log);
84 virtual int initialize_transcode(SrsConfDirective* engine); 82 virtual int initialize_transcode(SrsConfDirective* engine);
85 virtual int initialize_copy(); 83 virtual int initialize_copy();
  84 +public:
86 virtual int start(); 85 virtual int start();
87 virtual int cycle(); 86 virtual int cycle();
88 - /**  
89 - * send SIGTERM then SIGKILL to ensure the process stopped.  
90 - * the stop will wait [0, SRS_PROCESS_QUIT_TIMEOUT_MS] depends on the  
91 - * process quit timeout.  
92 - * @remark use fast_stop before stop one by one, when got lots of process to quit.  
93 - */  
94 virtual void stop(); 87 virtual void stop();
95 public: 88 public:
96 - /**  
97 - * the fast stop is to send a SIGTERM.  
98 - * for example, the ingesters owner lots of FFMPEG, it will take a long time  
99 - * to stop one by one, instead the ingesters can fast_stop all FFMPEG, then  
100 - * wait one by one to stop, it's more faster.  
101 - * @remark user must use stop() to ensure the ffmpeg to stopped.  
102 - * @remark we got N processes to stop, compare the time we spend,  
103 - * when use stop without fast_stop, we spend maybe [0, SRS_PROCESS_QUIT_TIMEOUT_MS * N]  
104 - * but use fast_stop then stop, the time is almost [0, SRS_PROCESS_QUIT_TIMEOUT_MS].  
105 - */  
106 virtual void fast_stop(); 89 virtual void fast_stop();
107 }; 90 };
108 91
  1 +/*
  2 + The MIT License (MIT)
  3 +
  4 + Copyright (c) 2013-2015 SRS(simple-rtmp-server)
  5 +
  6 + Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 + this software and associated documentation files (the "Software"), to deal in
  8 + the Software without restriction, including without limitation the rights to
  9 + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 + the Software, and to permit persons to whom the Software is furnished to do so,
  11 + subject to the following conditions:
  12 +
  13 + The above copyright notice and this permission notice shall be included in all
  14 + copies or substantial portions of the Software.
  15 +
  16 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 + */
  23 +
  24 +#include <srs_app_process.hpp>
  25 +
  26 +#include <stdlib.h>
  27 +#include <unistd.h>
  28 +#include <sys/wait.h>
  29 +#include <fcntl.h>
  30 +#include <signal.h>
  31 +#include <sys/types.h>
  32 +
  33 +using namespace std;
  34 +
  35 +#include <srs_kernel_error.hpp>
  36 +#include <srs_kernel_log.hpp>
  37 +#include <srs_app_config.hpp>
  38 +#include <srs_app_utility.hpp>
  39 +
  40 +SrsProcess::SrsProcess()
  41 +{
  42 + is_started = false;
  43 + fast_stopped = false;
  44 + pid = -1;
  45 +}
  46 +
  47 +SrsProcess::~SrsProcess()
  48 +{
  49 +}
  50 +
  51 +bool SrsProcess::started()
  52 +{
  53 + return is_started;
  54 +}
  55 +
  56 +int SrsProcess::initialize(string binary, vector<string> argv)
  57 +{
  58 + int ret = ERROR_SUCCESS;
  59 +
  60 + bin = binary;
  61 + params = argv;
  62 +
  63 + return ret;
  64 +}
  65 +
  66 +int SrsProcess::start()
  67 +{
  68 + int ret = ERROR_SUCCESS;
  69 +
  70 + if (is_started) {
  71 + return ret;
  72 + }
  73 +
  74 + std::string cli;
  75 + if (true) {
  76 + for (int i = 0; i < (int)params.size(); i++) {
  77 + std::string ffp = params[i];
  78 + cli += ffp;
  79 + if (i < (int)params.size() - 1) {
  80 + cli += " ";
  81 + }
  82 + }
  83 + srs_trace("fork process: %s %s", bin.c_str(), cli.c_str());
  84 + }
  85 +
  86 + // for log
  87 + int cid = _srs_context->get_id();
  88 +
  89 + // TODO: fork or vfork?
  90 + if ((pid = fork()) < 0) {
  91 + ret = ERROR_ENCODER_FORK;
  92 + srs_error("vfork process failed. ret=%d", ret);
  93 + return ret;
  94 + }
  95 +
  96 + // child process: ffmpeg encoder engine.
  97 + if (pid == 0) {
  98 + // ignore the SIGINT and SIGTERM
  99 + signal(SIGINT, SIG_IGN);
  100 + signal(SIGTERM, SIG_IGN);
  101 +
  102 + // log basic info
  103 + if (true) {
  104 + fprintf(stderr, "\n");
  105 + fprintf(stderr, "process parent cid=%d", cid);
  106 + fprintf(stderr, "process binary=%s", bin.c_str());
  107 + fprintf(stderr, "process params: %s %s", bin.c_str(), cli.c_str());
  108 + }
  109 +
  110 + // close other fds
  111 + // TODO: do in right way.
  112 + for (int i = 3; i < 1024; i++) {
  113 + ::close(i);
  114 + }
  115 +
  116 + // memory leak in child process, it's ok.
  117 + char** charpv_params = new char*[params.size() + 1];
  118 + for (int i = 0; i < (int)params.size(); i++) {
  119 + std::string& p = params[i];
  120 + charpv_params[i] = (char*)p.data();
  121 + }
  122 + // EOF: NULL
  123 + charpv_params[params.size()] = NULL;
  124 +
  125 + // TODO: execv or execvp
  126 + ret = execv(bin.c_str(), charpv_params);
  127 + if (ret < 0) {
  128 + fprintf(stderr, "fork process failed, errno=%d(%s)", errno, strerror(errno));
  129 + }
  130 + exit(ret);
  131 + }
  132 +
  133 + // parent.
  134 + if (pid > 0) {
  135 + is_started = true;
  136 + srs_trace("vfored process, pid=%d, cli=%s", pid, bin.c_str());
  137 + return ret;
  138 + }
  139 +
  140 + return ret;
  141 +}
  142 +
  143 +int SrsProcess::cycle()
  144 +{
  145 + int ret = ERROR_SUCCESS;
  146 +
  147 + if (!is_started) {
  148 + return ret;
  149 + }
  150 +
  151 + // ffmpeg is prepare to stop, donot cycle.
  152 + if (fast_stopped) {
  153 + return ret;
  154 + }
  155 +
  156 + int status = 0;
  157 + pid_t p = waitpid(pid, &status, WNOHANG);
  158 +
  159 + if (p < 0) {
  160 + ret = ERROR_SYSTEM_WAITPID;
  161 + srs_error("process waitpid failed, pid=%d, ret=%d", pid, ret);
  162 + return ret;
  163 + }
  164 +
  165 + if (p == 0) {
  166 + srs_info("process process pid=%d is running.", pid);
  167 + return ret;
  168 + }
  169 +
  170 + srs_trace("process pid=%d terminate, restart it.", pid);
  171 + is_started = false;
  172 +
  173 + return ret;
  174 +}
  175 +
  176 +void SrsProcess::stop()
  177 +{
  178 + if (!is_started) {
  179 + return;
  180 + }
  181 +
  182 + // kill the ffmpeg,
  183 + // when rewind, upstream will stop publish(unpublish),
  184 + // unpublish event will stop all ffmpeg encoders,
  185 + // then publish will start all ffmpeg encoders.
  186 + int ret = srs_kill_forced(pid);
  187 + if (ret != ERROR_SUCCESS) {
  188 + srs_warn("ignore kill the process failed, pid=%d. ret=%d", pid, ret);
  189 + return;
  190 + }
  191 +
  192 + // terminated, set started to false to stop the cycle.
  193 + is_started = false;
  194 +}
  195 +
  196 +void SrsProcess::fast_stop()
  197 +{
  198 + int ret = ERROR_SUCCESS;
  199 +
  200 + if (!is_started) {
  201 + return;
  202 + }
  203 +
  204 + if (pid <= 0) {
  205 + return;
  206 + }
  207 +
  208 + if (kill(pid, SIGTERM) < 0) {
  209 + ret = ERROR_SYSTEM_KILL;
  210 + srs_warn("ignore fast stop process failed, pid=%d. ret=%d", pid, ret);
  211 + return;
  212 + }
  213 +
  214 + return;
  215 +}
  216 +
  1 +/*
  2 + The MIT License (MIT)
  3 +
  4 + Copyright (c) 2013-2015 SRS(simple-rtmp-server)
  5 +
  6 + Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 + this software and associated documentation files (the "Software"), to deal in
  8 + the Software without restriction, including without limitation the rights to
  9 + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 + the Software, and to permit persons to whom the Software is furnished to do so,
  11 + subject to the following conditions:
  12 +
  13 + The above copyright notice and this permission notice shall be included in all
  14 + copies or substantial portions of the Software.
  15 +
  16 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 + */
  23 +
  24 +#ifndef SRS_APP_PROCESS_HPP
  25 +#define SRS_APP_PROCESS_HPP
  26 +
  27 +/*
  28 +#include <srs_app_process.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +#include <string>
  33 +#include <vector>
  34 +
  35 +/**
  36 + * to start and stop a process, cycle to restart the process when terminated.
  37 + * the usage:
  38 + * process = new SrsProcess();
  39 + * if ((ret = process->initialize(binary, argv)) != ERROR_SUCCESS) { return ret; }
  40 + * if ((ret = process->start()) != ERROR_SUCCESS) { return ret; }
  41 + * if ((ret = process->cycle()) != ERROR_SUCCESS) { return ret; }
  42 + * process->fast_stop();
  43 + * process->stop();
  44 + */
  45 +class SrsProcess
  46 +{
  47 +private:
  48 + bool is_started;
  49 + // whether SIGTERM send but need to wait or SIGKILL.
  50 + bool fast_stopped;
  51 + pid_t pid;
  52 +private:
  53 + std::string bin;
  54 + std::vector<std::string> params;
  55 +public:
  56 + SrsProcess();
  57 + virtual ~SrsProcess();
  58 +public:
  59 + /**
  60 + * whether process is already started.
  61 + */
  62 + virtual bool started();
  63 + /**
  64 + * initialize the process with binary and argv.
  65 + */
  66 + virtual int initialize(std::string binary, std::vector<std::string> argv);
  67 +public:
  68 + /**
  69 + * start the process, ignore when already started.
  70 + */
  71 + virtual int start();
  72 + /**
  73 + * cycle check the process, update the state of process.
  74 + * @remark when process terminated(not started), user can restart it again by start().
  75 + */
  76 + virtual int cycle();
  77 + /**
  78 + * send SIGTERM then SIGKILL to ensure the process stopped.
  79 + * the stop will wait [0, SRS_PROCESS_QUIT_TIMEOUT_MS] depends on the
  80 + * process quit timeout.
  81 + * @remark use fast_stop before stop one by one, when got lots of process to quit.
  82 + */
  83 + virtual void stop();
  84 +public:
  85 + /**
  86 + * the fast stop is to send a SIGTERM.
  87 + * for example, the ingesters owner lots of FFMPEG, it will take a long time
  88 + * to stop one by one, instead the ingesters can fast_stop all FFMPEG, then
  89 + * wait one by one to stop, it's more faster.
  90 + * @remark user must use stop() to ensure the ffmpeg to stopped.
  91 + * @remark we got N processes to stop, compare the time we spend,
  92 + * when use stop without fast_stop, we spend maybe [0, SRS_PROCESS_QUIT_TIMEOUT_MS * N]
  93 + * but use fast_stop then stop, the time is almost [0, SRS_PROCESS_QUIT_TIMEOUT_MS].
  94 + */
  95 + virtual void fast_stop();
  96 +};
  97 +
  98 +#endif
  99 +
@@ -920,7 +920,11 @@ extern int srs_human_print_rtmp_packet4(char type, u_int32_t timestamp, char* da @@ -920,7 +920,11 @@ extern int srs_human_print_rtmp_packet4(char type, u_int32_t timestamp, char* da
920 920
921 // log to console, for use srs-librtmp application. 921 // log to console, for use srs-librtmp application.
922 extern const char* srs_human_format_time(); 922 extern const char* srs_human_format_time();
923 - 923 +
  924 +#ifndef _WIN32
  925 + // for getpid.
  926 + #include <unistd.h>
  927 +#endif
924 // when disabled log, donot compile it. 928 // when disabled log, donot compile it.
925 #ifdef SRS_DISABLE_LOG 929 #ifdef SRS_DISABLE_LOG
926 #define srs_human_trace(msg, ...) (void)0 930 #define srs_human_trace(msg, ...) (void)0
@@ -936,15 +940,13 @@ extern const char* srs_human_format_time(); @@ -936,15 +940,13 @@ extern const char* srs_human_format_time();
936 ************************************************************** 940 **************************************************************
937 * IO hijack, use your specified io functions. 941 * IO hijack, use your specified io functions.
938 ************************************************************** 942 **************************************************************
939 -*************************************************************/ 943 + *************************************************************/
940 // the void* will convert to your handler for io hijack. 944 // the void* will convert to your handler for io hijack.
941 typedef void* srs_hijack_io_t; 945 typedef void* srs_hijack_io_t;
942 #ifdef SRS_HIJACK_IO 946 #ifdef SRS_HIJACK_IO
943 #ifndef _WIN32 947 #ifndef _WIN32
944 // for iovec. 948 // for iovec.
945 #include <sys/uio.h> 949 #include <sys/uio.h>
946 - // for getpid.  
947 - #include <unistd.h>  
948 #endif 950 #endif
949 /** 951 /**
950 * get the hijack io object in rtmp protocol sdk. 952 * get the hijack io object in rtmp protocol sdk.