FFMPEG 吃掉所有内存
FFMPEG eats all the memory
可能是最陈词滥调的问题之一,但问题是:所以我有一台 Ubuntu 服务器 运行 作为一台孤立的机器,仅用于处理 FFMPEG 作业。它有 4 个 vCPU、4GB RAM、80GB 存储空间。我目前正在使用此脚本将视频转换为 HLS 播放列表:https://gist.github.com/maitrungduc1410/9c640c61a7871390843af00ae1d8758e 这适用于所有视频,包括从 iPhone 录制的 4K。但是,我正在尝试添加水印,所以我更改了此脚本的第 106 行
来自:
cmd+=" ${static_params} -vf scale=w=${widthParam}:h=${heightParam}"
至:
cmd+=" ${static_params} -filter_complex [1]colorchannelmixer=aa=0.5,scale=iw*0.1:-1[wm];[0][wm]overlay=W-w-5:H-h-5[out];[out]scale=w=${widthParam}:h=${heightParam}[final] -map [final]"
现在这在来自 Youtube 或其他来源的视频中完美运行,但是当我尝试使用来自 iPhone 的 4K 视频时,RAM 使用量在不到一分钟内从 250MB 增加到 3.8GB 并崩溃整个过程。所以我寻找了一些类似的问题:
- FFmpeg Concat Filter High Memory Usage
- https://github.com/jitsi/jibri/issues/269
- https://superuser.com/questions/1509906/reduce-ffmpeg-memory-usage-when-joining-videos
- ffmpeg amerge Error while filtering: Cannot allocate memory
我知道 FFMPEG 需要大量内存消耗,但我不确定在不将流保存在内存中而是实时释放任何内存分配的情况下处理视频的确切方法是什么。即使我们决定在没有水印的情况下工作,它仍然需要 1.8GB RAM 来处理 5 秒 4K 视频,这会产生风险,如果我们的用户上传更长的视频而不是最终导致服务器崩溃。我考虑过 ulimit
但这看起来确实像限制 FFMPEG 而不是编写改进的命令。让我知道如何解决这个问题。谢谢
好的,我找到了解决办法。问题是 4K 视频具有极高的比特率,它会加载到您的 RAM 上以处理 filter_complex
,这最终会终止您的进程。为了解决这个问题,我做的第一件事就是将输入视频转码为 H264 格式(如果你愿意,你可以设置自定义比特率,但我把它留了下来)。
所以我在这个脚本的第 58 行之后添加了这个新命令 https://gist.github.com/maitrungduc1410/9c640c61a7871390843af00ae1d8758e
ffmpeg -i SOURCE.MOV -c:a aac -ar 48000 -c:v libx264 -profile:v main -crf 19 -preset ultrafast /home/myusername/myfolder/out.mp4
现在我们有一个新的处理 out.mp4
。我们将沿着脚本第 121 行删除它。这样做的原因是为了阻止 FFMPEG 一次重载所有命令。现在我们将删除第 107 到 109 行并执行此操作:
filters=[1]colorchannelmixer=aa=0.5,scale=iw*0.1:-1[wm];[0][wm]overlay=W-w-5:H-h-5[out];[out]scale=w=${widthParam}:h=${heightParam}[final]
cmd=""
cmd+=" ${static_params} -filter_complex ${filters} -map [final]"
cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.*}k -bufsize ${bufsize%.*}k -b:a ${audiorate}"
cmd+=" -hls_segment_filename ${target}/${name}_%03d.ts ${target}/${name}.m3u8"
ffmpeg ${misc_params} -i /home/myusername/myfolder/out.mp4 -i mylogo.png ${cmd}
所以现在我们在一个循环中 运行ning FFMPEG 来处理每个分辨率的基础输出。这将立即消除内存中所有过滤器的过载。根据您的用例,您甚至可能想删除第 53 行。
测试
- 4K HEVC iPhone 1.2 分钟长的视频 (453MB)
- 转码为 H264 - 内存使用量保持在 750MB
- HLS + 水印 - 内存使用保持在 430MB 到 1.1GB 之间
- 1.13 分钟长的 4K HEVC LG HDR 视频 (448MB)
- 转码为 H264 - 内存使用量保持在 800MB
- HLS + 水印 - 内存使用保持在 380MB 到 850MB 之间
最后的想法
- FFMPEG 是一个耗能者。 core/memory 要求的总数主要取决于您要处理的视频量。就我而言,我们只想支持最多 500MB 的视频,因此我们对 4K 视频处理的测试符合需要,但如果您有更大的视频要求,那么您必须使用更多 RAM/CPU 核心进行测试
- 运行 并行 FFMPEG 从来都不是一个好主意。分批处理视频将确保可用资源的最佳使用,并减少半夜破坏系统的机会
- 始终运行 FFMPEG 在远离网络服务器、数据库、邮件服务器等的隔离机器中
- 增加资源并不总是答案。虽然我们倾向于首先得出结论,更多的资源 === 更多的稳定性并不总是正确的。我已经阅读了足够多的关于 32 核 64GB Ram 如何跟不上 FFMPEG 的帖子,所以你最好的选择是首先改进你的命令或将命令分离成更小的命令以尽可能有效地处理资源
我不是 FFMPEG 方面的专家,但我认为这些信息会对可能有类似问题的人有所帮助。
可能是最陈词滥调的问题之一,但问题是:所以我有一台 Ubuntu 服务器 运行 作为一台孤立的机器,仅用于处理 FFMPEG 作业。它有 4 个 vCPU、4GB RAM、80GB 存储空间。我目前正在使用此脚本将视频转换为 HLS 播放列表:https://gist.github.com/maitrungduc1410/9c640c61a7871390843af00ae1d8758e 这适用于所有视频,包括从 iPhone 录制的 4K。但是,我正在尝试添加水印,所以我更改了此脚本的第 106 行
来自:
cmd+=" ${static_params} -vf scale=w=${widthParam}:h=${heightParam}"
至:
cmd+=" ${static_params} -filter_complex [1]colorchannelmixer=aa=0.5,scale=iw*0.1:-1[wm];[0][wm]overlay=W-w-5:H-h-5[out];[out]scale=w=${widthParam}:h=${heightParam}[final] -map [final]"
现在这在来自 Youtube 或其他来源的视频中完美运行,但是当我尝试使用来自 iPhone 的 4K 视频时,RAM 使用量在不到一分钟内从 250MB 增加到 3.8GB 并崩溃整个过程。所以我寻找了一些类似的问题:
- FFmpeg Concat Filter High Memory Usage
- https://github.com/jitsi/jibri/issues/269
- https://superuser.com/questions/1509906/reduce-ffmpeg-memory-usage-when-joining-videos
- ffmpeg amerge Error while filtering: Cannot allocate memory
我知道 FFMPEG 需要大量内存消耗,但我不确定在不将流保存在内存中而是实时释放任何内存分配的情况下处理视频的确切方法是什么。即使我们决定在没有水印的情况下工作,它仍然需要 1.8GB RAM 来处理 5 秒 4K 视频,这会产生风险,如果我们的用户上传更长的视频而不是最终导致服务器崩溃。我考虑过 ulimit
但这看起来确实像限制 FFMPEG 而不是编写改进的命令。让我知道如何解决这个问题。谢谢
好的,我找到了解决办法。问题是 4K 视频具有极高的比特率,它会加载到您的 RAM 上以处理 filter_complex
,这最终会终止您的进程。为了解决这个问题,我做的第一件事就是将输入视频转码为 H264 格式(如果你愿意,你可以设置自定义比特率,但我把它留了下来)。
所以我在这个脚本的第 58 行之后添加了这个新命令 https://gist.github.com/maitrungduc1410/9c640c61a7871390843af00ae1d8758e
ffmpeg -i SOURCE.MOV -c:a aac -ar 48000 -c:v libx264 -profile:v main -crf 19 -preset ultrafast /home/myusername/myfolder/out.mp4
现在我们有一个新的处理 out.mp4
。我们将沿着脚本第 121 行删除它。这样做的原因是为了阻止 FFMPEG 一次重载所有命令。现在我们将删除第 107 到 109 行并执行此操作:
filters=[1]colorchannelmixer=aa=0.5,scale=iw*0.1:-1[wm];[0][wm]overlay=W-w-5:H-h-5[out];[out]scale=w=${widthParam}:h=${heightParam}[final]
cmd=""
cmd+=" ${static_params} -filter_complex ${filters} -map [final]"
cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.*}k -bufsize ${bufsize%.*}k -b:a ${audiorate}"
cmd+=" -hls_segment_filename ${target}/${name}_%03d.ts ${target}/${name}.m3u8"
ffmpeg ${misc_params} -i /home/myusername/myfolder/out.mp4 -i mylogo.png ${cmd}
所以现在我们在一个循环中 运行ning FFMPEG 来处理每个分辨率的基础输出。这将立即消除内存中所有过滤器的过载。根据您的用例,您甚至可能想删除第 53 行。
测试
- 4K HEVC iPhone 1.2 分钟长的视频 (453MB)
- 转码为 H264 - 内存使用量保持在 750MB
- HLS + 水印 - 内存使用保持在 430MB 到 1.1GB 之间
- 1.13 分钟长的 4K HEVC LG HDR 视频 (448MB)
- 转码为 H264 - 内存使用量保持在 800MB
- HLS + 水印 - 内存使用保持在 380MB 到 850MB 之间
最后的想法
- FFMPEG 是一个耗能者。 core/memory 要求的总数主要取决于您要处理的视频量。就我而言,我们只想支持最多 500MB 的视频,因此我们对 4K 视频处理的测试符合需要,但如果您有更大的视频要求,那么您必须使用更多 RAM/CPU 核心进行测试
- 运行 并行 FFMPEG 从来都不是一个好主意。分批处理视频将确保可用资源的最佳使用,并减少半夜破坏系统的机会
- 始终运行 FFMPEG 在远离网络服务器、数据库、邮件服务器等的隔离机器中
- 增加资源并不总是答案。虽然我们倾向于首先得出结论,更多的资源 === 更多的稳定性并不总是正确的。我已经阅读了足够多的关于 32 核 64GB Ram 如何跟不上 FFMPEG 的帖子,所以你最好的选择是首先改进你的命令或将命令分离成更小的命令以尽可能有效地处理资源
我不是 FFMPEG 方面的专家,但我认为这些信息会对可能有类似问题的人有所帮助。