Change video resolution in loop

Viewed 486

I am trying to decrease the resolution of a video to under 500x500. I don't want to change it to exactly 500x500 because that would mess up video quality. So what I am trying to do is to decrease the resolution by 75% in a loop, and that loop would only stop when the video is under 500x500. In theory that would not be hard, but I can't seem to figure it out.

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
    }
}

This is the current code I am using with comments. Basically what happens is it gets stuck in the while loop because the dimensions of the video won't change. Tested with console.log() line. I think that if I can fix the ffmpeg problem somehow it will all be fixed. I'd appreciate any help :)

PS: This is all made in typescript, then build into js using npx tsc

1 Answers

The problem is that the loop prevents the callbacks from getting called because javascript runs on one thread (read more about this in this other SO question: Callback of an asynchronous function is never called). One of those callbacks that doesn't get called is the callback of then where the variables vidwidth and vidheight get changed, so the condition that checks if they're less than 500 and eventually break the loop is never true and the loop keeps running forever. This is not the proper way to deal with asynchronous functions anyway (read more about this in this other SO question: How do I return the response from an asynchronous call?).

By the way, copyFile and the while loop are not necessary at all for this kind of work, you can just use getDimensions to get the dimensions of the video, calculate the desired dimensions based on them and start an ffmpeg task (ffmpeg will handle the creation of the resulting file without altering the input file so no need for copyFile). Like so:

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();       
});

As simple as that!

Related