Estoy tratando de disminuir la resolución de un video a menos de 500x500. No quiero cambiarlo a exactamente 500x500 porque eso estropearía la calidad del video. Entonces, lo que estoy tratando de hacer es disminuir la resolución en un 75% en un bucle, y ese bucle solo se detendría cuando el video esté por debajo de 500x500. En teoría, eso no sería difícil, pero parece que no puedo entenderlo.

var vidwidth = 501; //Create variable and put it to 501
var vidheight = 501; //so that it won't go through the If Statement
fs.copyFile(filepath2, './media/media.mp4', (err: any) => { //Copy given file to directory
    console.log('filepath2 was copied to media.mp4'); //Log confirmation (Not appearing for some reason, but file is copied)
})
while (true) {
    getDimensions('./media/media.mp4').then(function (dimensions: any) { //Get dimensions of copied video
        var vidwidth = parseInt(dimensions.width)   //Parse to Int
        var vidheight = parseInt(dimensions.height) //and put in variables
    })
    ffmpeg('./media/media.mp4')                 //Call ffmpeg function with copied video path
        .output('./media/media.mp4')            //Set output to the same file so we can loop it
        .size('75%')                            //Reduce resolution by 75%
        .on('end', function() {                 //Log confirmation on end
            console.log('Finished processing'); //(Not appearing)
        })                                      //
        .run();                                 //Run function
    if (vidwidth < 500 && vidheight < 500) {    //Check if both the width and height is under 500px
        break;                                  //If true, break the loop and continue
    }
}

Este es el código actual que estoy usando con comentarios. Básicamente, lo que sucede es que se atasca en el ciclo while porque las dimensiones del video no cambiarán. Probado con la línea console.log(). Creo que si puedo solucionar el problema de ffmpeg de alguna manera, todo se solucionará. Agradecería cualquier ayuda :)

PD: Todo esto está hecho en mecanografiado, luego se construye en js usando npx tsc

2
WoJo 24 jul. 2020 a las 16:29

1 respuesta

La mejor respuesta

El problema es que el bucle evita que se llamen las devoluciones de llamada porque javascript se ejecuta en un hilo (lea más sobre esto en esta otra pregunta SO: Callback de una función asincrónica nunca se llama). Una de esas devoluciones de llamada que no se llama es la devolución de llamada de then donde las variables vidwidth y vidheight se cambian, por lo que la condición que verifica si son menores de 500 romper el ciclo nunca es true y el ciclo sigue funcionando para siempre. De todos modos, esta no es la forma correcta de lidiar con las funciones asincrónicas (lea más sobre esto en esta otra pregunta SO: ¿Cómo devuelvo la respuesta de una llamada asincrónica?).

Por cierto, copyFile y el bucle while no son necesarios en absoluto para este tipo de trabajo, puedes usar getDimensions para obtener las dimensiones del video, calcular las dimensiones deseadas según en ellos e iniciar una tarea ffmpeg (ffmpeg manejará la creación del archivo resultante sin alterar el archivo de entrada, por lo que no es necesario copyFile). Al igual que:

getDimensions(filepath2).then((dimensions: any) => {                            // get the dimension of the input file
  let sizeStr = dimensions.width < dimensions.height ? "?x500" : "500x?";       // if width is smaller than height, reduce the height to 500 and calculate width based on that, same goes for the other way around
  
  ffmpeg(filepath2)                                                             // the input is the original video, don't worry 'ffmpeg' won't alter the input file
    .output('./media/media.mp4')                                                // the output file path
    .size(sizeStr)                                                              // use the 'sizeStr' string calculated previously (read more about it here: https://github.com/fluent-ffmpeg/node-fluent-ffmpeg#video-frame-size-options) 
    .on('end', () => console.log('Finished processing'))
    .run();       
});

¡Tan sencillo como eso!

2
ibrahim mahrir 24 jul. 2020 a las 14:43