winlin

support ffmpeg filter

@@ -69,15 +69,16 @@ Supported operating systems and hardware: @@ -69,15 +69,16 @@ Supported operating systems and hardware:
69 14. support forward publish stream to build active-standby cluster.<br/> 69 14. support forward publish stream to build active-standby cluster.<br/>
70 15. support broadcast by forward the stream to other servers(origin/edge).<br/> 70 15. support broadcast by forward the stream to other servers(origin/edge).<br/>
71 16. support live stream transcoding by ffmpeg.<br/> 71 16. support live stream transcoding by ffmpeg.<br/>
72 -17. [plan] support full http callback api.<br/>  
73 -18. [plan] support network based cli and json result.<br/>  
74 -19. [plan] support bandwidth test api and flash client.<br/>  
75 -20. [plan] support adobe flash refer/token/swf verification.<br/>  
76 -21. [plan] support adobe amf3 codec.<br/>  
77 -22. [plan] support dvr(record live to vod file)<br/>  
78 -23. [plan] support FMS edge protocol<br/>  
79 -24. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/>  
80 -25. [plan] support RTMPT, http to tranverse firewalls<br/> 72 +17. support live stream transcoding by ffmpeg.<br/>
  73 +18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/>
  74 +19. [plan] support network based cli and json result.<br/>
  75 +20. [plan] support bandwidth test api and flash client.<br/>
  76 +21. [plan] support adobe flash refer/token/swf verification.<br/>
  77 +22. [plan] support adobe amf3 codec.<br/>
  78 +23. [plan] support dvr(record live to vod file)<br/>
  79 +24. [plan] support FMS edge protocol<br/>
  80 +25. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/>
  81 +26. [plan] support RTMPT, http to tranverse firewalls<br/>
81 82
82 ### Performance 83 ### Performance
83 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. 84 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB.
@@ -84,6 +84,7 @@ else @@ -84,6 +84,7 @@ else
84 --extra-ldflags='-L${ffmpeg_exported_release_dir}/lib -lm -ldl' \ 84 --extra-ldflags='-L${ffmpeg_exported_release_dir}/lib -lm -ldl' \
85 --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc \ 85 --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc \
86 --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \ 86 --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \
  87 + --enable-libfreetype \
