using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; namespace DownKyi.Core.FFmpeg { public static class FFmpegHelper { private const string Tag = "FFmpegHelper"; /// /// 合并音频和视频 /// /// 音频 /// 视频 /// public static bool MergeVideo(string video1, string video2, string destVideo) { string param = $"-y -i \"{video1}\" -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\""; if (video1 == null || !File.Exists(video1)) { param = $"-y -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\""; } if (video2 == null || !File.Exists(video2)) { param = $"-y -i \"{video1}\" -acodec copy -f aac \"{destVideo}\""; } if (!File.Exists(video1) && !File.Exists(video2)) { return false; } // 如果存在 try { File.Delete(destVideo); } catch (IOException e) { Console.WriteLine("MergeVideo()发生IO异常: {0}", e); Logging.LogManager.Error(Tag, e); return false; } ExcuteProcess("ffmpeg.exe", param, null, (s, e) => Console.WriteLine(e.Data)); try { if (video1 != null) { File.Delete(video1); } if (video2 != null) { File.Delete(video2); } } catch (IOException e) { Console.WriteLine("MergeVideo()发生IO异常: {0}", e); Logging.LogManager.Error(Tag, e); } return true; } /// /// 拼接多个视频 /// /// /// /// /// public static bool ConcatVideo(string workingDirectory, List flvFiles, string destVideo) { // contact的文件名,不包含路径 string concatFileName = Guid.NewGuid().ToString("N") + "_concat.txt"; try { string contact = ""; foreach (string flv in flvFiles) { contact += $"file '{flv}'\n"; } FileStream fileStream = new FileStream(workingDirectory + "/" + concatFileName, FileMode.Create); StreamWriter streamWriter = new StreamWriter(fileStream); //开始写入 streamWriter.Write(contact); //清空缓冲区 streamWriter.Flush(); //关闭流 streamWriter.Close(); fileStream.Close(); } catch (Exception e) { Console.WriteLine("ConcatVideo()发生异常: {0}", e); Logging.LogManager.Error(Tag, e); return false; } // ffmpeg -y -f concat -safe 0 -i filelist.txt -c copy output.mkv // 加上-y,表示如果有同名文件,则默认覆盖 string param = $"-y -f concat -safe 0 -i {concatFileName} -c copy \"{destVideo}\" -y"; ExcuteProcess("ffmpeg.exe", param, workingDirectory, (s, e) => Console.WriteLine(e.Data)); // 删除临时文件 try { // 删除concat文件 File.Delete(workingDirectory + "/" + concatFileName); foreach (string flv in flvFiles) { File.Delete(flv); } } catch (Exception e) { Console.WriteLine("ConcatVideo()发生异常: {0}", e); Logging.LogManager.Error(Tag, e); } return true; } /// /// 去水印,非常消耗cpu资源 /// /// /// /// /// /// /// /// public static void Delogo(string video, string destVideo, int x, int y, int width, int height, Action action) { // ffmpeg -y -i "video.mp4" -vf delogo=x=1670:y=50:w=180:h=70:show=1 "delogo.mp4" string param = $"-y -i \"{video}\" -vf delogo=x={x}:y={y}:w={width}:h={height}:show=0 \"{destVideo}\" -hide_banner -y"; ExcuteProcess("ffmpeg.exe", param, null, (s, e) => { Console.WriteLine(e.Data); action.Invoke(e.Data); }); } /// /// 从一个视频中仅提取音频 /// /// 源视频 /// 目标音频 /// 输出信息 public static void ExtractAudio(string video, string audio, Action action) { // 抽取音频命令 // ffmpeg -i 3.mp4 -vn -y -acodec copy 3.aac // ffmpeg -i 3.mp4 -vn -y -acodec copy 3.m4a string param = $"-i \"{video}\" -vn -y -acodec copy \"{audio}\" -hide_banner"; ExcuteProcess("ffmpeg.exe", param, null, (s, e) => { Console.WriteLine(e.Data); action.Invoke(e.Data); }); } /// /// 从一个视频中仅提取视频 /// /// 源视频 /// 目标视频 /// 输出信息 public static void ExtractVideo(string video, string destVideo, Action action) { // 提取视频 (Extract Video) // ffmpeg -i Life.of.Pi.has.subtitles.mkv -vcodec copy –an videoNoAudioSubtitle.mp4 string param = $"-i \"{video}\" -y -vcodec copy -an \"{destVideo}\" -hide_banner"; ExcuteProcess("ffmpeg.exe", param, null, (s, e) => { Console.WriteLine(e.Data); action.Invoke(e.Data); }); } /// /// 提取视频的帧,输出为图片 /// /// /// /// public static void ExtractFrame(string video, string image, uint number) { // 提取帧 // ffmpeg -i caiyilin.wmv -vframes 1 wm.bmp string param = $"-i \"{video}\" -y -vframes {number} \"{image}\""; ExcuteProcess("ffmpeg.exe", param, null, (s, e) => Console.WriteLine(e.Data)); } /// /// 执行一个控制台程序 /// /// 程序名称 /// 参数 /// 工作路径 /// 输出重定向 private static void ExcuteProcess(string exe, string arg, string workingDirectory, DataReceivedEventHandler output) { using (var p = new Process()) { p.StartInfo.FileName = exe; p.StartInfo.Arguments = arg; // 工作目录 if (workingDirectory != null) { p.StartInfo.WorkingDirectory = workingDirectory; } p.StartInfo.UseShellExecute = false; //输出信息重定向 p.StartInfo.CreateNoWindow = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.RedirectStandardOutput = true; // 将 StandardErrorEncoding 改为 UTF-8 才不会出现中文乱码 p.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; p.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8; p.OutputDataReceived += output; p.ErrorDataReceived += output; p.Start(); //启动线程 p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.WaitForExit(); //等待进程结束 } } } }