/*
* myLib - https://github.com/taktod/myLib
* Copyright (c) 2014 ttProject. All rights reserved.
*
* Licensed under The MIT license.
*/
package com.ttProject.frame.flv1;
import com.ttProject.frame.VideoSelector;
import com.ttProject.frame.flv1.type.DisposableInterFrame;
import com.ttProject.frame.flv1.type.InterFrame;
import com.ttProject.frame.flv1.type.IntraFrame;
import com.ttProject.nio.channels.IReadChannel;
import com.ttProject.unit.IUnit;
import com.ttProject.unit.extra.Bit;
import com.ttProject.unit.extra.BitLoader;
import com.ttProject.unit.extra.bit.Bit16;
import com.ttProject.unit.extra.bit.Bit17;
import com.ttProject.unit.extra.bit.Bit1;
import com.ttProject.unit.extra.bit.Bit2;
import com.ttProject.unit.extra.bit.Bit3;
import com.ttProject.unit.extra.bit.Bit5;
import com.ttProject.unit.extra.bit.Bit8;
/**
* selector for flv1 frame.
* @author taktod
*/
public class Flv1FrameSelector extends VideoSelector {
/**
* select flv1 frame.
* @param channel (expect the channel has only 1 frame.)
* @return
*/
@Override
public IUnit select(IReadChannel channel) throws Exception {
if(channel.size() - channel.position() < 4) {
// need more than 32 bit(4byte).
return null;
}
BitLoader bitLoader = new BitLoader(channel);
Bit17 pictureStartCode = new Bit17();
Bit5 version = new Bit5();
Bit8 temporalReference = new Bit8();
Bit3 pictureSize = new Bit3();
bitLoader.load(pictureStartCode,
version, temporalReference, pictureSize);
if(pictureStartCode.get() != 1) {
throw new Exception("picture start code is unexpected. currept?");
}
int width = 0;
int height = 0;
Bit customWidth = null;
Bit customHeight = null;
switch(pictureSize.get()) {
case 0: // custom1
customWidth = new Bit8();
customHeight = new Bit8();
bitLoader.load(customWidth, customHeight);
width = customWidth.get();
height = customHeight.get();
break;
case 1: // custom2
customWidth = new Bit16();
customHeight = new Bit16();
bitLoader.load(customWidth, customHeight);
width = customWidth.get();
height = customHeight.get();
break;
case 2: // CIF
width = 352;
height = 288;
break;
case 3: // QCIF
width = 176;
height = 144;
break;
case 4: // SQCIF
width = 128;
height = 96;
break;
case 5: // 320x240
width = 320;
height = 240;
break;
case 6: // 160x120
width = 160;
height = 120;
break;
case 7: // reserved
throw new Exception("picture size is reserved.");
}
Bit2 pictureType = new Bit2();
Bit1 deblockingFlag = new Bit1();
Bit5 quantizer = new Bit5();
Bit1 extraInformationFlag = new Bit1();
bitLoader.load(pictureType, deblockingFlag, quantizer, extraInformationFlag);
Bit8 extraInformation = null;
if(extraInformationFlag.get() == 1) {
extraInformation = new Bit8();
bitLoader.load(extraInformation);
}
Flv1Frame frame = null;
switch(pictureType.get()) {
case 0: // intraFrame
frame = new IntraFrame(pictureStartCode, version, temporalReference,
pictureSize, customWidth, customHeight, width, height,
pictureType, deblockingFlag, quantizer, extraInformationFlag,
extraInformation, bitLoader.getExtraBit());
break;
case 1: // interFrame
frame = new InterFrame(pictureStartCode, version, temporalReference,
pictureSize, customWidth, customHeight, width, height,
pictureType, deblockingFlag, quantizer, extraInformationFlag,
extraInformation, bitLoader.getExtraBit());
break;
case 2: // disposableInterFrame
frame = new DisposableInterFrame(pictureStartCode, version, temporalReference,
pictureSize, customWidth, customHeight, width, height,
pictureType, deblockingFlag, quantizer, extraInformationFlag,
extraInformation, bitLoader.getExtraBit());
break;
case 3: // reserved
default:
throw new Exception("unexpected flv1 frame/");
}
setup(frame);
frame.minimumLoad(channel);
return frame;
}
}