最快的方法是查找文件的末尾,然后返回找到的最后一个Ogg页面标题,并读取其granulePosition(文件中每个通道的样本总数)。这不是万无一失的(您可能正在查看一个链接的文件,在这种情况下,您只能得到最后一个流的长度),但是应该可以用于绝大多数Ogg文件。
如果需要阅读Ogg页面标题的帮助,则可以阅读Jorbis源代码。简短的版本是查找“ OggS”,读取一个字节(应为0),读取一个字节(应仅将bit 3设置),然后读取一个64位Little Endian值。
我实现了 ioctlLR 描述的解决方案,它似乎有效:
double calculateDuration(final File oggFile) throws IOException {
int rate = -1;
int length = -1;
int size = (int) oggFile.length();
byte[] t = new byte[size];
FileInputStream stream = new FileInputStream(oggFile);
stream.read(t);
for (int i = size-1-8-2-4; i>=0 && length<0; i--) { //4 bytes for "OggS", 2 unused bytes, 8 bytes for length
// Looking for length (value after last "OggS")
if (
t[i]==(byte)'O'
&& t[i+1]==(byte)'g'
&& t[i+2]==(byte)'g'
&& t[i+3]==(byte)'S'
) {
byte[] byteArray = new byte[]{t[i+6],t[i+7],t[i+8],t[i+9],t[i+10],t[i+11],t[i+12],t[i+13]};
ByteBuffer bb = ByteBuffer.wrap(byteArray);
bb.order(ByteOrder.LITTLE_ENDIAN);
length = bb.getInt(0);
}
}
for (int i = 0; i<size-8-2-4 && rate<0; i++) {
// Looking for rate (first value after "vorbis")
if (
t[i]==(byte)'v'
&& t[i+1]==(byte)'o'
&& t[i+2]==(byte)'r'
&& t[i+3]==(byte)'b'
&& t[i+4]==(byte)'i'
&& t[i+5]==(byte)'s'
) {
byte[] byteArray = new byte[]{t[i+11],t[i+12],t[i+13],t[i+14]};
ByteBuffer bb = ByteBuffer.wrap(byteArray);
bb.order(ByteOrder.LITTLE_ENDIAN);
rate = bb.getInt(0);
}
}
stream.close();
double duration = (double) (length*1000) / (double) rate;
return duration;
}
Run Code Online (Sandbox Code Playgroud)
请注意,以这种方式查找汇率仅适用于vorbis OGG!
请随意编辑我的答案,它可能并不完美。