1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-12 11:21:52 +00:00

support ffmpeg filter

This commit is contained in:
winlin 2013-12-01 10:54:41 +08:00
parent f85b70966c
commit 9a0d8855d8
8 changed files with 280 additions and 85 deletions

View file

@ -69,15 +69,16 @@ Supported operating systems and hardware:
14. support forward publish stream to build active-standby cluster.<br/> 14. support forward publish stream to build active-standby cluster.<br/>
15. support broadcast by forward the stream to other servers(origin/edge).<br/> 15. support broadcast by forward the stream to other servers(origin/edge).<br/>
16. support live stream transcoding by ffmpeg.<br/> 16. support live stream transcoding by ffmpeg.<br/>
17. [plan] support full http callback api.<br/> 17. support live stream transcoding by ffmpeg.<br/>
18. [plan] support network based cli and json result.<br/> 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/>
19. [plan] support bandwidth test api and flash client.<br/> 19. [plan] support network based cli and json result.<br/>
20. [plan] support adobe flash refer/token/swf verification.<br/> 20. [plan] support bandwidth test api and flash client.<br/>
21. [plan] support adobe amf3 codec.<br/> 21. [plan] support adobe flash refer/token/swf verification.<br/>
22. [plan] support dvr(record live to vod file)<br/> 22. [plan] support adobe amf3 codec.<br/>
23. [plan] support FMS edge protocol<br/> 23. [plan] support dvr(record live to vod file)<br/>
24. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/> 24. [plan] support FMS edge protocol<br/>
25. [plan] support RTMPT, http to tranverse firewalls<br/> 25. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/>
26. [plan] support RTMPT, http to tranverse firewalls<br/>
### Performance ### Performance
1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB.

View file

@ -84,6 +84,7 @@ else
--extra-ldflags='-L${ffmpeg_exported_release_dir}/lib -lm -ldl' \ --extra-ldflags='-L${ffmpeg_exported_release_dir}/lib -lm -ldl' \
--disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc \ --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc \
--enable-postproc --enable-bzlib --enable-zlib --enable-parsers \ --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \
--enable-libfreetype \
--enable-libx264 --enable-libmp3lame --enable-libaacplus \ --enable-libx264 --enable-libmp3lame --enable-libaacplus \
--enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers && --enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers &&
make && make install make && make install

View file

