正在显示
8 个修改的文件
包含
281 行增加
和
86 行删除
@@ -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 | } |
trunk/doc/ffmpeg-logo.png
0 → 100644
8.5 KB
@@ -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: |
-
请 注册 或 登录 后发表评论