package org.jcodec.movtool.streaming.tracks;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import org.jcodec.common.SeekableByteChannel;
import org.jcodec.containers.mp4.MP4Packet;
import org.jcodec.containers.mp4.boxes.Box;
import org.jcodec.containers.mp4.boxes.Edit;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.jcodec.containers.mp4.boxes.SampleEntry;
import org.jcodec.containers.mp4.boxes.SampleSizesBox;
import org.jcodec.containers.mp4.boxes.TrakBox;
import org.jcodec.containers.mp4.demuxer.AbstractMP4DemuxerTrack;
import org.jcodec.containers.mp4.demuxer.FramesMP4DemuxerTrack;
import org.jcodec.containers.mp4.demuxer.PCMMP4DemuxerTrack;
import org.jcodec.movtool.streaming.VirtualPacket;
import org.jcodec.movtool.streaming.VirtualTrack;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Track taken from a real movie
*
* @author The JCodec project
*
*/
public class RealTrack implements VirtualTrack {
private TrakBox trak;
private ByteChannelPool pool;
private AbstractMP4DemuxerTrack demuxer;
private MovieBox movie;
public RealTrack(MovieBox movie, TrakBox trak, ByteChannelPool pool) {
this.movie = movie;
SampleSizesBox stsz = Box.findFirst(trak, SampleSizesBox.class, "mdia", "minf", "stbl", "stsz");
if (stsz.getDefaultSize() == 0) {
this.demuxer = new FramesMP4DemuxerTrack(movie, trak, null) {
@Override
protected ByteBuffer readPacketData(SeekableByteChannel ch, ByteBuffer buffer, long position, int size)
throws IOException {
return buffer;
}
};
} else {
this.demuxer = new PCMMP4DemuxerTrack(movie, trak, null) {
@Override
protected ByteBuffer readPacketData(SeekableByteChannel ch, ByteBuffer buffer, long position, int size)
throws IOException {
return buffer;
}
};
}
this.trak = trak;
this.pool = pool;
}
@Override
public VirtualPacket nextPacket() throws IOException {
MP4Packet pkt = demuxer.nextFrame(null);
if (pkt == null)
return null;
return new RealPacket(pkt);
}
@Override
public SampleEntry getSampleEntry() {
return trak.getSampleEntries()[0];
}
@Override
public void close() {
// System.out.println("CLOSING FILE");
pool.close();
}
public class RealPacket implements VirtualPacket {
private MP4Packet packet;
public RealPacket(MP4Packet nextFrame) {
this.packet = nextFrame;
}
@Override
public ByteBuffer getData() throws IOException {
ByteBuffer bb = ByteBuffer.allocate(packet.getSize());
SeekableByteChannel ch = null;
try {
ch = pool.getChannel();
if(packet.getFileOff() >= ch.size())
return null;
ch.position(packet.getFileOff());
ch.read(bb);
bb.flip();
return bb;
} finally {
if (ch != null)
ch.close();
}
}
@Override
public int getDataLen() {
return packet.getSize();
}
@Override
public double getPts() {
return (double) packet.getMediaPts() / packet.getTimescale();
}
@Override
public double getDuration() {
return (double) packet.getDuration() / packet.getTimescale();
}
@Override
public boolean isKeyframe() {
return packet.isKeyFrame() || packet.isPsync();
}
@Override
public int getFrameNo() {
return (int) packet.getFrameNo();
}
}
@Override
public VirtualEdit[] getEdits() {
List<Edit> edits = demuxer.getEdits();
if (edits == null)
return null;
VirtualEdit[] result = new VirtualEdit[edits.size()];
for (int i = 0; i < edits.size(); i++) {
Edit ee = edits.get(i);
result[i] = new VirtualEdit((double) ee.getMediaTime() / trak.getTimescale(), (double) ee.getDuration()
/ movie.getTimescale());
}
return result;
}
@Override
public int getPreferredTimescale() {
return (int) demuxer.getTimescale();
}
}