167 lines
6.0 KiB
C#
167 lines
6.0 KiB
C#
using FFMpegCore.Enums;
|
||
using FFMpegCore.Helpers;
|
||
using FFMpegCore;
|
||
using System.IO;
|
||
using System.Security.Cryptography;
|
||
|
||
namespace VideoConcat.Common.Tools
|
||
{
|
||
internal class VideoCombine
|
||
{
|
||
|
||
public static List<string> mustClearPath = [];
|
||
|
||
/// <summary>
|
||
/// 生成所有组合
|
||
/// </summary>
|
||
public static void GenerateCombinations(List<List<string>> videoLists, int index, List<string> currentCombination, List<List<string>> result)
|
||
{
|
||
if (index == videoLists.Count)
|
||
{
|
||
result.Add([.. currentCombination]);
|
||
return;
|
||
}
|
||
|
||
|
||
foreach (string video in videoLists[index])
|
||
{
|
||
currentCombination.Add(video);
|
||
GenerateCombinations(videoLists, index + 1, currentCombination, result);
|
||
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);
|
||
|
||
string mediaInfo = "";
|
||
|
||
mediaInfo += $"视频: {videoPath}";
|
||
mediaInfo += $"时长: {video.Duration}";
|
||
mediaInfo += $"格式: {video.Format}";
|
||
// 视频流信息
|
||
foreach (var videoStream in video.VideoStreams)
|
||
{
|
||
mediaInfo += $"视频编码: {videoStream.CodecName}, 分辨率: {videoStream.Width}x{videoStream.Height}";
|
||
}
|
||
// 音频流信息
|
||
foreach (var audioStream in video.AudioStreams)
|
||
{
|
||
mediaInfo += $"音频编码: {audioStream.CodecName}, 采样率: {audioStream.SampleRateHz} Hz";
|
||
}
|
||
|
||
LogUtils.Info(mediaInfo);
|
||
|
||
|
||
FFMpegHelper.ConversionSizeExceptionCheck(video);
|
||
|
||
string _tempMd5Name = GetLargeFileMD5(videoPath);
|
||
|
||
//GlobalFFOptions.Current.TemporaryFilesFolder
|
||
var destinationPath = Path.Combine(Path.GetTempPath(), $"{_tempMd5Name}{FileExtension.Ts}");
|
||
|
||
if (File.Exists(destinationPath))
|
||
{
|
||
return destinationPath;
|
||
}
|
||
|
||
//Directory.CreateDirectory(GlobalFFOptions.Current.TemporaryFilesFolder);
|
||
try
|
||
{
|
||
FFMpeg.Convert(videoPath, destinationPath, VideoType.Ts);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
|
||
LogUtils.Info("视频转换失败!尝试另外一种转换");
|
||
// 创建FFmpeg参数
|
||
try
|
||
{
|
||
// string _tempPathError = Path.GetDirectoryName(videoPath) ?? "";
|
||
|
||
//GlobalFFOptions.Current.TemporaryFilesFolder
|
||
//var destinationPathExecp = Path.Combine(Path.GetTempPath(), $"{Path.GetFileNameWithoutExtension(videoPath)}{FileExtension.Mp4}");
|
||
|
||
|
||
//VideoCombine.mustClearPath.Add(destinationPathExecp);
|
||
|
||
// 配置 FFmpeg 参数
|
||
//var options = new FFMpegArgumentOptions()
|
||
// .WithVideoCodec("libx264") // 指定支持 CRF 的编码器
|
||
// .WithConstantRateFactor(23) // 内置方法设置 CRF
|
||
// .WithAudioCodec("aac") // 音频编码器
|
||
// .WithFastStart(); // 流媒体优化
|
||
|
||
|
||
FFMpegArguments
|
||
.FromFileInput(videoPath)
|
||
.OutputToFile(destinationPath, true, o => o
|
||
.WithVideoCodec("libx264") // 设置视频编码器
|
||
.WithAudioCodec("aac") // 设置音频编码器
|
||
.WithAudioSamplingRate(44100)
|
||
.WithAudioBitrate(128000)
|
||
.WithConstantRateFactor(23) // 设置质量调整参数
|
||
.WithCustomArgument("-vf fps=30") // 强制指定帧率(例如 30fps)
|
||
.WithFastStart()
|
||
//.WithCustomArgument("-movflags +faststart") // 确保 moov atom 正确写入
|
||
//.CopyChannel()
|
||
//.WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB)
|
||
.ForceFormat(VideoType.Ts)
|
||
)
|
||
//.NotifyOnOutput(Console.WriteLine) // 打印 FFmpeg 详细日志
|
||
.ProcessSynchronously(true);
|
||
//FFMpeg.Convert(destinationPathExecp, destinationPath, VideoType.Ts);
|
||
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
LogUtils.Error($"{videoPath} 转换失败", ex);
|
||
LogUtils.Error($"{videoPath} 转换再次失败", e);
|
||
}
|
||
|
||
}
|
||
|
||
return destinationPath;
|
||
}
|
||
|
||
public static string GetLargeFileMD5(string filePath)
|
||
{
|
||
using var md5 = MD5.Create();
|
||
using var stream = File.OpenRead(filePath);
|
||
|
||
byte[] buffer = new byte[8192]; // 8KB 缓冲区
|
||
int bytesRead;
|
||
long totalBytesRead = 0;
|
||
|
||
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
|
||
{
|
||
md5.TransformBlock(buffer, 0, bytesRead, null, 0);
|
||
totalBytesRead += bytesRead;
|
||
// 可在此添加进度显示:Console.WriteLine($"已读取 {totalBytesRead / 1024 / 1024}MB");
|
||
}
|
||
|
||
md5.TransformFinalBlock(buffer, 0, 0);
|
||
return BitConverter.ToString(value: md5.Hash).Replace("-", "").ToLowerInvariant();
|
||
}
|
||
}
|
||
}
|