前段时间由于项目需求,要对即时视频通话进行本地录制,而且要求将对方视频及双方音频合并成所需视频,并生成mp4格式。视频通话是WebRTC技术,录下的视频格式是webm,一个远端,一个近端,由于需求比较奇怪,简单的视频合成难以完成任务,这就需要使用ffmpeg这款强大的工具来实现了。
ffmpeg详细功能可通过:https://ffmpeg.zeranoe.com/forum/ 来学习。我这只说遇到的一些问题。
先看需求,要求将远端的音视频及近端的音频合成一个mp4格式的视频,目前只保存了一个远端一个近端两个视频。
所以需要先将远端音频分离出来,
string cmd = string.Format("-y -i {0} -f mp3 -vn {1}", inAudio, outFileName);
ExcuteCMD(cmd);
得到remote.mp3,再将近端音频分离出来,得到local.mp3,
再将远端视频分离出来,
string cmd = string.Format("-y -threads 2 -i {0} -c:v libx264 -strict -2 {1}", inVideo, outFileName);
ExcuteCMD(cmd);
得到remote.mp4,此时将远端音频与近端音频合并成一个音频,
string cmd = string.Format("-y -i {0} -i {1} -filter_complex amix=inputs=2:duration=first:dropout_transition=2 -f mp3 {2}", inAudio1, inAudio2, outFileName);
ExcuteCMD(cmd);
得到mix.mp3,最后将remote.mp4与mix.mp3,合成新的视频
string cmd = string.Format("-y -threads 2 -i {0} -i {1} -vcodec copy -acodec copy {2}", inVideo, inAudio, outFileName);
ExcuteCMD(cmd);
经过这些步骤得到的就是需要的视频了。
虽然代码很简单,但在这过程中遇到不少坑。
第一个坑,ffmpeg要求指令中的路径不能有空格或者别的非法字符,否则会报
也很容易理解,就是ffmpeg找不到目录,经过一番查找,发现只需要将指令中的路径加上双引号即可,原来如此简单,比如上面的合成视频指令改成如下即可:
string cmd = string.Format("-y -threads 2 -i \"{0}\" -i \"{1}\" -vcodec copy -acodec copy \"{2}\"", inVideo, inAudio, outFileName);
第二个坑,在c#中调用ffmpeg程序执行指令首先想到的是Process.Start() 这个功能,也很简单:
private static void ExcuteCMD(string cmd)
{
Process p = new Process();
p.StartInfo.FileName = @"D:\Program Files (x86)\远程程控客户端\ffmpeg.exe";
p.StartInfo.Arguments = cmd; //执行参数
p.StartInfo.UseShellExecute = false; ////不使用系统外壳程序启动进程
p.StartInfo.CreateNoWindow = true; //不显示dos程序窗口
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中
p.Start();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
}
p.WaitForExit();这个设置必不可少,因为转换的视频如果较大,这个指令执行的时间会比较长,所以需要等待进程结束才可进行下一步操作,否则会出错。