You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用FFmpeg基于SMPTE时码同步多机位视频帧并输出匹配片段

如何使用FFmpeg基于SMPTE时码同步多机位视频帧并输出匹配片段

嘿,你已经搞定了最关键的第一步——成功提取出两个视频的SMPTE时码!接下来我们只需要把这些时码转换成FFmpeg能理解的时间偏移,算出两个视频的重合时间段,最后裁剪出完全匹配的片段就行。下面是完整的解决方案:

核心思路

  1. 将提取到的SMPTE时码(比如00:00:53;30)转换为总秒数,方便计算时间差
  2. 获取每个视频的总时长,推算出各自的结束时码对应的秒数
  3. 找出两个视频时间线重合的区间(即较晚的起始时间到较早的结束时间)
  4. 用FFmpeg分别裁剪两个视频,只保留重合区间内的内容

完整bash脚本

我把所有步骤整合到了一个脚本里,你可以直接替换自己的文件名使用:

#!/bin/bash

# 替换成你的两个视频文件路径
file1="A001C002_220101EB_CANON.MXF"
file2="A001C002_220101US_CANON.MXF"

# --------------------------
# 1. 提取SMPTE时码
# --------------------------
timecode1=$(ffmpeg -i "$file1" -hide_banner -f ffmetadata - 2>/dev/null | awk -F'=' '/timecode/{print $2}')
timecode2=$(ffmpeg -i "$file2" -hide_banner -f ffmetadata - 2>/dev/null | awk -F'=' '/timecode/{print $2}')

echo "视频1起始时码: $timecode1"
echo "视频2起始时码: $timecode2"

# --------------------------
# 2. 定义SMPTE时码转总秒数的函数
# 区分Drop-Frame(分号分隔)和Non-Drop-Frame(冒号分隔)
# --------------------------
tc_to_seconds() {
    local tc="$1"
    local hours minutes seconds frames
    local frame_rate=29.97  # 根据你的视频帧率修改,佳能常用29.97或25

    # 处理Drop-Frame时码(分号)
    if [[ "$tc" == *";"* ]]; then
        IFS=':;' read -r hours minutes seconds frames <<< "$tc"
        # Drop-Frame时码的转换公式:总帧数 = (hours*3600 + minutes*60 + seconds)*frame_rate + frames - 2*minutes + 2*(minutes//10)
        local total_frames=$(( (hours*3600 + minutes*60 + seconds)*frame_rate + frames - 2*minutes + 2*(minutes/10) ))
        echo "scale=6; $total_frames / $frame_rate" | bc
    else
        # Non-Drop-Frame时码(冒号)
        IFS=':' read -r hours minutes seconds frames <<< "$tc"
        echo "scale=6; ($hours*3600 + $minutes*60 + $seconds) + $frames/$frame_rate" | bc
    fi
}

# --------------------------
# 3. 获取每个视频的总时长(秒)
# --------------------------
duration1=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file1")
duration2=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file2")

echo "视频1总时长: $duration1 秒"
echo "视频2总时长: $duration2 秒"

# --------------------------
# 4. 计算每个视频的起始/结束时间(秒)
# --------------------------
start1=$(tc_to_seconds "$timecode1")
start2=$(tc_to_seconds "$timecode2")

end1=$(echo "scale=6; $start1 + $duration1" | bc)
end2=$(echo "scale=6; $start2 + $duration2" | bc)

# --------------------------
# 5. 计算重合时间区间
# --------------------------
# 重合起始点:取两个起始时间的最大值
overlap_start=$(echo "if($start1 > $start2) $start1 else $start2" | bc)
# 重合结束点:取两个结束时间的最小值
overlap_end=$(echo "if($end1 < $end2) $end1 else $end2" | bc)

# 检查是否有重合区间
if (( $(echo "$overlap_start >= $overlap_end" | bc -l) )); then
    echo "错误:两个视频没有时间重合的部分!"
    exit 1
fi

echo "重合区间: $overlap_start 秒 到 $overlap_end 秒"

# --------------------------
# 6. 计算每个视频需要裁剪的起始点和时长
# --------------------------
trim_start1=$(echo "scale=6; $overlap_start - $start1" | bc)
trim_duration1=$(echo "scale=6; $overlap_end - $overlap_start" | bc)

trim_start2=$(echo "scale=6; $overlap_start - $start2" | bc)
trim_duration2=$(echo "scale=6; $overlap_end - $overlap_start" | bc)

# --------------------------
# 7. 用FFmpeg裁剪视频
# --------------------------
echo "开始裁剪视频1..."
ffmpeg -i "$file1" -ss "$trim_start1" -t "$trim_duration1" -c:v copy -c:a copy "synced_$file1" -y

echo "开始裁剪视频2..."
ffmpeg -i "$file2" -ss "$trim_start2" -t "$trim_duration2" -c:v copy -c:a copy "synced_$file2" -y

echo "同步裁剪完成!输出文件为 synced_$file1 和 synced_$file2"

关键注意事项

  • 帧率修改:脚本里默认帧率是29.97(佳能常用的Drop-Frame时码帧率),如果你的视频是25fps或其他帧率,记得修改tc_to_seconds函数里的frame_rate变量。
  • 无损裁剪:脚本里用了-c:v copy -c:a copy参数,这是直接复制音视频流,不会重新编码,速度很快且无质量损失。如果你的视频需要重新编码(比如裁剪点不在关键帧上),可以去掉这两个参数,FFmpeg会自动重新编码。
  • 时码格式:如果你的时码是Non-Drop-Frame(用冒号分隔帧,比如00:00:53:30),脚本也能自动识别处理。

备注:内容来源于stack exchange,提问作者user9114146

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 13:59:09