org.jcodec.containers.mps.MTSUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package org.jcodec.containers.mps;
import static org.jcodec.common.io.NIOUtils.getRel;
import org.jcodec.common.Assert;
import org.jcodec.common.IntArrayList;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.containers.mps.psi.PATSection;
import org.jcodec.containers.mps.psi.PMTSection;
import org.jcodec.containers.mps.psi.PMTSection.PMTStream;
import org.jcodec.containers.mps.psi.PSISection;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* @author The JCodec project
*
*/
public class MTSUtils {
/**
* Parses PAT ( Program Association Table )
*
* @param data
* @deprecated Use org.jcodec.containers.mps.psi.PAT.parse method instead,
* this method will not work correctly for streams with multiple
* programs
* @return Pid of the first PMT found in the PAT
*/
@Deprecated
public static int parsePAT(ByteBuffer data) {
PATSection pat = PATSection.parsePAT(data);
if (pat.getPrograms().size() > 0)
return pat.getPrograms().values()[0];
else
return -1;
}
@Deprecated
public static PMTSection parsePMT(ByteBuffer data) {
return PMTSection.parsePMT(data);
}
@Deprecated
public static PSISection parseSection(ByteBuffer data) {
return PSISection.parsePSI(data);
}
private static void parseEsInfo(ByteBuffer read) {
}
public static PMTStream[] getProgramGuids(File src) throws IOException {
SeekableByteChannel ch = null;
try {
ch = NIOUtils.readableChannel(src);
return getProgramGuidsFromChannel(ch);
} finally {
NIOUtils.closeQuietly(ch);
}
}
public static PMTStream[] getProgramGuidsFromChannel(SeekableByteChannel _in) throws IOException {
PMTExtractor ex = new PMTExtractor();
ex.readTsFile(_in);
PMTSection pmt = ex.getPmt();
return pmt.getStreams();
}
private static class PMTExtractor extends TSReader {
public PMTExtractor() {
super(false);
}
private int pmtGuid = -1;
private PMTSection pmt;
@Override
public boolean onPkt(int guid, boolean payloadStart, ByteBuffer tsBuf, long filePos, boolean sectionSyntax,
ByteBuffer fullPkt) {
if (guid == 0) {
pmtGuid = parsePAT(tsBuf);
} else if (pmtGuid != -1 && guid == pmtGuid) {
pmt = parsePMT(tsBuf);
return false;
}
return true;
}
public PMTSection getPmt() {
return pmt;
}
};
public static abstract class TSReader {
private static final int TS_SYNC_MARKER = 0x47;
private static final int TS_PKT_SIZE = 188;
// Buffer must have an integral number of MPEG TS packets
public static final int BUFFER_SIZE = TS_PKT_SIZE << 9;
private boolean flush;
public TSReader(boolean flush) {
this.flush = flush;
}
public void readTsFile(SeekableByteChannel ch) throws IOException {
ch.setPosition(0);
ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
for (long pos = ch.position(); ch.read(buf) >= TS_PKT_SIZE; pos = ch.position()) {
long posRem = pos;
buf.flip();
while (buf.remaining() >= TS_PKT_SIZE) {
ByteBuffer tsBuf = NIOUtils.read(buf, TS_PKT_SIZE);
ByteBuffer fullPkt = tsBuf.duplicate();
pos += TS_PKT_SIZE;
Assert.assertEquals(TS_SYNC_MARKER, tsBuf.get() & 0xff);
int guidFlags = ((tsBuf.get() & 0xff) << 8) | (tsBuf.get() & 0xff);
int guid = (int) guidFlags & 0x1fff;
int payloadStart = (guidFlags >> 14) & 0x1;
int b0 = tsBuf.get() & 0xff;
int counter = b0 & 0xf;
if ((b0 & 0x20) != 0) {
NIOUtils.skip(tsBuf, tsBuf.get() & 0xff);
}
boolean sectionSyntax = payloadStart == 1 && (getRel(tsBuf, getRel(tsBuf, 0) + 2) & 0x80) == 0x80;
if (sectionSyntax) {
// Adaptation field
NIOUtils.skip(tsBuf, tsBuf.get() & 0xff);
}
if (!onPkt(guid, payloadStart == 1, tsBuf, pos - tsBuf.remaining(), sectionSyntax, fullPkt))
return;
}
if (flush) {
buf.flip();
ch.setPosition(posRem);
ch.write(buf);
}
buf.clear();
}
}
protected boolean onPkt(int guid, boolean payloadStart, ByteBuffer tsBuf, long filePos, boolean sectionSyntax,
ByteBuffer fullPkt) {
// DO NOTHING
return true;
}
}
public static int getVideoPid(File src) throws IOException {
for (PMTStream stream : MTSUtils.getProgramGuids(src)) {
if (stream.getStreamType().isVideo())
return stream.getPid();
}
throw new RuntimeException("No video stream");
}
public static int getAudioPid(File src) throws IOException {
for (PMTStream stream : MTSUtils.getProgramGuids(src)) {
if (stream.getStreamType().isAudio())
return stream.getPid();
}
throw new RuntimeException("No audio stream");
}
public static int[] getMediaPidsFromChannel(SeekableByteChannel src) throws IOException {
return filterMediaPids(MTSUtils.getProgramGuidsFromChannel(src));
}
public static int[] getMediaPids(File src) throws IOException {
return filterMediaPids(MTSUtils.getProgramGuids(src));
}
private static int[] filterMediaPids(PMTStream[] programs) {
IntArrayList result = IntArrayList.createIntArrayList();
for (PMTStream stream : programs) {
if (stream.getStreamType().isVideo() || stream.getStreamType().isAudio())
result.add(stream.getPid());
}
return result.toArray();
}
}