VideoConcat/Video.xaml.cs
2024-11-19 21:40:09 +08:00

369 lines
11 KiB
C#

using Standard;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Shapes;
using WPFDevelopers.Helpers;
using File = System.IO.File;
namespace VideoConcat
{
/// <summary>
/// Video.xaml 的交互逻辑
/// </summary>
public partial class Video : Window
{
public string text = "", outPut = "";
static int totalVideoCount = 0;
public Dictionary<int, string[]> videoFolders = [];
private static string Path = "", ParentPath = "";
public Dictionary<int, A> AllPublicCombinVideos = [];
int GenerateVideoCount = 0;
public static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public Video()
{
InitializeComponent();
Init();
}
public static void Init()
{
ParentPath = Directory.GetCurrentDirectory();
log4net.Config.XmlConfigurator.Configure();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
GenerateVideoCount = int.Parse(videoCount.Text);
}
catch (Exception)
{
MessageBox.Show("请输入正确的数字");
return;
}
totalVideoCount = 0;
Check_Folder();
WriteTxt($"最多可生成视频个数为{totalVideoCount}个");
if (GenerateVideoCount > totalVideoCount)
{
WriteTxt($"生成视频个数不能超过{totalVideoCount}个");
return;
}
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;//记录开票用时
try
{
string mp4Path = $"{Directory.GetCurrentDirectory()}\\temp\\";
DirectoryInfo directoryInfo = new DirectoryInfo(mp4Path);
FileInfo[] files = directoryInfo.GetFiles("*.mp4"); // 获取指定目录下的所有 txt 文件
foreach (FileInfo file in files)
{
file.Delete(); // 删除文件
}
}
catch (Exception)
{
}
WriteTxt($"用时:{timeSpan.TotalSeconds}秒");
}
private void Check_Folder()
{
WriteTxt("开始检测视频文件路径");
DirectoryInfo? directory = Directory.GetParent(ParentPath);
if (directory == null)
{
WriteTxt("获取视频路径失败!");
return;
}
Path = directory.FullName;
WriteTxt("当前目录为:" + Path);
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))
{
string[] videos = GetAllVideos(currentFolderPath);
if (videos.Length > 0)
{
if (totalVideoCount == 0)
{
totalVideoCount = 1;
}
WriteTxt($"检测到视频文件夹:{folder},视频个数:{videos.Length}");
totalVideoCount *= videos.Length;
videoFolders.Add(k, videos);
AllPublicCombinVideos.Add(k, new A());
k++;
}
else
{
WriteTxt($"视频文件夹【{folder}】未发现MP4格式视频文件");
}
}
}
return;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
private void WriteTxt(string str)
{
outputTxt.Dispatcher.Invoke(() =>
{
log.Info(str);
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)
{
var random = new Random();
//int i = 0;
//string vao = "";
List<string> ooootext = [];
files.ForEach(file =>
{
string tmpOut = $"{Directory.GetCurrentDirectory()}\\temp\\{Guid.NewGuid()}{random.Next(100000, 999999)}.mp4";
// ffmpeg.exe - i a.mp4 - ac 1 - ar 48000 - vcodec copy a_re.mp4
Run_Command($"-i \"{file}\" -c:v libx264 -c:a aac {tmpOut}");
ooootext.Add($"file '{tmpOut}'");
});
log.Info(ooootext);
string tmpConcatFile = $"{Directory.GetCurrentDirectory()}\\temp\\{Guid.NewGuid()}{random.Next(100000, 999999)}";
// 也可以指定编码方式
//File.WriteAllLines(tmpConcatFile, ooootext, Encoding.UTF8);
File.WriteAllText(tmpConcatFile, string.Join("\n", [.. ooootext]), new System.Text.UTF8Encoding(false));
string StrArg = $"-f concat -safe 0 -i {tmpConcatFile} -c copy {StrOutMp4Path}";
//string StrArg = $"-i {combineFile} -filter_complex \"{vao} concat=n={i}:v=1:a=1 [v][a]\" -map \"[v]\" -map \"[a]\" {StrOutMp4Path}";
Run_Command(StrArg);
if (File.Exists(tmpConcatFile))
{
try
{
File.Delete(tmpConcatFile);
}
catch
{
}
}
}
public void Run_Command(string command)
{
Process p = new();//建立外部调用线程
p.StartInfo.FileName = Directory.GetCurrentDirectory() + "\\ffmpeg.exe";//要调用外部程序的绝对路径
p.StartInfo.Arguments = command;
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))
{
log.Info(output.Data, null);
}
}
public void MakeOutPutDir()
{
outPut = $"{Path}\\output";
if (!Directory.Exists(outPut))
{
Directory.CreateDirectory(outPut);
}
}
public async Task<IEnumerable<string>> MockIOPerformanceAsync(List<List<string>> ls)
{
List<string> lss = [];
List<Task> tasks = [];
Random rd = new();
ls = [.. ls.OrderBy(x => rd.Next())];
foreach (var item in ls)
{
Task task = new(() =>
{
DateTime now = DateTime.Now;
Random random = new();
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 static 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 = [];
// 递归计算全排列的辅助函数
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([], 0);
return result;
}
}
public class A
{
public int Index { get; set; }
};
}