Search code examples
node.jsffmpegmediarecorderwebmweb-mediarecorder

How to convert and merge a list of webm files into a single large mp4 file with Node.js?


I am using MediaRecorder in the browser to get a chunk of webm file each 5 seconds, so it would end up with a list of webm files stored in AWS S3.

And then, I am currently trying to convert them into one single MP4 file within my Node.js application with the help of ffmpeg. My code looks like this:

async function convertAndMergeWebmStreams(webmStreams, outputFilePath) {
    return new Promise((resolve, reject) => {
        const command = ffmpeg();
    
        // Create a PassThrough stream to combine multiple readable streams
        const combinedStream = new PassThrough();
        
        // Pipe each webmStream into the combinedStream
        webmStreams.forEach(webmStream => {
            webmStream.pipe(combinedStream, { end: false });
        });

        // Set the combinedStream as the input for ffmpeg
        command.input(combinedStream);
    
        // Set input options
        command.inputOptions('-f webm');
    
        // Set output options
        command.outputOptions([
            '-c:v copy',
            '-c:a aac',
        ]);
    
        // Set the output format
        command.toFormat('mp4');
    
        // Set the output file path
        command.output(outputFilePath);
    
        // Event handling
        command
            .on('start', commandLine => {
                console.log('Spawned Ffmpeg with command: ' + commandLine);
            })
            .on('codecData', data => {
                console.log('Input is ' + data.audio + ' audio ' +
                'with ' + data.video + ' video');
            })
            .on('progress', progress => {
                console.log('Processing: ' + progress.percent + '% done');
            })
            .on('stderr', stderrLine => {
                console.log('Stderr output: ' + stderrLine);
            })
            .on('error', (err, stdout, stderr) => {
                console.error('Error converting and merging streams:', err);
                console.error('ffmpeg stdout:', stdout);
                console.error('ffmpeg stderr:', stderr);
                reject(err);
            })
            .on('end', () => {
                console.log('Conversion and merging finished successfully.');
                resolve();
            });
    
        // Run the command
        command.run();
    });
}

And now ffmpeg says that:

[matroska,webm @ 0x3712a6f0] EBML header parsing failed
[in#0 @ 0x3712a5f0] Error opening input: Invalid data found when processing input
Error opening input file pipe:0.
Error opening input files: Invalid data found when processing input

convertAndMergeWebmStreams error:  Error: ffmpeg exited with code 183: Error opening input file pipe:0.
Error opening input files: Invalid data found when processing input

Based on this link, it seems it is a known issue that it does not have a valid EBML header with MediaRecorder from browsers. Is there another way to merge them and get one single MP4 file?


Solution

  • Turns out it is because my webms are chunks of a larger file, which makes all files except the first one don't have a valid header. So what I need to do is to merge them in the correct order.