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

使用FFmpeg拼接MP4视频后输出时长超出预期的问题求助

FFmpeg拼接MP4视频时长超出预期问题

问题现象

将两段时长1.66秒的相同MP4视频(0.mp4)拼接,预期输出时长3.32秒,但实际输出时长为3.38秒。尝试以下方式均出现相同问题:

  • 使用FFmpeg concat demuxer命令:ffmpeg -f concat -i inputs.txt -c copy mergedVideo.mp4(inputs.txt包含两行file '0.mp4')
  • 指定帧率的FFmpeg命令
  • 使用MoviePy库执行合并代码

相关日志与检测信息

FFmpeg执行输出

ffmpeg  -f concat -i inputs.txt -c copy mergedVideo.mp4
ffmpeg version 5.0.1 Copyright (c) 2000-2022 the FFmpeg developers
  built with clang version 12.0.1
  configuration: --prefix=/Users/runner/miniforge3/conda-bld/ffmpeg_1649114094397/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pl --cc=arm64-apple-darwin20.0.0-clang --disable-doc --disable-openssl --enable-demuxer=dash --enable-gnutls --enable-gpl --enable-hardcoded-tables --enable-libfreetype --enable-libopenh264 --enable-neon --enable-libx264 --enable-libx265 --enable-libaom --enable-libsvtav1 --enable-libxml2 --enable-libvpx --enable-pic --enable-pthreads --enable-shared --disable-static --enable-version3 --enable-zlib --enable-libmp3lame --pkg-config=/Users/runner/miniforge3/conda-bld/ffmpeg_1649114094397/_build_env/bin/pkg-config --enable-cross-compile --arch=arm64 --target-os=darwin --cross-prefix=arm64-apple-darwin20.0.0- --host-cc=/Users/runner/miniforge3/conda-bld/ffmpeg_1649114094397/_build_env/bin/x86_64-apple-darwin13.4.0-clang
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1561044a0] Auto-inserting h264_mp4toannexb bitstream filter
Input #0, concat, from 'inputs.txt':
  Duration: N/A, start: -0.064000, bitrate: 1424 kb/s
  Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 1355 kb/s, 50 fps, 50 tbr, 12800 tbn
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 16000 Hz, mono, fltp, 68 kb/s
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
File 'mergedVideo.mp4' already exists. Overwrite? [y/N] y
Output #0, mp4, to 'mergedVideo.mp4':
  Metadata:
    encoder         : Lavf59.16.100
  Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 1355 kb/s, 50 fps, 50 tbr, 12800 tbn
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 16000 Hz, mono, fltp, 68 kb/s
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame=    0 fps=0.0 q=-1.0 size=       0kB time=00:00:00.06 bitrate=   6.0k[mov,mp4,m4a,3gp,3g2,mj2 @ 0x154f28b20] Auto-inserting h264_mp4toannexb bitstream filter
frame=  166 fps=0.0 q=-1.0 Lsize=     583kB time=00:00:03.39 bitrate=1407.4kbits/s speed= 179x    
video:550kB audio:29kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.737394%

ffprobe检测输出视频结果

ffprobe -v error -select_streams v -show_entries stream=codec_name,time_base,start_pts,start_time,duration -of default=noprint_wrappers=1 mergedVideo.mp4 
codec_name=h264
time_base=1/12800
start_pts=0
start_time=0.000000
duration=3.380000

ffprobe检测输入视频结果

ffprobe -v error -select_streams v -show_entries stream=codec_name,time_base,start_pts,start_time,duration -of default=noprint_wrappers=1 0.mp4          
codec_name=h264
time_base=1/12800
start_pts=0
start_time=0.000000
duration=1.660000

MoviePy合并代码

from moviepy.editor import VideoFileClip, concatenate_videoclips
videos = [VideoFileClip("0.mp4"), VideoFileClip("0.mp4")]
concatenate_videoclips(videos).write_videofile('mergedVideo.mp4')

原因分析

  1. MP4编辑列表或时间戳偏移:FFmpeg日志显示输入流start: -0.064000,说明原视频可能包含隐藏的编辑列表,或帧时间戳存在偏移。即使ffprobe显示start_time=0,实际播放的时间戳基准仍有偏差,-c copy模式下会保留该偏移,拼接后累积导致时长超出预期。
  2. 帧时长对齐问题:原视频为50fps(每帧理论时长0.02秒),单段1.66秒对应83帧,但实际视频的帧时间戳未严格按标准间隔递增,最后一帧时长被延长。两段视频的非标准帧时长叠加,造成总时长偏差。
  3. Copy模式局限:-c copy仅复制流数据,不重新生成时间戳或修正容器元数据,原视频的时间戳问题会直接传递到输出视频。MoviePy底层依赖FFmpeg,因此也出现相同问题。

解决方法

方法1:重新编码修正时间戳

放弃-c copy,让FFmpeg重新编码视频与音频,生成标准时间戳:

ffmpeg -f concat -i inputs.txt -c:v libx264 -c:a aac mergedVideo.mp4

此方法确保时间戳严格对齐,输出时长符合预期,但耗时较长。

方法2:修复原视频时间戳后拼接

先处理原视频,去除编辑列表并修正时间戳,再进行拼接:

  1. 修复原视频:
ffmpeg -i 0.mp4 -c copy -movflags +faststart -ignore_editlist 1 fixed_0.mp4
  1. 更新inputs.txt内容为两行file 'fixed_0.mp4',再执行拼接:
ffmpeg -f concat -i inputs.txt -c copy mergedVideo.mp4

方法3:使用concat滤镜替代demuxer

concat滤镜能精确控制时间戳与流拼接,无需依赖输入文件元数据:

ffmpeg -i 0.mp4 -i 0.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" mergedVideo.mp4

此方法自动处理时间戳对齐,输出时长准确。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:50:32