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


当前回答

下面将三个.mp3文件连接成一个.m4a。

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

期权的含义

-filter_complex“concat=n=3:v=0:a=1

连接:连接过滤器连接流n: 输入段计数(=同步的音频-视频流或仅音频或仅视频流)v: 输出视频流计数a: 输出音频流计数-vn:禁用视频(-an将禁用音频)-y: 无提示覆盖输出文件

请参阅man ffmpeg或ffmpeg-h full以打印所有选项(包括所有格式和编解码器特定选项)。

其他回答

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.凹面分离器

如果您希望避免重新编码,并且您的格式不支持文件级连接(一般用户使用的大多数文件不支持文件级别连接),请使用此方法。

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

对于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协议

将此方法用于支持文件级连接的格式(MPEG-1、MPEG-2ps、DV)。不要与MP4一起使用。

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

该方法不适用于许多格式,包括MP4,因为这些格式的性质以及该方法执行的简单连接。


如果对使用哪种方法有疑问,请尝试concat解复用器。

另请参见

FFmpeg常见问题解答:如何加入视频文件?FFmpeg Wiki:如何连接(连接、合并)媒体文件

对于Windows Powershell

创建文件列表

PS > ls file* | % { $n = $_.name; "file '\$n'" } | out-file mylist.txt

检查创建的文件

PS > cat mylist.txt
file '/path/to/file1.mkv'
file '/path/to/file2.mkv'
file '/path/to/file3.mkv'

运行ffmpeg(不要忘记列表文件的attach./)

PS > ffmpeg -safe 0 -f concat -i ./mylist.txt -c copy file.mkv
ffmpeg version git-2020-05-15-b18fd2b Copyright (c) 2000-2020 the FFmpeg developers
...

这里有一种快速(不到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转义)。

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

我个人喜欢不创建以后必须删除的外部文件,因此我的解决方案如下,其中包括文件编号列表(如file_1_name、file_2_name、file_10_name、file_20_name、file_00_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

可重用PowerShell脚本形式的接受答案

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
}