首页 文章

如何使用FFmpeg连接两个MP4文件?

提问于
浏览
211

我正在尝试使用ffmpeg连接两个mp4文件 . 我需要这是一个自动过程因此我选择ffmpeg . 我正在将这两个文件转换为.ts文件,然后将它们连接起来,然后尝试对该连接的.ts文件进行编码 . 文件是h264和aac编码,我希望保持质量相同或尽可能接近原始 .

ffmpeg -i part1.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part1.ts
ffmpeg -i part2.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part2.ts
cat part1.ts part2.ts > parts.ts
ffmpeg -y -i parts.ts -acodec copy -ar 44100 -ab 96k -coder ac -vbsf h264_mp4toannexb parts.mp4

不幸的是,我在编码期间收到来自ffmpeg的以下错误消息:

[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[NULL @ 0x101d600]error, non monotone timestamps 13779431 >= 13779431kbits/s    
av_interleaved_write_frame(): Error while opening file

这种情况发生在编码的一半左右,这让我觉得你不能将两个.ts文件连在一起并让它工作 .

15 回答

  • 42

    FFmpeg有三种串联方法 .

    1. concat视频过滤器

    ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv \
      -filter_complex "[0:v] [0:a] [1:v] [1:a] [2:v] [2:a] concat=n=3:v=1:a=1 [v] [a]" \
      -map "[v]" -map "[a]" output.mkv
    

    请注意,此方法执行重新编码 .

    2. concat demuxer

    $ cat mylist.txt
    file '/path/to/file1'
    file '/path/to/file2'
    file '/path/to/file3'
    
    $ ffmpeg -f concat -i mylist.txt -c copy output
    

    对于Windows:

    (echo file 'first file.mp4' & echo file 'second file.mp4' )>list.txt
    ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4
    

    3. concat协议

    ffmpeg -i "concat:input1|input2" -codec copy output
    

    由于这些格式的性质和此方法执行的简单连接,此方法不适用于许多格式,包括MP4 .

    使用哪一个

    • concat filter :如果您的输入没有相同的参数(宽度,高度等),或者格式/编解码器不相同,或者您想要执行任何过滤,请使用此选项 . (您可以仅重新编码不匹配的输入,以便它们共享相同的编解码器和其他参数,然后使用concat解复用器来避免重新编码其他输入) .

    • concat demuxer :当您想要避免重新编码时使用,并且您的格式不支持文件级别连接(一般用户使用的大多数文件不支持文件级别连接) .

    • concat protocol :与支持文件级联接的格式(MPEG-1,MPEG-2 PS,DV)一起使用 . 不要与MP4一起使用 .

    如果有疑问,请尝试使用concat demuxer .

    另见

  • 10

    这是一个快速(不到1分钟)和无损的方式来做到这一点,而不需要中间文件:

    ls Movie_Part_1.mp4 Movie_Part_2.mp4 | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4
    

    “ls”包含要连接的文件“perl”将连接文件即时创建到管道中“-i - ”部分告诉ffmpeg从管道读取

    (注意 - 我的文件中没有空格或奇怪的东西 - 如果你想用“硬”文件做这个想法,你需要适当的shell转义) .

  • 29

    for MP4文件:

    如果它们不完全相同(100%相同的编解码器,相同的分辨率,相同的类型)MP4文件,那么您必须首先将它们转码为中间流:

    ffmpeg -i myfile1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp1.ts
    ffmpeg -i myfile2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp2.ts
    // now join
    ffmpeg -i "concat:temp1.ts|temp2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
    

    NOTE! :输出将像第一个文件(而不是第二个文件)

  • 28

    我最终使用mpg作为中间格式并且它工作(注意这是一个危险的例子,-qscale 0将重新编码视频......)

    ffmpeg -i 1.mp4 -qscale 0 1.mpg
    ffmpeg -i 2.mp4 -qscale 0 2.mpg
    cat 1.mpg 2.mpg | ffmpeg -f mpeg -i - -qscale 0 -vcodec mpeg4 output.mp4
    
  • 0

    FOR MP4 FILES

    对于 .mp4 文件(我从DailyMotion.com获得:一个50分钟的电视剧集,只能分三部分下载,作为三个.mp4视频文件),以下是 Windows 7 的有效解决方案,并且 NOT 涉及重新编码文件 .

    我重命名了文件(如file1.mp4,file2.mp4,file3.mp4),以便部件按照正确的顺序查看完整的电视剧集 .

    然后我创建了一个简单的 batch file (concat.bat),其中包含以下内容:

    :: Create File List
    echo file file1.mp4 >  mylist.txt 
    echo file file2.mp4 >> mylist.txt
    echo file file3.mp4 >> mylist.txt
    
    :: Concatenate Files
    ffmpeg -f concat -i mylist.txt -c copy output.mp4
    

    必须将 batch fileffmpeg.exe 放在与要连接的 .mp4 files 相同的文件夹中 . 然后运行批处理文件 . 运行通常不到十秒钟 .
    .

    Addendum (2018/10/21) -

    如果您正在寻找的是一种方法,用于指定当前文件夹中的所有mp4文件而无需重新输入,请在Windows _686645中尝试此操作( MUST 包括选项 -safe 0 ):

    :: Create File List
    for %%i in (*.mp4) do echo file '%%i'>> mylist.txt
    
    :: Concatenate Files
    ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4
    

    这适用于Windows 7中的批处理文件 . Don't 尝试在命令行中使用它,因为它只能在批处理文件中使用!

  • 31

    我试图将三个 .mp3 音频文件连接成一个 .m4a 文件,这个ffmpeg命令可以工作 .

    输入命令:

    ffmpeg -i input1.mp3 -i input2.mp3 -i input3.mp3 -filter_complex concat=n=3:v=0:a=1 -f MOV -vn -y input.m4a
    

    含义: " -filter_complex concat=n=3:v=0:a=1"

    concat表示使用媒体连接(join)功能 . n表示确认输入文件的总数 . v意味着有视频吗?使用0 =没有视频,1 =包含视频 . 手段有音频吗?使用0 =无音频,1 =包含音频 . -f表示强制设置文件格式(查看所有支持的格式,使用ffmpeg -formats)-vn表示禁用视频(如果不需要,也会禁用音频)-y表示覆盖输出文件(如果输出文件已存在) .

    有关更多信息:使用 ffmpeg -h full 打印所有选项(包括所有格式和编解码器特定选项,非常长)

  • 443

    有关ffmpeg中各种串联方式的详细文档可以是found here .

    您可以使用'Concat filter'进行快速连接 .

    它执行重新编码 . 当输入具有不同的视频/音频格式时,此选项最佳 .

    For Concatenating 2 files:

    ffmpeg -i input1.mp4 -i input2.webm \
    -filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" \
    -map "[v]" -map "[a]" output.mp4
    

    For Concatenating 3 files:

    ffmpeg -i input1.mp4 -i input2.webm -i input3.mp4 \
    -filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] [2:v:0] [2:a:0] concat=n=3:v=1:a=1 [v] [a]" \
    -map "[v]" -map "[a]" output.mp4
    

    这适用于同一个以及多个输入文件类型 .

  • 2

    这是我用几个GoPro mp4连接到720p mp4的脚本 . 希望它有所帮助 .

    #!/bin/sh
    cmd="( "
    for i; do
        cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
    done
    cmd="${cmd} ) | ffmpeg -i - -vb 10000000 -ab 256000 -s 1280x720 -y out-`date +%F-%H%M.%S`.mp4"
    echo "${cmd}"
    eval ${cmd}
    
  • 2

    基于rogerdpack和Ed999的回复,我创建了我的.sh版本

    #!/bin/bash
    
    [ -e list.txt ] && rm list.txt
    for f in *.mp4
    do
       echo "file $f" >> list.txt
    done
    
    ffmpeg -f concat -i list.txt -c copy joined-out.mp4 && rm list.txt
    

    它将当前文件夹中的所有 *.mp4 文件加入 joined-out.mp4

    在Mac上测试 .

    结果文件大小是我的60个测试文件的精确总和 . 不应该有任何损失 . 正是我需要的

  • -1

    从这里的文档:https://trac.ffmpeg.org/wiki/Concatenate

    如果您有MP4文件,可以通过首先将它们转码为MPEG-2传输流来无损地连接这些文件 . 使用H.264视频和AAC音频,可以使用以下内容:

    ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
    ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
    ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
    

    这种方法适用于所有平台 .

    我需要能够在跨平台脚本中封装它,所以我使用了 fluent-ffmpeg 并提出了以下解决方案:

    const unlink = path =>
      new Promise((resolve, reject) =>
        fs.unlink(path, err => (err ? reject(err) : resolve()))
      )
    
    const createIntermediate = file =>
      new Promise((resolve, reject) => {
        const out = `${Math.random()
          .toString(13)
          .slice(2)}.ts`
    
        ffmpeg(file)
          .outputOptions('-c', 'copy', '-bsf:v', 'h264_mp4toannexb', '-f', 'mpegts')
          .output(out)
          .on('end', () => resolve(out))
          .on('error', reject)
          .run()
      })
    
    const concat = async (files, output) => {
      const names = await Promise.all(files.map(createIntermediate))
      const namesString = names.join('|')
    
      await new Promise((resolve, reject) =>
        ffmpeg(`concat:${namesString}`)
          .outputOptions('-c', 'copy', '-bsf:a', 'aac_adtstoasc')
          .output(output)
          .on('end', resolve)
          .on('error', reject)
          .run()
      )
    
      names.map(unlink)
    }
    
    concat(['file1.mp4', 'file2.mp4', 'file3.mp4'], 'output.mp4').then(() =>
      console.log('done!')
    )
    
  • 1

    我发现在使用选项3在接受的答案中在Mac上连接几个MP4时,管道操作员对我不起作用 .

    以下单行程序在Mac(High Sierra)上工作以连接mp4s,无需创建中间文件 .

    ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4

  • 0
    ffmpeg \
      -i input_1.mp4 \
      -i input_2.mp4 \
      -filter_complex '[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]' \
      -map [vid] \
      -c:v libx264 \
      -crf 23 \
      -preset veryfast \
      output.mp4
    
  • 0

    合并当前目录中的所有mp4文件

    我个人喜欢不创建我之后必须删除的外部文件,所以我的解决方案是包含文件编号列表(如 file_1_name, file_2_name, file_10_name, file_20_name, file_100_name ,...)

    #!/bin/bash
    filesList=""
    for file in $(ls -1v *.mp4);do #lists even numbered file
        filesList="${filesList}${file}|"
    done
    filesList=${filesList%?} # removes trailing pipe
    ffmpeg -i "concat:$filesList" -c copy $(date +%Y%m%d_%H%M%S)_merged.mp4
    
  • 1

    这对我有用(在Windows上)

    ffmpeg -i "concat:input1|input2" -codec copy output
    

    特别是

    ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4
    

    Python

    使用一些python代码用尽可能多的mp4来实现一个文件夹import glob import os

    stringa = ""
    for f in glob.glob("*.mp4"):
        stringa += f + "|"
    
    os.system("ffmpeg -i \"concat:" + stringa + "\" -codec copy output.mp4")
    
  • 29

    对于mp4文件,我发现使用opensource命令行工具“mp4box”会更好更快 . 然后你可以这样使用它:

    mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4

    在大多数平台上下载:https://gpac.wp.imt.fr/mp4box/

相关问题