如何在视频的第一帧之前放置一张静态图像?

19
当我使用FFMpeg编码视频时,我想在第一个视频帧之前放置一个jpg图像,因为当我在网页上嵌入视频时,它会显示第一张图片作为闪屏图像。或者,我想将一张图像编码为1帧视频,并将其连接到我的编码视频中。我不想使用“video”html5元素的“poster”属性。
3个回答

32
你可以使用concat过滤器来实现此功能。确切的命令取决于你想要多长时间的启动画面。我相信你不希望有一个只有1帧的启动画面,这大约是1/25到1/30秒,具体取决于视频的帧率;)
答案:
首先,你需要获取视频的帧率。尝试使用ffmpeg -i 输入 命令并查找 tbr 值。例如:
$ ffmpeg -i a.mkv
ffmpeg version N-62860-g9173602 Copyright (c) 2000-2014 the FFmpeg developers
  built on Apr 30 2014 21:42:15 with gcc 4.8 (Ubuntu 4.8.2-19ubuntu1)
[...]
Input #0, matroska,webm, from 'a.mkv':
  Metadata:
    ENCODER         : Lavf55.37.101
  Duration: 00:00:10.08, start: 0.080000, bitrate: 23 kb/s
    Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p, 320x240 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
At least one output file must be specified

在上面的例子中,它显示了 25 tbr。请记住这个数字。
其次,您需要将图像与视频连接起来。尝试使用此命令:
ffmpeg -loop 1 -framerate FPS -t SECONDS -i IMAGE \
       -t SECONDS -f lavfi -i aevalsrc=0 \
       -i INPUTVIDEO \
       -filter_complex '[0:0] [1:0] [2:0] [2:1] concat=n=2:v=1:a=1' \
       [OPTIONS] OUTPUT

如果您的视频没有声音,请尝试以下方法:

ffmpeg -loop 1 -framerate FPS -t SECONDS -i IMAGE \
       -i INPUTVIDEO \
       -filter_complex '[0:0] [1:0] concat=n=2:v=1:a=0' \
       [OPTIONS] OUTPUT

FPS = 从步骤1获取的tbr值。

SECONDS = 想要显示图像的持续时间。

IMAGE = 图像名称。

INPUTVIDEO = 原始视频名称。

[OPTIONS] = 可选编码参数(例如-vcodec libx264-b:a 160k)。

OUTPUT = 输出视频文件名。

这是怎么工作的?

我们将使用我使用的命令行进行分割:

-loop 1 -framerate FPS -t SECONDS -i IMAGE:这基本上意味着:打开图像,并循环使其成为具有FPS帧速率和SECONDS秒的视频。您需要它与输入视频具有相同的FPS,因为稍后我们将使用的concat过滤器有限制。

-t SECONDS -f lavfi -i aevalsrc=0:这意味着:生成静音以供SECONDS使用(0表示静音)。您需要静音来填补闪屏图像的时间。如果原始视频没有音频,则不需要此操作。

-i INPUTVIDEO:打开视频本身。

-filter_complex '[0:0] [1:0] [2:0] [2:1] concat=n=2:v=1:a=1':这是最好的部分。您打开文件0流0(图像视频),文件1流0(静音音频),文件2流0和1(真实输入音频和视频),并将它们concat在一起。选项nva表示有2个段、1个输出视频和1个输出音频。

[OPTIONS] OUTPUT:这只是意味着对输出文件名称进行编码。如果您使用HTML5流式传输,则可能需要使用-c:v libx264 -crf 23 -c:a libfdk_aac(或-c:a libfaac)-b:a 128k来获得H.264视频和AAC音频。

更多信息


谢谢,它有效了。但是我该如何传递我通常使用的其他过滤器以及 -vf 选项:ffmpeg 说 -vf 和 -filter_complex 不能同时使用。 - Konstantin
有没有办法淡入/淡出启动画面?@TimothyGu - mvalencaa
对于上述命令,图像和视频必须是相同的大小吗?或者是否可能通过命令覆盖这一点? - Damien
由于编辑队列已满,我在这里写下:
  • 如果您使用的是Windows,则需要从代码中删除\
  • 您还可能需要删除-filter_complex周围的引号。 示例命令:ffmpeg -loop 1 -framerate 23.98 -t 2 -i cover.jpg -t 2 -f lavfi -i aevalsrc=0 -i vid.mp4 -filter_complex [0:0][1:0][2:0][2:1]concat=n=2:v=1:a=1 -c:v libx264 -crf 23 final.mp4
