ffmpegwasm / ffmpeg.wasm

FFmpeg for browser, powered by WebAssembly
https://ffmpegwasm.netlify.app
MIT License
13.45k stars 772 forks source link

(bug/question) How to properly use one ffmpeg.exec() execution output as another's ffmpeg.exec() input? #749

Open knuurr opened 1 month ago

knuurr commented 1 month ago

Describe the bug Whenever I'm using previous ffmpeg.exec() output filename (i.e output-temp.mp4) in next ffmpeg.exec operation is input (by passing string with filename to -i), transformations do not stack - instead only first operation called gets presented.

To Reproduce

Here's a code simillar to which I run in my project. For this scenario let's assume all conditionals are met (As I do in my environment, with console output). In the final stage, video is presented in <video> element and blob data is used in src attribute, to return effect of ffmpeg processing to the user visually.

To verify that it's not problem with logic or ffmpeg commands, all that I need is to specify in some step different output name i.e output.mp4 and then use that as data for blob. This way I can verify that my transformation are working properly (just as in debugging bash script I maintain).

NAME_TEMP_OUTPUT = "output_temp.mp4";
...
async function convertVideo(file) {
    await ffmpeg.exec([
      "-i",
      DATA.NAME_GREENSCREEN_PNG,
      "-i",
      file.name,
      "-filter_complex",
      "... (transformation)",
      "-c:v",
      "libx264",
      "-c:a",
      "copy",
      "-preset",
      "ultrafast",
      DATA.NAME_TEMP_OUTPUT,
    ]);
}

    if (conditional1) {
      console.log("conditional 1 runs");
      await ffmpeg.writeFile(
        DATA.NAME_TEMPLATE_VIDEO,
        await fetchFile(DATA.PATH_TEMPLATE_VIDEO),
      );
      await ffmpeg.exec([
        "-i",
        DATA.NAME_TEMP_OUTPUT,
        "-i",
        DATA.NAME_TEMPLATE_VIDEO,
        "-filter_complex",
        "...",
        "-map",
        "[v]",
        "-map",
        "[a]",
        "-preset",
        "ultrafast",
        DATA.NAME_TEMP_OUTPUT,
      ]);
    }
....
    if (conditional2) {
      console.log("Conditional 2 runs");
      await ffmpeg.writeFile(
        DATA.NAME_INTRO_AUDIO,
        await fetchFile(DATA.NAME_INTRO_AUDIO),
      );
      await ffmpeg.exec([
        "-i",
        DATA.NAME_TEMP_OUTPUT, // Input video file
        "-i",
        DATA.NAME_INTRO_AUDIO, // Input audio file
        "-filter_complex",
        "..."
        "-c:v",
        "copy", // Copy video stream without re-encoding
        DATA.NAME_TEMP_OUTPUT, // Output file name
        // "output.mp4", // Output file name
      ]);
      // await ffmpeg.writeFile(DATA.NAME_TEMP_OUTPUT, DATA.NAME_TEMP_OUTPUT);
    }

        const data = await ffmpeg.readFile("output.mp4");
    // const data = await ffmpeg.readFile(DATA.NAME_TEMP_OUTPUT);

Expected behavior Whenever I use name for output, such as 'temp_output.mp4', and use this name in string format as another ffmpeg.exec() input file (i.e -i temp_output.mp4 ), ffmpeg wil use the latest version of the file with latest applied transformations in memory.

Screenshots

Desktop (please complete the following information):

Additional context Add any other context about the problem here.

tiuvi commented 1 month ago

Doing this does not interest you because you will be duplicating memory. Better write the original file, process it with ffmpeg, delete the original file, read the new processed file and send it to the new output. image This is my wrapper function for the exe command

knuurr commented 1 month ago

Thanks @tiuvi I've taken a look at your logic, learned form how do you do it, and looks like it solves my issue, at least from my experiments. I've been debugging with ffmpeg.listDir() method and from what I see, any intrmediate steps get removed in process.

Do you have any solution if I just wanted to prune any custom element within filesystem and start from scratch? because I'm not sure, if I destroy and reinitialize FFMpeg object, it won't get re-downloaded again - scenario I'd like to avoid at all costs.

tiuvi commented 3 weeks ago

I always end the ffmpeg process ` const terminateFfmpeg = globalThis[nameGlobal]['terminateFfmpeg'] = function () {

    try {

        $ffmpeg.ffmpeg.terminate();
        return ({ err: null })
    } catch (error) {
        return ({ err: err.message })
    }

    return ({ err: null })

}`

This is the file where I am working with ffmpeg to make a video editor in conjunction with webcodecs
https://cell1.tiuvi.com:1030/ffmpegToolkit.js

This is a thread where I hope to reduce the memory by half by passing the buffer by reference
https://github.com/ffmpegwasm/ffmpeg.wasm/issues/745#issuecomment-2146063353

You need to combine url.createurl with the ffmpeg outputs, nothing much can be done.