ffmpeg,记一次录音文件信息里面码率,时间丢失的问题。
1.起因
同事在调用录音控件生成的MP3,在部分浏览器中加载失败,出现弹框提示。
经过同事的对比,发现当文件属性中比特率 为0kbps,时长为空的时候就会出现上图这种情况。并给找到一个解决方案,使用ffmpeg进行一次转码后就会出现比特率和时长,浏览器也可以正常加载。
ffmpeg.exe -i out.mp3 -b:a 128k -y -acodec libmp3lame out2.mp3 //cmd 中执行转换命令
异常的情况 正常的情况
2.问题原因
由上面可以知道,mp3文件是由于比特率信息丢失导致的问题出现,通过查找文档,多次修改参数试验,问题一直存在。偶然一次再参数里设置了录音时间,发现生成的文件时正常的。得出结论,是ffmpeg.exe没有正常关闭导致,文件信息没有写完。
ffmpeg没有正常关闭的原因,测试时候是用过关闭cmd窗口,用播放器播放mp3文件发现音频可以正常播放,也就没有过多思考,在代码实现过程了,通过直接kill掉Process来实现录制完毕。
[DllImport("kernel32.dll")] static extern bool GenerateConsoleCtrlEvent(int dwCtrlEvent, int dwProcessGroupId); [DllImport("kernel32.dll")] static extern bool SetConsoleCtrlHandler(IntPtr handlerRoutine, bool add); [DllImport("kernel32.dll")] static extern bool AttachConsole(int dwProcessId); [DllImport("kernel32.dll")] static extern bool FreeConsole(); /// <summary> /// 功能: 停止录制 /// </summary> public static void Stop() { try { AttachConsole(p.Id); SetConsoleCtrlHandler(IntPtr.Zero, true); GenerateConsoleCtrlEvent(0, 0); FreeConsole(); //p.Close(); if (!p.HasExited) { p.Kill(); p.WaitForExit(); } // p.Dispose(); } catch (Exception ex) { // Log.Error("关闭录音工具ffmpeg异常", ex); } }
所以只需要正常关闭录制就可以解决这个问题,后来发现上图cmd界面中倒数第二行 Press [q] to stop, 试验了下果然可以,生成的MP3也是正常的。现在只需要代码模拟输入q就可以解决这个问题了,
c#代码如下
static StreamWriter myStreamWriter; /// <summary> /// 功能: 开始录制 /// </summary> public static void Start(string audioDevice, string outFilePath) { if (File.Exists(outFilePath)) { File.Delete(outFilePath); } ProcessStartInfo startInfo = new ProcessStartInfo(ffmpegPath); startInfo.WindowStyle = ProcessWindowStyle.Hidden; startInfo.CreateNoWindow = true; //不加这句会显示cmd窗口 startInfo.UseShellExecute = false; //关闭Shell的使用 startInfo.RedirectStandardOutput = true; //重定向标准输出 startInfo.RedirectStandardInput = true; startInfo.Arguments = audioDevice; p = new Process(); p.StartInfo = startInfo; p.Start(); myStreamWriter = p.StandardInput; } /// <summary> /// 功能: 停止录制 /// </summary> public static void Stop() { try { myStreamWriter.WriteLine("q"); Thread.Sleep(100);//q命令没有那么快执行 if (!p.HasExited) { p.Kill(); p.WaitForExit(); } // p.Dispose(); } catch (Exception ex) { // Log.Error("关闭录音工具ffmpeg异常", ex); } }
分享一个录音的测试demo https://pan.baidu.com/s/1mizerUS