/*
* $ProjectName$
* $ProjectRevision$
* -----------------------------------------------------------
* $Id: LogicalOggStreamImpl.java,v 1.3 2003/03/31 00:23:04 jarnbjo Exp $
* -----------------------------------------------------------
*
* $Author: jarnbjo $
*
* Description:
*
* Copyright 2002-2003 Tor-Einar Jarnbjo
* -----------------------------------------------------------
*
* Change History
* -----------------------------------------------------------
* $Log: LogicalOggStreamImpl.java,v $
* Revision 1.3 2003/03/31 00:23:04 jarnbjo
* no message
*
* Revision 1.2 2003/03/16 01:11:26 jarnbjo
* no message
*
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
* no message
*
*/
package de.jarnbjo.ogg;
import java.io.*;
import java.util.*;
public class LogicalOggStreamImpl implements LogicalOggStream {
private PhysicalOggStream source;
private int serialNumber;
private ArrayList pageNumberMapping=new ArrayList();
private ArrayList granulePositions=new ArrayList();
private int pageIndex=0;
private OggPage currentPage;
private int currentSegmentIndex;
private boolean open=true;
private String format=FORMAT_UNKNOWN;
public LogicalOggStreamImpl(PhysicalOggStream source, int serialNumber) {
this.source=source;
this.serialNumber=serialNumber;
}
public void addPageNumberMapping(int physicalPageNumber) {
pageNumberMapping.add(new Integer(physicalPageNumber));
}
public void addGranulePosition(long granulePosition) {
granulePositions.add(new Long(granulePosition));
}
public synchronized void reset() throws OggFormatException, IOException {
currentPage=null;
currentSegmentIndex=0;
pageIndex=0;
}
public synchronized OggPage getNextOggPage() throws EndOfOggStreamException, OggFormatException, IOException {
if(source.isSeekable()) {
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
}
else {
currentPage=source.getOggPage(-1);
}
return currentPage;
}
public synchronized byte[] getNextOggPacket() throws EndOfOggStreamException, OggFormatException, IOException {
ByteArrayOutputStream res=new ByteArrayOutputStream();
int segmentLength=0;
if(currentPage==null) {
currentPage=getNextOggPage();
}
do {
if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
currentSegmentIndex=0;
if(!currentPage.isEos()) {
if(source.isSeekable() && pageNumberMapping.size()<=pageIndex) {
while(pageNumberMapping.size()<=pageIndex+10) {
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
}
}
}
currentPage=getNextOggPage();
if(res.size()==0 && currentPage.isContinued()) {
boolean done=false;
while(!done) {
if(currentPage.getSegmentLengths()[currentSegmentIndex++]!=255) {
done=true;
}
if(currentSegmentIndex>currentPage.getSegmentTable().length) {
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
}
}
}
}
else {
throw new EndOfOggStreamException();
}
}
segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
res.write(currentPage.getData(), currentPage.getSegmentOffsets()[currentSegmentIndex], segmentLength);
currentSegmentIndex++;
} while(segmentLength==255);
return res.toByteArray();
}
public boolean isOpen() {
return open;
}
public void close() throws IOException {
open=false;
}
public long getMaximumGranulePosition() {
Long mgp=(Long)granulePositions.get(granulePositions.size()-1);
return mgp.longValue();
}
public synchronized long getTime() {
return currentPage!=null?currentPage.getAbsoluteGranulePosition():-1;
}
public synchronized void setTime(long granulePosition) throws IOException {
int page=0;
for(page=0; page<granulePositions.size(); page++) {
Long gp=(Long)granulePositions.get(page);
if(gp.longValue()>granulePosition) {
break;
}
}
pageIndex=page;
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
currentSegmentIndex=0;
int segmentLength=0;
do {
if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
currentSegmentIndex=0;
if(pageIndex>=pageNumberMapping.size()) {
throw new EndOfOggStreamException();
}
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
}
segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
currentSegmentIndex++;
} while(segmentLength==255);
}
public void checkFormat(OggPage page) {
byte[] data=page.getData();
if(data.length>=7 &&
data[1]==0x76 &&
data[2]==0x6f &&
data[3]==0x72 &&
data[4]==0x62 &&
data[5]==0x69 &&
data[6]==0x73) {
format=FORMAT_VORBIS;
}
else if(data.length>=7 &&
data[1]==0x74 &&
data[2]==0x68 &&
data[3]==0x65 &&
data[4]==0x6f &&
data[5]==0x72 &&
data[6]==0x61) {
format=FORMAT_THEORA;
}
else if (data.length==4 &&
data[0]==0x66 &&
data[1]==0x4c &&
data[2]==0x61 &&
data[3]==0x43) {
format=FORMAT_FLAC;
}
}
public String getFormat() {
return format;
}
}