87 --enable-libx264 --enable-libmp3lame --enable-libaacplus \ 88 --enable-libx264 --enable-libmp3lame --enable-libaacplus \
88 --enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers && 89 --enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers &&
89 make && make install 90 make && make install
@@ -15,13 +15,19 @@ vhost __defaultVhost__ { @@ -15,13 +15,19 @@ vhost __defaultVhost__ {
15 hls_path ./objs/nginx/html; 15 hls_path ./objs/nginx/html;
16 hls_fragment 5; 16 hls_fragment 5;
17 hls_window 30; 17 hls_window 30;
18 - #forward 127.0.0.1:1936; 18 + forward 127.0.0.1:1936;
19 transcode { 19 transcode {
20 enabled on; 20 enabled on;
21 ffmpeg ./objs/ffmpeg/bin/ffmpeg; 21 ffmpeg ./objs/ffmpeg/bin/ffmpeg;
22 #ffmpeg ./research/ffempty/ffempty; 22 #ffmpeg ./research/ffempty/ffempty;
23 engine fast{ 23 engine fast{
24 enabled on; 24 enabled on;
  25 + vfilter {
  26 + vf 'drawtext=text=SRS';
  27 + #vf 'crop=in_w-20:in_h-160:10:80';
  28 + #i ./doc/ffmpeg-logo.png;
  29 + #filter_complex 'overlay=10:10';
  30 + }
25 vcodec libx264; 31 vcodec libx264;
26 vbitrate 300; 32 vbitrate 300;
27 vfps 20; 33 vfps 20;
@@ -37,11 +43,15 @@ vhost __defaultVhost__ { @@ -37,11 +43,15 @@ vhost __defaultVhost__ {
37 asample_rate 44100; 43 asample_rate 44100;
38 achannels 2; 44 achannels 2;
39 aparams { 45 aparams {
  46 + profile:a aac_low;
40 } 47 }
41 output rtmp://[vhost]:[port]/[app]/[stream]_fast; 48 output rtmp://[vhost]:[port]/[app]/[stream]_fast;
42 } 49 }
43 engine sd{ 50 engine sd{
44 - enabled on; 51 + enabled off;
  52 + vfilter {
  53 + vf 'split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2';
  54 + }
45 vcodec libx264; 55 vcodec libx264;
46 vbitrate 500; 56 vbitrate 500;
47 vfps 20; 57 vfps 20;
@@ -79,6 +89,14 @@ vhost all.transcode.vhost.com { @@ -79,6 +89,14 @@ vhost all.transcode.vhost.com {
79 # whether the engine is enabled 89 # whether the engine is enabled
80 # default: off. 90 # default: off.
81 enabled on; 91 enabled on;
  92 + # ffmpeg filters, follows the main input.
  93 + vfilter {
  94 + # the logo input file.
  95 + i ./doc/ffmpeg-logo.png;
  96 + # the ffmpeg complex filter.
  97 + # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html
  98 + filter_complex 'overlay=10:10';
  99 + }
82 # video encoder name 100 # video encoder name
83 vcodec libx264; 101 vcodec libx264;
84 # video bitrate, in kbps 102 # video bitrate, in kbps
@@ -100,6 +118,13 @@ vhost all.transcode.vhost.com { @@ -100,6 +118,13 @@ vhost all.transcode.vhost.com {
100 vpreset medium; 118 vpreset medium;
101 # other x264 or ffmpeg video params 119 # other x264 or ffmpeg video params
102 vparams { 120 vparams {
  121 + # ffmpeg options, @see: http://ffmpeg.org/ffmpeg.html
  122 + t 100;
  123 + # 264 params, @see: http://ffmpeg.org/ffmpeg-codecs.html#libx264
  124 + coder 1;
  125 + b_strategy 2;
  126 + bf 3;
  127 + refs 10;
103 } 128 }
104 # audio encoder name 129 # audio encoder name
105 acodec libaacplus; 130 acodec libaacplus;
@@ -182,12 +207,102 @@ vhost all.transcode.vhost.com { @@ -182,12 +207,102 @@ vhost all.transcode.vhost.com {
182 } 207 }
183 } 208 }
184 } 209 }
  210 +# the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction
  211 +vhost mirror.transcode.vhost.com {
  212 + transcode {
  213 + enabled on;
  214 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  215 + engine mirror{
  216 + enabled on;
  217 + vfilter {
  218 + vf 'split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2';
  219 + }
  220 + vcodec libx264;
  221 + vbitrate 300;
  222 + vfps 20;
  223 + vwidth 480;
  224 + vheight 320;
  225 + vthreads 2;
  226 + vprofile baseline;
  227 + vpreset superfast;
  228 + vparams {
  229 + }
  230 + acodec libaacplus;
  231 + abitrate 30;
  232 + asample_rate 44100;
  233 + achannels 2;
  234 + aparams {
  235 + }
  236 + output rtmp://[vhost]:[port]/[app]/[stream]_mirror;
  237 + }
  238 + }
  239 +}
  240 +# the logo filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop
  241 +vhost crop.transcode.vhost.com {
  242 + transcode {
  243 + enabled on;
  244 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  245 + engine crop{
  246 + enabled on;
  247 + vfilter {
  248 + vf 'crop=in_w-20:in_h-160:10:80';
  249 + }
  250 + vcodec libx264;
  251 + vbitrate 300;
  252 + vfps 20;
  253 + vwidth 480;
  254 + vheight 320;
  255 + vthreads 2;
  256 + vprofile baseline;
  257 + vpreset superfast;
  258 + vparams {
  259 + }
  260 + acodec libaacplus;
  261 + abitrate 30;
  262 + asample_rate 44100;
  263 + achannels 2;
  264 + aparams {
  265 + }
  266 + output rtmp://[vhost]:[port]/[app]/[stream]_crop;
  267 + }
  268 + }
  269 +}
  270 +# the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop
  271 +vhost logo.transcode.vhost.com {
  272 + transcode {
  273 + enabled on;
  274 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  275 + engine logo{
  276 + enabled on;
  277 + vfilter {
  278 + vf 'crop=200:100:10:10';
  279 + }
  280 + vcodec libx264;
  281 + vbitrate 300;
  282 + vfps 20;
  283 + vwidth 480;
  284 + vheight 320;
  285 + vthreads 2;
  286 + vprofile baseline;
  287 + vpreset superfast;
  288 + vparams {
  289 + }
  290 + acodec libaacplus;
  291 + abitrate 30;
  292 + asample_rate 44100;
  293 + achannels 2;
  294 + aparams {
  295 + }
  296 + output rtmp://[vhost]:[port]/[app]/[stream]_logo;
  297 + }
  298 + }
  299 +}
185 # transcode all stream using the empty ffmpeg demo, donothing. 300 # transcode all stream using the empty ffmpeg demo, donothing.
186 vhost ffempty.transcode.vhost.com { 301 vhost ffempty.transcode.vhost.com {
187 transcode { 302 transcode {
188 enabled on; 303 enabled on;
189 ffmpeg ./research/ffempty/ffempty; 304 ffmpeg ./research/ffempty/ffempty;
190 - engine fd{ 305 + engine empty{
191 enabled on; 306 enabled on;
192 vcodec libx264; 307 vcodec libx264;
193 vbitrate 300; 308 vbitrate 300;
@@ -205,7 +320,7 @@ vhost ffempty.transcode.vhost.com { @@ -205,7 +320,7 @@ vhost ffempty.transcode.vhost.com {
205 achannels 2; 320 achannels 2;
206 aparams { 321 aparams {
207 } 322 }
208 - output rtmp://[vhost]:[port]/[app]/[stream]_fast; 323 + output rtmp://[vhost]:[port]/[app]/[stream]_empty;
209 } 324 }
210 } 325 }
211 } 326 }
@@ -768,30 +768,48 @@ std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) @@ -768,30 +768,48 @@ std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
768 return conf->arg0(); 768 return conf->arg0();
769 } 769 }
770 770
771 -std::string SrsConfig::get_engine_vparams(SrsConfDirective* engine) 771 +void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams)
772 { 772 {
773 if (!engine) { 773 if (!engine) {
774 - return ""; 774 + return;
775 } 775 }
776 776
777 SrsConfDirective* conf = engine->get("vparams"); 777 SrsConfDirective* conf = engine->get("vparams");
778 if (!conf) { 778 if (!conf) {
779 - return ""; 779 + return;
780 } 780 }
781 781
782 - std::string avparams;  
783 for (int i = 0; i < (int)conf->directives.size(); i++) { 782 for (int i = 0; i < (int)conf->directives.size(); i++) {
784 SrsConfDirective* p = conf->directives[i]; 783 SrsConfDirective* p = conf->directives[i];
785 if (!p) { 784 if (!p) {
786 continue; 785 continue;
787 } 786 }
788 787
789 - avparams += p->name;  
790 - avparams += " ";  
791 - avparams += p->arg0(); 788 + vparams.push_back("-" + p->name);
  789 + vparams.push_back(p->arg0());
  790 + }
  791 +}
  792 +
  793 +void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter)
  794 +{
  795 + if (!engine) {
  796 + return;
  797 + }
  798 +
  799 + SrsConfDirective* conf = engine->get("vfilter");
  800 + if (!conf) {
  801 + return;
  802 + }
  803 +
  804 + for (int i = 0; i < (int)conf->directives.size(); i++) {
  805 + SrsConfDirective* p = conf->directives[i];
  806 + if (!p) {
  807 + continue;
792 } 808 }
793 809
794 - return avparams; 810 + vfilter.push_back("-" + p->name);
  811 + vfilter.push_back(p->arg0());
  812 + }
795 } 813 }
796 814
797 std::string SrsConfig::get_engine_acodec(SrsConfDirective* engine) 815 std::string SrsConfig::get_engine_acodec(SrsConfDirective* engine)
@@ -850,30 +868,26 @@ int SrsConfig::get_engine_achannels(SrsConfDirective* engine) @@ -850,30 +868,26 @@ int SrsConfig::get_engine_achannels(SrsConfDirective* engine)
850 return ::atoi(conf->arg0().c_str()); 868 return ::atoi(conf->arg0().c_str());
851 } 869 }
852 870
853 -std::string SrsConfig::get_engine_aparams(SrsConfDirective* engine) 871 +void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams)
854 { 872 {
855 if (!engine) { 873 if (!engine) {
856 - return ""; 874 + return;
857 } 875 }
858 876
859 SrsConfDirective* conf = engine->get("aparams"); 877 SrsConfDirective* conf = engine->get("aparams");
860 if (!conf) { 878 if (!conf) {
861 - return ""; 879 + return;
862 } 880 }
863 881
864 - std::string avparams;  
865 for (int i = 0; i < (int)conf->directives.size(); i++) { 882 for (int i = 0; i < (int)conf->directives.size(); i++) {
866 SrsConfDirective* p = conf->directives[i]; 883 SrsConfDirective* p = conf->directives[i];
867 if (!p) { 884 if (!p) {
868 continue; 885 continue;
869 } 886 }
870 887
871 - avparams += p->name;  
872 - avparams += " ";  
873 - avparams += p->arg0(); 888 + aparams.push_back("-" + p->name);
  889 + aparams.push_back(p->arg0());
874 } 890 }
875 -  
876 - return avparams;  
877 } 891 }
878 892
879 std::string SrsConfig::get_engine_output(SrsConfDirective* engine) 893 std::string SrsConfig::get_engine_output(SrsConfDirective* engine)
@@ -128,12 +128,13 @@ public: @@ -128,12 +128,13 @@ public:
128 virtual int get_engine_vthreads(SrsConfDirective* engine); 128 virtual int get_engine_vthreads(SrsConfDirective* engine);
129 virtual std::string get_engine_vprofile(SrsConfDirective* engine); 129 virtual std::string get_engine_vprofile(SrsConfDirective* engine);
130 virtual std::string get_engine_vpreset(SrsConfDirective* engine); 130 virtual std::string get_engine_vpreset(SrsConfDirective* engine);
131 - virtual std::string get_engine_vparams(SrsConfDirective* engine); 131 + virtual void get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams);
  132 + virtual void get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter);
