es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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:

  1. El tiempo está desordenado y no es secuencial en absoluto.
  2. 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?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El problema es que el comando run() de ffmpeg en realidad no es síncrono y se devuelve inmediatamente antes de que el proceso haya terminado. Al usar await en la Promise, solo estamos esperando que ocurra el evento end del proceso ffmpeg 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 evento close, lo cual indica que ffmpeg ha completado su procesamiento. También necesitamos escuchar el evento stderr 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:

    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', () => {
            console.log(`${videoIdx}/${VIDEOS}`)
            videoIdx++
            resolve()
          })
          .on('error', (err) => {
            console.log('Error:', err)
          })
          .on('stderr', (stderrLine) => {
            console.log('StdErr:', stderrLine) // Imprimir stderr en la consola
          })
          .input(`MyExternalHardDrive/input/video-${videoIdx}-frame-%d.png`)
          .inputFPS(1 / 0.0425)
          .output(`MyExternalHardDrive/output/video-${videoIdx}.mp4`)
          .outputFPS(24)
          .noAudio()
          .run()
          .on('close', () => {
            resolve()
          })
      })
    }
    

    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.

Comments are closed.