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

如何用FFmpeg实现过场单屏、其余分屏的混合视频输出?

FFmpeg分屏与过场动画切换的优化实现

需求说明

现有视频素材需处理为:

  • 00:00-01:15、10:00-10:30、29:00至结尾:显示单源单屏的过场动画(各时段内容一致)
  • 其余时段:显示四屏分屏画面(各屏内容不同,带玩家名称字幕)

现有脚本(全程生成分屏)

ffmpeg -i "$player_one.$player_one_extension" \
    -i "$player_two.$player_two_extension" \
    -i "$player_three.$player_three_extension" \
    -i "$player_four.$player_four_extension" \
    -filter_complex \
        "nullsrc=size=${video_width}x${video_height} [base]; \
        [0:v] trim=start=$player_one_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_one_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [upperleft]; \
        [1:v] trim=start=$player_two_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_two_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [upperright]; \
        [2:v] trim=start=$player_three_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_three_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [lowerleft]; \
        [3:v] trim=start=$player_four_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_four_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [lowerright]; \
        [3:a] atrim=start=$audio_offset,asetpts=PTS-STARTPTS[outa]; [base][upperleft] overlay=shortest=1 [tmp1]; [tmp1][upperright] overlay=shortest=1:x=${half_width} [tmp2]; [tmp2][lowerleft] overlay=shortest=1:y=${half_height} [tmp3]; [tmp3][lowerright] overlay=shortest=1:x=${half_width}:y=${half_height}[v]"
    -map "[v]" -map "[outa]" -c:v libx264 -shortest -t $duration "100_100_hardcore_ghost_recon_future_soldier_coop_pc_${mission}4k.mp4"

问题

当前脚本全程生成分屏画面,我想到的方案是分段制作各时段视频后用concat合并,但这样会生成多个中间文件。请问有没有更高效的单命令实现方式?


最优实现方案:单命令搞定,无中间文件

当然有更高效的方式——不用分段生成视频再合并,直接在单个FFmpeg命令的滤镜链里完成所有时段的裁剪、画面处理和拼接,全程无中间文件,步骤更简洁:

核心思路

  1. 复用原有逻辑生成完整的分屏画面流
  2. 从分屏流里裁剪出需要显示分屏的时段(01:15-10:00、10:30-29:00)
  3. 处理过场动画流,裁剪出需要显示单屏的时段(00:00-01:15、10:00-10:30、29:00至结尾)
  4. 把所有处理好的视频段按时间顺序用concat滤镜拼接
  5. 同步处理音频的分段裁剪与拼接,保证音画同步

完整脚本示例

假设过场动画单独存为opening.mp4,如果过场是某个玩家视频的片段,直接替换成对应输入流即可:

ffmpeg -i "$player_one.$player_one_extension" \
    -i "$player_two.$player_two_extension" \
    -i "$player_three.$player_three_extension" \
    -i "$player_four.$player_four_extension" \
    -i "opening.mp4" \
    -filter_complex \
        # 1. 生成完整分屏画面(复用原有分屏逻辑)
        "nullsrc=size=${video_width}x${video_height} [base]; \
        [0:v] trim=start=$player_one_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_one_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [ul]; \
        [1:v] trim=start=$player_two_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_two_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [ur]; \
        [2:v] trim=start=$player_three_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_three_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [ll]; \
        [3:v] trim=start=$player_four_offset,setpts=PTS-STARTPTS, scale=${half_width}x${half_height}, drawtext=fontfile=control-freak-font/CONTF___.ttf:text='${player_four_name}':fontsize=$font_size:fontcolor=0xFFFFFF:alpha='$alpha':x=w-text_w-${font_padding}:y=h-text_h-${font_padding} [lr]; \
        [base][ul] overlay=shortest=1 [t1]; [t1][ur] overlay=shortest=1:x=${half_width} [t2]; [t2][ll] overlay=shortest=1:y=${half_height} [t3]; [t3][lr] overlay=shortest=1:x=${half_width}:y=${half_height} [full_split]; \
        # 2. 裁剪分屏需要显示的时段(转成秒计算)
        [full_split] trim=start=75:end=600,setpts=PTS-STARTPTS [split_seg1]; \
        [full_split] trim=start=630:end=1740,setpts=PTS-STARTPTS [split_seg2]; \
        # 3. 处理过场动画,裁剪对应时段
        [4:v] scale=${video_width}x${video_height},setpts=PTS-STARTPTS [opening_full]; \
        [opening_full] trim=end=75,setpts=PTS-STARTPTS [opening_seg1]; \
        [opening_full] trim=start=0:end=30,setpts=PTS-STARTPTS [opening_seg2]; \
        [opening_full] trim=start=0,setpts=PTS-STARTPTS [opening_seg3]; \
        # 4. 按顺序拼接所有视频段
        [opening_seg1][split_seg1][opening_seg2][split_seg2][opening_seg3] concat=n=5:v=1:a=0 [v_out]; \
        # 5. 同步处理音频(以player4的音频为例,按对应时段裁剪拼接)
        [3:a] atrim=start=$audio_offset:end=$((audio_offset+75)),asetpts=PTS-STARTPTS [a_seg1]; \
        [3:a] atrim=start=$((audio_offset+75)):end=$((audio_offset+600)),asetpts=PTS-STARTPTS [a_seg2]; \
        [3:a] atrim=start=$((audio_offset+600)):end=$((audio_offset+630)),asetpts=PTS-STARTPTS [a_seg3]; \
        [3:a] atrim=start=$((audio_offset+630)):end=$((audio_offset+1740)),asetpts=PTS-STARTPTS [a_seg4]; \
        [3:a] atrim=start=$((audio_offset+1740)),asetpts=PTS-STARTPTS [a_seg5]; \
        [a_seg1][a_seg2][a_seg3][a_seg4][a_seg5] concat=n=5:v=0:a=1 [a_out]" \
    -map "[v_out]" -map "[a_out]" -c:v libx264 -c:a aac "100_100_hardcore_ghost_recon_future_soldier_coop_pc_${mission}4k.mp4"

注意事项

  • 所有时间统一用秒计算,避免时:分:秒格式的解析问题(比如01:15=75秒,10:00=600秒)
  • 如果过场动画是从某个玩家的视频里截取的(比如player1的开头片段),把[4:v]换成[0:v] trim=start=xxx:end=xxx即可,不用额外导入过场文件
  • 音频要严格对应视频的时段长度,否则会出现音画不同步的问题
  • 若分屏流的时长不够,可去掉shortest=1参数,或者确保所有输入视频的时长满足需求

内容的提问来源于stack exchange,提问作者PirateApp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:10:07