This commit is contained in:
xiangbing 2025-08-12 23:11:03 +08:00
parent e2a75a64bd
commit da5f023390
2 changed files with 114 additions and 57 deletions

View File

@ -27,7 +27,7 @@ namespace VideoConcat.Services.Video
try
{
// 1. 获取视频信息
var mediaInfo = await FFProbe.AnalyseAsync(inputPath);
IMediaAnalysis mediaInfo = await FFProbe.AnalyseAsync(inputPath);
var videoStream = mediaInfo.PrimaryVideoStream;
if (videoStream == null)
{
@ -60,77 +60,44 @@ namespace VideoConcat.Services.Video
throw new Exception("转换失败!");
}
}
// 1. 获取视频信息
mediaInfo = await FFProbe.AnalyseAsync(inputPath);
videoStream = mediaInfo.PrimaryVideoStream;
if (videoStream == null)
{
Console.WriteLine("没有找到视频流");
return false;
}
// 视频总时长(秒)
var totalDuration = mediaInfo.Duration.TotalSeconds;
// 计算帧时间参数
double totalDuration = mediaInfo.Duration.TotalSeconds;
double frameRate = videoStream.FrameRate;
double frameDuration = Math.Round(1.0 / frameRate, 6); // 一帧时长(秒)
int totalFram = (int)(totalDuration * frameRate);
// 2. 随机生成要删除的帧的时间点(避开最后一帧,防止越界)
var random = new Random();
var randomFrame = random.Next(20, totalFram - 10);
double frameTime = Math.Round((randomFrame - 1) * frameDuration,6); // 目标帧开始时间
double nextFrameTime = Math.Round(randomFrame * frameDuration,6); // 下一帧开始时间
// 临时文件路径
var random = new Random();
var randomFrame = random.Next(1, (int)totalDuration);
string videoPart1 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string videoPart2 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string audioPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
string videoNoaudioPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string finalyPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string audioPart1 = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
string audioPart2 = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
// 分离视频流(不含音频)
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(videoNoaudioPath, true, opt => opt.WithCustomArgument("-an -c:v copy"))
.ProcessAsynchronously();
if (!File.Exists(videoNoaudioPath))
return false;
// 分离音频流(不含视频)(如有音频)
if (mediaInfo.PrimaryAudioStream != null)
{
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(audioPath, true, opt => opt.WithCustomArgument("-vn -c:a copy"))
.ProcessAsynchronously();
if (!File.Exists(audioPath))
return false;
}
inputPath = videoNoaudioPath;
bool hasSubVideo1 = SubVideo(inputPath, videoPart1, 0, frameTime);
bool hasSubVideo2 = SubVideo(inputPath, videoPart2, nextFrameTime, totalDuration);
bool hasSubVideo1 = SubVideo(inputPath, videoPart1, 0, randomFrame-0.016);
bool hasSubVideo2 = SubVideo(inputPath, videoPart2, randomFrame, totalDuration);
if (!hasSubVideo1 || !hasSubVideo2)
{
return false;
}
bool isJoinSuccess = JoinVideo(finalyPath, [videoPart1, videoPart2]);
bool isJoinSuccess = JoinVideo(outputPath, [videoPart1, videoPart2]);
if (!isJoinSuccess)
{
return false;
}
return await FFMpegArguments.FromFileInput(finalyPath)
.AddFileInput(audioPath)
.OutputToFile(outputPath, true, opt =>
opt.WithCustomArgument("-c copy -shortest -y"))
.ProcessAsynchronously();
return false;
}
catch (Exception ex)
{
@ -153,7 +120,7 @@ namespace VideoConcat.Services.Video
{
return FFMpegArguments
.FromFileInput(inputPath, true, options => options.Seek(TimeSpan.FromSeconds(startSec)).EndSeek(TimeSpan.FromSeconds(endSec)))
.OutputToFile(outputPath, true, options => options.CopyChannel().WithCustomArgument("-an"))
.OutputToFile(outputPath, true, options => options.CopyChannel()) //.WithCustomArgument("-an") 去掉音频
.ProcessSynchronously();
}
@ -170,5 +137,88 @@ namespace VideoConcat.Services.Video
{
return FFMpeg.Join(outPutPath, videoParts);
}
public async Task<bool> ProcessVideo(string inputPath,string outputPath, string tempDir)
{
// 1. 获取视频信息
IMediaAnalysis mediaInfo = await FFProbe.AnalyseAsync(inputPath);
var videoStream = mediaInfo.PrimaryVideoStream;
if (videoStream == null)
{
Console.WriteLine("没有找到视频流");
return false;
}
// 视频总时长(秒)
var totalDuration = mediaInfo.Duration.TotalSeconds;
// 计算帧时间参数
double frameRate = videoStream.FrameRate;
double frameDuration = Math.Round(1.0 / frameRate, 6); // 一帧时长(秒)
int totalFram = (int)(totalDuration * frameRate);
// 2. 随机生成要删除的帧的时间点(避开最后一帧,防止越界)
var random = new Random();
var randomFrame = random.Next(20, totalFram - 10);
double frameTime = Math.Round((randomFrame - 1) * frameDuration, 6); // 目标帧开始时间
double nextFrameTime = Math.Round((randomFrame + 1) * frameDuration, 6); // 下一帧开始时间
// 临时文件路径
string videoPart1 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string videoPart2 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string audioPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
string videoNoaudioPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string finalyPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
string audioPart1 = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
string audioPart2 = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
// 分离视频流(不含音频)
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(videoNoaudioPath, true, opt => opt.WithCustomArgument("-an -c:v copy"))
.ProcessAsynchronously();
if (!File.Exists(videoNoaudioPath))
return false;
// 分离音频流(不含视频)(如有音频)
if (mediaInfo.PrimaryAudioStream != null)
{
await FFMpegArguments
.FromFileInput(inputPath)
.OutputToFile(audioPath, true, opt => opt.WithCustomArgument("-vn -c:a copy"))
.ProcessAsynchronously();
if (!File.Exists(audioPath))
return false;
}
inputPath = videoNoaudioPath;
bool hasSubVideo1 = SubVideo(inputPath, videoPart1, 0, frameTime);
bool hasSubVideo2 = SubVideo(inputPath, videoPart2, nextFrameTime, totalDuration);
if (!hasSubVideo1 || !hasSubVideo2)
{
return false;
}
bool isJoinSuccess = JoinVideo(finalyPath, [videoPart1, videoPart2]);
if (!isJoinSuccess)
{
return false;
}
return await FFMpegArguments.FromFileInput(finalyPath)
.AddFileInput(audioPath)
.OutputToFile(outputPath, true, opt =>
opt.WithCustomArgument("-c copy -shortest -y"))
.ProcessAsynchronously();
}
}
}

View File

@ -76,8 +76,15 @@ namespace VideoConcat.ViewModels
var remover = new VideoProcess();
// 删除4秒处的帧需根据实际帧位置调整
string _tmpPath = Path.GetDirectoryName(video) ?? "";
string _tmpFileName = $"抽帧视频-{Path.GetFileName(video)}";
await VideoProcess.RemoveFrameRandomeAsync(video, $"{_tmpPath}\\{_tmpFileName}");
string _tmpFileName = $"{(new Random()).Next(10000,99999)}{Path.GetFileName(video)}";
string outPath = Path.Combine(_tmpPath, "out");
if (!Path.Exists(outPath))
{
Directory.CreateDirectory(outPath);
}
await VideoProcess.RemoveFrameRandomeAsync(video, $"{_tmpPath}\\out\\{_tmpFileName}");
}
finally
{