amishshah / prism-media

Easily transcode media using Node.js 🎶
https://amishshah.github.io/prism-media
Apache License 2.0
235 stars 54 forks source link

How to save opus stream to a file? #68

Open OnkelTem opened 3 years ago

OnkelTem commented 3 years ago

Is there a way to save an Opus stream into a file using prism-media?

Mesteery commented 3 years ago

https://github.com/amishshah/prism-media#what-is-it

// This example will demux and decode an Opus-containing OGG file, and then write it to a file.
const prism = require('prism-media');
const fs = require('fs');

fs.createReadStream('./audio.ogg')
  .pipe(new prism.opus.OggDemuxer())
  .pipe(new prism.opus.Decoder({ rate: 48000, channels: 2, frameSize: 960 }))
  .pipe(fs.createWriteStream('./audio.pcm')); // <--
amishshah commented 3 years ago

@Mesteery's solution is the closest thing you can do at the moment. I have plans to add an Ogg containeriser (is that a word?) stream to let you save Opus streams in .ogg files, but that will have to wait until the TypeScript refactor.

OnkelTem commented 3 years ago

Thanks @Mesteery, but I meant Opus stream, not raw/pcm. @amishshah

I have plans to add an Ogg containeriser (is that a word?)

Ogg Muxer?

but that will have to wait until the TypeScript refactor?

Could you please elaborate? Why TypeScript?

amishshah commented 3 years ago

@OnkelTem at the moment I'm prioritising refactoring the library to TypeScript to make it easier for me to maintain and add new features. I'd much rather write the Ogg muxer once in TypeScript, than have to port it from JavaScript to TypeScript.

However, I think I have a solution for this use-case in the meantime, see https://gist.github.com/amishshah/1f7e202dfb8f5595ebb19b9338a4d8f2

This will allow you to send your Opus streams to some other place (e.g. send them across processes, write to filesystem) and then recover them safely. Example usage:

Saving an Opus stream to filesystem:

createReadStream('file.ogg')
  .pipe(new prism.opus.OggDemuxer())
  .pipe(new Serialiser())
  .pipe(createWriteStream('file.nodestream'))

Later re-reading the Opus stream:

createReadStream('file.nodestream')
  .pipe(new Deserialiser())
  // now you have the original Opus packet object stream back

Essentially, it is a very lightweight alternative to the .ogg format and so it doesn't contain support for metadata, it stores only the Opus packets. Until I get the time to write the Ogg Muxer (I'm reluctant to call it this, since I'm planning on only supporting one input stream anyway), I think that this is a more than adequate solution.

OnkelTem commented 3 years ago

It's nice to hear that you support TypeScript, you have my vote on this!

I think I got the idea of your proposition of dumping packets. Well, in my case I'm implementing a history writer for an audio channel in Zello and I would want to have just normal OGG files at the end of course. Maybe it wouldn't be that difficult to package raw packets in a subset of OGG after all? You said "one input stream"? Maybe that would be enough.

amishshah commented 3 years ago

This is now being implemented in https://github.com/amishshah/prism-media/pull/70 :tada:

OnkelTem commented 3 years ago

Cool, gonna test it!