运行 while循环中的ffmpeg导致内存泄漏
Running ffmpeg in a while loop causes memory leak
我正在尝试 运行 在 while
循环中执行以下 ffmpeg
命令 同步。
每次循环我都会等待当前命令完成,然后再继续下一个命令。但是我得到了意想不到的结果然后它崩溃了。
import ffmpegPath from '@ffmpeg-installer/ffmpeg'
import ffmpeg from 'fluent-ffmpeg'
ffmpeg.setFfmpegPath(ffmpegPath.path)
const command = ffmpeg()
let VIDEOS = 1000
let videoIdx = 1
while (videoIdx <= VIDEOS) {
await new Promise((resolve) => {
command
.on('end', () => {
setTimeout(() => {
console.log(`${videoIdx}/${VIDEOS}`)
videoIdx++
resolve()
}, 100)
})
.on('error', () => {
console.log('error = ', error)
})
.input(`MyExernalHardDrive/input/video-${videoIdx}-frame-%d.png`)
.inputFPS(1/0.0425)
.output(`MyExernalHardDrive/output/video-${videoIdx}.mp4`)
.outputFPS(24)
.noAudio()
.run()
})
}
我希望在控制台中看到:
1/1000
then
2/1000
then
3/1000
etc..
相反,我正在批量获取日志,例如:
1/1000
2/1000
3/1000
then
4/1000
5/1000
6/1000
7/1000
then it keeps incrementing but I get them in even bigger batches:
45/1000
46/1000
47/1000
48/1000
49/1000
50/1000
51/1000
52/1000
53/1000
54/1000
55/1000
然后我得到:
(node:14509) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 end listeners added to [FfmpegCommand].
Use emitter.setMaxListeners() to increase limit
然后我退出进程,这些是已创建的文件:
video-1.mp4
video-2.mp4
video-4.mp4
video-7.mp4
video-11.mp4
video-16.mp4
video-22.mp4
video-29.mp4
video-37.mp4
video-46.mp4
video-56.mp4
video-67.mp4
这么看来:
- 时间安排无处不在,根本没有顺序
- 进程不断堆积,直到出现内存泄漏
为什么会发生这种情况,因为我在进入下一个过程之前使用 await
,我该如何解决这个问题?
// ...
const command = ffmpeg()
let VIDEOS = 1000
let videoIdx = 1
while (videoIdx <= VIDEOS) {
await new Promise((resolve) => {
command
.on('end', () => {
setTimeout(() => {
console.log(`${videoIdx}/${VIDEOS}`)
videoIdx++
resolve()
}, 100)
})
// ...
变量 command
中的 ffmpeg
实例在每个循环中重复使用。它是一个事件发射器,不应该重复使用,因为有些事件只触发一次,比如“结束”。此单个实例上的“结束”事件接收到许多侦听器。 Node 运行时发出警告,因为这通常不是您想要的(如果是,您可以选择加入以禁用限制)。
解决方案是不要重复使用同一个实例:
// ...
let VIDEOS = 1000
let videoIdx = 1
while (videoIdx <= VIDEOS) {
await new Promise((resolve) => {
ffmpeg()
.on('end', () => {
setTimeout(() => {
console.log(`${videoIdx}/${VIDEOS}`)
videoIdx++
resolve()
}, 100)
})
// ...
现在每次循环迭代都会创建一个全新的实例。
我正在尝试 运行 在 while
循环中执行以下 ffmpeg
命令 同步。
每次循环我都会等待当前命令完成,然后再继续下一个命令。但是我得到了意想不到的结果然后它崩溃了。
import ffmpegPath from '@ffmpeg-installer/ffmpeg'
import ffmpeg from 'fluent-ffmpeg'
ffmpeg.setFfmpegPath(ffmpegPath.path)
const command = ffmpeg()
let VIDEOS = 1000
let videoIdx = 1
while (videoIdx <= VIDEOS) {
await new Promise((resolve) => {
command
.on('end', () => {
setTimeout(() => {
console.log(`${videoIdx}/${VIDEOS}`)
videoIdx++
resolve()
}, 100)
})
.on('error', () => {
console.log('error = ', error)
})
.input(`MyExernalHardDrive/input/video-${videoIdx}-frame-%d.png`)
.inputFPS(1/0.0425)
.output(`MyExernalHardDrive/output/video-${videoIdx}.mp4`)
.outputFPS(24)
.noAudio()
.run()
})
}
我希望在控制台中看到:
1/1000
then
2/1000
then
3/1000
etc..
相反,我正在批量获取日志,例如:
1/1000
2/1000
3/1000
then
4/1000
5/1000
6/1000
7/1000
then it keeps incrementing but I get them in even bigger batches:
45/1000
46/1000
47/1000
48/1000
49/1000
50/1000
51/1000
52/1000
53/1000
54/1000
55/1000
然后我得到:
(node:14509) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 end listeners added to [FfmpegCommand].
Use emitter.setMaxListeners() to increase limit
然后我退出进程,这些是已创建的文件:
video-1.mp4
video-2.mp4
video-4.mp4
video-7.mp4
video-11.mp4
video-16.mp4
video-22.mp4
video-29.mp4
video-37.mp4
video-46.mp4
video-56.mp4
video-67.mp4
这么看来:
- 时间安排无处不在,根本没有顺序
- 进程不断堆积,直到出现内存泄漏
为什么会发生这种情况,因为我在进入下一个过程之前使用 await
,我该如何解决这个问题?
// ...
const command = ffmpeg()
let VIDEOS = 1000
let videoIdx = 1
while (videoIdx <= VIDEOS) {
await new Promise((resolve) => {
command
.on('end', () => {
setTimeout(() => {
console.log(`${videoIdx}/${VIDEOS}`)
videoIdx++
resolve()
}, 100)
})
// ...
变量 command
中的 ffmpeg
实例在每个循环中重复使用。它是一个事件发射器,不应该重复使用,因为有些事件只触发一次,比如“结束”。此单个实例上的“结束”事件接收到许多侦听器。 Node 运行时发出警告,因为这通常不是您想要的(如果是,您可以选择加入以禁用限制)。
解决方案是不要重复使用同一个实例:
// ...
let VIDEOS = 1000
let videoIdx = 1
while (videoIdx <= VIDEOS) {
await new Promise((resolve) => {
ffmpeg()
.on('end', () => {
setTimeout(() => {
console.log(`${videoIdx}/${VIDEOS}`)
videoIdx++
resolve()
}, 100)
})
// ...
现在每次循环迭代都会创建一个全新的实例。