1

This is how I did it.

const ffmpegPath = require('@ffmpeg-installer/ffmpeg');
import ffmpeg from 'fluent-ffmpeg';
import path from 'path';
const os = require('os');
ffmpeg.setFfmpegPath(ffmpegPath.path);


export const generateThumbnailFromVideo = async (mp4Buffer) => {
    console.log('generateThumbnailFromVideo is triggered');
    const timePosition = '00:00:00.500';
    const filename = `temp/temp-${new Date().getTime()}.png`;
    return new Promise((resolve, reject) => {
        ffmpeg({
            source: bufferToStream(mp4Buffer)
        })
        .on('error', (err) => {
            console.error('An error occurred: ' + err.message);
            reject(err);
        })
        .on('end', () => {
            console.log('Thumbnail generated successfully');
            fs.readFile(filename, (err, data) => {
                if (err) {
                    console.error('An error occurred while reading the thumbnail file:', err);
                    reject(err);
                    return;
                }
                fs.unlink(filename);
                uploadBuffer(data, filename, data.length)
            })
            resolve(filename);
        })
        .screenshots({
            timestamps: [timePosition],
            filename: filename,
            folder: 'temp/',
            size: '320x240',
        });
    });
}

And this is the log came up.

generateThumbnailFromVideo is triggered
Thumbnail generated successfully
createProjectMedia is triggered
userId:  1
projectId:  25
mediaArray:  [
  {
    mediaUrl: 'medias/1/1686843801535/medias_1_1684753043519_1_(1)_(4)_(1).mp4',
    thumbnailUrl: 'medias/1/1686843801535/medias_1_1684753043519_1_(1)_(4)_(1)_thumbnail.jpg',
    mediaType: 2
  }
]
An error occurred while reading the thumbnail file: [Error: ENOENT: no such file or directory, open 'temp/temp-1686843802255.png'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'temp/temp-1686843802255.png'
}

It claims the screenshot has been created but I cannot find it anywhere. Tried absolute route with __dirname and os.tmpdir() with no luck. The screenshot it claimed has been created are not there.

Can somebody help me out? I have been stuck here for 5 hours with no progress so far.

Also, I have checked the file temp in the root directory of the repo. It is empty.

UPDATE: Checked and can confirm that the router used in the key "folder" (temp/) is correct, since deleting that folder will trigger an error saying that the folder is not found. Creating the folder again will remove this error. But even though the "generated successfully" log is printed, the image is not saved in that folder, and the folder is still empty after that log is printed.

That fs.unlink is also unrelated. Removing it won't cause any change.

Terry Windwalker
  • 1,343
  • 2
  • 16
  • 36
  • If you are using "node-ffmpeg", it has a function called `fnExtractFrameToJPG`. Have you tried using that? Also, I don't understand where the `screenshot` function is coming from? Can you post the npm packages that you are using – deepanshu Jun 16 '23 at 04:49
  • @deepanshu Updated. I am using `fluent-ffmpeg` but can give `node-ffmpeg` a try. – Terry Windwalker Jun 16 '23 at 06:25
  • I believe `filename` is the problem. Can you try removing `temp/` prefix from the same? – deepanshu Jun 16 '23 at 07:33
  • Moreover the documentation says: `screenshot will not work on input streams`. Is that a problem? – deepanshu Jun 16 '23 at 07:36
  • @deepanshu You mean removing `temp/` and leave the folder field empty? Also, I tried storing the videos locally and using their routes, and that didn't work either. – Terry Windwalker Jun 16 '23 at 08:34
  • I tested this stuff locally, and was able to succesfully create thumbnail file by, firstly, changing argument to video file path ( `abc.mp4` ) instead of a stream (`{ source: bufferToStream(mp4Buffer) }`), in `ffmpeg` function. Secondly, removing `folder` property from `screenshot` method. Can you test this out? – deepanshu Jun 16 '23 at 13:20
  • @deepanshu Just tried and it works! Thanks a lot! Can you post an answer below so I can accept it? – Terry Windwalker Jun 16 '23 at 20:54

1 Answers1

1

To make this work, you are required to do two things.

First, change the argument of ffmpeg fuction, from a stream to a file path. ffmpeg({source: bufferToStream(mp4Buffer)}) => ffmpeg("abc.mp4"). Because according to docs,

It will not work on input streams

Second, remove the folder property from screenshot method, as you've already specified designated folder in filename variable.

const filename = `temp/temp-${new Date().getTime()}.png`;

and your screenshot method becomes:

  .screenshots({
        timestamps: [timePosition],
        filename: filename,
        size: '320x240',
    });
deepanshu
  • 625
  • 5
  • 15