132 virtual std::string get_engine_acodec(SrsConfDirective* engine); 133 virtual std::string get_engine_acodec(SrsConfDirective* engine);
133 virtual int get_engine_abitrate(SrsConfDirective* engine); 134 virtual int get_engine_abitrate(SrsConfDirective* engine);
134 virtual int get_engine_asample_rate(SrsConfDirective* engine); 135 virtual int get_engine_asample_rate(SrsConfDirective* engine);
135 virtual int get_engine_achannels(SrsConfDirective* engine); 136 virtual int get_engine_achannels(SrsConfDirective* engine);
136 - virtual std::string get_engine_aparams(SrsConfDirective* engine); 137 + virtual void get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams);
137 virtual std::string get_engine_output(SrsConfDirective* engine); 138 virtual std::string get_engine_output(SrsConfDirective* engine);
138 virtual SrsConfDirective* get_gop_cache(std::string vhost); 139 virtual SrsConfDirective* get_gop_cache(std::string vhost);
139 virtual SrsConfDirective* get_forward(std::string vhost); 140 virtual SrsConfDirective* get_forward(std::string vhost);
@@ -60,6 +60,7 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, @@ -60,6 +60,7 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
60 { 60 {
61 int ret = ERROR_SUCCESS; 61 int ret = ERROR_SUCCESS;
62 62
  63 + config->get_engine_vfilter(engine, vfilter);
63 vcodec = config->get_engine_vcodec(engine); 64 vcodec = config->get_engine_vcodec(engine);
64 vbitrate = config->get_engine_vbitrate(engine); 65 vbitrate = config->get_engine_vbitrate(engine);
65 vfps = config->get_engine_vfps(engine); 66 vfps = config->get_engine_vfps(engine);
@@ -68,12 +69,12 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, @@ -68,12 +69,12 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
68 vthreads = config->get_engine_vthreads(engine); 69 vthreads = config->get_engine_vthreads(engine);
69 vprofile = config->get_engine_vprofile(engine); 70 vprofile = config->get_engine_vprofile(engine);
70 vpreset = config->get_engine_vpreset(engine); 71 vpreset = config->get_engine_vpreset(engine);
71 - vparams = config->get_engine_vparams(engine); 72 + config->get_engine_vparams(engine, vparams);
72 acodec = config->get_engine_acodec(engine); 73 acodec = config->get_engine_acodec(engine);
73 abitrate = config->get_engine_abitrate(engine); 74 abitrate = config->get_engine_abitrate(engine);
74 asample_rate = config->get_engine_asample_rate(engine); 75 asample_rate = config->get_engine_asample_rate(engine);
75 achannels = config->get_engine_achannels(engine); 76 achannels = config->get_engine_achannels(engine);
76 - aparams = config->get_engine_aparams(engine); 77 + config->get_engine_aparams(engine, aparams);
77 output = config->get_engine_output(engine); 78 output = config->get_engine_output(engine);
78 79
79 // ensure the size is even. 80 // ensure the size is even.
@@ -198,37 +199,109 @@ int SrsFFMPEG::start() @@ -198,37 +199,109 @@ int SrsFFMPEG::start()
198 return ret; 199 return ret;
199 } 200 }
200 201
201 - // prepare execl params  
202 - char vsize[22];  
203 - snprintf(vsize, sizeof(vsize), "%dx%d", vwidth, vheight);  
204 - char vaspect[22];  
205 - snprintf(vaspect, sizeof(vaspect), "%d:%d", vwidth, vheight);  
206 - char s_vbitrate[10];  
207 - snprintf(s_vbitrate, sizeof(s_vbitrate), "%d", vbitrate * 1000);  
208 - char s_vfps[10];  
209 - snprintf(s_vfps, sizeof(s_vfps), "%.2f", vfps);  
210 - char s_vthreads[10];  
211 - snprintf(s_vthreads, sizeof(s_vthreads), "%d", vthreads);  
212 - char s_abitrate[10];  
213 - snprintf(s_abitrate, sizeof(s_abitrate), "%d", abitrate * 1000);  
214 - char s_asample_rate[10];  
215 - snprintf(s_asample_rate, sizeof(s_asample_rate), "%d", asample_rate);  
216 - char s_achannels[10];  
217 - snprintf(s_achannels, sizeof(s_achannels), "%d", achannels);  
218 -  
219 - // TODO: execl donot support the params.  
220 - // video params  
221 - std::string s_vpreset = vpreset; 202 + // prepare exec params
  203 + char tmp[256];
  204 + std::vector<std::string> params;
  205 +
  206 + // argv[0], set to ffmpeg bin.
  207 + // The execv() and execvp() functions ....
  208 + // The first argument, by convention, should point to
  209 + // the filename associated with the file being executed.
  210 + params.push_back(ffmpeg);
  211 +
  212 + // input.
  213 + params.push_back("-f");
  214 + params.push_back("flv");
  215 +
  216 + params.push_back("-i");
  217 + params.push_back(input);
  218 +
  219 + // build the filter
  220 + if (!vfilter.empty()) {
  221 + std::vector<std::string>::iterator it;
  222 + for (it = vfilter.begin(); it != vfilter.end(); ++it) {
  223 + std::string p = *it;
  224 + if (!p.empty()) {
  225 + params.push_back(p);
  226 + }
  227 + }
  228 + }
  229 +
  230 + // video specified.
  231 + params.push_back("-vcodec");
  232 + params.push_back(vcodec);
  233 +
  234 + params.push_back("-b:v");
  235 + snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000);
  236 + params.push_back(tmp);
  237 +
  238 + params.push_back("-r");
  239 + snprintf(tmp, sizeof(tmp), "%.2f", vfps);
  240 + params.push_back(tmp);
  241 +
  242 + params.push_back("-s");
  243 + snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight);
  244 + params.push_back(tmp);
  245 +
  246 + // TODO: add aspect if needed.
  247 + params.push_back("-aspect");
  248 + snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight);
  249 + params.push_back(tmp);
  250 +
  251 + params.push_back("-threads");
  252 + snprintf(tmp, sizeof(tmp), "%d", vthreads);
  253 + params.push_back(tmp);
  254 +
  255 + params.push_back("-profile:v");
  256 + params.push_back(vprofile);
  257 +
  258 + params.push_back("-preset");
  259 + params.push_back(vpreset);
  260 +
  261 + // vparams
