使用Accord.Video.FFMPEG处理长视频时读取帧返回空值求助
问题分析与解决方案
你遇到的问题核心是Accord.Video.FFMPEG返回的FrameCount与视频实际可读取的帧数不匹配,长视频中这种帧计数偏差会被放大,导致循环后期ReadVideoFrame()已经读完所有帧返回null,但你的循环还在基于FrameCount继续执行,最终触发空引用问题。
解决思路
放弃依赖FrameCount控制循环,改为以ReadVideoFrame()的返回值是否为null作为终止条件,精准匹配实际可读帧数量;同时优化帧提取逻辑,避免冗余判断。
优化后的代码示例
using (var vReader = new VideoFileReader()) { vReader.Open(files[0]); TotalFrame = vReader.FrameCount; // 仅用于统计,不再控制循环 countin = Convert.ToInt32(TotalFrame / Convert.ToDouble(countAsset)); Fps = vReader.FrameRate.Value; int frameIndex = 0; int savedCount = 0; Bitmap currentFrame; Bitmap lastFrame = null; // 循环读取所有实际存在的帧,直到返回null while ((currentFrame = vReader.ReadVideoFrame()) != null) { frameIndex++; lastFrame = currentFrame; // 每10帧保存一次 if (frameIndex % 10 == 0) { savedCount++; currentFrame.Save($@"{dirVideo.FullName}\{savedCount}.jpeg", ImageFormat.Jpeg); // 保存后立即释放当前帧资源 currentFrame.Dispose(); lastFrame = null; } } // 确保最后一帧即使不是10的倍数也能保存(和原逻辑一致) if (lastFrame != null) { savedCount++; lastFrame.Save($@"{dirVideo.FullName}\{savedCount}.jpeg", ImageFormat.Jpeg); lastFrame.Dispose(); } }
关键改动说明
- 循环逻辑调整:用
while循环替代for循环,直接以ReadVideoFrame()的返回值判断是否还有帧可读,彻底避免FrameCount不准导致的多读问题。 - 资源管理优化:每保存完帧立即释放资源,避免长视频中内存占用过高;同时记录最后一帧,确保符合你原代码中强制保存末尾帧的需求。
- 代码简化:用字符串插值替代
string.Format,去掉冗余的分支判断,代码更简洁易维护。
额外注意事项
- 确保目标保存目录存在,可提前添加
Directory.CreateDirectory(dirVideo.FullName);避免保存失败。 - 尝试更新Accord.Video.FFMPEG到最新稳定版,旧版本对部分编码的长视频帧读取存在兼容性bug。
内容的提问来源于stack exchange,提问作者wahyu
相关产品推荐
相关产品推荐

