Ejecutar ffmpeg en un bucle while causa una fuga de memoria.
Estoy intentando ejecutar los siguientes comandos de ffmpeg
en un bucle while
de forma sincrónica.
En cada vuelta del bucle, espero a que el comando actual termine antes de pasar al siguiente. Sin embargo, estoy obteniendo resultados inesperados y luego se produce un error.
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()
})
}
En la consola espero ver:
“`
1/1000
luego
2/1000
luego
3/1000
etc..
En su lugar, obtengo registros en lotes como:
1/1000
2/1000
3/1000
luego
4/1000
5/1000
6/1000
7/1000
y luego sigue incrementándose, pero los lotes son aún más grandes:
45/1000
46/1000
47/1000
48/1000
49/1000
50/1000
51/1000
52/1000
53/1000
54/1000
55/1000
Y luego obtengo:
(node:14509) MaxListenersExceededWarning: Se ha detectado una posible fuga de memoria EventEmitter.
11 escuchas de fin añadidas a [FfmpegCommand].
Usa emitter.setMaxListeners() para aumentar el límite
Entonces salgo del proceso y estos son los archivos que se han creado:
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
Por lo tanto, parece que:
- El tiempo está desordenado y no es secuencial en absoluto.
- Los procesos se acumulan hasta que hay una fuga de memoria.
¿Por qué está sucediendo esto si estoy usando await
antes de pasar al siguiente proceso y cómo puedo solucionarlo?
davy.ai
El problema es que el comando
run()
deffmpeg
en realidad no es síncrono y se devuelve inmediatamente antes de que el proceso haya terminado. Al usarawait
en laPromise
, solo estamos esperando que ocurra el eventoend
del procesoffmpeg
actual, pero no estamos esperando a que el proceso completo se complete antes de pasar a la siguiente iteración del bucle.Para solucionar esto, podemos usar la
Promise
para esperar a que ocurra el eventoclose
, lo cual indica queffmpeg
ha completado su procesamiento. También necesitamos escuchar el eventostderr
para evitar que el proceso se bloquee si hay errores en la salida.Aquí tienes una versión actualizada del código con los cambios mencionados:
Esto asegurará que cada proceso
ffmpeg
se complete antes de pasar a la siguiente iteración del bucle y evitará la acumulación de memoria debido a la acumulación de listeners.