/*
* myLib - https://github.com/taktod/myLib
* Copyright (c) 2014 ttProject. All rights reserved.
*
* Licensed under The MIT license.
*/
package com.ttProject.container.ogg;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import com.ttProject.container.Container;
import com.ttProject.container.ogg.type.StartPage;
import com.ttProject.frame.IFrame;
import com.ttProject.nio.channels.IReadChannel;
import com.ttProject.unit.extra.BitConnector;
import com.ttProject.unit.extra.BitLoader;
import com.ttProject.unit.extra.bit.Bit1;
import com.ttProject.unit.extra.bit.Bit32;
import com.ttProject.unit.extra.bit.Bit5;
import com.ttProject.unit.extra.bit.Bit64;
import com.ttProject.unit.extra.bit.Bit8;
/**
* basic of oggPage
* @author taktod
* TODO theora is not tested yet.
*/
public abstract class OggPage extends Container {
/** logger */
// private Logger logger = Logger.getLogger(OggPage.class);
public static final String capturePattern = "OggS"; // fixed?
// private final Bit32 syncString;
private final Bit1 packetContinurousFlag;
private final Bit1 logicStartFlag;
private final Bit1 logicEndFlag;
private final Bit5 zeroFill;
private final Bit8 version;
private Bit64 absoluteGranulePosition = new Bit64();
private Bit32 streamSerialNumber = new Bit32();
private Bit32 pageSequenceNo = new Bit32();
private Bit32 pageChecksum = new Bit32();
private Bit8 segmentCount = new Bit8();
private List<Bit8> segmentSizeList = new ArrayList<Bit8>();
private List<ByteBuffer> bufferList = new ArrayList<ByteBuffer>();
private List<IFrame> frameList = new ArrayList<IFrame>(); // TODO should I use multiFrame?
private StartPage startPage = null;
/**
* constructor
* @param version
* @param zeroFill
* @param logicEndFlag
* @param logicStartFlag
* @param packetContinurousFlag
*/
public OggPage(Bit8 version,
Bit1 packetContinurousFlag,
Bit1 logicStartFlag,
Bit1 logicEndFlag,
Bit5 zeroFill) {
// this.syncString = new Bit32('O' | ('g' << 8) | ('g' << 16) | ('S' << 24));
this.version = version;
this.zeroFill = zeroFill;
this.logicEndFlag = logicEndFlag;
this.logicStartFlag = logicStartFlag;
this.packetContinurousFlag = packetContinurousFlag;
super.update();
}
/**
* {@inheritDoc}
*/
@Override
public void minimumLoad(IReadChannel channel) throws Exception {
super.setPosition(channel.position() - 6);
BitLoader loader = new BitLoader(channel);
loader.setLittleEndianFlg(true);
loader.load(absoluteGranulePosition, streamSerialNumber, pageSequenceNo, pageChecksum, segmentCount);
int size = 0;
for(int i = 0;i < segmentCount.get();i ++) {
Bit8 segmentSize = new Bit8();
loader.load(segmentSize);
size += segmentSize.get();
segmentSizeList.add(segmentSize);
}
super.setSize(size + channel.position() - getPosition());
}
/**
* ref the header buffer
* @return
*/
protected ByteBuffer getHeaderBuffer() {
for(IFrame frame : frameList) {
// TODO is there is the frame over 255, there is a trouble.
int size = frame.getSize();
do {
if(size > 0xFF) {
segmentSizeList.add(new Bit8(0xFF));
size -= 0xFF;
}
else if(size == 0xFF) {
segmentSizeList.add(new Bit8(0xFF));
segmentSizeList.add(new Bit8(0x00));
break;
}
else {
segmentSizeList.add(new Bit8(size));
break;
}
} while(size > 0);
}
segmentCount.set(segmentSizeList.size());
BitConnector connector = new BitConnector();
connector.setLittleEndianFlg(true);
connector.feed(new Bit8('O'), new Bit8('g'), new Bit8('g'), new Bit8('S'), version, packetContinurousFlag, logicStartFlag, logicEndFlag, zeroFill,
absoluteGranulePosition, streamSerialNumber, pageSequenceNo, pageChecksum, segmentCount);
int size = 0;
for(Bit8 bit : segmentSizeList) {
connector.feed(bit);
size += bit.get();
}
super.setSize(27 + segmentCount.get() + size);
return connector.connect();
}
/**
* ref of segment size list.
* @return
*/
protected List<Bit8> getSegmentSizeList() {
return segmentSizeList;
}
/**
* ref of buffers
* @return
*/
protected List<ByteBuffer> getBufferList() {
return bufferList;
}
/**
* ref analyzed frame list.
* @return
*/
public List<IFrame> getFrameList() {
return frameList;
}
/**
* ref stream serial number.
* @return
*/
public Integer getStreamSerialNumber() {
return streamSerialNumber.get();
}
/**
* set startPage object.
* @param startPage
*/
public void setStartPage(StartPage startPage) {
this.startPage = startPage;
}
/**
* ref startPage
* @return
*/
protected StartPage getStartPage() {
return startPage;
}
/**
* ref page sequence num.
* @return
*/
public int getPageSequenceNo() {
return pageSequenceNo.get();
}
public void setAbsoluteGranulePosition(long granulePosition) {
absoluteGranulePosition.setLong(granulePosition);
}
public void setStreamSerialNumber(int serialNumber) {
streamSerialNumber.set(serialNumber);
}
public void setPageSequenceNo(int sequenceNo) {
pageSequenceNo.set(sequenceNo);
}
public void setLogicEndFlag(boolean flag) {
if(flag) {
logicEndFlag.set(1);
}
else {
logicEndFlag.set(0);
}
}
public long getAbsoluteGranulePosition() {
return absoluteGranulePosition.getLong();
}
}