222 if (!vparams.empty()) { 262 if (!vparams.empty()) {
223 - s_vpreset += " ";  
224 - s_vpreset += vparams; 263 + std::vector<std::string>::iterator it;
  264 + for (it = vparams.begin(); it != vparams.end(); ++it) {
  265 + std::string p = *it;
  266 + if (!p.empty()) {
  267 + params.push_back(p);
225 } 268 }
226 - // audio params  
227 - std::string s_aparams = s_achannels; 269 + }
  270 + }
  271 +
  272 + // audio specified.
  273 + params.push_back("-acodec");
  274 + params.push_back(acodec);
  275 +
  276 + params.push_back("-b:a");
  277 + snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000);
  278 + params.push_back(tmp);
  279 +
  280 + params.push_back("-ar");
  281 + snprintf(tmp, sizeof(tmp), "%d", asample_rate);
  282 + params.push_back(tmp);
  283 +
  284 + params.push_back("-ac");
  285 + snprintf(tmp, sizeof(tmp), "%d", achannels);
  286 + params.push_back(tmp);
  287 +
  288 + // aparams
228 if (!aparams.empty()) { 289 if (!aparams.empty()) {
229 - s_aparams += " ";  
230 - s_aparams += aparams; 290 + std::vector<std::string>::iterator it;
  291 + for (it = aparams.begin(); it != aparams.end(); ++it) {
  292 + std::string p = *it;
  293 + if (!p.empty()) {
  294 + params.push_back(p);
  295 + }
231 } 296 }
  297 + }
  298 +
  299 + // output
  300 + params.push_back("-f");
  301 + params.push_back("flv");
  302 +
  303 + params.push_back("-y");
  304 + params.push_back(output);
