package org.jcodec.api.specific;
import java.nio.ByteBuffer;
import org.jcodec.api.MediaInfo;
import org.jcodec.codecs.h264.H264Decoder;
import org.jcodec.codecs.h264.H264Utils;
import org.jcodec.codecs.h264.io.model.NALUnit;
import org.jcodec.codecs.h264.io.model.NALUnitType;
import org.jcodec.codecs.h264.io.model.SeqParameterSet;
import org.jcodec.common.DemuxerTrackMeta;
import org.jcodec.common.model.ColorSpace;
import org.jcodec.common.model.Packet;
import org.jcodec.common.model.Picture;
import org.jcodec.common.model.Picture8Bit;
import org.jcodec.common.model.Rational;
import org.jcodec.common.model.Size;
import org.jcodec.containers.mp4.MP4Packet;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* High level frame grabber helper.
*
* @author The JCodec project
*
*/
public class AVCMP4Adaptor implements ContainerAdaptor {
private H264Decoder decoder;
private int curENo;
private Size size;
private DemuxerTrackMeta meta;
public AVCMP4Adaptor(DemuxerTrackMeta meta) {
this.meta = meta;
this.curENo = -1;
calcBufferSize();
}
private void calcBufferSize() {
int w = Integer.MIN_VALUE, h = Integer.MIN_VALUE;
ByteBuffer bb = meta.getCodecPrivate().duplicate();
ByteBuffer b;
while((b = H264Utils.nextNALUnit(bb)) != null) {
NALUnit nu = NALUnit.read(b);
if(nu.type != NALUnitType.SPS)
continue;
SeqParameterSet sps = H264Utils.readSPS(b);
int ww = sps.pic_width_in_mbs_minus1 + 1;
if (ww > w)
w = ww;
int hh = SeqParameterSet.getPicHeightInMbs(sps);
if (hh > h)
h = hh;
}
size = new Size(w << 4, h << 4);
}
@Deprecated
public Picture decodeFrame(Packet packet, int[][] data) {
updateState(packet);
Picture pic = decoder.decodeFrameFromNals(H264Utils.splitFrame(packet.getData()), data);
Rational pasp = meta.getVideoCodecMeta().getPixelAspectRatio();
if (pasp != null) {
// TODO: transform
}
return pic;
}
@Override
public Picture8Bit decodeFrame8Bit(Packet packet, byte[][] data) {
updateState(packet);
Picture8Bit pic = decoder.decodeFrame8Bit(packet.getData(), data);
Rational pasp = meta.getVideoCodecMeta().getPixelAspectRatio();
if (pasp != null) {
// TODO: transform
}
return pic;
}
private void updateState(Packet packet) {
int eNo = ((MP4Packet) packet).getEntryNo();
if (eNo != curENo) {
curENo = eNo;
// avcCBox = H264Utils.parseAVCC((VideoSampleEntry) ses[curENo]);
// decoder = new H264Decoder();
// ((H264Decoder) decoder).addSps(avcCBox.getSpsList());
// ((H264Decoder) decoder).addPps(avcCBox.getPpsList());
}
if(decoder == null) {
decoder = H264Decoder.createH264DecoderFromCodecPrivate(meta.getCodecPrivate());
}
}
@Override
public boolean canSeek(Packet pkt) {
updateState(pkt);
return H264Utils.idrSlice(H264Utils.splitFrame(pkt.getData()));
}
@Override
@Deprecated
public int[][] allocatePicture() {
return Picture.create(size.getWidth(), size.getHeight(), ColorSpace.YUV444).getData();
}
@Override
public byte[][] allocatePicture8Bit() {
return Picture8Bit.create(size.getWidth(), size.getHeight(), ColorSpace.YUV444).getData();
}
@Override
public MediaInfo getMediaInfo() {
return new MediaInfo(size);
}
}