package org.jcodec.containers.mps; import static org.jcodec.containers.mps.MPSUtils.mediaStream; import static org.jcodec.containers.mps.MPSUtils.readPESHeader; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import org.jcodec.common.Assert; import org.jcodec.common.NIOUtils; import org.jcodec.containers.mps.MPSDemuxer.PESPacket; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * Indexes MPEG TS file for the purpose of quick random access in the future * * @author The JCodec project * */ public class MTSIndexer { public static final int BUFFER_SIZE = 188 << 9; private MTSAnalyser[] indexers; public void index(File source, NIOUtils.FileReaderListener listener) throws IOException { index(source, listener, MTSUtils.getMediaPids(source)); } public void index(File source, NIOUtils.FileReaderListener listener, int[] targetGuids) throws IOException { indexers = new MTSAnalyser[targetGuids.length]; for (int i = 0; i < targetGuids.length; i++) { indexers[i] = new MTSAnalyser(targetGuids[i]); } new NIOUtils.FileReader() { protected void data(ByteBuffer data, long filePos) { analyseBuffer(data, filePos); } protected void analyseBuffer(ByteBuffer buf, long pos) { while (buf.hasRemaining()) { ByteBuffer tsBuf = NIOUtils.read(buf, 188); pos += 188; Assert.assertEquals(0x47, tsBuf.get() & 0xff); int guidFlags = ((tsBuf.get() & 0xff) << 8) | (tsBuf.get() & 0xff); int guid = (int) guidFlags & 0x1fff; for (int i = 0; i < indexers.length; i++) { if (guid == indexers[i].targetGuid) { int payloadStart = (guidFlags >> 14) & 0x1; int b0 = tsBuf.get() & 0xff; int counter = b0 & 0xf; if ((b0 & 0x20) != 0) { NIOUtils.skip(tsBuf, tsBuf.get() & 0xff); } indexers[i].analyseBuffer(tsBuf, pos - tsBuf.remaining()); } } } } }.readFile(source, BUFFER_SIZE, listener); } public void serializeTo(ByteBuffer buf) { for (MTSAnalyser mtsAnalyser : indexers) { ByteBuffer dup = buf.duplicate(); NIOUtils.skip(buf, 4); mtsAnalyser.serializeTo(buf); dup.putInt(buf.position() - dup.position()); } } public ByteBuffer serialize() { ByteBuffer buf = ByteBuffer.allocate(estimateSize()); serializeTo(buf); buf.flip(); return buf; } public int estimateSize() { int totalSize = 0; for (MTSAnalyser mtsAnalyser : indexers) { totalSize += mtsAnalyser.estimateSize(); } return totalSize; } private class MTSAnalyser extends BaseIndexer { private int targetGuid; private long predFileStartInTsPkt; public MTSAnalyser(int targetGuid) { this.targetGuid = targetGuid; } @Override public void serializeTo(ByteBuffer index) { index.putShort((short) targetGuid); super.serializeTo(index); } protected void pes(ByteBuffer pesBuffer, long start, int pesLen, int stream) { if (!mediaStream(stream)) return; System.out.println(String.format("PES: %08x, %d", start, pesLen)); PESPacket pesHeader = readPESHeader(pesBuffer, start); int leadingTsPkt = 0;// pesBuffer.position(); if (predFileStartInTsPkt != start) { leadingTsPkt = (int) (start / 188 - predFileStartInTsPkt); } predFileStartInTsPkt = (start + pesLen) / 188; int tsPktInPes = (int) (predFileStartInTsPkt - start / 188); savePesMeta(stream, leadingTsPkt, tsPktInPes, pesBuffer.remaining()); getAnalyser(stream).pkt(pesBuffer, pesHeader); } } public static void main(String[] args) throws IOException { File src = new File(args[0]); MTSIndexer indexer = new MTSIndexer(); indexer.index(src, new NIOUtils.FileReaderListener() { public void progress(int percentDone) { System.out.println(percentDone); } }); NIOUtils.writeTo(indexer.serialize(), new File(args[1])); } }