de.jarnbjo.vorbis.VorbisStream Maven / Gradle / Ivy
/*
* $ProjectName$
* $ProjectRevision$
* -----------------------------------------------------------
* $Id: VorbisStream.java,v 1.4 2003/04/10 19:49:04 jarnbjo Exp $
* -----------------------------------------------------------
*
* $Author: jarnbjo $
*
* Description:
*
* Copyright 2002-2003 Tor-Einar Jarnbjo
* -----------------------------------------------------------
*
* Change History
* -----------------------------------------------------------
* $Log: VorbisStream.java,v $
* Revision 1.4 2003/04/10 19:49:04 jarnbjo
* no message
*
* Revision 1.3 2003/03/31 00:20:16 jarnbjo
* no message
*
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
* no message
*/
package de.jarnbjo.vorbis;
import de.jarnbjo.ogg.LogicalOggStream;
import de.jarnbjo.util.io.BitInputStream;
import de.jarnbjo.util.io.ByteArrayBitInputStream;
import java.io.IOException;
import java.util.LinkedList;
/**
*/
public class VorbisStream {
private LogicalOggStream oggStream;
private IdentificationHeader identificationHeader;
private CommentHeader commentHeader;
private SetupHeader setupHeader;
private AudioPacket lastAudioPacket, nextAudioPacket;
final private LinkedList audioPackets = new LinkedList();
private byte[] currentPcm;
private int currentPcmIndex;
private int currentPcmLimit;
private static final int IDENTIFICATION_HEADER = 1;
private static final int COMMENT_HEADER = 3;
private static final int SETUP_HEADER = 5;
final private Object streamLock = new Object();
private int currentBitRate = 0;
private long currentGranulePosition;
public static final int BIG_ENDIAN = 0;
public static final int LITTLE_ENDIAN = 1;
public VorbisStream() {
}
public VorbisStream(LogicalOggStream oggStream) throws IOException {
this.oggStream = oggStream;
for (int i = 0; i < 3; i++) {
BitInputStream source
= new ByteArrayBitInputStream(oggStream.getNextOggPacket());
int headerType = source.getInt(8);
switch (headerType) {
case IDENTIFICATION_HEADER:
identificationHeader = new IdentificationHeader(source);
break;
case COMMENT_HEADER:
commentHeader = new CommentHeader(source);
break;
case SETUP_HEADER:
setupHeader = new SetupHeader(this, source);
break;
default:
}
}
if (identificationHeader == null) {
throw new VorbisFormatException(
"The file has no identification header.");
}
if (commentHeader == null) {
throw new VorbisFormatException("The file has no commentHeader.");
}
if (setupHeader == null) {
throw new VorbisFormatException("The file has no setup header.");
}
//currentPcm=new int[identificationHeader.getChannels()][16384];
currentPcm = new byte[identificationHeader.getChannels()
* identificationHeader.getBlockSize1() * 2];
//new BufferThread().start();
}
public IdentificationHeader getIdentificationHeader() {
return identificationHeader;
}
public CommentHeader getCommentHeader() {
return commentHeader;
}
protected SetupHeader getSetupHeader() {
return setupHeader;
}
public boolean isOpen() {
return oggStream.isOpen();
}
public void close() throws IOException {
oggStream.close();
}
public int readPcm(byte[] buffer, int offset, int length)
throws IOException {
synchronized (streamLock) {
final int channels = identificationHeader.getChannels();
if (lastAudioPacket == null) {
lastAudioPacket = getNextAudioPacket();
}
if (currentPcm == null || currentPcmIndex >= currentPcmLimit) {
AudioPacket ap = getNextAudioPacket();
try {
ap.getPcm(lastAudioPacket, currentPcm);
currentPcmLimit = ap.getNumberOfSamples()
* identificationHeader.getChannels() * 2;
} catch (ArrayIndexOutOfBoundsException e) {
return 0;
}
currentPcmIndex = 0;
lastAudioPacket = ap;
}
int written = 0;
int i = 0;
int arrIx = 0;
for (i = currentPcmIndex;
i < currentPcmLimit && arrIx < length; i++) {
buffer[offset + arrIx++] = currentPcm[i];
written++;
}
currentPcmIndex = i;
return written;
}
}
private AudioPacket getNextAudioPacket() throws IOException {
AudioPacket res = null;
byte[] data = null;
while (res == null) {
try {
data = oggStream.getNextOggPacket();
res = new AudioPacket(this, new ByteArrayBitInputStream(data));
} catch (ArrayIndexOutOfBoundsException e) {
// ignore and continue with next packet
}
}
currentGranulePosition += res.getNumberOfSamples();
currentBitRate = data.length * 8 * identificationHeader.getSampleRate()
/ res.getNumberOfSamples();
return res;
}
public long getCurrentGranulePosition() {
return currentGranulePosition;
}
public int getCurrentBitRate() {
return currentBitRate;
}
public byte[] processPacket(byte[] packet) throws IOException {
if (packet.length == 0) {
throw new VorbisFormatException(
"Cannot decode a vorbis packet with length = 0");
}
if (((int) packet[0] & 1) == 1) {
// header packet
BitInputStream source = new ByteArrayBitInputStream(packet);
switch (source.getInt(8)) {
case IDENTIFICATION_HEADER:
identificationHeader = new IdentificationHeader(source);
break;
case COMMENT_HEADER:
commentHeader = new CommentHeader(source);
break;
case SETUP_HEADER:
setupHeader = new SetupHeader(this, source);
break;
default:
}
return null;
} else {
// audio packet
if (identificationHeader == null
|| commentHeader == null
|| setupHeader == null) {
throw new VorbisFormatException("Cannot decode audio packet "
+ "before all three header packets have been decoded.");
}
AudioPacket ap = new AudioPacket(
this, new ByteArrayBitInputStream(packet));
currentGranulePosition += ap.getNumberOfSamples();
if (lastAudioPacket == null) {
lastAudioPacket = ap;
return null;
}
byte[] res = new byte[identificationHeader.getChannels()
* ap.getNumberOfSamples() * 2];
try {
ap.getPcm(lastAudioPacket, res);
} catch (IndexOutOfBoundsException e) {
java.util.Arrays.fill(res, (byte) 0);
}
lastAudioPacket = ap;
return res;
}
}
}