使用FFMPEG进行一些视频处理(C#)视频合并、转码、获取时长
FFMPEG的强大无需多说,举几个用到的功能,直接贴代码了
还有更多命令用到时搜索即可
视频转码
public static string DecodeMp4ToFlv(string mp4, string format = ".flv", int timeout = 0) { var args = "-y -i {0} -vcodec copy {1}".Formatting("\"{0}\"".Formatting(mp4), "\"{0}\"".Formatting(strFlvPath)); string output, error; if (timeout <= 0) timeout = 5*60*1000; // 超时时间 = 5 分钟 ProcessHelper.Process(strFFMPEGPath, args, timeout, out output, out error); if (!error.IsNullOrEmpty()) { Logger.Error("{0}{1} : {2}{0}".Formatting(Environment.NewLine, "FFmpeg", error)); } return flv; }
视频合并
public static string ConcatMp4(string mp41, string mp42) {
var args = " -i \"concat:" + mp41 + "|" + mp42 + "|\" -c copy -bsf:a aac_adtstoasc -movflags +faststart " + outputpath; string output, error; int timeout = 2 * 60 * 1000; // 超时时间 = 2 分钟 ProcessHelper.Process(strFFMPEGPath, args, timeout, out output, out error); if (!error.IsNullOrEmpty()) { Logger.Error("{0}{1} : {2}{0}".Formatting(Environment.NewLine, "FFmpeg", error)); } return outputpath;
}
获取视频时长
private static int GetVideoDuration(string ffmpegfile, string sourceFile) { try { using (System.Diagnostics.Process ffmpeg = new System.Diagnostics.Process()) { String duration; // soon will hold our video's duration in the form "HH:MM:SS.UU" String result; // temp variable holding a string representation of our video's duration StreamReader errorreader; // StringWriter to hold output from ffmpeg // we want to execute the process without opening a shell ffmpeg.StartInfo.UseShellExecute = false; //ffmpeg.StartInfo.ErrorDialog = false; ffmpeg.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // redirect StandardError so we can parse it // for some reason the output comes through over StandardError ffmpeg.StartInfo.RedirectStandardError = true; // set the file name of our process, including the full path // (as well as quotes, as if you were calling it from the command-line) ffmpeg.StartInfo.FileName = ffmpegfile; // set the command-line arguments of our process, including full paths of any files // (as well as quotes, as if you were passing these arguments on the command-line) ffmpeg.StartInfo.Arguments = "-i " + sourceFile; // start the process ffmpeg.Start(); // now that the process is started, we can redirect output to the StreamReader we defined errorreader = ffmpeg.StandardError; // wait until ffmpeg comes back ffmpeg.WaitForExit(); // read the output from ffmpeg, which for some reason is found in Process.StandardError result = errorreader.ReadToEnd(); // a little convoluded, this string manipulation... // working from the inside out, it: // takes a substring of result, starting from the end of the "Duration: " label contained within, // (execute "ffmpeg.exe -i somevideofile" on the command-line to verify for yourself that it is there) // and going the full length of the timestamp duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00").Length); string[] ss = duration.Split(':'); int h = int.Parse(ss[0]); int m = int.Parse(ss[1]); int s = int.Parse(ss[2]); return h * 3600 + m * 60 + s; } } catch (System.Exception ex) { return 60; } }
Process处理类如下,也可以自己写个
public static void Process(string startFile, string args, int timeout, out string standardOutput, out string standardError) { using (var process = new ProcessExecutor(startFile, args, timeout)) { process.Execute(out standardOutput, out standardError); } }
internal class ProcessExecutor : IDisposable { private readonly StringBuilder error; private readonly AutoResetEvent errorWaitHandle; private readonly StringBuilder output; private readonly int timeout; private AutoResetEvent outputWaitHandle; private Process process; public ProcessExecutor(string startFile, string args, int timeout = 0) { process = new Process(); //设置进程启动信息属性StartInfo,这是ProcessStartInfo类 process.StartInfo.FileName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(startFile)); process.StartInfo.Arguments = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(args)); process.StartInfo.UseShellExecute = false; //提供的标准输出流只有2k,超过大小会卡住;如果有大量输出,就读出来 process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; output = new StringBuilder(); error = new StringBuilder(); outputWaitHandle = new AutoResetEvent(false); errorWaitHandle = new AutoResetEvent(false); this.timeout = timeout; RegisterToEvents(); } public void Dispose() { UnregisterFromEvents(); if (process != null) { process.Dispose(); process = null; } if (errorWaitHandle != null) { errorWaitHandle.Close(); outputWaitHandle = null; } if (outputWaitHandle != null) { outputWaitHandle.Close(); outputWaitHandle = null; } } public void Execute(out string standardOutput, out string standardError) { process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); if (process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout) && errorWaitHandle.WaitOne(timeout)) { } else { // if timeout then kill the procee process.Kill(); } standardOutput = output.ToString(); standardError = error.ToString(); } private void RegisterToEvents() { process.OutputDataReceived += process_OutputDataReceived; process.ErrorDataReceived += process_ErrorDataReceived; } private void UnregisterFromEvents() { process.OutputDataReceived -= process_OutputDataReceived; process.ErrorDataReceived -= process_ErrorDataReceived; } private void process_ErrorDataReceived(object sender, DataReceivedEventArgs e) { if (e.Data == null) { errorWaitHandle.Set(); } else { error.AppendLine(e.Data); } } private void process_OutputDataReceived(object sender, DataReceivedEventArgs e) { if (e.Data == null) { outputWaitHandle.Set(); } else { output.AppendLine(e.Data); } } }