如何用FFmpeg裁剪音视频片段且保留另一轨道完整?
FFmpeg 保留原时长的多片段裁剪方案
你的现有脚本是将两段视频/音频拼接,输出时长是两段的总和(10秒),但需求是保持原文件的完整时长,不需要的片段用冻结帧/黑屏+静音填充。下面是两种实现方案:
方案一:分段拼接(直观易理解)
这种方法把原时长拆分为「保留段」和「填充段」,分别处理后拼接,总时长与原文件一致。
步骤说明
- 视频处理:将原视频拆分为多个片段,不需要的部分替换为冻结帧(或黑屏)
- 音频处理:将原音频拆分为多个片段,不需要的部分替换为静音
- 分别拼接视频和音频片段,最后合并输出
完整命令(需先获取原文件时长)
先通过ffprobe获取原视频时长(存为变量DURATION):
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 bdt.mkv)
然后执行FFmpeg命令:
ffmpeg -i bdt.mkv -filter_complex " # 视频处理:拆分并替换不需要的片段为冻结帧 [0:v]trim=start=0:end=10,setpts=PTS-STARTPTS[v0]; [0:v]trim=start=10:end=15,setpts=PTS-STARTPTS[v1]; [0:v]trim=start=15:end=15.1,setpts=PTS-STARTPTS,loop=loop=-1:size=1[v2]; # 冻结15秒处的帧作为填充 [0:v]trim=start=65:end=70,setpts=PTS-STARTPTS[v3]; [0:v]trim=start=70:end=$DURATION,setpts=PTS-STARTPTS,loop=loop=-1:size=1[v4]; [v0][v1][v2][v3][v4]concat=n=5:v=1:a=0[outv]; # 音频处理:拆分并替换不需要的片段为静音 aevalsrc=0:d=10[a0]; # 0-10秒静音 [0:a]atrim=start=10:end=15,asetpts=PTS-STARTPTS[a1]; aevalsrc=0:d=50[a2]; # 15-65秒静音(时长65-15=50) [0:a]atrim=start=65:end=70,asetpts=PTS-STARTPTS[a3]; aevalsrc=0:d=$(echo "$DURATION - 70" | bc)[a4]; # 70到结束的静音 [a0][a1][a2][a3][a4]concat=n=5:v=0:a=1[outa] " -map [outv] -map [outa] out.mp4
方案二:基础流覆盖(简洁高效)
这种方法先创建与原时长一致的黑屏/静音基础流,再将需要保留的片段覆盖到对应时间段,无需拆分多个片段。
完整命令
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 bdt.mkv) VIDEO_SIZE=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 bdt.mkv) ffmpeg -i bdt.mkv -filter_complex " # 视频:创建黑屏基础流,覆盖需要保留的片段 color=c=black:s=$VIDEO_SIZE:d=$DURATION[basev]; [0:v]trim=start=10:end=15,setpts=PTS-STARTPTS+10/TB[v1]; # 调整时间戳回到原位置 [basev][v1]overlay=enable='between(t,10,15)'[tmpv]; [0:v]trim=start=65:end=70,setpts=PTS-STARTPTS+65/TB[v2]; [tmpv][v2]overlay=enable='between(t,65,70)'[outv]; # 音频:创建静音基础流,混合需要保留的片段 aevalsrc=0:d=$DURATION[basea]; [0:a]atrim=start=10:end=15,asetpts=PTS-STARTPTS+10/TB[a1]; [basea][a1]amix=inputs=2:duration=longest[tmpa]; [0:a]atrim=start=65:end=70,asetpts=PTS-STARTPTS+65/TB[a2]; [tmpa][a2]amix=inputs=2:duration=longest[outa] " -map [outv] -map [outa] out.mp4
关键参数说明
setpts=PTS-STARTPTS+X/TB:将截取的片段时间戳偏移X秒,使其回到原文件中的位置overlay=enable='between(t,X,Y)':仅在X到Y秒时间段内覆盖视频片段amix=inputs=2:duration=longest:将保留的音频片段混合到静音基础流上loop=loop=-1:size=1:单帧循环生成冻结画面,比黑屏更贴合原视频风格
适配Python变量的建议
在Python中,你可以先通过subprocess调用ffprobe获取时长和分辨率,再将时间戳变量(如start1=10、end1=15等)代入FFmpeg命令字符串,动态生成完整执行命令。
内容的提问来源于stack exchange,提问作者limejellodragon
相关产品推荐
相关产品推荐

