如何使用ffmpeg不实际生成分片文件即可获取各视频分段时长
实现方法
可以不实际生成分片文件,直接获取和现有分片逻辑完全一致的各切片时长。
原理说明
你当前分片时长不是精确15秒是正常表现:流复制模式下ffmpeg只能在关键帧位置切分视频,你设置的GOP长度为9秒,-segment_time 15参数的实际逻辑是找到15秒节点之后最近的关键帧作为切分点,所以才会出现17秒、10秒这类非整数值的分片时长。
ffmpeg的segment分片器每次触发切分动作时,会在info级别的日志中输出每个分片的起始时间戳,不需要把分片真的写入磁盘:只要把分片输出指向系统空设备(写入的内容会被直接丢弃,不占用磁盘空间),提取日志里的分段时间点计算差值即可——相邻两个分片的起始时间差就是前一个分片的实际时长,最后一个分片的时长用源视频总时长减去最后一个分片的起始时间就能得到,计算结果和实际生成文件后用ffprobe读取的数值完全一致。
可直接执行的命令
Linux/macOS 系统
在视频所在目录执行以下命令即可,全程不会生成分片文件:
ffmpeg -i "ev.mp4" -c copy -map 0 -segment_time 15 -g 9 \ -sc_threshold 0 -force_key_frames "expr:gte(t,n_forced*9)" \ -reset_timestamps 1 -f segment -v info /dev/null 2>&1 | \ awk ' /^ Duration:/ { split($2, t, ":"); total = t[1]*3600 + t[2]*60 + t[3] } /Opening.*for writing/ { gsub(/'\''/, "", $4); seg_idx = count++; seg_start[seg_idx] = last_pts } /segment:/ { split($0, arr, "start:"); split(arr[2], t, ","); last_pts = t[1]+0 } END { seg_start[count] = total for(i=0; i<count; i++) { printf "ev-%04d.mp4 == %.6f\n", i, seg_start[i+1] - seg_start[i] } } '
命令输出格式和你原有COMMAND2的输出完全一致,示例如下:
ev-0000.mp4 == 17.251000 ev-0001.mp4 == 17.918000 ev-0002.mp4 == 10.444000
Windows 系统
如果安装了Git Bash,可以直接运行上述命令,把命令里的/dev/null替换为Windows系统空设备NUL即可;如果使用PowerShell,只需要先捕获ffmpeg输出的info级日志,按相同逻辑提取分段起始时间、计算相邻时间差就能得到结果。
注意事项
- 命令完全保留了你原有的所有分片参数,没有修改任何切分逻辑,结果和实际生成分片后的测量值100%匹配
- 全程使用流复制模式,没有重编码开销,执行速度和磁盘读取速度相当,远快于先写文件再逐个读取时长的方案
- 执行过程中不会在本地生成任何
ev-*.mp4分片文件,不占用额外磁盘空间
内容的提问来源于stack exchange,提问作者iChux
相关产品推荐
相关产品推荐

