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

如何使用FFmpeg连接两个MP4文件?,ffmpeg,h.264,mp4,Ffmpeg,H.264,Mp4,我正在尝试使用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_m

我正在尝试使用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文件合并在一起并使其工作。

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


下面是我制作的一个脚本,将几个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}

FFmpeg有三种连接方法:

1. 如果您的输入没有相同的参数(宽度、高度等),或者格式/编解码器不相同,或者您想要执行任何过滤,请使用此方法

请注意,此方法对所有输入执行重新编码。如果要避免重新编码,可以只对不匹配的输入进行重新编码,以便它们共享相同的编解码器和其他参数,然后使用concat demuxer避免对所有内容进行重新编码

ffmpeg-i opening.mkv-i eposion.mkv-i ending.mkv\
-过滤组合“[0:v][0:a][1:v][1:a][2:v][2:a]\
concat=n=3:v=1:a=1[v][a]。”\
-映射“[v]”-map“[a]”output.mkv
2. 如果要避免重新编码,并且格式不支持文件级连接(一般用户使用的大多数文件不支持文件级连接),请使用此方法

$cat mylist.txt
文件“/path/to/file1”
文件“/path/to/file2”
文件“/path/to/file3”
$ffmpeg-f concat-safe 0-i mylist.txt-c copy output.mp4
对于Windows:

(echo文件'first file.mp4'和echo文件'second file.mp4')>list.txt
ffmpeg-safe 0-f concat-i list.txt-c copy output.mp4
3. 对支持文件级连接的格式使用此方法 (MPEG-1、MPEG-2 PS、DV)。请勿与MP4一起使用

ffmpeg-i“concat:input1 | input2”-codec copy output.mkv
此方法不适用于许多格式,包括MP4,因为这些格式的性质以及此方法执行的简单连接


如果对使用哪种方法有疑问,请尝试concat demuxer

也看到
    • 这里有一种快速(不到1分钟)无损的方法,无需中间文件即可完成此操作:

      ls Movie_Part_1.mp4 Movie_Part_2.mp4|\
      perl-ne“打印”文件$|\
      ffmpeg-f concat-i--c拷贝电影_.mp4
      
      “ls”包含要加入的文件 “perl”在管道中动态创建连接文件 “-i-”部分告诉ffmpeg从管道中读取


      (注意-我的文件中没有空格或奇怪的东西-如果你想使用“硬”文件,你需要适当的外壳转义)。

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

      输入命令:

      ffmpeg-i input1.mp3-i input2.mp3-i input3.mp3\
      -过滤器“concat=n=3:v=0:a=1”-f MOV-vn-y input.m4a
      
      含义: -过滤复合物“concat=n=3:v=0:a=1”

      concat表示使用媒体连接(连接)功能。
      n表示确认输入文件的总数。
      v表示有视频?使用0=无视频,1=包含视频。
      a表示有音频?使用0=无音频,1=包含音频。
      -f表示强制设置文件格式(要查看所有支持的格式,请使用
      ffmpeg-formats

      -vn表示禁用视频(并且
      -an
      将禁用音频,如果不需要的话)
      -y表示覆盖输出文件(如果输出文件已存在)

      有关更多信息:请使用
      ffmpeg-h full

      打印所有选项(包括所有特定于格式和编解码器的选项,非常长)

      可以查看ffmpeg中各种连接方式的详细文档

      您可以使用快速连接

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

      用于连接2个文件:

      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
      
      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
      

      用于连接3个文件:

      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
      
      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
      
      这适用于相同和多个输入文件类型

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

      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
      
      注意
      对于MP4文件,输出将类似于第一个文件(而不是第二个文件)

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

      我重新命名了这些文件(分别为file1.mp4、file2.mp4、file3.mp4),这样这些部分就可以按照正确的顺序观看完整的电视节目了

      然后我创建了一个简单的批处理文件(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
      
      批处理文件和ffmpeg.exe必须与要加入的.mp4文件放在同一文件夹中。然后运行批处理文件。运行通常不到10秒。
      .

      附录(2018/10/21)-

      如果您想要的是一种在不需要大量重新键入的情况下指定当前文件夹中所有mp4文件的方法,请在Windows中尝试此方法
      #!/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
      
      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
      
      #!/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
      
      ffmpeg -i "concat:input1|input2" -codec copy output
      
      ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4
      
      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
      
      mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4
      
          $files=Get-ChildItem -path e:\ -Filter *.mp4
      
      
          $files| ForEach-Object  {"file '$($_.FullName)'"}| Out-File -FilePath e:\temp.txt -Encoding ASCII
      
      
          if (-not (test-path "e:\ffmpeg\bin\ffmpeg.exe")) {throw "e:\ffmpeg\bin\ffmpeg.exe needed"}
      
          E:\ffmpeg\bin\ffmpeg.exe -safe 0 -f concat -i "e:\temp.txt" -c copy -bsf:v hevc_mp4toannexb -an e:\joined.mp4
      
          # Conversion Cleanup
          Remove-Item e:\temp.txt
      
      file 'e:\first.mp4'
      file 'e:\second.mp4'
      
      usage  of -bsf:v hevc_mp4toannexb -an
      
      h264_mp4toannexb
      
      ffmpeg $(for f in *.mp4 ; do echo -n "-i $f "; done) -filter_complex \
      "$(i=0 ; for f in *.mp4 ; do echo -n "[$i:v] [$i:a] " ; i=$((i+1)) ; done \
      && echo "concat=n=$i:v=1:a=1 [v] [a]")" -map "[v]" -map "[a]" output.mp4
      
      Param(
      [string]$WildcardFilePath,
      [string]$OutFilePath
      )
      try
      {
          $tempFile = [System.IO.Path]::GetTempFileName()
          Get-ChildItem -path $wildcardFilePath | foreach  { "file '$_'" } | Out-File -FilePath $tempFile -Encoding ascii
          ffmpeg.exe -safe 0 -f concat -i $tempFile -c copy $outFilePath
      }
      finally
      {
          Remove-Item $tempFile
      }
      
      #!/bin/bash
      
      if [ $# -lt 1 ]; then
          echo "Usage: `basename $0` input_1.mp4 input_2.mp4 ... output.mp4"
          exit 0
      fi
      
      ARGS=("$@") # determine all arguments
      output=${ARGS[${#ARGS[@]}-1]} # get the last argument (output file)
      unset ARGS[${#ARGS[@]}-1] # drop it from the array
      (for f in "${ARGS[@]}"; do echo "file '$f'"; done) | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy $output