using FFMpegCore; using FFMpegCore.Enums; using System; using System.IO; using System.Threading.Tasks; using VideoConcat.Common.Tools; using static System.Windows.Forms.DataFormats; namespace VideoConcat.Services.Video { public class VideoProcess { /// /// 同步删除视频指定帧和对应音频片段 /// /// 输入文件路径 /// 输出文件路径 /// 要删除的帧编号(从1开始) /// 操作是否成功 public static async Task RemoveFrameRandomeAsync(string inputPath, string outputPath) { if (!File.Exists(inputPath)) return false; try { // 1. 获取视频信息 var mediaInfo = await FFProbe.AnalyseAsync(inputPath); var videoStream = mediaInfo.PrimaryVideoStream; if (videoStream == null) { Console.WriteLine("没有找到视频流"); return false; } bool isHevc = videoStream.CodecName == "hevc"; // 2. 创建临时目录 string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempDir); if (isHevc) { try { // 临时文件路径 string videoConvert = Path.Combine(tempDir, "convert.mp4"); await FFMpegArguments.FromFileInput(inputPath) .OutputToFile(videoConvert, true, opt => // 设置输出格式 opt.WithVideoCodec("libx264") ).ProcessAsynchronously(); mediaInfo = await FFProbe.AnalyseAsync(videoConvert); inputPath = videoConvert; } catch (Exception) { File.Delete(outputPath); } } // 视频总时长(秒) var totalDuration = mediaInfo.Duration.TotalSeconds; // 计算帧时间参数 double frameRate = videoStream.FrameRate; double frameDuration = 1.0 / frameRate; // 一帧时长(秒) int totalFram = (int)(totalDuration * frameRate); // 2. 随机生成要删除的帧的时间点(避开最后一帧,防止越界) var random = new Random(); var randomFrame = random.Next(20, totalFram - 10); double frameTime = (randomFrame - 1) * frameDuration; // 目标帧开始时间 double nextFrameTime = frameTime + frameDuration; // 下一帧开始时间 // 临时文件路径 string videoPart1 = Path.Combine(tempDir, "video_part1.mp4"); string videoPart2 = Path.Combine(tempDir, "video_part2.mp4"); bool hasSubVideo1 = SubVideo(inputPath, videoPart1, 0, frameTime); bool hasSubVideo2 = SubVideo(inputPath, videoPart2, nextFrameTime, totalDuration); if (hasSubVideo1 && hasSubVideo2) { return JoinVideo(outputPath, [videoPart1, videoPart2]); } return false; } catch (Exception ex) { LogUtils.Error("抽帧失败", ex); Console.WriteLine($"操作失败: {ex.Message}"); return false; } } public static bool SubVideo(string inputPath, string outputPath, Double startSec, Double endSec) { return FFMpeg.SubVideo(inputPath, outputPath, TimeSpan.FromSeconds(startSec), TimeSpan.FromSeconds(endSec)); } public static bool JoinVideo(string outPutPath, string[] videoParts) { return FFMpeg.Join(outPutPath, videoParts); } } }