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


当前回答

这里有一个脚本(适用于任意数量的指定文件(不仅仅是工作目录中的所有文件),没有附加文件,也适用于.mov;在macOS上测试):

#!/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

其他回答

此处描述的concat协议;https://trac.ffmpeg.org/wiki/Concatenate#protocol

当使用命名管道实现以避免中间文件时

速度非常快(读:即时),没有掉帧,工作正常。

记住删除命名的管道文件,并记住检查视频是否为H264和AAC,您可以只使用ffmpeg-i filename.mp4(检查H264和AAC提及)

经过多次尝试后,以下脚本在windows 10 powershell上对我有效。

    $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

这里,前两行创建一个文本文件temp.txt,其中包含以下内容

file 'e:\first.mp4'
file 'e:\second.mp4'

第三、第四行检查ffmpeg在路径上是否可用,并创建“joind.mp4”

与其他答案的主要区别如下

usage  of -bsf:v hevc_mp4toannexb -an

对于我上面的mp4文件,您可能需要根据您的视频编码使用以下其他选项。

h264_mp4toannexb

所有这些可能的比特流过滤器都可以在https://ffmpeg.org/ffmpeg-bitstream-filters.html

这里有两个纯bash解决方案,只使用ffmpeg,不使用

中间文件perl、python或javascript

使用ls的单线解决方案

ls video1.mp4 video2.mp4 | while read line; do echo file \'$line\'; done | ffmpeg -protocol_whitelist file,pipe -f concat -i - -c copy output.mp4

采用0或2+参数的函数

#######################################
# Merge mp4 files into one output mp4 file
# usage:
#   mergemp4 #merges all mp4 in current directory
#   mergemp4 video1.mp4 video2.mp4
#   mergemp4 video1.mp4 video2.mp4 [ video3.mp4 ...] output.mp4 
#######################################
function mergemp4() {
  if [ $# = 1 ]; then return; fi

  outputfile="output.mp4"

  #if no arguments we take all mp4 in current directory as array
  if [ $# = 0 ]; then inputfiles=($(ls -1v *.mp4)); fi
  if [ $# = 2 ]; then inputfiles=($1 $2); fi  
  if [ $# -ge 3 ]; then
    outputfile=${@: -1} # Get the last argument
    inputfiles=(${@:1:$# - 1}) # Get all arguments besides last one as array
  fi
  
  # -y: automatically overwrite output file if exists
  # -loglevel quiet: disable ffmpeg logs
  ffmpeg -y \
  -loglevel quiet \
  -f concat \
  -safe 0 \
  -i <(for f in $inputfiles; do echo "file '$PWD/$f'"; done) \
  -c copy $outputfile

  if test -f "$outputfile"; then echo "$outputfile created"; fi
}

注意:在这个线程中尝试了一些解决方案,但没有一个让我满意

对于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批处理文件中尝试此方法(必须包含选项-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上以批处理文件的形式运行。不要尝试在命令行上使用它,因为它只在批处理文件中工作!

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