FFmpeg如何按原视频时间轴精准设置剪切起止点
这个偏差是FFmpeg参数作用域规则导致的:当-ss作为输入选项放在-i之前时,FFmpeg会直接跳转到指定偏移位置开始读取文件,此时后续输出侧的时间类参数(包括-to)的时间零点会被重置为该跳转位置,而非原视频的起始时间点,传入的原视频绝对结束时间会被误判为相对于剪切起点的时长。
可用解决方法
方法1:零计算全局时间剪切(批量场景优先推荐)
直接把-ss(起始时间)和-to(结束时间)都作为输出选项,放在-i(输入文件)参数之后,此时两个时间参数默认以原视频00:00:00为绝对基准,完全不需要手动计算时间差,剪切精度为帧级准确。
对应复现场景的修正命令:ffmpeg -an -i "2022-05-30.mp4" -ss 00:14:15 -to 01:30:40 -crf 23 -c:v libx264 PART1.mp4该写法的唯一缺点是如果剪切起始点距离视频开头很远,FFmpeg会从头解码到起始位置,速度比输入侧seek稍慢,但对于绝大多数日常剪辑场景,这点性能差异完全可以被「不用算时间、不会出错」的优势覆盖。
方法2:长视频快速seek全局时间剪切
如果需要剪切数小时级的长视频、追求更快的seek速度,且使用的是4.4及以上版本的FFmpeg,可以在输入侧添加-seek_timestamp 1参数,此时即使把-ss放在-i前面做快速seek,后续的-to参数依然会以原视频全局时间轴为基准,不需要计算偏移。
示例命令:ffmpeg -seek_timestamp 1 -ss 00:14:15 -an -i "2022-05-30.mp4" -to 01:30:40 -crf 23 -c:v libx264 PART1.mp4方法3:老版本FFmpeg兼容方案
如果使用的是4.4以下的老版本FFmpeg,又想保留输入侧快速seek的速度,可以写简单脚本自动计算起止时间的差值,把计算出的时长传给-t参数即可,不需要每次手动算减法。以bash脚本为例:#!/bin/bash # 用法:./cut.sh 起始时间 结束时间 输入文件路径 输出文件路径 START=$1 END=$2 INPUT=$3 OUTPUT=$4 # 自动把时分秒格式转成秒数计算时长 start_sec=$(echo $START | awk -F: '{print $1*3600 + $2*60 + $3}') end_sec=$(echo $END | awk -F: '{print $1*3600 + $2*60 + $3}') duration=$((end_sec - start_sec)) # 调用ffmpeg执行剪切 ffmpeg -ss $START -an -i "$INPUT" -t $duration -crf 23 -c:v libx264 "$OUTPUT"使用时直接传入原视频的绝对起止时间即可,脚本自动完成时间计算,批量处理时直接循环调用就行。
注意:FFmpeg所有参数都严格区分输入/输出作用域:放在
-i前面的参数只对紧邻的输入文件生效,放在-i后面、输出文件路径前面的参数只对对应的输出生效,时间类参数的基准会随输入侧的seek操作重置,记住这个规则就能避开绝大多数FFmpeg剪切的时间偏差问题。
内容的提问来源于stack exchange,提问作者Wayne Julian

