using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Windows; using System.Windows.Shapes; using WPFDevelopers.Helpers; using static System.Net.WebRequestMethods; using File = System.IO.File; namespace VideoConcat { /// /// Video.xaml 的交互逻辑 /// public partial class Video : Window { public string text = "", outPut = ""; public Dictionary videoFolders = []; public DirectoryInfo Path; public Dictionary AllPublicCombinVideos = []; int GenerateVideoCount = 0; public Video() { InitializeComponent(); string currentPath = Directory.GetCurrentDirectory(); DirectoryInfo ExecParentPath = Directory.GetParent(currentPath) ?? new DirectoryInfo(""); if (ExecParentPath != null) { Path = ExecParentPath; } } private async void Button_Click(object sender, RoutedEventArgs e) { try { GenerateVideoCount = int.Parse(videoCount.Text); } catch (Exception) { MessageBox.Show("请输入正确的数字"); return; } WriteTxt($"生成视频的个数:{GenerateVideoCount} 个"); Check_Folder(); MakeOutPutDir(); startButton.IsEnabled = false; GenerateAllvideos(videoFolders); var dateStart = DateTime.Now; //记录用时的起始时间 await Task.Run(async () => { List> lists = GenerateAllvideos(videoFolders); await MockIOPerformanceAsync(lists); startButton.Dispatcher.Invoke(() => { startButton.IsEnabled = true; }); }); var dateEnd = DateTime.Now; var timeSpan = dateEnd - dateStart;//记录开票用时 WriteTxt($"用时:{timeSpan.TotalSeconds}秒"); } private void Check_Folder() { if (Path == null) { WriteTxt("获取相关视频文件目录失败!"); return; } WriteTxt("当前目录为:" + Path.FullName); videoFolders.Clear(); AllPublicCombinVideos.Clear(); try { int k = 1; for (int i = 1; i < 100; i++) { var folder = string.Format("{0:D2}", i); string currentFolderPath = $"{Path}\\{folder}"; if (Directory.Exists(currentFolderPath)) { WriteTxt(folder); string[] videos = GetAllVideos(currentFolderPath); if (videos.Length > 0) { videoFolders.Add(k, videos); AllPublicCombinVideos.Add(k, new A()); k++; } } } return; } catch (Exception ex) { MessageBox.Show(ex.Message); return; } } private void WriteTxt(string str) { outputTxt.Dispatcher.Invoke(() => { text += str + "\r\n"; outputTxt.Text = text; scrowText.ScrollToEnd(); }); } public static string[] GetAllVideos(string path) { return Directory.GetFiles(path, "*.mp4", SearchOption.AllDirectories); } public void CombineMp4WithoutTxt(List files, string StrOutMp4Path) { Process p = new();//建立外部调用线程 p.StartInfo.FileName = Directory.GetCurrentDirectory() + "\\ffmpeg.exe";//要调用外部程序的绝对路径 //int i = 0; //string vao = ""; List ooootext = []; files.ForEach(file => { ooootext.Add($"file '{file}'"); }); string tmpConcatFile = $"{outPut}\\{Guid.NewGuid().ToString()}"; // 也可以指定编码方式 File.WriteAllLines(tmpConcatFile, ooootext, Encoding.ASCII); string StrArg = $"-f concat -safe 0 -i {tmpConcatFile} -c copy -bsf:a aac_adtstoasc -movflags +faststart {StrOutMp4Path}"; //string StrArg = $"-i {combineFile} -filter_complex \"{vao} concat=n={i}:v=1:a=1 [v][a]\" -map \"[v]\" -map \"[a]\" {StrOutMp4Path}"; p.StartInfo.Arguments = StrArg; p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN) p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的) p.StartInfo.CreateNoWindow = true;//不创建进程窗口 p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN p.Start();//启动线程 p.BeginErrorReadLine();//开始异步读取 p.WaitForExit();//阻塞等待进程结束 p.Close();//关闭进程 p.Dispose();//释放资源 } private void Output(object sendProcess, DataReceivedEventArgs output) { if (!String.IsNullOrEmpty(output.Data)) { WriteTxt(output.Data); } } public void MakeOutPutDir() { outPut = $"{Path.FullName}\\output"; if (!Directory.Exists(outPut)) { Directory.CreateDirectory(outPut); } } public async Task> MockIOPerformanceAsync(List> ls) { List lss = []; List tasks = []; foreach (var item in ls) { Task task = new(() => { DateTime now = DateTime.Now; Random random = new Random(); string randomString = random.Next(100000, 999999).ToString(); string result = now.ToString("yyyyMMddHHmmss") + randomString; CombineMp4WithoutTxt(item, $"{outPut}\\{result}.mp4"); }); tasks.Add(task); task.Start(); if (tasks.Count >= GenerateVideoCount) { break; } } foreach (var item in tasks) { await item; } return lss; } private List> GenerateAllvideos(Dictionary dict) { List> ls = []; foreach (var item in dict) { ls.Add(new List(item.Value)); } List> permutations = CalculatePermutations(ls); return permutations; } static List> CalculatePermutations(List> inputList) { List> result = new List>(); // 递归计算全排列的辅助函数 void Permute(List currentPermutation, int index) { if (index == inputList.Count) { result.Add(new List(currentPermutation)); return; } foreach (string item in inputList[index]) { currentPermutation.Add(item); Permute(currentPermutation, index + 1); currentPermutation.RemoveAt(currentPermutation.Count - 1); } } Permute(new List(), 0); return result; } } public class A { public int Index { get; set; } }; }