using FFMpegCore;
using FFMpegCore.Enums;
using Standard;
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
    {
        /// <summary>
        /// 在前30%、中间30%、后30%三个位置各随机删除一帧，确保通过广告平台相似度检查
        /// </summary>
        /// <param name="inputPath">输入文件路径</param>
        /// <param name="outputPath">输出文件路径</param>
        /// <returns>操作是否成功</returns>
        public static async Task<bool> RemoveFrameRandomeAsync(string inputPath, string outputPath)
        {
            if (!File.Exists(inputPath))
            {
                LogUtils.Error($"输入文件不存在：{inputPath}");
                return false;
            }

            // 创建临时目录
            string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            try
            {
                Directory.CreateDirectory(tempDir);

                // 1. 获取视频信息
                IMediaAnalysis mediaInfo = await FFProbe.AnalyseAsync(inputPath);
                var videoStream = mediaInfo.PrimaryVideoStream;
                if (videoStream == null)
                {
                    LogUtils.Error("没有找到视频流");
                    return false;
                }

                // 视频总时长（秒）
                double totalDuration = mediaInfo.Duration.TotalSeconds;
                double frameRate = videoStream.FrameRate;
                
                // 确保视频时长足够（至少20秒）
                if (totalDuration < 20)
                {
                    LogUtils.Error($"视频时长太短（{totalDuration:F2}秒），无法抽帧（需要至少20秒）");
                    return false;
                }

                // 计算总帧数
                int totalFrames = (int)(totalDuration * frameRate);
                if (totalFrames <= 0)
                {
                    LogUtils.Error($"无法计算视频总帧数，帧率={frameRate}");
                    return false;
                }

                // 如果是 HEVC 编码，先转换为 H.264（select 过滤器在某些编码格式下可能不稳定）
                bool isHevc = videoStream.CodecName == "hevc";
                string workingInputPath = inputPath;
                
                if (isHevc)
                {
                    try
                    {
                        string videoConvert = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
                        LogUtils.Info($"检测到 HEVC 编码，先转换为 H.264：{inputPath} -> {videoConvert}");
                        
                        await FFMpegArguments.FromFileInput(inputPath)
                            .OutputToFile(videoConvert, true, opt => 
                                opt.WithVideoCodec("libx264")
                                   .WithAudioCodec("copy") // 复制音频流，不重新编码
                            ).ProcessAsynchronously();
                        
                        // 重新分析转换后的视频
                        mediaInfo = await FFProbe.AnalyseAsync(videoConvert);
                        videoStream = mediaInfo.PrimaryVideoStream;
                        if (videoStream == null)
                        {
                            LogUtils.Error("转换后没有找到视频流");
                            return false;
                        }
                        
                        totalDuration = mediaInfo.Duration.TotalSeconds;
                        frameRate = videoStream.FrameRate;
                        totalFrames = (int)(totalDuration * frameRate);
                        workingInputPath = videoConvert;
                        
                        LogUtils.Info($"HEVC 转换完成，新帧率={frameRate}, 总帧数={totalFrames}");
                    }
                    catch (Exception ex)
                    {
                        LogUtils.Error("HEVC 转换失败", ex);
                        return false;
                    }
                }

                // 2. 计算三个区域的范围（前30%、中间30%、后30%）
                // 前30%：0% 到 30%
                int front30StartFrame = 0;
                int front30EndFrame = (int)(totalFrames * 0.30);
                
                // 中间30%：35% 到 65%（避开边界）
                int middle30StartFrame = (int)(totalFrames * 0.35);
                int middle30EndFrame = (int)(totalFrames * 0.65);
                
                // 后30%：70% 到 100%
                int back30StartFrame = (int)(totalFrames * 0.70);
                int back30EndFrame = totalFrames - 1; // 最后一帧

                // 确保范围有效
                if (front30EndFrame <= front30StartFrame) front30EndFrame = front30StartFrame + 1;
                if (middle30EndFrame <= middle30StartFrame) middle30EndFrame = middle30StartFrame + 1;
                if (back30EndFrame <= back30StartFrame) back30EndFrame = back30StartFrame + 1;

                // 使用时间戳和文件路径作为随机种子，确保每次处理都不同
                var random = new Random((int)(DateTime.Now.Ticks % int.MaxValue) + inputPath.GetHashCode());
                
                // 3. 在每个区域随机选择一帧删除
                int frame1 = random.Next(front30StartFrame, front30EndFrame + 1);   // 前30%
                int frame2 = random.Next(middle30StartFrame, middle30EndFrame + 1); // 中间30%
                int frame3 = random.Next(back30StartFrame, back30EndFrame + 1);     // 后30%

                // 确保三帧不重复（如果重复，调整其中一个）
                if (frame2 == frame1) frame2 = (frame2 + 1) % totalFrames;
                if (frame3 == frame1 || frame3 == frame2) 
                {
                    frame3 = (frame3 + 1) % totalFrames;
                    if (frame3 == frame1 || frame3 == frame2) frame3 = (frame3 + 1) % totalFrames;
                }

                double time1 = frame1 / frameRate;
                double time2 = frame2 / frameRate;
                double time3 = frame3 / frameRate;
                
                LogUtils.Info($"开始精确抽帧：输入={inputPath}, 输出={outputPath}, 总帧数={totalFrames}");
                LogUtils.Info($"删除帧1（前30%）：帧编号={frame1}, 时间≈{time1:F2}秒");
                LogUtils.Info($"删除帧2（中间30%）：帧编号={frame2}, 时间≈{time2:F2}秒");
                LogUtils.Info($"删除帧3（后30%）：帧编号={frame3}, 时间≈{time3:F2}秒");

                // 4. 只删除视频帧，音频直接复制，使用最快编码设置以达到1秒内完成
                // 注意：使用 select 过滤器删除帧时，视频需要重新编码，但使用最快设置
                LogUtils.Info("使用最快模式删除帧（仅处理视频，音频直接复制）...");
                
                var ffmpegArgs = FFMpegArguments
                    .FromFileInput(workingInputPath)
                    .OutputToFile(outputPath, true, options =>
                    {
                        // 使用 select 过滤器删除三帧（只删除视频帧）
                        options.WithCustomArgument($"-vf select='not(eq(n\\,{frame1})+eq(n\\,{frame2})+eq(n\\,{frame3}))'");
                        
                        // 视频编码：使用最快设置
                        options.WithVideoCodec("libx264");
                        options.WithCustomArgument("-preset ultrafast"); // 最快编码预设
                        options.WithCustomArgument("-tune zerolatency"); // 零延迟调优
                        options.WithConstantRateFactor(28); // 质量设置（28比23快）
                        options.WithCustomArgument("-g 30"); // 减少关键帧间隔
                        options.WithCustomArgument("-threads 0"); // 使用所有CPU核心
                        options.WithCustomArgument("-vsync cfr"); // 恒定帧率
                        
                        // 音频：直接复制，不重新编码（最快，不处理）
                        options.WithAudioCodec("copy"); // 直接复制音频流，零处理时间
                    });
                
                bool success = ffmpegArgs.ProcessSynchronously();

                // 验证输出文件是否存在且有效
                if (success && File.Exists(outputPath))
                {
                    FileInfo fileInfo = new FileInfo(outputPath);
                    if (fileInfo.Length > 0)
                    {
                        // 验证输出视频的帧数是否正确（应该比原视频少3帧）
                        try
                        {
                            var outputMediaInfo = await FFProbe.AnalyseAsync(outputPath);
                            var outputVideoStream = outputMediaInfo.PrimaryVideoStream;
                            if (outputVideoStream != null)
                            {
                                int expectedFrames = totalFrames - 3;
                                double outputDuration = outputMediaInfo.Duration.TotalSeconds;
                                int actualFrames = (int)(outputDuration * outputVideoStream.FrameRate);
                                
                                LogUtils.Info($"抽帧完成：输出文件={outputPath}, 大小={fileInfo.Length / 1024 / 1024:F2}MB, 时长={outputDuration:F2}秒, 帧数≈{actualFrames} (预期少3帧)");
                                
                                // 验证时长是否合理（应该略小于原视频）
                                if (outputDuration >= totalDuration)
                                {
                                    LogUtils.Warn($"警告：输出视频时长({outputDuration:F2}秒) >= 原视频时长({totalDuration:F2}秒)，可能未成功删除帧");
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            LogUtils.Warn($"验证输出视频信息时出错（不影响结果）：{ex.Message}");
                        }
                        
                        return true;
                    }
                    else
                    {
                        LogUtils.Error($"输出文件存在但大小为0：{outputPath}");
                        return false;
                    }
                }
                else
                {
                    LogUtils.Error($"抽帧失败：success={success}, 文件存在={File.Exists(outputPath)}, 输出路径={outputPath}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogUtils.Error("抽帧过程发生异常", ex);
                return false;
            }
            finally
            {
                // 清理临时目录
                try
                {
                    if (Directory.Exists(tempDir))
                    {
                        string[] files = Directory.GetFiles(tempDir);
                        foreach (string file in files)
                        {
                            try
                            {
                                File.Delete(file);
                            }
                            catch
                            {
                                // 忽略删除失败
                            }
                        }
                        try
                        {
                            Directory.Delete(tempDir);
                        }
                        catch
                        {
                            // 忽略删除失败
                        }
                    }
                }
                catch
                {
                    // 忽略清理错误
                }
            }
        }




        /// <summary>
        /// 通过修改视频元数据（添加注释）改变MD5
        /// </summary>
        public static bool ModifyByMetadata(string inputPath, string outputPath, string comment = "JSY")
        {
            // 添加或修改视频元数据中的注释信息
            return FFMpegArguments
                   .FromFileInput(inputPath)
                   .OutputToFile(outputPath, true, options => options
                       //.WithVideoCodec("copy")  // 直接复制视频流，不重新编码
                       //.WithAudioCodec("copy")  // 直接复制音频流
                       .CopyChannel()
                       .WithCustomArgument($"-metadata comment=\"{comment}_{Guid.NewGuid()}\"")  // 添加唯一注释
                   )
                   .ProcessSynchronously();
        }


        public static bool SubVideo(string inputPath, string outputPath, Double startSec, Double endSec)
        {
            try
            {
                // 计算时长
                double duration = endSec - startSec;
                if (duration <= 0)
                {
                    LogUtils.Error($"SubVideo失败：时长无效，开始={startSec}秒, 结束={endSec}秒");
                    return false;
                }

                LogUtils.Info($"SubVideo：输入={inputPath}, 输出={outputPath}, 开始={startSec}秒, 结束={endSec}秒, 时长={duration}秒");
                
                // 使用输入时的 -ss 参数（在输入参数中），这样可以更精确地定位，减少重新编码
                // 使用 -c copy 确保不重新编码
                bool result = FFMpegArguments
                    .FromFileInput(inputPath, true, options => options
                        .WithCustomArgument($"-ss {startSec:F3}"))  // 在输入时指定起始时间，更精确
                    .OutputToFile(outputPath, true, options => options
                        .WithCustomArgument($"-t {duration:F3}")  // 指定时长
                        .WithVideoCodec("copy")  // 明确指定复制视频流
                        .WithAudioCodec("copy"))  // 明确指定复制音频流
                    .ProcessSynchronously();
                
                // 验证输出文件是否存在
                if (result && File.Exists(outputPath))
                {
                    FileInfo fileInfo = new FileInfo(outputPath);
                    LogUtils.Info($"SubVideo成功：{outputPath}, 文件大小={fileInfo.Length / 1024 / 1024}MB");
                    return true;
                }
                else
                {
                    LogUtils.Error($"SubVideo失败：输入={inputPath}, 输出={outputPath}, 开始={startSec}秒, 结束={endSec}秒, 结果={result}, 文件存在={File.Exists(outputPath)}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogUtils.Error($"SubVideo异常：输入={inputPath}, 输出={outputPath}", ex);
                return false;
            }
        }


        public static bool SubAudio(string inputPath, string outputPath, Double startSec, Double endSec)
        {
            return FFMpegArguments
                .FromFileInput(inputPath, true, options => options.Seek(TimeSpan.FromSeconds(startSec)).EndSeek(TimeSpan.FromSeconds(endSec)))
                .OutputToFile(outputPath, true, options => options.CopyChannel())
                .ProcessSynchronously();
        }

        public static bool JoinVideo(string outPutPath, string[] videoParts)
        {
            try
            {
                // 验证所有输入文件是否存在
                foreach (var part in videoParts)
                {
                    if (!File.Exists(part))
                    {
                        LogUtils.Error($"JoinVideo失败：输入文件不存在 - {part}");
                        return false;
                    }
                }
                
                bool result = FFMpeg.Join(outPutPath, videoParts);
                
                // 验证输出文件是否存在
                if (result && File.Exists(outPutPath))
                {
                    LogUtils.Info($"JoinVideo成功：{outPutPath}");
                    return true;
                }
                else
                {
                    LogUtils.Error($"JoinVideo失败：输出文件不存在 - {outPutPath}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogUtils.Error($"JoinVideo异常：输出={outPutPath}", ex);
                return false;
            }
        }

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


        public static bool RemoveVideoFrame(string inputPath, string outputPath, int frameToRemove)
        {
            // 使用FFMpegArguments构建转换流程
            return FFMpegArguments
                 .FromFileInput(inputPath)
                 .OutputToFile(outputPath, true, options => options
                     // 使用select过滤器排除指定帧（帧序号从0开始）
                     .WithCustomArgument($"select=not(eq(n\\,{frameToRemove}))")

                // $"not(eq(n\\,{frameToRemove}))");   // 注意：在C#中需要转义反斜杠
                //// 保持其他编码参数
                .WithVideoCodec("libx264")
                .WithAudioCodec("copy") // 如果不需要处理音频，直接复制
                )
                .ProcessSynchronously();
        }

        /// <summary>
        /// 随机删除一个非关键帧
        /// </summary>
        /// <param name="inputPath">输入文件路径</param>
        /// <param name="outputPath">输出文件路径</param>
        /// <param name="index">当前处理的序号（用于确保每次删除位置不同）</param>
        /// <returns>操作是否成功</returns>
        public static async Task<bool> RemoveNonKeyFrameAsync(string inputPath, string outputPath, int index = 0)
        {
            if (!File.Exists(inputPath))
            {
                LogUtils.Error($"输入文件不存在：{inputPath}");
                return false;
            }

            string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            try
            {
                Directory.CreateDirectory(tempDir);

                // 1. 获取视频信息
                IMediaAnalysis mediaInfo = await FFProbe.AnalyseAsync(inputPath);
                var videoStream = mediaInfo.PrimaryVideoStream;
                if (videoStream == null)
                {
                    LogUtils.Error("没有找到视频流");
                    return false;
                }

                double totalDuration = mediaInfo.Duration.TotalSeconds;
                double frameRate = videoStream.FrameRate;

                // 确保视频时长足够（至少20秒）
                if (totalDuration < 20)
                {
                    LogUtils.Error($"视频时长太短（{totalDuration:F2}秒），无法抽帧（需要至少20秒）");
                    return false;
                }

                // 计算总帧数
                int totalFrames = (int)(totalDuration * frameRate);
                if (totalFrames <= 10)
                {
                    LogUtils.Error($"视频帧数太少（{totalFrames}帧），无法删除帧");
                    return false;
                }

                // 2. 找出非关键帧（避开前5帧和后5帧，以及关键帧）
                // 使用index确保每次删除的位置不同（基于输入路径和序号生成不同位置）
                // 关键帧通常是每30帧一个（取决于编码设置）
                
                // 避开前5%和后5%的帧，在这些范围内选择
                int startFrame = Math.Max(5, (int)(totalFrames * 0.05));
                int endFrame = Math.Min(totalFrames - 5, (int)(totalFrames * 0.95));
                int availableRange = endFrame - startFrame;
                
                // 使用输入路径的哈希值和index来确定删除位置，确保每次不同
                int hashSeed = inputPath.GetHashCode() + index * 997; // 997是质数，帮助分散
                var random = new Random(hashSeed);
                
                // 在可用范围内基于index均匀分布选择位置
                // 使用模运算确保index越大，位置也相应变化
                double ratio = (index % (availableRange / 3)) / (double)(availableRange / 3); // 使用1/3范围来分散
                int baseFrame = startFrame + (int)(ratio * availableRange);
                
                // 在baseFrame附近随机选择，但确保每次都不同
                int offsetRange = Math.Max(1, availableRange / 20); // 在baseFrame附近±5%范围内
                int offset = random.Next(-offsetRange, offsetRange);
                int selectedFrame = baseFrame + offset;
                
                // 确保在有效范围内
                selectedFrame = Math.Max(startFrame, Math.Min(endFrame, selectedFrame));
                
                // 确保不是关键帧位置（关键帧通常在0, 30, 60, 90...位置）
                while (selectedFrame % 30 == 0 && selectedFrame < endFrame - 1)
                {
                    selectedFrame++;
                }
                
                // 如果还是关键帧位置，尝试减1
                if (selectedFrame % 30 == 0 && selectedFrame > startFrame)
                {
                    selectedFrame--;
                }

                double frameDuration = 1.0 / frameRate; // 一帧的时长
                
                // 找到要删除帧所在GOP的起始关键帧位置
                // 关键帧通常每30帧一个（取决于编码设置）
                int gopSize = 30; // 默认GOP大小
                int gopStartFrame = (selectedFrame / gopSize) * gopSize; // 找到当前帧所在GOP的起始关键帧
                
                // 计算裁剪时间点
                // 策略：在关键帧边界处裁剪，确保可以完全使用copy模式
                // 第一部分：从开始到删除帧所在GOP的起始关键帧（包含关键帧）
                // 第二部分：从删除帧的下一帧开始到结束
                double frameTime = gopStartFrame * frameDuration; // 在第一部分保留关键帧
                double nextFrameTime = (selectedFrame + 1) * frameDuration; // 第二部分从删除帧的下一帧开始
                
                // 如果删除的帧就在或非常接近关键帧位置，调整策略
                if (selectedFrame <= gopStartFrame + 1)
                {
                    // 如果删除的帧太靠近关键帧，从下一个GOP开始
                    int nextGopStart = gopStartFrame + gopSize;
                    if (nextGopStart < totalFrames)
                    {
                        frameTime = gopStartFrame * frameDuration;
                        nextFrameTime = nextGopStart * frameDuration;
                    }
                    else
                    {
                        // 如果已经是最后一个GOP，调整到前一个GOP
                        int prevGopStart = Math.Max(0, gopStartFrame - gopSize);
                        frameTime = prevGopStart * frameDuration;
                        nextFrameTime = gopStartFrame * frameDuration;
                    }
                }
                
                // 确保时间有效
                frameTime = Math.Max(0, frameTime);
                nextFrameTime = Math.Min(totalDuration, nextFrameTime);
                
                // 确保第二部分时间大于第一部分
                if (nextFrameTime <= frameTime)
                {
                    nextFrameTime = frameTime + frameDuration;
                }
                
                LogUtils.Info($"开始删除非关键帧（在关键帧边界裁剪以保持copy模式）：输入={inputPath}, 输出={outputPath}, 总帧数={totalFrames}, 删除帧编号={selectedFrame}, GOP起始帧={gopStartFrame}, 分割时间={frameTime:F3}秒和{nextFrameTime:F3}秒");

                // 3. 使用时间分割方式直接删除帧，不重新编码
                // 将视频分为两部分：删除帧之前和之后，然后合并
                string videoPart1 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
                string videoPart2 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
                string mergedVideo = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
                
                // 分离音频（如有）
                string audioPath = Path.Combine(tempDir, $"{Guid.NewGuid()}.aac");
                bool hasAudio = mediaInfo.PrimaryAudioStream != null;
                
                if (hasAudio)
                {
                    bool audioExtracted = FFMpegArguments
                        .FromFileInput(inputPath)
                        .OutputToFile(audioPath, true, options => options
                            .WithCustomArgument("-vn -c:a copy"))
                        .ProcessSynchronously();
                    
                    if (!audioExtracted || !File.Exists(audioPath))
                    {
                        LogUtils.Warn("音频分离失败，继续仅处理视频");
                        hasAudio = false;
                    }
                }
                
                // 裁剪第一部分（从开始到删除帧之前）
                bool part1Success = false;
                if (frameTime > 0)
                {
                    part1Success = SubVideo(inputPath, videoPart1, 0, frameTime);
                    if (!part1Success || !File.Exists(videoPart1))
                    {
                        LogUtils.Error($"裁剪第一部分失败");
                        return false;
                    }
                }
                
                // 裁剪第二部分（从删除帧之后到结束）
                bool part2Success = SubVideo(inputPath, videoPart2, nextFrameTime, totalDuration);
                if (!part2Success || !File.Exists(videoPart2))
                {
                    LogUtils.Error($"裁剪第二部分失败");
                    return false;
                }
                
                // 合并两部分视频
                List<string> videoParts = [];
                if (frameTime > 0 && File.Exists(videoPart1))
                {
                    videoParts.Add(videoPart1);
                }
                if (File.Exists(videoPart2))
                {
                    videoParts.Add(videoPart2);
                }
                
                if (videoParts.Count == 0)
                {
                    LogUtils.Error("没有可合并的视频部分");
                    return false;
                }
                
                bool mergeSuccess = false;
                if (videoParts.Count == 1)
                {
                    // 如果只有一部分，直接复制
                    File.Copy(videoParts[0], mergedVideo, true);
                    mergeSuccess = File.Exists(mergedVideo);
                }
                else
                {
                    mergeSuccess = JoinVideo(mergedVideo, videoParts.ToArray());
                }
                
                if (!mergeSuccess || !File.Exists(mergedVideo))
                {
                    LogUtils.Error("合并视频失败");
                    return false;
                }
                
                // 如果有音频，合并音频和视频
                bool success = false;
                if (hasAudio && File.Exists(audioPath))
                {
                    // 使用明确的 copy 参数，确保不重新编码
                    success = await FFMpegArguments
                        .FromFileInput(mergedVideo)
                        .AddFileInput(audioPath)
                        .OutputToFile(outputPath, true, options => options
                            .WithVideoCodec("copy")  // 明确指定复制视频流
                            .WithAudioCodec("copy")  // 明确指定复制音频流
                            .WithCustomArgument("-shortest -y"))
                        .ProcessAsynchronously();
                }
                else
                {
                    // 没有音频，直接复制视频
                    File.Copy(mergedVideo, outputPath, true);
                    success = File.Exists(outputPath);
                }

                // 验证输出文件
                if (success && File.Exists(outputPath))
                {
                    FileInfo outputFileInfo = new FileInfo(outputPath);
                    FileInfo inputFileInfo = new FileInfo(inputPath);
                    
                    if (outputFileInfo.Length > 0)
                    {
                        try
                        {
                            var outputMediaInfo = await FFProbe.AnalyseAsync(outputPath);
                            double outputDuration = outputMediaInfo.Duration.TotalSeconds;
                            
                            long sizeDiff = outputFileInfo.Length - inputFileInfo.Length;
                            double sizeDiffMB = sizeDiff / 1024.0 / 1024.0;
                            string sizeChange = sizeDiff > 0 ? $"+{sizeDiffMB:F2}MB" : sizeDiff < 0 ? $"{sizeDiffMB:F2}MB" : "0MB";
                            
                            LogUtils.Info($"删除非关键帧完成：输出文件={outputPath}, 原始大小={inputFileInfo.Length / 1024.0 / 1024.0:F2}MB, 输出大小={outputFileInfo.Length / 1024.0 / 1024.0:F2}MB ({sizeChange}), 时长={outputDuration:F2}秒");
                            
                            if (sizeDiff > 0)
                            {
                                LogUtils.Warn($"注意：输出文件比原始文件大了 {sizeDiffMB:F2}MB，这可能是因为在非关键帧位置裁剪需要重新编码部分内容");
                            }
                        }
                        catch (Exception ex)
                        {
                            LogUtils.Warn($"验证输出视频信息时出错（不影响结果）：{ex.Message}");
                        }
                        
                        return true;
                    }
                    else
                    {
                        LogUtils.Error($"输出文件存在但大小为0：{outputPath}");
                        return false;
                    }
                }
                else
                {
                    LogUtils.Error($"删除非关键帧失败：success={success}, 文件存在={File.Exists(outputPath)}, 输出路径={outputPath}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogUtils.Error("删除非关键帧过程发生异常", ex);
                return false;
            }
            finally
            {
                // 清理临时目录
                try
                {
                    if (Directory.Exists(tempDir))
                    {
                        string[] files = Directory.GetFiles(tempDir);
                        foreach (string file in files)
                        {
                            try
                            {
                                File.Delete(file);
                            }
                            catch { }
                        }
                        try
                        {
                            Directory.Delete(tempDir);
                        }
                        catch { }
                    }
                }
                catch { }
            }
        }

        /// <summary>
        /// 在随机位置添加一个肉眼无法感知的小像素透明图
        /// </summary>
        /// <param name="inputPath">输入文件路径</param>
        /// <param name="outputPath">输出文件路径</param>
        /// <returns>操作是否成功</returns>
        public static async Task<bool> AddTransparentImageAsync(string inputPath, string outputPath)
        {
            if (!File.Exists(inputPath))
            {
                LogUtils.Error($"输入文件不存在：{inputPath}");
                return false;
            }

            string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            try
            {
                Directory.CreateDirectory(tempDir);

                // 1. 获取视频信息
                IMediaAnalysis mediaInfo = await FFProbe.AnalyseAsync(inputPath);
                var videoStream = mediaInfo.PrimaryVideoStream;
                if (videoStream == null)
                {
                    LogUtils.Error("没有找到视频流");
                    return false;
                }

                int videoWidth = videoStream.Width;
                int videoHeight = videoStream.Height;
                double totalDuration = mediaInfo.Duration.TotalSeconds;

                // 确保视频时长足够
                if (totalDuration < 1)
                {
                    LogUtils.Error($"视频时长太短（{totalDuration:F2}秒）");
                    return false;
                }

                // 2. 随机选择叠加位置（可以在视频的任意位置，1x1透明图肉眼无法感知）
                var random = new Random((int)(DateTime.Now.Ticks % int.MaxValue) + inputPath.GetHashCode());
                // 完全随机选择位置，覆盖整个视频区域（0到宽度-1，0到高度-1）
                int x = random.Next(0, videoWidth);
                int y = random.Next(0, videoHeight);

                // 3. 创建1x1透明PNG文件（使用FFmpeg命令行直接执行）
                string transparentImagePath = Path.Combine(tempDir, "transparent_1x1.png");
                
                // 使用FFmpeg命令行创建透明PNG（通过System.Diagnostics.Process）
                try
                {
                    // 查找ffmpeg.exe路径
                    string ffmpegPath = "";
                    
                    // 方法1: 尝试从当前程序目录查找
                    string currentDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? "";
                    ffmpegPath = Path.Combine(currentDir, "ffmpeg.exe");
                    
                    // 方法2: 如果在net8.0-windows目录下
                    if (!File.Exists(ffmpegPath))
                    {
                        string netDir = Path.Combine(currentDir, "net8.0-windows");
                        ffmpegPath = Path.Combine(netDir, "ffmpeg.exe");
                    }
                    
                    // 方法3: 从系统PATH查找
                    if (!File.Exists(ffmpegPath))
                    {
                        ffmpegPath = "ffmpeg.exe"; // 如果在PATH中
                    }
                    
                    if (!File.Exists(ffmpegPath) && ffmpegPath != "ffmpeg.exe")
                    {
                        LogUtils.Error($"无法找到ffmpeg.exe，已尝试路径：{Path.Combine(currentDir, "ffmpeg.exe")}");
                        return false;
                    }

                    var processInfo = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = ffmpegPath,
                        Arguments = $"-f lavfi -i \"color=c=0x00000000:s=1x1:d=0.04\" -frames:v 1 -pix_fmt rgba \"{transparentImagePath}\"",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    };

                    using (var process = System.Diagnostics.Process.Start(processInfo))
                    {
                        if (process == null)
                        {
                            LogUtils.Error("无法启动ffmpeg进程");
                            return false;
                        }

                        process.WaitForExit();

                        if (process.ExitCode != 0)
                        {
                            string error = await process.StandardError.ReadToEndAsync();
                            LogUtils.Error($"FFmpeg创建透明PNG失败，退出码：{process.ExitCode}，错误：{error}");
                            return false;
                        }
                    }

                    if (!File.Exists(transparentImagePath))
                    {
                        LogUtils.Error("透明PNG文件创建失败，文件不存在");
                        return false;
                    }

                    LogUtils.Info($"透明PNG文件已创建：{transparentImagePath}");
                }
                catch (Exception ex)
                {
                    LogUtils.Error($"创建透明PNG文件失败：{ex.Message}", ex);
                    return false;
                }

                LogUtils.Info($"开始添加透明图：输入={inputPath}, 输出={outputPath}, 视频尺寸={videoWidth}x{videoHeight}, 叠加位置=({x},{y})");

                // 4. 使用overlay过滤器在指定位置叠加透明图（在整个视频中持续存在）
                var ffmpegArgs = FFMpegArguments
                    .FromFileInput(inputPath)
                    .AddFileInput(transparentImagePath)
                    .OutputToFile(outputPath, true, options =>
                    {
                        // 使用overlay过滤器叠加透明图，在整个视频的所有帧中都存在
                        // 透明图会自动循环以适应视频长度
                        options.WithCustomArgument($"-filter_complex \"[0:v][1:v]overlay={x}:{y}:shortest=0[v]\"");
                        options.WithCustomArgument("-map \"[v]\"");
                        
                        // 视频编码：使用最快设置
                        options.WithVideoCodec("libx264");
                        options.WithCustomArgument("-preset ultrafast");
                        options.WithCustomArgument("-tune zerolatency");
                        options.WithConstantRateFactor(28);
                        options.WithCustomArgument("-g 30");
                        options.WithCustomArgument("-threads 0");
                        options.WithCustomArgument("-vsync cfr");
                        
                        // 音频：直接复制
                        options.WithCustomArgument("-map 0:a?");
                        options.WithAudioCodec("copy");
                    });

                bool success = ffmpegArgs.ProcessSynchronously();

                // 验证输出文件
                if (success && File.Exists(outputPath))
                {
                    FileInfo fileInfo = new FileInfo(outputPath);
                    if (fileInfo.Length > 0)
                    {
                        try
                        {
                            var outputMediaInfo = await FFProbe.AnalyseAsync(outputPath);
                            double outputDuration = outputMediaInfo.Duration.TotalSeconds;
                            LogUtils.Info($"添加透明图完成：输出文件={outputPath}, 大小={fileInfo.Length / 1024 / 1024:F2}MB, 时长={outputDuration:F2}秒");
                        }
                        catch (Exception ex)
                        {
                            LogUtils.Warn($"验证输出视频信息时出错（不影响结果）：{ex.Message}");
                        }
                        
                        return true;
                    }
                    else
                    {
                        LogUtils.Error($"输出文件存在但大小为0：{outputPath}");
                        return false;
                    }
                }
                else
                {
                    LogUtils.Error($"添加透明图失败：success={success}, 文件存在={File.Exists(outputPath)}, 输出路径={outputPath}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogUtils.Error("添加透明图过程发生异常", ex);
                return false;
            }
            finally
            {
                // 清理临时目录
                try
                {
                    if (Directory.Exists(tempDir))
                    {
                        string[] files = Directory.GetFiles(tempDir);
                        foreach (string file in files)
                        {
                            try
                            {
                                File.Delete(file);
                            }
                            catch { }
                        }
                        try
                        {
                            Directory.Delete(tempDir);
                        }
                        catch { }
                    }
                }
                catch { }
            }
        }
    }
}
