update
This commit is contained in:
parent
baf1592fc5
commit
6fa231b010
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user