From 56f24eb4a1d382626ed925a539fa41ebd35f46fb Mon Sep 17 00:00:00 2001 From: flyself <1432593898@qq.com> Date: Wed, 20 Oct 2021 14:30:04 +0800 Subject: [PATCH] =?UTF-8?q?FFmpeg=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DownKyi.Core/FFmpeg/FFmpegHelper.cs | 232 ++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 src/DownKyi.Core/FFmpeg/FFmpegHelper.cs diff --git a/src/DownKyi.Core/FFmpeg/FFmpegHelper.cs b/src/DownKyi.Core/FFmpeg/FFmpegHelper.cs new file mode 100644 index 0000000..b77bf99 --- /dev/null +++ b/src/DownKyi.Core/FFmpeg/FFmpegHelper.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace DownKyi.Core.FFmpeg +{ + public static class FFmpegHelper + { + private const string Tag = "PageToolboxDelogo"; + + /// + /// 合并音频和视频 + /// + /// + /// + /// + public static bool MergeVideo(string video1, string video2, string destVideo) + { + string param = $"-i \"{video1}\" -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\""; + if (video1 == null || !File.Exists(video1)) + { + param = $"-i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\""; + } + if (video2 == null || !File.Exists(video2)) + { + param = $"-i \"{video1}\" -acodec copy -vcodec copy -f mp4 \"{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 -f concat -safe 0 -i filelist.txt -c copy output.mkv + // 加上-y,表示如果有同名文件,则默认覆盖 + string param = $"-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 -i "video.mp4" -vf delogo=x=1670:y=50:w=180:h=70:show=1 "delogo.mp4" + string param = $"-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(); //等待进程结束 + } + } + + } +}