ffmpegwasm / ffmpeg.wasm

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

How do I return/retrieve data such as supported fomats? #277

Open Fanna1119 opened 3 years ago

Fanna1119 commented 3 years ago

When the logger is on:

const ffmpeg = createFFmpeg({
  log: true,
  // corePath: 'https://unpkg.com/@ffmpeg/core@0.10.0/dist/ffmpeg-core.js'
  logger: (msg) => {
    //log msg if type == 'ffer'
    if (msg.type === 'ffer') {
      console.log(msg.message);
    }
  },
});

And I run:

let check = await ffmpeg.run("-formats")
console.log(check)

it does return the formats in the log so the command itself works. But How do I retrieve the data. the check variable returns undefined Which makes sense since ffmpeg.run does not return anything.

julienbeisel commented 3 years ago

I would first store it in the FS:

await ffmpeg.run("-formats", ">", "formatList.txt")

And then read it:

let check = ffmpeg.FS('readFile', 'formatList.txt');
AnsgarLichter commented 4 months ago

I tried this approach and get an FS error evrytime - the log shows the following: image

I don't know what the reason for the Aborted() at the end is. This is my code:

await ffmpeg.createDir("test");
    ffmpeg.writeFile("test/test.txt", new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]));
    const successVersion = await ffmpeg.exec(["-version", ">", "test/version.txt"]);

    const data = await ffmpeg.listDir("test");
    ffmpeg.readFile("test/version.txt").catch((error) => console.error(error));

The data directory does not contain the version.txt after I execute the -version command. Does somebody know why the file is not written?

DerStimmler commented 4 months ago

I think > is not possible because thats a shell specific operation and probably not available in the ffmpeg.wasm context.

Another solution would be to use the -report option to create a log file. But in my tests the output of -formats doesn't get logged to the file regardless of the loglevel.

So I think the only way is to parse the ffmpeg.wasm logs.

First, capture the logs.

let log = "";
ffmpeg = new FFmpeg();
ffmpeg.on("log", ({ message }) => {
    log += message + "\n";
});

Second, execute the -formats command.

await ffmpeg.exec(["-formats"]);

Third, parse the logs.

const formats = getFormatsFromLog(log);

function getFormatsFromLog(log: string) {
    const formatLineRegex = /^(D|DE|E)\s+(\S+)\s+(.+)$/;
    const results = [];

    const lines = log.split("\n");

    for (const line of lines) {
        // Trim any leading or trailing whitespace
        const trimmedLine = line.trim();

        // Skip lines that don't start with 'D', 'DE', or 'E'
        if (formatLineRegex.test(trimmedLine)) {
            // Use a regex to match and capture support, abbreviation, and name
            const match = trimmedLine.match(formatLineRegex);
            if (match) {
                const [, support, abbreviation, name] = match;

                const demuxingSupported = support.includes("D");
                const muxingSupported = support.includes("E");
                results.push({
                    demuxingSupported,
                    muxingSupported,
                    abbreviation,
                    name,
                });
            }
        }
    }

    return results;
}

This output:

File formats:
 D. = Demuxing supported
 .E = Muxing supported
 --
 D  3dostr          3DO STR
  E 3g2             3GP2 (3GPP2 file format)
  E 3gp             3GP (3GPP file format)
 D  4xm             4X Technologies
  E a64             a64 - video for Commodore 64
 D  aa              Audible AA format files
 D  aac             raw ADTS AAC (Advanced Audio Coding)
 D  aax             CRI AAX
 DE ac3             raw AC-3
 ...

Will give you this array:

[
    {
        "demuxingSupported": true,
        "muxingSupported": false,
        "abbreviation": "3dostr",
        "name": "3DO STR"
    },
    {
        "demuxingSupported": false,
        "muxingSupported": true,
        "abbreviation": "3g2",
        "name": "3GP2 (3GPP2 file format)"
    },
    {
        "demuxingSupported": false,
        "muxingSupported": true,
        "abbreviation": "3gp",
        "name": "3GP (3GPP file format)"
    },
    {
        "demuxingSupported": true,
        "muxingSupported": false,
        "abbreviation": "4xm",
        "name": "4X Technologies"
    },
    {
        "demuxingSupported": false,
        "muxingSupported": true,
        "abbreviation": "a64",
        "name": "a64 - video for Commodore 64"
    },
    {
        "demuxingSupported": true,
        "muxingSupported": false,
        "abbreviation": "aa",
        "name": "Audible AA format files"
    },
    {
        "demuxingSupported": true,
        "muxingSupported": false,
        "abbreviation": "aac",
        "name": "raw ADTS AAC (Advanced Audio Coding)"
    },
    {
        "demuxingSupported": true,
        "muxingSupported": false,
        "abbreviation": "aax",
        "name": "CRI AAX"
    },
    {
        "demuxingSupported": true,
        "muxingSupported": true,
        "abbreviation": "ac3",
        "name": "raw AC-3"
    }
]
AnsgarLichter commented 4 months ago

Thanks @DerStimmler, this solution works fine. It would be more comftorable if you needn't parse the logs, but I don't see any other solution here.