package org.jcodec.containers.mps.index; import static org.jcodec.containers.mps.MPSUtils.mediaStream; import static org.jcodec.containers.mps.MPSUtils.readPESHeader; import static org.jcodec.containers.mps.index.MTSIndex.createMTSProgram; import org.jcodec.common.Assert; import org.jcodec.common.io.NIOUtils; import org.jcodec.common.io.NIOUtils.FileReader; import org.jcodec.common.io.SeekableByteChannel; import org.jcodec.common.logging.Logger; import org.jcodec.containers.mps.MTSUtils; import org.jcodec.containers.mps.PESPacket; import org.jcodec.containers.mps.index.MTSIndex.MTSProgram; import java.io.File; import java.io.IOException; import java.lang.System; import java.nio.ByteBuffer; /** * 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 { indexReader(listener, MTSUtils.getMediaPids(source)).readFile(source, BUFFER_SIZE, listener); } public void indexChannel(SeekableByteChannel source, NIOUtils.FileReaderListener listener) throws IOException { indexReader(listener, MTSUtils.getMediaPidsFromChannel(source)).readChannel(source, BUFFER_SIZE, listener); } public FileReader indexReader(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]); } return new MTSFileReader(this); } public MTSIndex serialize() { MTSProgram[] programs = new MTSProgram[indexers.length]; for (int i = 0; i < indexers.length; i++) programs[i] = indexers[i].serializeTo(); return new MTSIndex(programs); } private static final class MTSFileReader extends NIOUtils.FileReader { private MTSIndexer indexer; public MTSFileReader(MTSIndexer indexer) { this.indexer = indexer; } 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 < indexer.indexers.length; i++) { if (guid == indexer.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); } indexer.indexers[i].analyseBuffer(tsBuf, pos - tsBuf.remaining()); } } } } @Override protected void done() { for (MTSAnalyser mtsAnalyser : indexer.indexers) { mtsAnalyser.finishAnalyse(); } } } private static class MTSAnalyser extends BaseIndexer { private int targetGuid; private long predFileStartInTsPkt; public MTSAnalyser(int targetGuid) { this.targetGuid = targetGuid; } public MTSProgram serializeTo() { return createMTSProgram(super.serialize(), targetGuid); } protected void pes(ByteBuffer pesBuffer, long start, int pesLen, int stream) { if (!mediaStream(stream)) return; Logger.debug(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, MPSIndex.makePESToken(leadingTsPkt, tsPktInPes, pesBuffer.remaining())); getAnalyser(stream).pkt(pesBuffer, pesHeader); } } public static void main1(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); } }); MTSIndex index = indexer.serialize(); NIOUtils.writeTo(index.serialize(), new File(args[1])); } }