From da5f023390cfa6ad15d4d4d7b5c193fb9ed24bc2 Mon Sep 17 00:00:00 2001 From: xiangbing Date: Tue, 12 Aug 2025 23:11:03 +0800 Subject: [PATCH] update --- Services/Video/VideoProcess.cs | 160 ++++++++++++++++++--------- ViewModels/ExtractWindowViewModel.cs | 11 +- 2 files changed, 114 insertions(+), 57 deletions(-) diff --git a/Services/Video/VideoProcess.cs b/Services/Video/VideoProcess.cs index 9783a07..29a1c50 100644 --- a/Services/Video/VideoProcess.cs +++ b/Services/Video/VideoProcess.cs @@ -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 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(); + } } } diff --git a/ViewModels/ExtractWindowViewModel.cs b/ViewModels/ExtractWindowViewModel.cs index 344e90c..e44fac8 100644 --- a/ViewModels/ExtractWindowViewModel.cs +++ b/ViewModels/ExtractWindowViewModel.cs @@ -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 {