From 9a0d8855d852a108701cbeed552e81c846832b7c Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 1 Dec 2013 10:54:41 +0800 Subject: [PATCH] support ffmpeg filter --- README.md | 19 ++-- trunk/auto/build_ffmpeg.sh | 1 + trunk/conf/srs.conf | 123 ++++++++++++++++++++- trunk/doc/ffmpeg-logo.png | Bin 0 -> 8727 bytes trunk/src/core/srs_core_config.cpp | 48 +++++--- trunk/src/core/srs_core_config.hpp | 5 +- trunk/src/core/srs_core_encoder.cpp | 164 +++++++++++++++++++--------- trunk/src/core/srs_core_encoder.hpp | 5 +- 8 files changed, 280 insertions(+), 85 deletions(-) create mode 100644 trunk/doc/ffmpeg-logo.png diff --git a/README.md b/README.md index 8daf0cf9d..c82901ab8 100755 --- a/README.md +++ b/README.md @@ -69,15 +69,16 @@ Supported operating systems and hardware: 14. support forward publish stream to build active-standby cluster.
15. support broadcast by forward the stream to other servers(origin/edge).
16. support live stream transcoding by ffmpeg.
-17. [plan] support full http callback api.
-18. [plan] support network based cli and json result.
-19. [plan] support bandwidth test api and flash client.
-20. [plan] support adobe flash refer/token/swf verification.
-21. [plan] support adobe amf3 codec.
-22. [plan] support dvr(record live to vod file)
-23. [plan] support FMS edge protocol
-24. [plan] support encryption: RTMPE/RTMPS, HLS DRM
-25. [plan] support RTMPT, http to tranverse firewalls
+17. support live stream transcoding by ffmpeg.
+18. support ffmpeg filters(logo/overlay/crop), x264 params.
+19. [plan] support network based cli and json result.
+20. [plan] support bandwidth test api and flash client.
+21. [plan] support adobe flash refer/token/swf verification.
+22. [plan] support adobe amf3 codec.
+23. [plan] support dvr(record live to vod file)
+24. [plan] support FMS edge protocol
+25. [plan] support encryption: RTMPE/RTMPS, HLS DRM
+26. [plan] support RTMPT, http to tranverse firewalls
### Performance 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. diff --git a/trunk/auto/build_ffmpeg.sh b/trunk/auto/build_ffmpeg.sh index 1c1350393..d2ad359d0 100755 --- a/trunk/auto/build_ffmpeg.sh +++ b/trunk/auto/build_ffmpeg.sh @@ -84,6 +84,7 @@ else --extra-ldflags='-L${ffmpeg_exported_release_dir}/lib -lm -ldl' \ --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc \ --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \ + --enable-libfreetype \ --enable-libx264 --enable-libmp3lame --enable-libaacplus \ --enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers && make && make install diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 464341e88..3212bc449 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -15,13 +15,19 @@ vhost __defaultVhost__ { hls_path ./objs/nginx/html; hls_fragment 5; hls_window 30; - #forward 127.0.0.1:1936; + forward 127.0.0.1:1936; transcode { enabled on; ffmpeg ./objs/ffmpeg/bin/ffmpeg; #ffmpeg ./research/ffempty/ffempty; engine fast{ enabled on; + vfilter { + vf 'drawtext=text=SRS'; + #vf 'crop=in_w-20:in_h-160:10:80'; + #i ./doc/ffmpeg-logo.png; + #filter_complex 'overlay=10:10'; + } vcodec libx264; vbitrate 300; vfps 20; @@ -37,11 +43,15 @@ vhost __defaultVhost__ { asample_rate 44100; achannels 2; aparams { + profile:a aac_low; } output rtmp://[vhost]:[port]/[app]/[stream]_fast; } engine sd{ - enabled on; + enabled off; + vfilter { + vf 'split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2'; + } vcodec libx264; vbitrate 500; vfps 20; @@ -79,6 +89,14 @@ vhost all.transcode.vhost.com { # whether the engine is enabled # default: off. enabled on; + # ffmpeg filters, follows the main input. + vfilter { + # the logo input file. + i ./doc/ffmpeg-logo.png; + # the ffmpeg complex filter. + # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html + filter_complex 'overlay=10:10'; + } # video encoder name vcodec libx264; # video bitrate, in kbps @@ -100,6 +118,13 @@ vhost all.transcode.vhost.com { vpreset medium; # other x264 or ffmpeg video params vparams { + # ffmpeg options, @see: http://ffmpeg.org/ffmpeg.html + t 100; + # 264 params, @see: http://ffmpeg.org/ffmpeg-codecs.html#libx264 + coder 1; + b_strategy 2; + bf 3; + refs 10; } # audio encoder name acodec libaacplus; @@ -182,12 +207,102 @@ vhost all.transcode.vhost.com { } } } +# the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction +vhost mirror.transcode.vhost.com { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine mirror{ + enabled on; + vfilter { + vf 'split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2'; + } + vcodec libx264; + vbitrate 300; + vfps 20; + vwidth 480; + vheight 320; + vthreads 2; + vprofile baseline; + vpreset superfast; + vparams { + } + acodec libaacplus; + abitrate 30; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://[vhost]:[port]/[app]/[stream]_mirror; + } + } +} +# the logo filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop +vhost crop.transcode.vhost.com { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine crop{ + enabled on; + vfilter { + vf 'crop=in_w-20:in_h-160:10:80'; + } + vcodec libx264; + vbitrate 300; + vfps 20; + vwidth 480; + vheight 320; + vthreads 2; + vprofile baseline; + vpreset superfast; + vparams { + } + acodec libaacplus; + abitrate 30; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://[vhost]:[port]/[app]/[stream]_crop; + } + } +} +# the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop +vhost logo.transcode.vhost.com { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine logo{ + enabled on; + vfilter { + vf 'crop=200:100:10:10'; + } + vcodec libx264; + vbitrate 300; + vfps 20; + vwidth 480; + vheight 320; + vthreads 2; + vprofile baseline; + vpreset superfast; + vparams { + } + acodec libaacplus; + abitrate 30; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://[vhost]:[port]/[app]/[stream]_logo; + } + } +} # transcode all stream using the empty ffmpeg demo, donothing. vhost ffempty.transcode.vhost.com { transcode { enabled on; ffmpeg ./research/ffempty/ffempty; - engine fd{ + engine empty{ enabled on; vcodec libx264; vbitrate 300; @@ -205,7 +320,7 @@ vhost ffempty.transcode.vhost.com { achannels 2; aparams { } - output rtmp://[vhost]:[port]/[app]/[stream]_fast; + output rtmp://[vhost]:[port]/[app]/[stream]_empty; } } } diff --git a/trunk/doc/ffmpeg-logo.png b/trunk/doc/ffmpeg-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d9333969093e9e406214a4c80501e44b2ba8fa40 GIT binary patch literal 8727 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 literal 0 HcmV?d00001 diff --git a/trunk/src/core/srs_core_config.cpp b/trunk/src/core/srs_core_config.cpp index a517449c0..60c64c572 100644 --- a/trunk/src/core/srs_core_config.cpp +++ b/trunk/src/core/srs_core_config.cpp @@ -768,30 +768,48 @@ std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) return conf->arg0(); } -std::string SrsConfig::get_engine_vparams(SrsConfDirective* engine) +void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector& vparams) { if (!engine) { - return ""; + return; } SrsConfDirective* conf = engine->get("vparams"); if (!conf) { - return ""; + return; } - std::string avparams; for (int i = 0; i < (int)conf->directives.size(); i++) { SrsConfDirective* p = conf->directives[i]; if (!p) { continue; } - avparams += p->name; - avparams += " "; - avparams += p->arg0(); + vparams.push_back("-" + p->name); + vparams.push_back(p->arg0()); + } +} + +void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector& vfilter) +{ + if (!engine) { + return; } - return avparams; + SrsConfDirective* conf = engine->get("vfilter"); + if (!conf) { + return; + } + + for (int i = 0; i < (int)conf->directives.size(); i++) { + SrsConfDirective* p = conf->directives[i]; + if (!p) { + continue; + } + + vfilter.push_back("-" + p->name); + vfilter.push_back(p->arg0()); + } } std::string SrsConfig::get_engine_acodec(SrsConfDirective* engine) @@ -850,30 +868,26 @@ int SrsConfig::get_engine_achannels(SrsConfDirective* engine) return ::atoi(conf->arg0().c_str()); } -std::string SrsConfig::get_engine_aparams(SrsConfDirective* engine) +void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector& aparams) { if (!engine) { - return ""; + return; } SrsConfDirective* conf = engine->get("aparams"); if (!conf) { - return ""; + return; } - std::string avparams; for (int i = 0; i < (int)conf->directives.size(); i++) { SrsConfDirective* p = conf->directives[i]; if (!p) { continue; } - avparams += p->name; - avparams += " "; - avparams += p->arg0(); + aparams.push_back("-" + p->name); + aparams.push_back(p->arg0()); } - - return avparams; } std::string SrsConfig::get_engine_output(SrsConfDirective* engine) diff --git a/trunk/src/core/srs_core_config.hpp b/trunk/src/core/srs_core_config.hpp index 7935262b0..a43c79899 100644 --- a/trunk/src/core/srs_core_config.hpp +++ b/trunk/src/core/srs_core_config.hpp @@ -128,12 +128,13 @@ public: virtual int get_engine_vthreads(SrsConfDirective* engine); virtual std::string get_engine_vprofile(SrsConfDirective* engine); virtual std::string get_engine_vpreset(SrsConfDirective* engine); - virtual std::string get_engine_vparams(SrsConfDirective* engine); + virtual void get_engine_vparams(SrsConfDirective* engine, std::vector& vparams); + virtual void get_engine_vfilter(SrsConfDirective* engine, std::vector& vfilter); virtual std::string get_engine_acodec(SrsConfDirective* engine); virtual int get_engine_abitrate(SrsConfDirective* engine); virtual int get_engine_asample_rate(SrsConfDirective* engine); virtual int get_engine_achannels(SrsConfDirective* engine); - virtual std::string get_engine_aparams(SrsConfDirective* engine); + virtual void get_engine_aparams(SrsConfDirective* engine, std::vector& aparams); virtual std::string get_engine_output(SrsConfDirective* engine); virtual SrsConfDirective* get_gop_cache(std::string vhost); virtual SrsConfDirective* get_forward(std::string vhost); diff --git a/trunk/src/core/srs_core_encoder.cpp b/trunk/src/core/srs_core_encoder.cpp index 1ee75172d..10f4acf31 100644 --- a/trunk/src/core/srs_core_encoder.cpp +++ b/trunk/src/core/srs_core_encoder.cpp @@ -60,6 +60,7 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, { int ret = ERROR_SUCCESS; + config->get_engine_vfilter(engine, vfilter); vcodec = config->get_engine_vcodec(engine); vbitrate = config->get_engine_vbitrate(engine); vfps = config->get_engine_vfps(engine); @@ -68,12 +69,12 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, vthreads = config->get_engine_vthreads(engine); vprofile = config->get_engine_vprofile(engine); vpreset = config->get_engine_vpreset(engine); - vparams = config->get_engine_vparams(engine); + config->get_engine_vparams(engine, vparams); acodec = config->get_engine_acodec(engine); abitrate = config->get_engine_abitrate(engine); asample_rate = config->get_engine_asample_rate(engine); achannels = config->get_engine_achannels(engine); - aparams = config->get_engine_aparams(engine); + config->get_engine_aparams(engine, aparams); output = config->get_engine_output(engine); // ensure the size is even. @@ -198,37 +199,109 @@ int SrsFFMPEG::start() return ret; } - // prepare execl params - char vsize[22]; - snprintf(vsize, sizeof(vsize), "%dx%d", vwidth, vheight); - char vaspect[22]; - snprintf(vaspect, sizeof(vaspect), "%d:%d", vwidth, vheight); - char s_vbitrate[10]; - snprintf(s_vbitrate, sizeof(s_vbitrate), "%d", vbitrate * 1000); - char s_vfps[10]; - snprintf(s_vfps, sizeof(s_vfps), "%.2f", vfps); - char s_vthreads[10]; - snprintf(s_vthreads, sizeof(s_vthreads), "%d", vthreads); - char s_abitrate[10]; - snprintf(s_abitrate, sizeof(s_abitrate), "%d", abitrate * 1000); - char s_asample_rate[10]; - snprintf(s_asample_rate, sizeof(s_asample_rate), "%d", asample_rate); - char s_achannels[10]; - snprintf(s_achannels, sizeof(s_achannels), "%d", achannels); + // prepare exec params + char tmp[256]; + std::vector params; - // TODO: execl donot support the params. - // video params - std::string s_vpreset = vpreset; + // argv[0], set to ffmpeg bin. + // The execv() and execvp() functions .... + // The first argument, by convention, should point to + // the filename associated with the file being executed. + params.push_back(ffmpeg); + + // input. + params.push_back("-f"); + params.push_back("flv"); + + params.push_back("-i"); + params.push_back(input); + + // build the filter + if (!vfilter.empty()) { + std::vector::iterator it; + for (it = vfilter.begin(); it != vfilter.end(); ++it) { + std::string p = *it; + if (!p.empty()) { + params.push_back(p); + } + } + } + + // video specified. + params.push_back("-vcodec"); + params.push_back(vcodec); + + params.push_back("-b:v"); + snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000); + params.push_back(tmp); + + params.push_back("-r"); + snprintf(tmp, sizeof(tmp), "%.2f", vfps); + params.push_back(tmp); + + params.push_back("-s"); + snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight); + params.push_back(tmp); + + // TODO: add aspect if needed. + params.push_back("-aspect"); + snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight); + params.push_back(tmp); + + params.push_back("-threads"); + snprintf(tmp, sizeof(tmp), "%d", vthreads); + params.push_back(tmp); + + params.push_back("-profile:v"); + params.push_back(vprofile); + + params.push_back("-preset"); + params.push_back(vpreset); + + // vparams if (!vparams.empty()) { - s_vpreset += " "; - s_vpreset += vparams; + std::vector::iterator it; + for (it = vparams.begin(); it != vparams.end(); ++it) { + std::string p = *it; + if (!p.empty()) { + params.push_back(p); + } + } } - // audio params - std::string s_aparams = s_achannels; + + // audio specified. + params.push_back("-acodec"); + params.push_back(acodec); + + params.push_back("-b:a"); + snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000); + params.push_back(tmp); + + params.push_back("-ar"); + snprintf(tmp, sizeof(tmp), "%d", asample_rate); + params.push_back(tmp); + + params.push_back("-ac"); + snprintf(tmp, sizeof(tmp), "%d", achannels); + params.push_back(tmp); + + // aparams if (!aparams.empty()) { - s_aparams += " "; - s_aparams += aparams; + std::vector::iterator it; + for (it = aparams.begin(); it != aparams.end(); ++it) { + std::string p = *it; + if (!p.empty()) { + params.push_back(p); + } + } } + + // output + params.push_back("-f"); + params.push_back("flv"); + + params.push_back("-y"); + params.push_back(output); // TODO: fork or vfork? if ((pid = fork()) < 0) { @@ -239,28 +312,17 @@ int SrsFFMPEG::start() // child process: ffmpeg encoder engine. if (pid == 0) { - // TODO: execl or execlp - ret = execl(ffmpeg.c_str(), - "-f", "flv", - "-i", input.c_str(), - // video specified. - "-vcodec", vcodec.c_str(), - "-b:v", s_vbitrate, - "-r", s_vfps, - "-s", vsize, - "-aspect", vaspect, // TODO: add aspect if needed. - "-threads", s_vthreads, - "-profile:v", vprofile.c_str(), - "-preset", s_vpreset.c_str(), - // audio specified. - "-acodec", acodec.c_str(), - "-b:a", s_abitrate, - "-ar", s_asample_rate, - "-ac", s_aparams.c_str(), - "-f", "flv", - "-y", output.c_str(), - NULL - ); + // memory leak in child process, it's ok. + char** charpv_params = new char*[params.size() + 1]; + for (int i = 0; i < (int)params.size(); i++) { + std::string p = params[i]; + charpv_params[i] = (char*)p.c_str(); + } + // EOF: NULL + charpv_params[params.size()] = NULL; + + // TODO: execv or execvp + ret = execv(ffmpeg.c_str(), charpv_params); if (ret < 0) { fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)", errno, strerror(errno)); @@ -347,7 +409,7 @@ int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _a ret = parse_scope_engines(); // ignore the loop encoder - if (ret = ERROR_ENCODER_LOOP) { + if (ret == ERROR_ENCODER_LOOP) { ret = ERROR_SUCCESS; } diff --git a/trunk/src/core/srs_core_encoder.hpp b/trunk/src/core/srs_core_encoder.hpp index f13e8dfa9..fe3bb362c 100644 --- a/trunk/src/core/srs_core_encoder.hpp +++ b/trunk/src/core/srs_core_encoder.hpp @@ -47,6 +47,7 @@ private: pid_t pid; private: std::string ffmpeg; + std::vector vfilter; std::string vcodec; int vbitrate; double vfps; @@ -55,12 +56,12 @@ private: int vthreads; std::string vprofile; std::string vpreset; - std::string vparams; + std::vector vparams; std::string acodec; int abitrate; int asample_rate; int achannels; - std::string aparams; + std::vector aparams; std::string output; std::string input; public: