问题
I need to read OPUS packets one by one from ogg/opus file and send them further in OPUS format so without decoding. I'm looking at opusfile lib but API and examples are rather complicated and more focused on decoding the file and getting resulted PCM. Is there a way to achieve what I want with this lib and how? If not what other options do I have?
回答1:
libogg could be used to parse the Ogg Opus file's "pages", and then the opus "packets" could then be extracted from those pages. Mind that packets may span across pages, but I have personally not come across that when testing files created by opusenc. You could also parse the pages manually (see Splitting an Ogg Opus File stream)
I recommend reading the basics of the Opus File Spec (RFC 7845) to understand the file structure first. https://opus-codec.org/docs/
回答2:
You can use libogg to get access to the Opus packets. It's not all that much simpler than opusfile
unfortunately. In C-ish pseudocode, the general flow is:
readPage(ogg_sync_state* syncState, ogg_page* page, file) {
while ((ogg_sync_pageout(syncState, page) != 1) && file is good) {
buffer = ogg_sync_buffer(syncState, yourMaxReadSize);
bytesActuallyRead = read(file, buffer, yourMaxReadSize);
ogg_sync_wrote(syncState, bytesActuallyReadFromFile); //tell the syncState how many bytes were actually read
} //now we have a page, or the file is done
}
read() {
ogg_sync_state oggSyncState;
ogg_stream_state oggStreamState;
ogg_page oggPage;
ogg_packet oggPacket;
open file;
while (file is good) {
readPage(&oggSyncState, &oggPage);
if (ogg_page_bos(&oggPage)) {
sn = ogg_page_serialno(&oggPage); //you can remember this serial number and check it on every page for robustness
ogg_stream_init(&oggStreamState, sn);
}
ogg_stream_pagein(&oggStreamState, &oggPage);
while (ogg_stream_packetout(&oggStreamState, &oggPacket) != 0) {
//check if it's a header packet, skip if so.
//See https://tools.ietf.org/html/rfc7845.html#section-5 to see how to identify a header packet
//Else it must be data
do something with the buffer oggPacket.packet with size oggPacket.bytes
}
readPage(&oggSyncState, &oggPage, file);
ogg_stream_pagein(&oggStreamState, &oggPage_);
}
}
readPage
pulls a bunch of bytes (yourMaxReadSize
) from the file into the oggSyncState
structure, and then extracts pages one by one. In read
, packets are extracted from the pages one by one.
回答3:
I guess I am slightly late. I had very similar use case, I wanted to extract opus packets from ogg opus file. I found this answer
https://stackoverflow.com/a/26285277/10110652
Following code will help you to get opus packets (without been decoded to pcm) in 'nextPacket' byteArray inside while loop
File audioFile = null;
try {
audioFile = new File("xyz.ogg"); //input ogg opus file
oggFile = new FileStream(new RandomAccessFile(audioFile, "r"));
for (LogicalOggStream stream : (Collection<LogicalOggStream>) oggFile.getLogicalStreams()) {
byte[] nextPacket = stream.getNextOggPacket();
while (nextPacket != null) {
//nextPacket here contains opus packet
//do what ever you want to do with this packet
nextPacket = stream.getNextOggPacket();
}
}
} catch (EndOfOggStreamException e) {
System.out.println("End of File");
//file usually get over by raising this exception while execution getNextOggPacket()
}
Same program can be used to extract vorbis encoded packets in ogg container, means ogg vorbis file.
Happy coding!!!
来源:https://stackoverflow.com/questions/64479365/how-can-i-read-opus-packets-one-by-one-from-ogg-opus-file