【发布时间】:2021-02-05 07:12:49
【问题描述】:
我需要从 ogg/opus 文件中一一读取 OPUS 数据包,并以 OPUS 格式进一步发送它们,因此无需解码。我正在查看opusfile lib,但 API 和示例相当复杂,并且更专注于解码文件并获得结果 PCM。有没有办法用这个库实现我想要的,以及如何实现?如果没有,我还有什么其他选择?
【问题讨论】:
我需要从 ogg/opus 文件中一一读取 OPUS 数据包,并以 OPUS 格式进一步发送它们,因此无需解码。我正在查看opusfile lib,但 API 和示例相当复杂,并且更专注于解码文件并获得结果 PCM。有没有办法用这个库实现我想要的,以及如何实现?如果没有,我还有什么其他选择?
【问题讨论】:
libogg 可用于解析 Ogg Opus 文件的“页面”,然后可以从这些页面中提取作品“数据包”。请注意,数据包可能跨越页面,但我个人在测试opusenc 创建的文件时没有遇到过这种情况。您也可以手动解析页面(参见Splitting an Ogg Opus File stream)
我建议先阅读 Opus 文件规范 (RFC 7845) 的基础知识,以了解文件结构。 https://opus-codec.org/docs/
【讨论】:
我想我有点晚了。我有非常相似的用例,我想从 ogg opus 文件中提取 opus 数据包。我找到了这个答案
https://stackoverflow.com/a/26285277/10110652
以下代码将帮助您在 while 循环内的 'nextPacket' byteArray 中获取 opus 数据包(未解码为 pcm)
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()
}
同样的程序可以用来提取 ogg 容器中的 vorbis 编码数据包,即 ogg vorbis 文件。
编码愉快!!!
【讨论】:
您可以使用libogg 来访问 Opus 数据包。不幸的是,它并不比opusfile 简单得多。在 C-ish 伪代码中,一般流程是:
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 从文件中拉取一堆字节(yourMaxReadSize)到oggSyncState 结构中,然后逐页提取。在read中,数据包是从页面中一一提取出来的。
【讨论】:
libogg,但希望有更简单的方法,使用opusfile,代码更少