/*
* myLib - https://github.com/taktod/myLib
* Copyright (c) 2014 ttProject. All rights reserved.
*
* Licensed under The MIT license.
*/
package com.ttProject.frame.vorbis.type;
import java.nio.ByteBuffer;
import org.apache.log4j.Logger;
import com.ttProject.frame.vorbis.VorbisFrame;
import com.ttProject.nio.channels.IReadChannel;
import com.ttProject.unit.extra.Bit;
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.Bit4;
import com.ttProject.unit.extra.bit.Bit48;
import com.ttProject.unit.extra.bit.Bit8;
import com.ttProject.util.BufferUtil;
/**
* header frame for vorbis
*
* packetType: 1byte 0x01 identification header
* string: 6Byte "vorbis"
* vorbisVersion 32bit integer
* audioChannels 8bit unsignedInteger
* audioSampleRate 32bit integer
* bitrateMaximum 32bit integer
* bitrateNominal 32bit integer
* bitrateMinimum 32bit integer
* blockSize0 2^x 4bit unsigned integer(samples per frame)
* blockSize1 2^x 4bit unsigned integer(?)
* framing flag 1bit(actual data is 1 byte.)
*
* @see http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-620004.2.2
* @author taktod
*
* sample data.
* 01 76 6F 72 62 69 73 00 00 00 00 02 44 AC 00 00 FF FF FF FF 00 77 01 00 FF FF FF FF B8 01
*
* identificationHeaderFrame decide the sampleNum too.
* sampleNum of first frame(blockSize0 + blockSize1) / 4
* sampleNum of others(blockSize1 + blockSize1) / 4
*/
public class IdentificationHeaderFrame extends VorbisFrame {
@SuppressWarnings("unused")
private Logger logger = Logger.getLogger(IdentificationHeaderFrame.class);
private Bit8 packetType = new Bit8();
private Bit48 string = new Bit48();
private Bit32 vorbisVersion = new Bit32();
private Bit8 audioChannels = new Bit8();
private Bit32 audioSampleRate = new Bit32();
private Bit32 bitrateMaximum = new Bit32();
private Bit32 bitrateNormal = new Bit32();
private Bit32 bitrateMinimum = new Bit32();
private Bit4 blockSize0 = new Bit4();
private Bit4 blockSize1 = new Bit4();
private Bit1 framingFlag = new Bit1();
private Bit extraBit = null;
private boolean isFirstPassed = false;
private int blockSize0Value = 0;
private int blockSize1Value = 0;
private CommentHeaderFrame commentHeaderFrame = null;
private SetupHeaderFrame setupHeaderFrame = null;
private ByteBuffer privateBuffer = null;
/**
* {@inheritDoc}
*/
@Override
public void minimumLoad(IReadChannel channel) throws Exception {
BitLoader loader = new BitLoader(channel);
loader.setLittleEndianFlg(true);
loader.load(packetType, string, vorbisVersion,
audioChannels, audioSampleRate,
bitrateMaximum, bitrateNormal, bitrateMinimum,
blockSize0, blockSize1, framingFlag);
extraBit = loader.getExtraBit();
if(packetType.get() != 1) {
throw new Exception("packetType value is unexpected.");
}
if(string.getLong() != 0x736962726F76L) {
throw new Exception("string value is different from expected.");
}
blockSize0Value = (1 << blockSize0.get());
blockSize1Value = (1 << blockSize1.get());
super.setSize(channel.size());
super.setBit(64);
super.setChannel(audioChannels.get());
super.setSampleRate(audioSampleRate.get());
super.update();
}
/**
* {@inheritDoc}
*/
@Override
public int getSampleNum() {
if(!isFirstPassed) {
isFirstPassed = true;
return (blockSize0Value + blockSize1Value) / 4;
}
else {
return (blockSize1Value + blockSize1Value) / 4;
}
}
/**
* {@inheritDoc}
*/
@Override
public void load(IReadChannel channel) throws Exception {
super.update();
}
/**
* {@inheritDoc}
*/
@Override
protected void requestUpdate() throws Exception {
BitConnector connector = new BitConnector();
connector.setLittleEndianFlg(true);
setData(connector.connect(packetType,
string, vorbisVersion, audioChannels, audioSampleRate,
bitrateMaximum, bitrateNormal, bitrateMinimum,
blockSize0, blockSize1, framingFlag, extraBit));
}
/**
* {@inheritDoc}
*/
@Override
public ByteBuffer getPackBuffer() throws Exception {
if(privateBuffer == null) {
// return data consists of identificationHeaderFrame + commentHeaderFrame + setupHeaderFrame.
ByteBuffer identificationData = getData();
ByteBuffer commentData = commentHeaderFrame.getMinimumBuffer();
ByteBuffer setupData = setupHeaderFrame.getPackBuffer();
BitConnector connector = new BitConnector();
privateBuffer = BufferUtil.connect(
connector.connect(new Bit8(2),
new Bit8(identificationData.remaining()),
new Bit8(commentData.remaining())),
identificationData,
commentData,
setupData);
}
return privateBuffer;
}
@Override
public ByteBuffer getPrivateData() throws Exception {
return getPackBuffer();
}
/**
* set the CommentHeaderFrame
* @param frame
*/
public void setCommentHeaderFrame(CommentHeaderFrame frame) {
this.commentHeaderFrame = frame;
}
/**
* set the SetupHeaderFrame
* @param frame
*/
public void setSetupHeaderFrame(SetupHeaderFrame frame) {
this.setupHeaderFrame = frame;
}
// 1つにまとめることができるかとおもったけど、だめっぽい。
/**
*
* @return
*/
public CommentHeaderFrame getCommentHeaderFrame() {
return commentHeaderFrame;
}
public SetupHeaderFrame getSetupHeaderFrame() {
return setupHeaderFrame;
}
}