FFmpeg无重新编码剪切MOV/MP4视频时出现时长超出范围错误及异常行为
我完全理解你遇到的困扰——在Ubuntu 18.04用得顺手的无损失剪切命令,换到22.04后突然失效,还抛出奇怪的时长超出范围错误,生成的视频片段完全不符合预期。结合你提供的FFmpeg输出日志,我来帮你拆解问题并给出可行的解决方案:
问题根源
你遇到的核心问题是FFmpeg版本升级后,对带有时间码轨道(tmcd)的MOV文件处理逻辑更严格。从日志里能看到你的源视频包含第三个时间码流(Stream #0:2(eng): Data: none (tmcd)),当你使用-ss放在-i前面的快速seek模式(这种模式会先定位到指定时间再读取文件,速度快但依赖关键帧),直接复制流时会导致时间码轨道的元数据冲突,触发了日志里的Application provided duration: -9223372036854775808 / timestamp: -9223372036854775808 is out of range错误,最终导致输出视频的时长异常。
另外注意到你命令里的-t 00:07:00是指7分钟,但你实际需要的是7秒片段,这里应该写成-t 00:00:07,这也是导致结果不符合预期的一个小细节。
解决方案
以下几种方法可以解决这个问题,按推荐程度排序:
1. 调整-ss位置,使用精确seek模式
把-ss参数移到-i后面,让FFmpeg先完整读取源文件,再定位到指定时间点。这种方式速度稍慢,但能避免时间码轨道的元数据冲突,同时保证剪切的准确性:
ffmpeg -i DSCF5984.MOV -ss 00:00:06 -t 00:00:07 -c copy DSCF5984_A_wszystkie.MOV
2. 跳过时间码轨道,只复制音视频流
如果调整-ss位置后还是有问题,可以通过-map选项明确只复制视频和音频轨道,忽略导致冲突的时间码轨道:
ffmpeg -ss 00:00:06 -i DSCF5984.MOV -t 00:00:07 -c copy -map 0:v -map 0:a DSCF5984_A_wszystkie.MOV
3. 使用-to参数替代-t,更直观指定结束时间
如果你需要的是从第6秒到第13秒的片段,用-to直接指定结束时间会更不容易出错,避免时长计算错误:
ffmpeg -i DSCF5984.MOV -ss 00:00:06 -to 00:00:13 -c copy DSCF5984_A_wszystkie.MOV
4. 检查关键帧位置(进阶)
因为-c copy要求剪切起始点必须是关键帧(I帧),如果你的起始时间6秒不是关键帧位置,FFmpeg会自动跳到最近的关键帧,可能导致起始时间有偏差。你可以用以下命令查看视频的关键帧时间:
ffprobe -select_streams v -show_frames -show_entries frame=pkt_pts_time,pict_type DSCF5984.MOV | grep -E '(pict_type=I|pkt_pts_time)'
找到6秒附近的关键帧时间,调整-ss到该时间点即可获得精确的无损失剪切。
总结
Ubuntu 22.04的FFmpeg 4.4.2对MOV格式的元数据检查更严格,尤其是带有时间码轨道的文件,导致旧版本的快速seek命令失效。通过调整参数位置、忽略冲突轨道或使用更直观的-to参数,就能恢复无损失剪切的功能。
备注:内容来源于stack exchange,提问作者user2707175