232 305
233 // TODO: fork or vfork? 306 // TODO: fork or vfork?
234 if ((pid = fork()) < 0) { 307 if ((pid = fork()) < 0) {
@@ -239,28 +312,17 @@ int SrsFFMPEG::start() @@ -239,28 +312,17 @@ int SrsFFMPEG::start()
239 312
240 // child process: ffmpeg encoder engine. 313 // child process: ffmpeg encoder engine.
241 if (pid == 0) { 314 if (pid == 0) {
242 - // TODO: execl or execlp  
243 - ret = execl(ffmpeg.c_str(),  
244 - "-f", "flv",  
245 - "-i", input.c_str(),  
246 - // video specified.  
247 - "-vcodec", vcodec.c_str(),  
248 - "-b:v", s_vbitrate,  
249 - "-r", s_vfps,  
250 - "-s", vsize,  
251 - "-aspect", vaspect, // TODO: add aspect if needed.  
252 - "-threads", s_vthreads,  
253 - "-profile:v", vprofile.c_str(),  
254 - "-preset", s_vpreset.c_str(),  
255 - // audio specified.  
256 - "-acodec", acodec.c_str(),  
257 - "-b:a", s_abitrate,  
258 - "-ar", s_asample_rate,  
259 - "-ac", s_aparams.c_str(),  
260 - "-f", "flv",  
261 - "-y", output.c_str(),  
262 - NULL  
263 - ); 315 + // memory leak in child process, it's ok.
  316 + char** charpv_params = new char*[params.size() + 1];
  317 + for (int i = 0; i < (int)params.size(); i++) {
  318 + std::string p = params[i];
  319 + charpv_params[i] = (char*)p.c_str();
  320 + }
  321 + // EOF: NULL
  322 + charpv_params[params.size()] = NULL;
  323 +
  324 + // TODO: execv or execvp
  325 + ret = execv(ffmpeg.c_str(), charpv_params);
264 if (ret < 0) { 326 if (ret < 0) {
265 fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)", 327 fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)",
266 errno, strerror(errno)); 328 errno, strerror(errno));
@@ -347,7 +409,7 @@ int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _a @@ -347,7 +409,7 @@ int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _a
347 ret = parse_scope_engines(); 409 ret = parse_scope_engines();
348 410
349 // ignore the loop encoder 411 // ignore the loop encoder
350 - if (ret = ERROR_ENCODER_LOOP) { 412 + if (ret == ERROR_ENCODER_LOOP) {
351 ret = ERROR_SUCCESS; 413 ret = ERROR_SUCCESS;
352 } 414 }
353 415
@@ -47,6 +47,7 @@ private: @@ -47,6 +47,7 @@ private:
47 pid_t pid; 47 pid_t pid;
48 private: 48 private:
49 std::string ffmpeg; 49 std::string ffmpeg;
  50 + std::vector<std::string> vfilter;
50 std::string vcodec; 51 std::string vcodec;
51 int vbitrate; 52 int vbitrate;
52 double vfps; 53 double vfps;
@@ -55,12 +56,12 @@ private: @@ -55,12 +56,12 @@ private:
55 int vthreads; 56 int vthreads;
56 std::string vprofile; 57 std::string vprofile;
57 std::string vpreset; 58 std::string vpreset;
58 - std::string vparams; 59 + std::vector<std::string> vparams;
59 std::string acodec; 60 std::string acodec;
60 int abitrate; 61 int abitrate;
61 int asample_rate; 62 int asample_rate;
62 int achannels; 63 int achannels;
63 - std::string aparams; 64 + std::vector<std::string> aparams;
64 std::string output; 65 std::string output;
65 std::string input; 66 std::string input;
66 public: 67 public: