NodeJs: How to pipe two streams into one spawned p

2019-07-20 03:13发布

问题:

In order to convert PCM audio to MP3 I'm using the following:

function spawnFfmpeg() {
    var args = [
        '-f', 's16le',
        '-ar', '48000',
        '-ac', '1',
        '-i', 'pipe:0',
        '-acodec', 'libmp3lame',
        '-f', 'mp3',
        'pipe:1'
    ];

    var ffmpeg = spawn('ffmpeg', args);

    console.log('Spawning ffmpeg ' + args.join(' '));

    ffmpeg.on('exit', function (code) {
        console.log('FFMPEG child process exited with code ' + code);
    });

    ffmpeg.stderr.on('data', function (data) {
        console.log('Incoming data: ' + data);
    });

    return ffmpeg;
}

Then I pipe everything together:

writeStream = fs.createWriteStream( "live.mp3" );
var ffmpeg = spawnFfmpeg();
stream.pipe(ffmpeg.stdin);
ffmpeg.stdout.pipe(/* destination */); 

The thing is... Now I want to merge (overlay) two streams into one. I already found how to do it with ffmpeg: How to overlay two audio files using ffmpeg

But, the ffmpeg command expects two inputs and so far I'm only able to pipe one input stream into the pipe:0 argument. How do I pipe two streams in the spawned command? Would something like ffmpeg -i pipe:0 -i pipe:0... work? How would I pipe the two incoming streams with PCM data (since the command expects two inputs)?

回答1:

You could use named pipes for this, but that isn't going to work on all platforms.

I would instead do the mixing in Node.js. Since your audio is in normal PCM samples, that makes this easy. To mix, you simply add them together.

The first thing I would do is convert your PCM samples to a common format... 32-bit float. Next, you'll have to decide how you want to handle cases where both channels are running at the same time and both are carrying loud sounds such that the signal will "clip" by exceeding 1.0 or -1.0. One option is to simply cut each channel's sample value in half before adding them together.

Another option, depending on your desired output, is to let it exceed the normal range and pass it to FFmpeg. FFmpeg can take in 32-bit float samples. There, you can apply proper compression/limiting to bring the signal back under clipping before encoding to MP3.