如何从背景和一组定位更改创建 mp4 或 gif

如何从背景和一组定位更改创建 mp4 或 gif

场景如下:

  1. 我有一个静态背景 png 文件,假设1920x1080
  2. 我有一组数百个小型 png 文件(每个文件的尺寸都不同,例如30x10010x20200x200),每个文件都代表与前一帧相比发生变化的矩形。每个变化可能出现在不同的位置,但我知道这些位置。
  3. 没有音频
  4. 我想从这些图像生成固定的 60fps mp4 或 gif,使用每个小 png 作为定位帧差异。每个帧都应在该 png 的给定位置上应用单个、预先分配的 png。

这能有效地完成吗?(我主要寻求时间优化)。

例如,创建一个代表 UI 记录的视频,其中您有一个起始帧,然后每一帧都会发生一些小的变化(光标移动一点,按下按钮并改变其样式),并且您想要生成完整的视频记录,每帧仅截取一小段屏幕截图,以减轻记录的影响。

我选择这种方法是因为我可以生成小的 png 变化,并且比每次拍摄全高清帧所花费的时间要少得多。

我知道我可以进行完整的逐帧生成,但生命太短暂,无法以这种方式进行,尤其是当你想创建数百个这样的视频时。如果需要,我会这样做,但我想尽可能地推广这个想法。

我希望使用可以在 AWS Lambda 上运行的任何东西来实现这一点,即 CPU 有限、RAM 不超过 3G,最好使用节点或 python 之类的技术,或者 Lambda 直接支持的任何技术。

答案1

我认为ffmpeg是你正在寻找的技术。(有一些精彩的例子和深入的讨论这里这超出了我的范围。)至于在 AWS Lambda 中使用它,它看起来像ffmpeg-aws-lambda是开始的最快方式。示例项目该存储库演示了一些基本用法。(它使用的 ffmpeg 是使用启用的 png 和 mp4 编解码器进行编译,这对于此目的是必要的。)

从图像序列生成 mp4相当容易完成使用 ffmpeg,我稍后也会演示。问题是你的源 png 文件大小不尽相同。你有偏移信息,还有可能有没有办法用 ffmpeg 为各个帧设置偏移量,但如果有的话,我还没有看到。

图像魔术师是解决诸如“获取此 png,并利用我们拥有的偏移信息,扩展其画布透明度,以便正确合成”等问题的首选解决方案。它已针对 AWS Lambda 进行打包这里。 图形魔法是 ImageMagick 的一个更快的分支,它似乎没有很好地打包成 Lambda 层,但是看起来人们已经让它发挥作用了。

您发送 ImageMagick(或 GraphicsMagick)来添加透明填充以使每个框架具有正确的大小的命令看起来如下所示:

composite -size ${WIDTH}x${HEIGHT} -geometry +$X_OFFSET+$Y_OFFSET $IMAGE_FILE xc:transparent output_${FRAME_INDEX}.png

您也许能够使用透明填充来生成源 PNG,这样可以节省该步骤、时间和处理能力。

我编写这个是为了生成一些示例 png 来玩:

#! /usr/bin/env bash
# How many frames to generate
LENGTH=$1
if [ -z $LENGTH ] || [ -z ${LENGTH##[!0-9]} ]; then
  echo "Usage: $0 LENGTH"
  echo "LENGTH must be a non-negative integer"
  exit 1
fi

mkdir -p frames

# Generate a zero-padded sequence
for i in $(seq -f "%04g" 0 $1); do
  # Some loading-icon math. The circle will grow and shrink.
  radius=$(echo "scale=1; (s($i/10) * 25) + 300" | bc -l)
  # Drawing a circle because circles are fun.
  gm convert -size 500x500 -stroke Red -fill Blue \
                           -strokewidth 2 -draw "circle 250,250 250,$radius" \
                           xc:transparent frames/frame_$i.png
done

然后用ffmpeg转换为mp4:

#! /usr/bin/env bash
# -r : 60 frames a second
# -i : the frames generated above
ffmpeg -r 60 -i frames/frame_%04d.png test.mp4

来自 png 的 ffmpeg 动画

(为了生成上述内容,我ffmpeg -r 30 -i frames/frame_%04d.png test.gif在发现 mp4 文件无法附加到 Stack Overflow 帖子后实际上使用了它。)

这仍然留下了合成透明帧而不是仅仅按顺序显示它们的问题;你可以找到更多关于如何做到这一点的讨论这里。

从性能方面来看,我不确定这是否能满足您的需求。

[gnubeard@mothership: ~/png_to_mp4]$ time ./generate_frames 600

real    0m25.061s
user    0m23.758s
sys     0m3.036s
[gnubeard@mothership: ~/png_to_mp4]$ time ./png_to_mp4 2>/dev/null

real    0m9.763s
user    0m18.649s
sys     0m0.115s

即便我使用 GraphicsMagick,ImageMagick 也是这个过程中最慢的部分,但部分原因是我用来制作傻瓜圆的操作更耗时draw。我将其更改为像上面建议的那样的复合操作,速度大大加快:

[gnubeard@mothership: ~/png_to_mp4]$ time ./generate_frames 600

real    0m7.261s
user    0m5.573s
sys     0m1.738s

好消息是,内存密集型部分(对视频进行编码)仅占用几百兆字节的 RAM,因此可行性将取决于您的时间限制以及是否可以通过生成具有适当大小和透明填充的 PNG 文件来跳过 ImageMagick 步骤。

相关内容