正在显示
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; | ||
| 792 | } | 802 | } |
| 793 | 803 | ||
| 794 | - return avparams; | 804 | + for (int i = 0; i < (int)conf->directives.size(); i++) { |
| 805 | + SrsConfDirective* p = conf->directives[i]; | ||
| 806 | + if (!p) { | ||
| 807 | + continue; | ||
| 808 | + } | ||
| 809 | + | ||
| 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); | ||
| 268 | + } | ||
| 269 | + } | ||
| 225 | } | 270 | } |
| 226 | - // audio params | ||
| 227 | - std::string s_aparams = s_achannels; | 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 | + } | ||
| 296 | + } | ||
| 231 | } | 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: |
-
请 注册 或 登录 后发表评论