ffmpeg:组合/合并多个 mp4 视频不起作用,输出仅包含第一个视频
Posted
技术标签:
【中文标题】ffmpeg:组合/合并多个 mp4 视频不起作用,输出仅包含第一个视频【英文标题】:ffmpeg: Combine/merge multiple mp4 videos not working, output only contains the first video 【发布时间】:2011-07-21 20:42:18 【问题描述】:这是我用来合并多个视频的命令:
ffmpeg -i 75_540_38HQ2.mp4 -i 76_70_20.mp4 -i 76_173_80.mp4 -i 81_186_35.mp4 -vcodec copy -acodec copy Mux1.mp4
生成的Mux1.mp4
不包含所有视频。只有第一个视频 (75_540_38HQ2.mp4
)。源和结果视频的文件大小如下(如您所见,结果视频比第一个 vid 略大):
这是ffmpeg
命令的输出。在我看来,它看起来不错,显示了多个源输入和单个输出。
我在这里做了什么愚蠢的事情吗?
源视频来自摄像机,是用ffmpeg -i bigfile.mp4 -ss 20 -t 10 -vcodec copy etc..
拍摄的小sn-ps
非常感谢! 戴夫
编辑:无法解决,所以我只使用 avidemux GUI 工具。它似乎附加了 MP4 就好了。
一定是 MP4 的问题,或者只是从 gopro 相机上取下来的问题。
【问题讨论】:
如果我尝试多个视频组合,我会得到相同的结果。例如:只有 Input0 和 Input1。它始终会生成包含第一个视频的输出。 另见***.com/questions/7333232/…和trac.ffmpeg.org/wiki/Concatenate 并非所有文件都允许这三种方法。例如,您不能将 concat 用作 MP4 文件的协议。使用 concat 作为过滤器以避免重新编码:trac.ffmpeg.org/wiki/Concatenate 【参考方案1】:假设你想连接电影,你可以使用以下命令:
ffmpeg -f concat -i inputs.txt -vcodec copy -acodec copy Mux1.mp4
在inputs.txt中包含以下文本:
file 75_540_38HQ2.mp4
file 76_70_20.mp4
file 76_173_80.mp4
file 81_186_35.mp4
注意:某些发行版(如 Ubuntu)的存储库中没有 ffmpeg,而是将 ffmpeg 定义为 avconv 的别名。这不适用于 avconv,因此在这种情况下,您必须自己编译 ffmpeg。您可以通过运行 ffmpeg 并检查第一个输出行是否以“FFmpeg 开发人员”结尾来检查您是否拥有真正的 ffmpeg。
【讨论】:
如何在没有文本文件的情况下发出该命令!我需要直接从命令行或脚本运行它。 您可以尝试使用-i -
或-i /dev/stdin
,然后通过管道将文件列表输入标准输入。或者使用命名管道或临时文件。如果您需要更多帮助,请发布问题。【参考方案2】:
忘掉FFmpeg,改用MP4Box吧,它既简单又快捷:
mp4box -add video1.mp4 -cat video2.mp4 -cat video3.mp4 output.mp4
它适用于 Windows、Linux 和 OS X: http://www.videohelp.com/tools/mp4box
如果您使用的是 Windows,则可以使用 YAMB,它是 MP4Box 的 GUI,效果很好: http://www.videohelp.com/tools/YAMB
2016 年 6 月更新: FFmpeg 添加了一个连接过滤器,更多信息在这里: https://***.com/a/11175851/218418
【讨论】:
mp4box
超级快速且易于使用!
前段时间FFmpeg添加了一个过滤器,可以连接相同的媒体文件,这里是信息:***.com/a/11175851/218418【参考方案3】:
来自 ffmpeg 手册页“示例”部分:
您可以在输出中放置许多相同类型的流:
ffmpeg -i test1.avi -i test2.avi -vcodec copy -acodec copy \
-vcodec copy -acodec copy test12.avi -newvideo -newaudio
除了第一个视频和音频流之外,生成的 输出文件 test12.avi 将包含第二个视频和第二个 在输入流列表中找到音频流。
“-newvideo”、“-newaudio”和“-newsubtitle”选项必须紧跟在要添加它们的输出文件的名称之后。
如果您想连接它们,FAQ 有说明。
我不确定这个问题/答案是否属于 SuperUser。
【讨论】:
-newvideo、-newaudio、-newsubtitle 已从当前版本中删除。您必须使用 -map 选项。 (我还没想好。)如果有人想展示如何使用 -map 将 MP4 串起来,那就太棒了。 这些文档描述了 concat 过滤器以及在这种情况下如何使用 -map 选项:ffmpeg.org/trac/ffmpeg/wiki/… 请注意,如果我连接很长的文件,我的视频会损坏,所以我将尝试 mp4->mpeg 然后使用简单的连接。 ffmpeg 中的 concat 选项不需要使用 -map 选项,如果您真的只是连接输入文件(例如,您有两个 mp4 文件,每个 2 分钟持续时间,并且想要创建一个 4 分钟持续时间的 mp4 文件作为输出)。 Windows 7 中的 ffmpeg 命令行(使用 bcmpinc 的“inputs.txt”文件,见上文)为:ffmpeg -f concat -i inputs.txt -c copy output.mp4【参考方案4】:您必须将它们转换为可以轻松连接的 MPEG 格式。下面是我为我的 GoPro 视频使用并称为“ffcat”的脚本。它本质上运行几个“ffmpeg -i”命令,这些命令产生可连接的 MPEG,这些命令通过管道传输到 ffmpeg 命令,然后将它们转换为 H.264 mp4 文件。
它还将视频大小调整为 720p,但您可能不希望这样。
“h264options”是我最近在互联网上找到的标志h264.code-shop.com
希望这会有所帮助, 里德
cmd="( "
h264options="-vcodec libx264 -b 512k -flags +loop+mv4 -cmp 256 \
-partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 \
-me_method hex -subq 7 -trellis 1 -refs 5 -bf 3 \
-flags2 +bpyramid+wpred+mixed_refs+dct8x8 -coder 1 -me_range 16 \
-g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10\
-qmax 51 -qdiff 4"
outfile="out-`date +%F-%H%M.%S`.mp4"
for i; do
cmd="$cmdffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
done
cmd="$cmd ) | ffmpeg -y -i - -threads 8 $h264options -vb 10000000 -acodec libfaac -ar 44100 -ab 128k -s 1280x720 $outfile"
echo "$cmd"
eval $cmd
【讨论】:
这会造成视频转码两次的负面影响。我可以想象您可能需要转码一次,但不需要两次。 MP4 文件在连接之前不需要转换为 MPEG 格式。为了做最简单的连接,所有输入文件都是mp4,输出文件也是mp4,根本不需要转码。 Windows 7中的ffmpeg命令行(使用bcmpinc的inputs.txt文件,见下文)为:ffmpeg -f concat -i inputs.txt -c copy output.mp4【参考方案5】:如果所有输入视频都具有相同的编解码器并且您希望输出视频也使用相同的编解码器,则简单 concat 适用于 mp4 和 mkv 文件。 https://trac.ffmpeg.org/wiki/Concatenate 您需要创建一个文本文件,如
# this is a comment
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'
然后使用命令
ffmpeg -f concat -i mylist.txt -c copy output.mp4
我使用了同一个参考页面中的示例,效果很好。唯一的问题是没有正确捕获视频。它可能会引入音频视频同步问题,因为它只是将 PTS 和 DTS 信息从源视频复制到目标视频。 要获得完整的证明解决方案,您需要逐包阅读视频和 然后将所有数据包放在一个视频中,并进行自定义优化,例如丢弃重复的 PTS 数据包并保持单调的 PTS 值。
【讨论】:
【参考方案6】:我一直非常成功地使用这个脚本。结果非常完美,因为它使用的是原始视频。
http://trac.ffmpeg.org/wiki/How%20to%20concatenate%20%28join,%20merge%29%20media%20files
确保您编辑了 EXTRA OPTIONS 字符串。
#!/bin/bash
################################################################################
#
# Script name: MultiMedia Concat Script (mmcat)
# Author: burek (burek021@gmail.com)
# License: GNU/GPL, see http://www.gnu.org/copyleft/gpl.html
# Date: 2012-07-14
#
# This script concatenates (joins, merges) several audio/video inputs into one
# final output (just like as if all the inputs were played in a playlist, one
# after another).
#
# All input files must have at least one audio and at least one video stream.
# If not, you can easily add audio silence, using FFmpeg. Just search the
# internet for "ffmpeg add silence".
#
# The script makes use of FFmpeg tool (www.ffmpeg.org) and is free for use under
# the GPL license. The inspiration for this script came from this FAQ item:
# http://ffmpeg.org/faq.html#How-can-I-join-video-files_003f
#
# If you find any bugs, please send me an e-mail so I can fix it.
#
################################################################################
#
# General syntax: mmcat <input1> <input2> <input3> ... <output>
#
# For example: mmcat file1.flv file2.flv output.flv
# would create "output.flv" out of "file1.flv" and "file2.flv".
#
################################################################################
# change this to what you need !!!
EXTRA_OPTIONS='-vcodec libx264 -crf 23 -preset medium -acodec aac -strict experimental -ac 2 -ar 44100 -ab 128k'
################################################################################
#
# NO NEED TO TOUCH ANYTHING AFTER THIS LINE!
#
################################################################################
# the version of the script
VERSION=1.3
# location of temp folder
TMP=/tmp
################################################################################
echo "MultiMedia Concat Script v$VERSION (mmcat) - A script to concatenate multiple multimedia files."
echo "Based on FFmpeg - www.ffmpeg.org"
echo "Don't forget to edit this script and change EXTRA_OPTIONS"
echo ""
################################################################################
# syntax check (has to have at least 3 params: infile1, infile2, outfile
################################################################################
if [ -z $3 ]; then
echo "Syntax: $0 <input1> <input2> <input3> ... <output>"
exit 1
fi
################################################################################
# get all the command line parameters, except for the last one, which is output
################################################################################
# $first - first parameter
# $last - last parameter (output file)
# $inputs - all the inputs, except the first input, because 1st input is
# handled separately
################################################################################
first=$@:1:1
last=$@:$#:1
len=$(($#-2))
inputs=$@:2:$len
# remove all previous tmp fifos (if exist)
rm -f $TMP/mcs_*
################################################################################
# decode first input differently, because the video header does not have to be
# kept for each video input, only the header from the first video is needed
################################################################################
mkfifo $TMP/mcs_a1 $TMP/mcs_v1
ffmpeg -y -i $first -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a1 2>/dev/null </dev/null &
ffmpeg -y -i $first -an -f yuv4mpegpipe -vcodec rawvideo $TMP/mcs_v1 2>/dev/null </dev/null &
# if you need to log the output of decoding processes (usually not necessary)
# then replace the "2>/dev/null" in 2 lines above with your log file names, like this:
#ffmpeg -y -i $first -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a1 2>$TMP/log.a.1 </dev/null &
#ffmpeg -y -i $first -an -f yuv4mpegpipe -vcodec rawvideo $TMP/mcs_v1 2>$TMP/log.v.1 </dev/null &
################################################################################
# decode all the other inputs, remove first line of video (header) with tail
# $all_a and $all_v are lists of all a/v fifos, to be used by "cat" later on
################################################################################
all_a=$TMP/mcs_a1
all_v=$TMP/mcs_v1
i=2
for f in $inputs
do
mkfifo $TMP/mcs_a$i $TMP/mcs_v$i
ffmpeg -y -i $f -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a$i 2>/dev/null </dev/null &
ffmpeg -y -i $f -an -f yuv4mpegpipe -vcodec rawvideo - 2>/dev/null </dev/null | tail -n +2 > $TMP/mcs_v$i ; &
# if you need to log the output of decoding processes (usually not necessary)
# then replace the "2>/dev/null" in 2 lines above with your log file names, like this:
#ffmpeg -y -i $f -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a$i 2>$TMP/log.a.$i </dev/null &
# ffmpeg -y -i $f -an -f yuv4mpegpipe -vcodec rawvideo - 2>$TMP/log.v.$i </dev/null | tail -n +2 > $TMP/mcs_v$i ; &
all_a="$all_a $TMP/mcs_a$i"
all_v="$all_v $TMP/mcs_v$i"
let i++
done
################################################################################
# concatenate all raw audio/video inputs into one audio/video
################################################################################
mkfifo $TMP/mcs_a_all
mkfifo $TMP/mcs_v_all
cat $all_a > $TMP/mcs_a_all &
cat $all_v > $TMP/mcs_v_all &
################################################################################
# finally, encode the raw concatenated audio/video into something useful
################################################################################
ffmpeg -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i $TMP/mcs_a_all \
-f yuv4mpegpipe -vcodec rawvideo -i $TMP/mcs_v_all \
$EXTRA_OPTIONS \
$last
################################################################################
# remove all fifos
################################################################################
rm -f $TMP/mcs_*
【讨论】:
【参考方案7】:Concat 解复用器
在 ffmpeg 1.1 中添加了 concat demuxer。如果您的 ffmpeg 版本过旧,请从此处获取最新的静态二进制文件: http://www.ffmpeg.org/download.html
说明
创建一个文件mylist.txt
,其中包含您想要以以下形式连接的所有文件(以破折号开头的行被忽略):
# this is a comment
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'
请注意,这些路径可以是相对路径,也可以是绝对路径。然后您可以使用以下代码对文件进行编码:
ffmpeg -f concat -i mylist.txt -c copy output
可以使用 bash for 循环或使用 printf 生成此列表文件。以下任一项都会生成一个列表文件,其中包含工作目录中的每个 *.wav:
for f in ./*.wav; do echo "file '$f'" >> mylist.txt; done
printf "file '%s'\n" ./*.wav > mylist.txt
来源:ffmpeg wiki
【讨论】:
【参考方案8】:在 ffmpeg 网站 concatenating media files page 上可以找到,您有几个选择:
1。连接协议:
ffmpeg -i "concat:input1.ts|input2.ts|input3.ts" -c copy output.ts
2。连接过滤器:
这个我不太明白,你可能需要查看所有图表和过滤图表,但它可以让你处理多种格式和不同的编解码器属性
ffmpeg -i input1.mp4 -i input2.webm -i input3.mov \
-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[outv][outa]" \
-map "[outv]" -map "[outa]" output.mkv
3。连接解复用器:
首先,您需要生成某种列表文件,例如。 “mylist.txt”
# this is a comment
file '/path/to/file1.wav'
file '/path/to/file2.wav'
file '/path/to/file3.wav'
其次,你需要运行一个命令才能使用列表
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.wav
【讨论】:
【参考方案9】:最初的问题更多是关于在一个输出文件中混合多个视频流,并让应用程序选择要解码的视频流。正如上面评论中提到的,您可以使用 FFmpeg 提供的-map
选项来实现。
下面是从单独的输入文件中混合 3 个视频流的快速示例命令:
ffmpeg -i video_A.mp4 -i video_B.mp4 -i video_C.mp4 -c copy \
-map 0:0 -map 1:0 -map 2:0 -map 2:1 output_mux_video.mp4
每个-map
选项都以特定的值格式<INPUT_INDEX>:<STREAM_INDEX>
开头
<INPUT_INDEX>
以上是-i <INPUT_FILE_NAME>
的顺序
以上<STREAM_INDEX>
是每个<INPUT_FILE_NAME>
中的流的顺序,也可以是特殊字符,例如a
(所有音频流)或v
(所有视频流),更高级的用法请查看@ 987654322@。在此示例中,假设视频流位于索引 0
,音频流位于索引 1
-c copy
表示 stream copy,因此 FFmpeg 将复制每个输入视频流以进行复用/解复用,而不是重新编码它们。
命令执行会输出如下消息:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from "/path/to/video_A.mp4"
..... <OMITTED_NOT_IMPORTANT> .....
Duration: 00:04:54.08, start: 0.000000, bitrate: 146 kb/s
Stream #0.0(und): Video: h264 (Main), yuv420p, 256x140 [PAR 1:1 DAR 64:35], 10 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc
Stream #0.1(und): Audio: aac, 44100 Hz, stereo, fltp, 127 kb/s
Input #1, mov,mp4,m4a,3gp,3g2,mj2, from "/path/to/video_B.mp4"
..... <OMITTED_NOT_IMPORTANT> .....
Duration: 00:05:35.01, start: 0.000000, bitrate: 363 kb/s
Stream #1.0(und): Video: h264 (Main), yuv420p, 426x240 [PAR 1:1 DAR 71:40], 229 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc
Stream #1.1(eng): Audio: aac, 44100 Hz, stereo, fltp, 127 kb/s
Input #2, mov,mp4,m4a,3gp,3g2,mj2, from "/path/to/video_C.mp4"
..... <OMITTED_NOT_IMPORTANT> .....
Duration: 00:05:35.01, start: 0.000000, bitrate: 363 kb/s
Stream #2.0(und): Video: h264 (Main), yuv420p, 426x240 [PAR 1:1 DAR 71:40], 229 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc
Stream #2.1(eng): Audio: aac, 44100 Hz, stereo, fltp, 127 kb/s
Output #0, mp4, to '/path/to/output_mux_video.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
..... <OMITTED_NOT_IMPORTANT> .....
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #1:0 -> #0:1 (copy)
Stream #2:0 -> #0:2 (copy)
Stream #2:1 -> #0:3 (copy)
Press ctrl-c to stop encoding
frame= 8818 fps= 0 q=-1.0 Lq=-1.0 size= 15342kB time=293.87 bitrate= 427.7kbits/s
video:9783kB audio:5235kB global headers:0kB muxing overhead 2.160838%
通过检查上面的Stream mapping
部分,您将知道映射是否符合您的预期。
对于那些遇到类似问题的人,这个答案可以节省您的时间。
【讨论】:
【参考方案10】:MP4Box 可以在不破坏音频的情况下工作。我做了以下以获得良好的结果:
从 gpac 网站下载最新的 Linux deb 构建: http://gpac.wp.mines-telecom.fr/downloads/gpac-nightly-builds/
使用-force-cat
选项
示例命令行:
MP4Box -force-cat -add in1.mp4 -cat in2.mp4 -cat in3.mp4 ... out.mp4
一些小的cmets:
上述方法很重要,因为与 Linux Mint 13 一起分发的最新版本的 MP4Box 存在错误,并且确实会导致音频损坏。
-force-cat
很重要,因为没有它,视频格式标签从 AVC 更改为 avc3。
【讨论】:
【参考方案11】:您可以避免显式创建列表文件并在一行中完成整个操作
ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4
请参阅ffmpeg wiki。
【讨论】:
以上是关于ffmpeg:组合/合并多个 mp4 视频不起作用,输出仅包含第一个视频的主要内容,如果未能解决你的问题,请参考以下文章