/*
* myLib - https://github.com/taktod/myLib
* Copyright (c) 2014 ttProject. All rights reserved.
*
* Licensed under The MIT license.
*/
package com.ttProject.frame.h264.type;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.ttProject.frame.h264.H264Frame;
import com.ttProject.frame.h264.SliceFrame;
import com.ttProject.nio.channels.IReadChannel;
import com.ttProject.unit.extra.BitConnector;
import com.ttProject.unit.extra.bit.Bit1;
import com.ttProject.unit.extra.bit.Bit2;
import com.ttProject.unit.extra.bit.Bit24;
import com.ttProject.unit.extra.bit.Bit32;
import com.ttProject.unit.extra.bit.Bit5;
import com.ttProject.unit.extra.bit.Bit8;
import com.ttProject.util.BufferUtil;
/**
* SliceIDR (keyFrame?)
* sliceIDRはIFrame(keyFrame)ならかならずsliceIDRになっているわけではなさそうです。
* KeyFrameでもその前のフレームを参照するBFrameがあると、randomAccessできないので、randomAccessしてOKの場合のみ
* sliceIDRになっているらしい。
*
* TODO slice系のクラスは複数のnalで1つになっていることがあるので、複数のnalで構成されている場合は始めのnalに参照を持たせておいて
* getPackBufferの動作で、一度に参照できるようにしておきたいところ。
* こうしないとxuggleがエラーを吐く
* @author taktod
*/
public class SliceIDR extends SliceFrame {
/** logger */
@SuppressWarnings("unused")
private Logger logger = Logger.getLogger(SliceIDR.class);
/** data */
private ByteBuffer buffer = null;
/**
* constructor
* @param forbiddenZeroBit
* @param nalRefIdc
* @param type
*/
public SliceIDR(Bit1 forbiddenZeroBit, Bit2 nalRefIdc, Bit5 type) {
super(forbiddenZeroBit, nalRefIdc, type);
super.setKeyFrame(true);
}
/**
* {@inheritDoc}
*/
@Override
public void minimumLoad(IReadChannel channel) throws Exception {
super.minimumLoad(channel);
setReadPosition(channel.position());
setSize(channel.size());
super.update();
}
/**
* {@inheritDoc}
*/
@Override
public void load(IReadChannel channel) throws Exception {
channel.position(getReadPosition());
buffer = BufferUtil.safeRead(channel, getSize() - channel.position());
super.update();
}
/**
* {@inheritDoc}
*/
@Override
protected void requestUpdate() throws Exception {
if(buffer == null) {
throw new Exception("data body is undefined");
}
setData(BufferUtil.connect(getTypeBuffer(),
getSliceHeaderBuffer(),
buffer));
}
/**
* {@inheritDoc}
*/
@Override
public ByteBuffer getPackBuffer() throws Exception {
// make 00 00 00 01 sps 00 00 00 01 pps 00 00 00 01 sliceIdr
BitConnector connector = new BitConnector();
List<ByteBuffer> bufferList = new ArrayList<ByteBuffer>();
// sps
bufferList.add(connector.connect(new Bit32(1)));
bufferList.add(getSps().getData());
// pps
bufferList.add(connector.connect(new Bit32(1)));
bufferList.add(getPps().getData());
// idrFrame
bufferList.add(connector.connect(new Bit8()));
for(H264Frame frame : getGroupFrameList()) {
if(frame instanceof SliceIDR) {
bufferList.add(connector.connect(new Bit24(1)));
bufferList.add(frame.getData());
}
else {
throw new Exception("unexpected frame is found.:" + getClass().getSimpleName());
}
}
return BufferUtil.connect(bufferList);
}
}