diff --git a/Common/Tools/VideoCombine.cs b/Common/Tools/VideoCombine.cs
index cf80b6e..d9ea783 100644
--- a/Common/Tools/VideoCombine.cs
+++ b/Common/Tools/VideoCombine.cs
@@ -1,13 +1,15 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using FFMpegCore.Enums;
+using FFMpegCore.Helpers;
+using FFMpegCore;
+using System.IO;
namespace VideoConcat.Common.Tools
{
internal class VideoCombine
{
+ ///
+ /// 生成所有组合
+ ///
public static void GenerateCombinations(List> videoLists, int index, List currentCombination, List> result)
{
if (index == videoLists.Count)
@@ -24,5 +26,37 @@ namespace VideoConcat.Common.Tools
currentCombination.RemoveAt(currentCombination.Count - 1);
}
}
+
+ ///
+ /// 清理临时文件
+ ///
+ public static void Cleanup(List pathList)
+ {
+ foreach (var path in pathList)
+ {
+ if (File.Exists(path))
+ {
+ File.Delete(path);
+ }
+ }
+ }
+
+ ///
+ /// 将视频文件转换为ts格式
+ ///
+ public static string ConvertVideos(string videoPath)
+ {
+
+ var video = FFProbe.Analyse(videoPath);
+ FFMpegHelper.ConversionSizeExceptionCheck(video);
+
+ string _tempPath = Path.GetDirectoryName(videoPath) ?? "";
+
+ //GlobalFFOptions.Current.TemporaryFilesFolder
+ var destinationPath = Path.Combine(_tempPath, $"{Path.GetFileNameWithoutExtension(videoPath)}{FileExtension.Ts}");
+ //Directory.CreateDirectory(GlobalFFOptions.Current.TemporaryFilesFolder);
+ FFMpeg.Convert(videoPath, destinationPath, VideoType.Ts);
+ return destinationPath;
+ }
}
}
diff --git a/ViewModels/VideoViewModel.cs b/ViewModels/VideoViewModel.cs
index 50bfde8..14016dc 100644
--- a/ViewModels/VideoViewModel.cs
+++ b/ViewModels/VideoViewModel.cs
@@ -5,6 +5,7 @@ using VideoConcat.Common.Tools;
using System.IO;
using Microsoft.Expression.Drawing.Core;
using FFMpegCore;
+using FFMpegCore.Enums;
namespace VideoConcat.ViewModels
{
@@ -75,21 +76,24 @@ namespace VideoConcat.ViewModels
{
DoExcue = obj =>
{
- Task.Run(action: () =>
+ Task.Run(action: async () =>
{
MessageBox.Show("开始合并视频");
+ if (Directory.Exists($"{VideoModel.FolderPath}\\output") == false)
+ {
+ Directory.CreateDirectory($"{VideoModel.FolderPath}\\output");
+ }
VideoModel.IsStart = true;
//开始时间
DateTime startTime = DateTime.Now;
- LogUtils.Info("开始合并视频");
+ LogUtils.Info("开始合并视频,进行视频拼接组合");
List> combinations = [];
List currentCombination = [];
List> videoLists = [];
- List taskList = [];
-
+
VideoModel.FolderInfos.ForEach(folderInfo =>
{
videoLists.Add(folderInfo.VideoPaths);
@@ -105,30 +109,83 @@ namespace VideoConcat.ViewModels
// 复制原列表,避免修改原列表
List> tempList = new(combinations);
+ string[] _converVideoPath = [];
+ List _clearPath = [];
for (int i = 0; i < VideoModel.Num && tempList.Count > 0; i++)
{
int index = random.Next(tempList.Count);
result.Add(tempList[index]);
+
+ _converVideoPath = [.. _converVideoPath, .. tempList[index]];
+
tempList.RemoveAt(index);
}
+ SemaphoreSlim semaphore = new(10); // Limit to 3 threads
+
+ List _tasks = [];
+
+ foreach (var _path in _converVideoPath)
+ {
+ await semaphore.WaitAsync(); // Wait when more than 3 threads are running
+ var _task = Task.Run(() =>
+ {
+ try
+ {
+ _clearPath.Add(VideoCombine.ConvertVideos(_path));
+ }
+ finally
+ {
+ semaphore.Release(); // Work is done, signal to semaphore that more work is possible
+ }
+ });
+ _tasks.Add(_task);
+ }
+
+ await Task.WhenAll(_tasks).ContinueWith((task) =>
+ {
+ LogUtils.Info($"转换完成,用时{(DateTime.Now - startTime).TotalSeconds}秒");
+ });
+
+ LogUtils.Info("开始拼接视频");
+
+
+ List taskList = [];
+ semaphore = new(10);
foreach (List combination in result)
{
- taskList.Add(Task.Run(() =>
+ await semaphore.WaitAsync();
+ var _task = Task.Run(() =>
{
-
try
{
- if (Directory.Exists($"{VideoModel.FolderPath}\\output") == false)
- {
- Directory.CreateDirectory($"{VideoModel.FolderPath}\\output");
- }
string _outPutName = $"{VideoModel.FolderPath}\\output\\{DateTime.Now:yyyyMMddHHmmss}{random.Next(100000, 999999)}.mp4";
- string _outPutNameImg = $"{VideoModel.FolderPath}\\output\\{DateTime.Now:yyyyMMddHHmmss}{random.Next(100000, 999999)}.mp4";
- bool _isSuccess = FFMpeg.Join(_outPutName, [.. combination]);
+ var temporaryVideoParts = combination.Select(_ => {
+ string _tempPath = Path.GetDirectoryName(_) ?? "";
+
+ //GlobalFFOptions.Current.TemporaryFilesFolder
+ return Path.Combine(_tempPath, $"{Path.GetFileNameWithoutExtension(_)}{FileExtension.Ts}");
+ }).ToArray();
+ bool _isSuccess = false;
+ try
+ {
+ _isSuccess= FFMpegArguments
+ .FromConcatInput(temporaryVideoParts)
+ .OutputToFile(_outPutName, true, options => options
+ .CopyChannel()
+ .WithBitStreamFilter(Channel.Audio, Filter.Aac_AdtstoAsc))
+ .ProcessSynchronously();
+ }
+ catch (Exception ex)
+ {
+ _isSuccess = false;
+ LogUtils.Error("拼接视频失败", ex);
+ }
+
+ //bool _isSuccess = FFMpeg.Join(_outPutName, [.. combination]);
@@ -140,6 +197,7 @@ namespace VideoConcat.ViewModels
// 配置 FFmpeg 二进制文件位置(如果 FFmpeg 不在系统路径中)
// GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "path/to/ffmpeg/bin" });
+ string _outPutNameImg = $"{VideoModel.FolderPath}\\output\\{DateTime.Now:yyyyMMddHHmmss}{random.Next(100000, 999999)}.mp4";
string _customArg = "-filter_complex \"[0:v][1:v] overlay=0:H-h\" ";
// 使用 FFMpegArguments 构建命令
@@ -169,19 +227,24 @@ namespace VideoConcat.ViewModels
{
LogUtils.Error($"视频{string.Join(",", combination)}合并失败", ex);
}
+ finally
+ {
+ semaphore.Release();
+ }
- }));
-
+ });
+ taskList.Add(_task);
}
- Task.WhenAll(taskList).ContinueWith((s) =>
+ await Task.WhenAll(taskList).ContinueWith((s) =>
{
//结束时间
DateTime endTime = DateTime.Now;
LogUtils.Info($"所有视频拼接完成,用时{(endTime - startTime).TotalSeconds}秒");
VideoModel.IsStart = false;
MessageBox.Show("所有视频拼接完成");
+ VideoCombine.Cleanup(_clearPath);
});
});
}