在 Linux 中合并 mp4 文件

在 Linux 中合并 mp4 文件

我想将两个 mp4 文件合并成一个。视频流采用 h264 编码,音频采用 aac 编码。由于计算原因,我无法将视频重新编码为其他格式。此外,我无法使用任何 GUI 程序,所有处理都必须使用 Linux 命令行实用程序执行。FFmpeg 无法对 mpeg4 文件执行此操作,因此我改用 MP4Box:

MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4

不幸的是,音频全都混在一起了。我以为问题出在音频是 aac 格式,所以我将其转码为 mp3,然后再次使用 MP4Box。在这种情况下,前半部分newvideo.mp4(对应于video1.mp4)的音频很好,但之后就没有音频了,我也无法在视频中导航。

我的下一个想法是音频和视频流的长度存在一些小差异,我应该修复它们。因此,对于每个输入视频,我拆分了视频和音频流,然后使用 FFmpeg 中的 -shortest 选项将它们合并。

因此,对于我播放的第一个视频:

 avconv -y -i video1.mp4 -c copy -map 0:0 videostream1.mp4
 avconv -y -i video1.mp4 -c copy -map 0:1 audiostream1.m4a
 avconv -y -i videostream1.mp4 -i audiostream1.m4a  -c copy -shortest  video1_aligned.mp4

第二个视频也一样,然后像之前一样使用 MP4Box。不幸的是,这也不起作用。我唯一成功的是当我分别加入视频流(即 videostream1.mp4 和 videostream2.mp4)和音频流(即 audiostream1.m4a 和 audiostream2.m4a)然后将视频和音频加入最终文件中时。但是,视频的后半部分丢失了同步。具体来说,音频和视频有 1 秒的延迟。非常欢迎任何建议。

答案1

目前最好的方法是使用连接解复用器。首先,创建一个名为的文件,inputs.txt格式如下:

file '/path/to/input1.mp4'
file '/path/to/input2.mp4'
file '/path/to/input3.mp4'

然后,只需运行此 ffmpeg 命令:

ffmpeg -f concat -i inputs.txt -c copy output.mp4

也可以看看ffmpeg常见问题解答中的串联


我在这里保留以下内容是为了让使用旧版本 ffmpeg 的人受益。

ffmpeg 的最新版本可以做到这一点:您必须先将文件重新混合为 mpeg 传输流(相当轻处理器,因为它只改变容器格式):

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

如果出现错误 [1]关于h264,您可能需要使用:

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf:v h264_mp4toannexb middle.ts

您必须对每个输入文件分别执行此操作。要将文件连接在一起,请使用:

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4

如果出现有关 aac 的错误,你可能需要使用

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy -absf aac_adtstoasc output.mp4

如果您的系统支持命名管道,您无需创建中间文件即可执行此操作。

mkfifo temp0 temp1

您必须在三个单独的虚拟终端中执行以下操作:

ffmpeg -i input0.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp0
ffmpeg -i input1.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1
ffmpeg -f mpegts -i "concat:temp0|temp1" -c copy -absf aac_adtstoasc output.mp4

如果 output.mp4 已经存在,第三个 ffmpeg 会询问您是否要覆盖它,但它会这样做访问 FIFO 后,这将使第一个 ffmpegs 关闭。因此,请确保为输出文件选择一个未使用的名称。

如果您的输入文件不同,这可能不起作用 - 我相信比特率的差异是可以的,但帧大小、帧速率等必须匹配。

答案2

对于 mp4,我发现的唯一可行的解​​决方案是使用 gpac 包中的 MP4Box

#!/bin/bash
filesList=""
for file in $(ls *.mp4|sort -n);do
    filesList="$filesList -cat $file"
done
MP4Box $filesList -new merged_files_$(date +%Y%m%d_%H%M%S).mp4

或命令是

MP4Box -cat file1.mp4 -cat file2.mp4 -new mergedFile.mp4

使用 mencoder 和 avconv 我无法让它工作 :-(

答案3

这里有一行代码,可以让一切变得简单很多。它会完成所有需要做的事情,最终为您提供一个最终的视频文件。干杯!

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts

答案4

在 Mac(macOS 10.13 High Sierra)上,我成功使用了以下操作:

for f in *.m4a; do echo "file '$f'" >> mylist.txt; done

如果有必要,请按上述类似方式重新排序(请注意,./ 已被删除 - 该路径导致 ffmpeg 抛出不安全的文件名错误)。

然后我必须删除为默认 MacPorts ffmpeg 指定的编解码器和比特率才能喜欢它:

ffmpeg -f concat -i mylist.txt  output.m4a

相关内容