- Shahriar
谢谢答案。这是我在视频之前添加两张图片的方式:fmpeg -loop 1 -framerate 29.97 -t 1.5 -i vac1.jpg -t 1.5 -f lavfi -i aevalsrc=0 -loop 1 -framerate 29.97 -t 1.5 -i vac2.jpg -t 1.5 -f lavfi -i aevalsrc=0 -i vac_ts.mkv -filter_complex '[0:v:0][1:a:0] [2:v:0][3:a:0] [4:v:0][4:a:0] concat=n=3:v=1:a=1' 选项 出口.mkv - Robpol86
显示剩余7条评论

20

上面的答案对我有用,但在我的情况下执行时间太长了(可能是因为它重新编码整个视频)。我找到了另一个解决方案,速度更快。基本思路是:

  1. 创建一个只包含图像的“视频”。
  2. 将上述视频与原始视频连接起来,而不重新编码。

创建一个只包含图像的视频:

ffmpeg -loop 1 -framerate 30 -i image.jpg -c:v libx264 -t 3 -pix_fmt yuv420p image.mp4

请注意-framerate 30选项。它必须与主视频相同。此外,图像应与主视频具有相同的尺寸。 -t 3指定视频长度为秒数。
将视频转换为MPEG-2传输流
根据ffmpeg官方文档,只有特定文件可以使用concat协议进行连接,其中包括MPEG-2传输流。由于我们有2个MP4视频,它们可以无损地转换为MPEG-2 TS。
ffmpeg -i image.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts image.ts

同时针对主视频:

ffmpeg -i video.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts video.ts

连接MPEG-2 TS文件

现在使用以下命令来连接上述中间文件:

ffmpeg -i "concat:image.ts|video.ts" -c copy -bsf:a aac_adtstoasc output.mp4

尽管需要运行4个命令,但综合起来仍比重新编码整个视频快得多。

1
工作得非常好!所有步骤都在瞬间执行,无需重新编码。但是需要大量手动操作。请问有人能否将这些步骤组合成一个脚本,一次性完成所有操作,并在之后清理辅助的“.ts”文件? 我想象中的命令如下:insertStillframeToMP4.sh -p <durationInSecs> <picFile> -v <videoFile> -o <outputFile>-p-v 的参数顺序决定了图片是在视频之前还是之后插入。帧率从 <videoFile> 中使用 ffmpeg -i | grep parseFPSexpression 读取。 - porg
1
不错 :-) 这使我能够在连接它们之前分别对图像和视频应用过滤器。尝试像Timothy的答案中那样一次性完成所有操作会导致错误,而我无法修复。 - craq
1
顺便提一句,你可以更新使用H265。只需将第一个命令中的“libx264”更改为“libx265”,并在其他所有地方将“h264_mp4toannexb”更改为“hevc_mp4toannexb”。 - craq

1

我的解决方案是:在视频前设置一张持续5秒的图片,并将视频对齐到1280x720。图片应该具有16/9的宽高比。

ffmpeg -i video.mp4 -i image.png -filter_complex '
       color=c=black:size=1280x720 [temp]; \
       [temp][1:v] overlay=x=0:y=0:enable='between(t,0,5)' [temp]; \
       [0:v] setpts=PTS+5/TB, scale=1280x720:force_original_aspect_ratio=decrease, pad=1280:720:-1:-1:color=black [v:0]; \
       [temp][v:0] overlay=x=0:y=0:shortest=1:enable='gt(t,5)' [v]; \
       [0:a] asetpts=PTS+5/TB [a]'
-map [v] -map [a] -preset veryfast output.mp4


对我来说,唯一有效的命令!可能需要更好地记录文档。 - SepSol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接