保存视频帧时出现非单调递增DTS复用器报错问题咨询
我帮你拆解这个问题——你遇到的这个错误本质是FFmpeg(Accord.Video底层依赖的库)的视频复用器要求时间戳必须严格单调递增,而你的帧出现了重复的DTS(解码时间戳)值(控制台提示的512 >= 512就是明证),哪怕是相等的DTS也不符合复用器的要求。
先明确报错的核心原因
FFmpeg的复用器对输入帧的时间戳有硬性规则:每一个后续帧的DTS必须严格大于前一帧的DTS,不允许相等,更不允许倒退。你的情况就是某帧的DTS和上一帧完全一样,触发了这个校验逻辑,抛出了Error -22: Invalid argument。
可能的触发场景&对应的解决方案
1. 缓冲区帧的时间戳本身重复
如果你的缓冲区里存在同一时间戳的重复帧,或者时间戳没有按预期递增,就会出问题。解决办法是维护一个记录上一帧DTS的变量,强制保证当前帧DTS严格大于上一帧:
// 初始化时记录上一帧的DTS,设为一个极小值 long lastFrameDts = -1; // 假设你遍历缓冲区帧的逻辑 foreach (var bufferedFrame in yourFrameBuffer) { long currentDts = bufferedFrame.TimeStamp; // 检查当前DTS是否不符合严格递增要求 if (currentDts <= lastFrameDts) { // 根据帧率计算合理的递增步长(单位:微秒,Accord.Video要求的时间戳单位) int frameRate = (int)yourVideoWriter.FrameRate; long step = 1000000 / frameRate; // 强制设置为上一帧DTS + 步长 currentDts = lastFrameDts + step; } // 写入调整后的帧 yourVideoWriter.WriteVideoFrame(bufferedFrame.Bitmap, currentDts); // 更新上一帧DTS记录 lastFrameDts = currentDts; }
2. 时间戳单位搞错了
Accord.Video的WriteVideoFrame方法要求时间戳的单位是微秒,如果你传入的是毫秒、帧序号或者其他单位,就会导致时间戳增长过慢甚至重复。比如你原本的时间戳是毫秒,需要乘以1000转成微秒:
// 假设原时间戳是毫秒,转换为微秒 long correctDts = bufferedFrame.TimeStampInMs * 1000;
3. 帧率设置与时间戳步长不匹配
如果初始化VideoWriter时设置的帧率,和你实际帧的时间戳递增步长不匹配,也容易出现DTS重复的问题。比如帧率设为30fps,那么每帧的DTS应该比前一帧大约33333微秒(1000000 / 30),确保这个步长和你的时间戳增长逻辑一致。
4. 缓冲区存在重复帧
检查你的缓冲区是否意外存入了同一帧(比如重复读取了同一个缓冲区位置),如果是,需要先对缓冲区的帧按时间戳去重,再进行写入操作。
总结
这个问题的核心就是满足FFmpeg复用器的严格单调递增DTS要求,只要保证每一个后续帧的DTS都比前一帧大,就能解决这个错误。
内容的提问来源于stack exchange,提问作者Eduardo Preto

