Moebits / waifu2x

waifu2x image upscaling in Node.js
MIT License
70 stars 11 forks source link

Specify ffmpeg binary path #6

Closed Specy closed 3 years ago

Specy commented 3 years ago

fluid-ffmpeg has a function called Ffmpeg.setFfmpegPath(path) to specify the path of ffmpeg, I suggest adding something to specify the path of ffmpeg so that It can be more easily bundled in projects as you only need to specify the path of the bin for it to work.

Moebits commented 3 years ago

Set the ffmpegPath option.

Specy commented 3 years ago

Using 0.3.1 and the waifu2x.upscaleVideo() with code:

const ffmpegBin = require('@ffmpeg-installer/ffmpeg');
            let videoOptions = {
                framerate:24,
                quality:16,
                speed:1,
                absolutePath: true,
                ffmpegPath: ffmpegBin.path
            }
            output = await waifu2x.upscaleVideo(filePath,endPath,videoOptions,callback)

The extraction of frames and upscale works as intended but when it's encoding i get:

Error: ffmpeg exited with code 1: Stream specifier ':a' in filtergraph description [0:v]setpts=1*PTS[v];[0:a]atempo=1[a] matches no streams.

    at ChildProcess.<anonymous> (C:\Users\dione\Desktop\Progetti\electron\scapix\node_modules\fluent-ffmpeg\lib\processor.js:182:22)
    at ChildProcess.emit (events.js:315:20)

Do you have a working example? what binary are you using for ffmpeg (if you had successful results)?

Moebits commented 3 years ago

Can you upgrade to v0.3.2? If it doesn't work can you send me your video file? I also removed the absolutePath option because I just check if the input paths are absolute or not.

Specy commented 3 years ago

Ok looks like specifying the speed option causes the error (tried with 1), also, is there a way to set the frame rate to the original video frame rate? also if i understood correctly, if i do quality:0 then i get the highest quality right?

Moebits commented 3 years ago

No, that doesn't make sense. I set the speed and it works fine. Can you post your video file? Does it have audio or not?

Specy commented 3 years ago

Original:

https://user-images.githubusercontent.com/59029985/105640576-20dacd80-5e7f-11eb-8c29-57aa3ba0df94.mp4

Upscaled:

https://user-images.githubusercontent.com/59029985/105640600-34863400-5e7f-11eb-9da5-67e88b5cf2a1.mp4

Takes about 1 minute to process

this is the working options:

            let videoOptions = {
                framerate:24,
                quality:0,
                noise: noise,
                scale: el.scale,
                ffmpegPath: ffmpegBin.path
            }

If i add speed:1 it generates the error mentioned before.

Specy commented 3 years ago

Also, could you please add the file name to the videoFrames temp directory? it would cause conflicts if there were two videos being upscaled in parallel

Moebits commented 3 years ago

If you upgrade to 0.3.3 then it works on your video. Omit the framerate to use the original. It uses ffprobe so set ffprobePath if needed.

Also, could you please add the file name to the videoFrames temp directory? it would cause conflicts if there were two videos being upscaled in parallel

It doesn't even get called videoFrames. It's [filename]Frames, up to you to rename the videos if you have multiple "video.mp4".

Specy commented 3 years ago

Ah sorry right, I was upscaling a video called video.mp4 and saw that path name so I thought it was always like that.

Specy commented 3 years ago

There's a workaround to not include ffprobe to get the fps of the video, this is what i came up with:

async function getFps (filePath){
    let command = "cd "+pathToFfmpeg+" && ffmpeg -i " + filePath +" 2>&1"
    return new Promise((resolve,reject) =>{
        exec(command,(err,stdout) => {
            let fps
            try{
                let regex = new RegExp("[0-9]* fps,")
                fps = regex.exec(stdout.toString())
                if(fps){
                    fps = fps[0].split(" ")[0]
                    fps = parseFloat(fps)
                }else{
                    fps = null
                }
            }catch{
                fps = null
            }
            resolve(fps)
        })
    })
}

Sharing in case it could be useful

Specy commented 3 years ago

Ah sorry right, I was upscaling a video called video.mp4 and saw that path name so I thought it was always like that.

Did you change something about where the files are saved since this comment? when i was using 0.3.2 the output gif / video were saved in the outputPath, now in 0.3.5 they are saved in outputPath + filename Example by upscaling a video called "video.mp4", the final path will be at "video.mp4/video.mp4" .

In case you did change it, wouldn't it be better to save the file in the same directory where it was specified? in the original comment i just had a misunderstanding with the temp path, it was fine like it was

Moebits commented 3 years ago

I kept getting Error: Command failed because ffmpeg wanted an output file, so I needed to catch the stderr as well. I'm not sure what 2>&1 is but it works without it. Also, use regex lookaheads (?=fps,) if you want to exclude that string from the match.

private static parseFramerate = async (file: string, ffmpegPath?: string) => {
        let command = `ffmpeg -i ${file}`
        if (ffmpegPath) command = `cd ${ffmpegPath} && ${command}`
        const str = await exec(command).then((s: any) => s.stdout).catch((e: any) => e.stderr)
        return Number(str.match(/[0-9]* (?=fps,)/)[0])
}

Example by upscaling a video called "video.mp4", the final path will be at "video.mp4/video.mp4" .

I can't replicate this. It should be exactly the same.

Specy commented 3 years ago

Ah strange, for me it worked with 2>&1 but didn't work without (without it generated the error). And yea I'm not that good at regex as you can see.

For the file being in a folder I'll have to see if it's an issue on my end then, since I didn't change anything and got different results I thought you made some changes, will ask further in case I still have the issue

Specy commented 3 years ago

ok so from here it seems that the endPath is only the ending folder and shouldn't include the file name (for videos and gifs), right ? While for images, it needs also the file name. This is strange honestly, shouldn't it always be like the upscaleImage? so for example:

waifu2x.upscaleVideo("./path/video.mp4","./upscaled/video.mp4", options, callaback)

this code above should save a file called video.mp4 in the upscaled folder but instead saves it in /upscaled/video.mp4/video.mp4

example, i just tried this, using ending path as

C:\Users\dione\Desktop\Progetti\electron\scapix\electron\results\26-0\ezgif-4-488cb1d7a8fe.gif

and result is this image

Moebits commented 3 years ago

this code above should save a file called video.mp4 in the upscaled folder but instead saves it in /upscaled/video.mp4/video.mp4

Please only post the exact code that is giving you the result, as in this case it was only for absolute paths not relative. It was fixed on v0.3.7. And you can pass either a directory or filepath.

Specy commented 3 years ago

Yes sorry, it was just to not rewrite the whole absolute path, also it works perfectly in v0.3.7 thanks