VideoConcat/Common/Tools/VideoCombine.cs

167 lines
6.0 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}
}
}