This commit is contained in:
xiangbing 2025-01-18 14:02:49 +08:00
parent baf1592fc5
commit 6fa231b010
2 changed files with 117 additions and 20 deletions

View File

@ -1,13 +1,15 @@
using System; using FFMpegCore.Enums;
using System.Collections.Generic; using FFMpegCore.Helpers;
using System.Linq; using FFMpegCore;
using System.Text; using System.IO;
using System.Threading.Tasks;
namespace VideoConcat.Common.Tools namespace VideoConcat.Common.Tools
{ {
internal class VideoCombine internal class VideoCombine
{ {
/// <summary>
/// 生成所有组合
/// </summary>
public static void GenerateCombinations(List<List<string>> videoLists, int index, List<string> currentCombination, List<List<string>> result) public static void GenerateCombinations(List<List<string>> videoLists, int index, List<string> currentCombination, List<List<string>> result)
{ {
if (index == videoLists.Count) if (index == videoLists.Count)
@ -24,5 +26,37 @@ namespace VideoConcat.Common.Tools
currentCombination.RemoveAt(currentCombination.Count - 1); currentCombination.RemoveAt(currentCombination.Count - 1);
} }
} }
/// <summary>
/// 清理临时文件
/// </summary>
public static void Cleanup(List<string> pathList)
{
foreach (var path in pathList)
{
if (File.Exists(path))
{
File.Delete(path);
}
}
}
/// <summary>
/// 将视频文件转换为ts格式
/// </summary>
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;
}
} }
} }

View File

@ -5,6 +5,7 @@ using VideoConcat.Common.Tools;
using System.IO; using System.IO;
using Microsoft.Expression.Drawing.Core; using Microsoft.Expression.Drawing.Core;
using FFMpegCore; using FFMpegCore;
using FFMpegCore.Enums;
namespace VideoConcat.ViewModels namespace VideoConcat.ViewModels
{ {
@ -75,20 +76,23 @@ namespace VideoConcat.ViewModels
{ {
DoExcue = obj => DoExcue = obj =>
{ {
Task.Run(action: () => Task.Run(action: async () =>
{ {
MessageBox.Show("开始合并视频"); MessageBox.Show("开始合并视频");
if (Directory.Exists($"{VideoModel.FolderPath}\\output") == false)
{
Directory.CreateDirectory($"{VideoModel.FolderPath}\\output");
}
VideoModel.IsStart = true; VideoModel.IsStart = true;
//开始时间 //开始时间
DateTime startTime = DateTime.Now; DateTime startTime = DateTime.Now;
LogUtils.Info("开始合并视频"); LogUtils.Info("开始合并视频,进行视频拼接组合");
List<List<string>> combinations = []; List<List<string>> combinations = [];
List<string> currentCombination = []; List<string> currentCombination = [];
List<List<string>> videoLists = []; List<List<string>> videoLists = [];
List<Task> taskList = [];
VideoModel.FolderInfos.ForEach(folderInfo => VideoModel.FolderInfos.ForEach(folderInfo =>
{ {
@ -105,30 +109,83 @@ namespace VideoConcat.ViewModels
// 复制原列表,避免修改原列表 // 复制原列表,避免修改原列表
List<List<string>> tempList = new(combinations); List<List<string>> tempList = new(combinations);
string[] _converVideoPath = [];
List<string> _clearPath = [];
for (int i = 0; i < VideoModel.Num && tempList.Count > 0; i++) for (int i = 0; i < VideoModel.Num && tempList.Count > 0; i++)
{ {
int index = random.Next(tempList.Count); int index = random.Next(tempList.Count);
result.Add(tempList[index]); result.Add(tempList[index]);
_converVideoPath = [.. _converVideoPath, .. tempList[index]];
tempList.RemoveAt(index); tempList.RemoveAt(index);
} }
SemaphoreSlim semaphore = new(10); // Limit to 3 threads
List<Task> _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<Task> taskList = [];
semaphore = new(10);
foreach (List<string> combination in result) foreach (List<string> combination in result)
{ {
taskList.Add(Task.Run(() => await semaphore.WaitAsync();
var _task = Task.Run(() =>
{ {
try 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 _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 不在系统路径中) // 配置 FFmpeg 二进制文件位置(如果 FFmpeg 不在系统路径中)
// GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "path/to/ffmpeg/bin" }); // 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\" "; string _customArg = "-filter_complex \"[0:v][1:v] overlay=0:H-h\" ";
// 使用 FFMpegArguments 构建命令 // 使用 FFMpegArguments 构建命令
@ -169,19 +227,24 @@ namespace VideoConcat.ViewModels
{ {
LogUtils.Error($"视频{string.Join("", combination)}合并失败", ex); 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; DateTime endTime = DateTime.Now;
LogUtils.Info($"所有视频拼接完成,用时{(endTime - startTime).TotalSeconds}秒"); LogUtils.Info($"所有视频拼接完成,用时{(endTime - startTime).TotalSeconds}秒");
VideoModel.IsStart = false; VideoModel.IsStart = false;
MessageBox.Show("所有视频拼接完成"); MessageBox.Show("所有视频拼接完成");
VideoCombine.Cleanup(_clearPath);
}); });
}); });
} }