Search code examples
javascriptnode.jsexpressffmpegfluent-ffmpeg

Fluent-ffmpeg won't process/do anything with videos - Nodejs


I have this code:

const ffmpegPath = require("@ffmpeg-installer/ffmpeg").path;
const ffmpeg = require("fluent-ffmpeg");
ffmpeg.setFfmpegPath(ffmpegPath);

app.put("/upload-content", async (req, res) => {
  // 1. Get video and save locally to the server
  const video = req.files.video;
  const localTempPath = "./tmp/" + video.name;
  video.mv(localTempPath, function (error) {
      if (error) return res.send(error);
  });
  // 2. Convert video and apply settings
  processVideo(localTempPath).catch((err) => {
    return res.send(err);
  });
  return res.send("done");
});

function processVideo(localTempPath) {
  return new Promise((resolve, reject) => {
    ffmpeg(localTempPath)
    .withVideoCodec("libx264")
    .withSize("630x320")
    .withOutputFormat("avi")
    .on("error", (error) => reject("Failed to process video: " + error))
    .on("progress", (progress) => console.log(progress))
    .on("end", resolve("Successfully processed video"))
    .saveToFile(localTempPath);
  });
}

Nothing works, I have tried just taking away audio, tried changing the video codec, tried outputting instead of saving, tried it outside a promise. I've also tried different Paths etc. When the request is sent, the res.send('done') practically gets sent straight away so it clearing isn't running either, there's no errors and I know the function is getting run as I have put debug statements inside it...still nothing.


Solution

  • Couple of issues. You are not waiting for the mv callback. Either make it a promise as well or run the code after its callback. Try this.

    const ffmpegPath = require("@ffmpeg-installer/ffmpeg").path;
    const ffmpeg = require("fluent-ffmpeg");
    ffmpeg.setFfmpegPath(ffmpegPath);
    
    app.put("/upload-content", async(req, res) => {
        try {
            // 1. Get video and save locally to the server
            const video = req.files.video;
            const localTempPath = "./tmp/" + video.name;
            video.mv(localTempPath, async function(error) {
                if (error) return res.send(error);
                const resp = await processVideo(localTempPath);
                return res.send("done");
            });
    
        } catch (err) {
            return res.send(error);
        }
    });
    
    function processVideo(localTempPath) {
         return new Promise((resolve, reject) => {
        ffmpeg()
            .input(localTempPath)
            .withVideoCodec("libx264")
            .withSize("630x320")
            .withOutputFormat("avi")
            .on("error", (error) => reject("Failed to process video: " + error))
            .output(newpath)
            .on("progress", (progress) => console.log(progress))
            .on('end', function() {
                console.log('Finished processing');
            })
            .run();
    });;
    }
    

    Either make this function a promise or execute after its called back.

    video.mv(localTempPath, function (error) {
          if (error) return res.send(error);
     // save file if nothing went wrong. Also wait for processVideo to complete.
      });