在SRS的Ingest功能中,会调用本地FFmpeg进行拉流转码,
调用的核心代码在srs_app_ffmpeg.cpp 的 SrsFFMPEG::start() 中:
// 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.data(); } // 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)); } exit(ret);
SrsFFMPEG 这个类提供了一个用户设置额外参数的接口
void SrsFFMPEG::set_iparams(string iparams) { _iparams = iparams; }
但是是一次性的,也就是只能设置一个参数,
如果你想设置多个,不能用空格的方法隔开,例如我自己就这么写的:
set_iparams("-rtsp_transport tcp");
结果死活都运行不成功,看log打印出来的参数是完全正确,而且我用同样的参数手动运行FFmpeg也是对的。
折腾了半天,最后还是通过仔细看代码发现问题所在:
重点在叫起 FFmpeg的函数:execv()
int execv(const char *path, char *const argv[]);
其参数是用字符串数组的方式存储,而SRS的代码里是直接将你填进去的参数当一个参数写进去,不看你的空格!
也就是说我的 "-rtsp_transport tcp" 在argv里面是这样的
{"...", "...", "-rtsp_transport tcp", "..."}
是个无效参数,所以只能将其分开写入到存储参数的params变量中。
注意 SrsFFMPEG 并没有提供这样的接口,需要自己修改代码。