@ -15,13 +15,19 @@ vhost __defaultVhost__ {
hls_path ./objs/nginx/html; hls_path ./objs/nginx/html;
hls_fragment 5; hls_fragment 5;
hls_window 30; hls_window 30;
#forward 127.0.0.1:1936; forward 127.0.0.1:1936;
transcode { transcode {
enabled on; enabled on;
ffmpeg ./objs/ffmpeg/bin/ffmpeg; ffmpeg ./objs/ffmpeg/bin/ffmpeg;
#ffmpeg ./research/ffempty/ffempty; #ffmpeg ./research/ffempty/ffempty;
engine fast{ engine fast{
enabled on; 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; vcodec libx264;
vbitrate 300; vbitrate 300;
vfps 20; vfps 20;
@ -37,11 +43,15 @@ vhost __defaultVhost__ {
asample_rate 44100; asample_rate 44100;
achannels 2; achannels 2;
aparams { aparams {
profile:a aac_low;
} }
output rtmp://[vhost]:[port]/[app]/[stream]_fast; output rtmp://[vhost]:[port]/[app]/[stream]_fast;
} }
engine sd{ 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; vcodec libx264;
vbitrate 500; vbitrate 500;
vfps 20; vfps 20;
@ -79,6 +89,14 @@ vhost all.transcode.vhost.com {
# whether the engine is enabled # whether the engine is enabled
# default: off. # default: off.
enabled on; 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 # video encoder name
vcodec libx264; vcodec libx264;
# video bitrate, in kbps # video bitrate, in kbps
@ -100,6 +118,13 @@ vhost all.transcode.vhost.com {
vpreset medium; vpreset medium;
# other x264 or ffmpeg video params # other x264 or ffmpeg video params
vparams { 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 # audio encoder name
acodec libaacplus; 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. # transcode all stream using the empty ffmpeg demo, donothing.
vhost ffempty.transcode.vhost.com { vhost ffempty.transcode.vhost.com {
transcode { transcode {
enabled on; enabled on;
ffmpeg ./research/ffempty/ffempty; ffmpeg ./research/ffempty/ffempty;
engine fd{ engine empty{
enabled on; enabled on;
vcodec libx264; vcodec libx264;
vbitrate 300; vbitrate 300;
@ -205,7 +320,7 @@ vhost ffempty.transcode.vhost.com {
achannels 2; achannels 2;
aparams { aparams {
} }
output rtmp://[vhost]:[port]/[app]/[stream]_fast; output rtmp://[vhost]:[port]/[app]/[stream]_empty;
} }
} }
} }

BIN
trunk/doc/ffmpeg-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

@ -768,30 +768,48 @@ std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
return conf->arg0(); return conf->arg0();
} }
std::string SrsConfig::get_engine_vparams(SrsConfDirective* engine) void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams)
{ {
if (!engine) { if (!engine) {
return ""; return;
} }
SrsConfDirective* conf = engine->get("vparams"); SrsConfDirective* conf = engine->get("vparams");
if (!conf) { if (!conf) {
return ""; return;
} }
std::string avparams;
for (int i = 0; i < (int)conf->directives.size(); i++) { for (int i = 0; i < (int)conf->directives.size(); i++) {
SrsConfDirective* p = conf->directives[i]; SrsConfDirective* p = conf->directives[i];
if (!p) { if (!p) {
continue; continue;
} }
avparams += p->name; vparams.push_back("-" + p->name);
avparams += " "; vparams.push_back(p->arg0());
avparams += p->arg0(); }
}
void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& 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) 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()); return ::atoi(conf->arg0().c_str());
} }
std::string SrsConfig::get_engine_aparams(SrsConfDirective* engine) void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams)
{ {
if (!engine) { if (!engine) {
return ""; return;
} }
SrsConfDirective* conf = engine->get("aparams"); SrsConfDirective* conf = engine->get("aparams");
if (!conf) { if (!conf) {
return ""; return;
} }
std::string avparams;
for (int i = 0; i < (int)conf->directives.size(); i++) { for (int i = 0; i < (int)conf->directives.size(); i++) {
SrsConfDirective* p = conf->directives[i]; SrsConfDirective* p = conf->directives[i];
if (!p) { if (!p) {
continue; continue;
} }
avparams += p->name; aparams.push_back("-" + p->name);
avparams += " "; aparams.push_back(p->arg0());
avparams += p->arg0();
} }
return avparams;
} }
std::string SrsConfig::get_engine_output(SrsConfDirective* engine) std::string SrsConfig::get_engine_output(SrsConfDirective* engine)

View file

@ -128,12 +128,13 @@ public:
virtual int get_engine_vthreads(SrsConfDirective* engine); virtual int get_engine_vthreads(SrsConfDirective* engine);
virtual std::string get_engine_vprofile(SrsConfDirective* engine); virtual std::string get_engine_vprofile(SrsConfDirective* engine);
virtual std::string get_engine_vpreset(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<std::string>& vparams);
virtual void get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter);
virtual std::string get_engine_acodec(SrsConfDirective* engine); virtual std::string get_engine_acodec(SrsConfDirective* engine);
virtual int get_engine_abitrate(SrsConfDirective* engine); virtual int get_engine_abitrate(SrsConfDirective* engine);
virtual int get_engine_asample_rate(SrsConfDirective* engine); virtual int get_engine_asample_rate(SrsConfDirective* engine);
virtual int get_engine_achannels(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<std::string>& aparams);
virtual std::string get_engine_output(SrsConfDirective* engine); virtual std::string get_engine_output(SrsConfDirective* engine);
virtual SrsConfDirective* get_gop_cache(std::string vhost); virtual SrsConfDirective* get_gop_cache(std::string vhost);
virtual SrsConfDirective* get_forward(std::string vhost); virtual SrsConfDirective* get_forward(std::string vhost);

View file

@ -60,6 +60,7 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app,
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
config->get_engine_vfilter(engine, vfilter);
vcodec = config->get_engine_vcodec(engine); vcodec = config->get_engine_vcodec(engine);
vbitrate = config->get_engine_vbitrate(engine); vbitrate = config->get_engine_vbitrate(engine);
vfps = config->get_engine_vfps(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); vthreads = config->get_engine_vthreads(engine);
vprofile = config->get_engine_vprofile(engine); vprofile = config->get_engine_vprofile(engine);
vpreset = config->get_engine_vpreset(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); acodec = config->get_engine_acodec(engine);
abitrate = config->get_engine_abitrate(engine); abitrate = config->get_engine_abitrate(engine);
asample_rate = config->get_engine_asample_rate(engine); asample_rate = config->get_engine_asample_rate(engine);
achannels = config->get_engine_achannels(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); output = config->get_engine_output(engine);
// ensure the size is even. // ensure the size is even.
@ -198,37 +199,109 @@ int SrsFFMPEG::start()
return ret; return ret;
} }
// prepare execl params // prepare exec params
char vsize[22]; char tmp[256];
snprintf(vsize, sizeof(vsize), "%dx%d", vwidth, vheight); std::vector<std::string> params;
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);
// TODO: execl donot support the params. // argv[0], set to ffmpeg bin.
// video params // The execv() and execvp() functions ....
std::string s_vpreset = vpreset; // 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<std::string>::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()) { if (!vparams.empty()) {
s_vpreset += " "; std::vector<std::string>::iterator it;
s_vpreset += vparams; 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()) { if (!aparams.empty()) {
s_aparams += " "; std::vector<std::string>::iterator it;
s_aparams += aparams; 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? // TODO: fork or vfork?
if ((pid = fork()) < 0) { if ((pid = fork()) < 0) {
@ -239,28 +312,17 @@ int SrsFFMPEG::start()
// child process: ffmpeg encoder engine. // child process: ffmpeg encoder engine.
if (pid == 0) { if (pid == 0) {
// TODO: execl or execlp // memory leak in child process, it's ok.
ret = execl(ffmpeg.c_str(), char** charpv_params = new char*[params.size() + 1];
"-f", "flv", for (int i = 0; i < (int)params.size(); i++) {
"-i", input.c_str(), std::string p = params[i];
// video specified. charpv_params[i] = (char*)p.c_str();
"-vcodec", vcodec.c_str(), }
"-b:v", s_vbitrate, // EOF: NULL
"-r", s_vfps, charpv_params[params.size()] = NULL;
"-s", vsize,
"-aspect", vaspect, // TODO: add aspect if needed. // TODO: execv or execvp
"-threads", s_vthreads, ret = execv(ffmpeg.c_str(), charpv_params);
"-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
);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)", fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)",
errno, strerror(errno)); errno, strerror(errno));
@ -347,7 +409,7 @@ int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _a
ret = parse_scope_engines(); ret = parse_scope_engines();
// ignore the loop encoder // ignore the loop encoder
if (ret = ERROR_ENCODER_LOOP) { if (ret == ERROR_ENCODER_LOOP) {
ret = ERROR_SUCCESS; ret = ERROR_SUCCESS;
} }

View file

@ -47,6 +47,7 @@ private:
pid_t pid; pid_t pid;
private: private:
std::string ffmpeg; std::string ffmpeg;
std::vector<std::string> vfilter;
std::string vcodec; std::string vcodec;
int vbitrate; int vbitrate;
double vfps; double vfps;
@ -55,12 +56,12 @@ private:
int vthreads; int vthreads;
std::string vprofile; std::string vprofile;
std::string vpreset; std::string vpreset;
std::string vparams; std::vector<std::string> vparams;
std::string acodec; std::string acodec;
int abitrate; int abitrate;
int asample_rate; int asample_rate;
int achannels; int achannels;
std::string aparams; std::vector<std::string> aparams;
std::string output; std::string output;
std::string input; std::string input;
public: public: