VideoConcat/Video.xaml.cs
2024-11-02 23:20:44 +08:00

287 lines
8.4 KiB
C#

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
{
/// <summary>
/// Video.xaml 的交互逻辑
/// </summary>
public partial class Video : Window
{
public string text = "", outPut = "";
public Dictionary<int, string[]> videoFolders = [];
public DirectoryInfo Path;
public Dictionary<int, A> 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<List<string>> 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<string> files, string StrOutMp4Path)
{
Process p = new();//建立外部调用线程
p.StartInfo.FileName = Directory.GetCurrentDirectory() + "\\ffmpeg.exe";//要调用外部程序的绝对路径
//int i = 0;
//string vao = "";
List<string> 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<IEnumerable<string>> MockIOPerformanceAsync(List<List<string>> ls)
{
List<string> lss = [];
List<Task> 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<List<string>> GenerateAllvideos(Dictionary<int, string[]> dict)
{
List<List<string>> ls = [];
foreach (var item in dict)
{
ls.Add(new List<string>(item.Value));
}
List<List<string>> permutations = CalculatePermutations(ls);
return permutations;
}
static List<List<string>> CalculatePermutations(List<List<string>> inputList)
{
List<List<string>> result = new List<List<string>>();
// 递归计算全排列的辅助函数
void Permute(List<string> currentPermutation, int index)
{
if (index == inputList.Count)
{
result.Add(new List<string>(currentPermutation));
return;
}
foreach (string item in inputList[index])
{
currentPermutation.Add(item);
Permute(currentPermutation, index + 1);
currentPermutation.RemoveAt(currentPermutation.Count - 1);
}
}
Permute(new List<string>(), 0);
return result;
}
}
public class A
{
public int Index { get; set; }
};
}