package org.jcodec.player.filters;
import static org.jcodec.common.NIOUtils.readableFileChannel;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.jcodec.common.SeekableByteChannel;
import org.jcodec.common.model.Packet;
import org.jcodec.common.model.RationalLarge;
import org.jcodec.common.model.Size;
import org.jcodec.containers.mp4.boxes.AudioSampleEntry;
import org.jcodec.containers.mp4.boxes.VideoSampleEntry;
import org.jcodec.containers.mp4.demuxer.AbstractMP4DemuxerTrack;
import org.jcodec.containers.mp4.demuxer.MP4Demuxer;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* @author The JCodec project
*
*/
public class JCodecPacketSource {
private MP4Demuxer demuxer;
private List<Track> tracks;
private SeekableByteChannel is;
public JCodecPacketSource(File file) throws IOException {
is = readableFileChannel(file);
demuxer = new MP4Demuxer(is);
tracks = new ArrayList<Track>();
for (AbstractMP4DemuxerTrack demuxerTrack : demuxer.getTracks()) {
if (demuxerTrack.getBox().isVideo() || demuxerTrack.getBox().isAudio())
tracks.add(new Track(demuxerTrack));
}
}
public List<? extends PacketSource> getTracks() {
return tracks;
}
public PacketSource getVideo() {
for (Track track : tracks) {
if (track.track.getBox().isVideo())
return track;
}
return null;
}
public List<? extends PacketSource> getAudio() {
List<Track> result = new ArrayList<Track>();
for (Track track : tracks) {
if (track.track.getBox().isAudio())
result.add(track);
}
return result;
}
public class Track implements PacketSource {
private AbstractMP4DemuxerTrack track;
private boolean closed;
public Track(AbstractMP4DemuxerTrack track) {
this.track = track;
}
public Packet getPacket(ByteBuffer buffer) {
try {
return track.nextFrame();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public MediaInfo getMediaInfo() {
RationalLarge duration = track.getDuration();
if (track.getBox().isVideo()) {
VideoSampleEntry se = (VideoSampleEntry) track.getSampleEntries()[0];
return new MediaInfo.VideoInfo(se.getFourcc(), (int) duration.getDen(), duration.getNum(),
track.getFrameCount(), track.getName(), null, track.getBox().getPAR(), new Size(
(int) se.getWidth(), (int) se.getHeight()));
} else if (track.getBox().isAudio()) {
AudioSampleEntry se = (AudioSampleEntry) track.getSampleEntries()[0];
return new MediaInfo.AudioInfo(se.getFourcc(), (int) duration.getDen(), duration.getNum(),
track.getFrameCount(), track.getName(), null, se.getFormat(), se.getLabels());
}
throw new RuntimeException("This shouldn't happen");
}
public boolean drySeek(RationalLarge second) {
return track.canSeek(second.multiplyS(track.getTimescale()));
}
public void seek(RationalLarge second) {
track.seek(second.multiplyS(track.getTimescale()));
}
public void close() throws IOException {
this.closed = true;
checkClose();
}
@Override
public void gotoFrame(int frameNo) {
track.gotoFrame(frameNo);
}
}
private void checkClose() throws IOException {
boolean closed = true;
for (Track track : tracks) {
closed &= track.closed;
}
if (closed)
is.close();
}
}