package org.jcodec.containers.mps; import static java.util.Arrays.asList; import org.jcodec.common.Assert; import org.jcodec.common.IntArrayList; import org.jcodec.common.IntIntMap; import org.jcodec.common.io.NIOUtils; import org.jcodec.common.tools.MainUtils; import org.jcodec.common.tools.MainUtils.Cmd; import org.jcodec.common.tools.ToJSON; import org.jcodec.containers.mps.MPSUtils.MPEGMediaDescriptor; import org.jcodec.containers.mps.psi.PATSection; import org.jcodec.containers.mps.psi.PMTSection; import org.jcodec.containers.mps.psi.PMTSection.PMTStream; import java.io.File; import java.io.IOException; import java.lang.System; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.util.HashMap; import java.util.HashSet; import java.util.Set; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project */ public class MTSDump extends MPSDump { private static final String DUMP_FROM = "dump-from"; private static final String STOP_AT = "stop-at"; private int guid; private ByteBuffer buf; private ByteBuffer tsBuf; private int tsNo; private int globalPayload; private int[] payloads; private int[] nums; private int[] prevPayloads; private int[] prevNums; public MTSDump(ReadableByteChannel ch, int targetGuid) { super(ch); this.buf = ByteBuffer.allocate(188 * 1024); this.tsBuf = ByteBuffer.allocate(188); this.guid = targetGuid; this.buf.position(buf.limit()); this.tsBuf.position(tsBuf.limit()); } public static void main2(String[] args) throws IOException { ReadableByteChannel ch = null; try { Cmd cmd = MainUtils.parseArguments(args); if (cmd.args.length < 1) { HashMap<String, String> map = new HashMap<String, String>(); map.put(STOP_AT, "Stop reading at timestamp"); map.put(DUMP_FROM, "Start dumping from timestamp"); MainUtils.printHelp(map, asList("file name", "guid")); return; } else if (cmd.args.length == 1) { System.out.println("MTS programs:"); dumpProgramPids(NIOUtils.readableChannel(new File(cmd.args[0]))); return; } ch = NIOUtils.readableChannel(new File(cmd.args[0])); Long dumpAfterPts = cmd.getLongFlag(DUMP_FROM); Long stopPts = cmd.getLongFlag(STOP_AT); new MTSDump(ch, Integer.parseInt(cmd.args[1])).dump(dumpAfterPts, stopPts); } finally { NIOUtils.closeQuietly(ch); } } private static void dumpProgramPids(ReadableByteChannel readableFileChannel) throws IOException { Set<Integer> pids = new HashSet<Integer>(); ByteBuffer buf = ByteBuffer.allocate(188 * 10240); readableFileChannel.read(buf); buf.flip(); buf.limit(buf.limit() - (buf.limit() % 188)); int pmtPid = -1; while (buf.hasRemaining()) { ByteBuffer tsBuf = NIOUtils.read(buf, 188); Assert.assertEquals(0x47, tsBuf.get() & 0xff); int guidFlags = ((tsBuf.get() & 0xff) << 8) | (tsBuf.get() & 0xff); int guid = guidFlags & 0x1fff; System.out.println(guid); if (guid != 0) pids.add(guid); if (guid == 0 || guid == pmtPid) { // PSI int payloadStart = (guidFlags >> 14) & 0x1; int b0 = tsBuf.get() & 0xff; int counter = b0 & 0xf; int payloadOff = 0; if ((b0 & 0x20) != 0) { NIOUtils.skip(tsBuf, (tsBuf.get() & 0xff)); } if (payloadStart == 1) { NIOUtils.skip(tsBuf, (tsBuf.get() & 0xff)); } if (guid == 0) { PATSection pat = PATSection.parsePAT(tsBuf); IntIntMap programs = pat.getPrograms(); pmtPid = programs.values()[0]; printPat(pat); } else if (guid == pmtPid) { PMTSection pmt = PMTSection.parsePMT(tsBuf); printPmt(pmt); return; } } } for (Integer pid : pids) { System.out.println(pid); } } private static void printPat(PATSection pat) { IntIntMap programs = pat.getPrograms(); System.out.print("PAT: "); int[] keys = programs.keys(); for (int i : keys) { System.out.print(i + ":" + programs.get(i) + ", "); } System.out.println(); } private static void printPmt(PMTSection pmt) { System.out.print("PMT: "); for (PMTStream pmtStream : pmt.getStreams()) { System.out.print(pmtStream.getPid() + ":" + pmtStream.getStreamTypeTag() + ", "); for (MPEGMediaDescriptor descriptor : pmtStream.getDesctiptors()) { System.out.println(ToJSON.toJSON(descriptor)); } } System.out.println(); } protected void logPes(PESPacket pkt, int hdrSize, ByteBuffer payload) { System.out.println(pkt.streamId + "(" + (pkt.streamId >= 0xe0 ? "video" : "audio") + ")" + " [ts#" + mapPos(pkt.pos) + ", " + (payload.remaining() + hdrSize) + "b], pts: " + pkt.pts + ", dts: " + pkt.dts); } private int mapPos(long pos) { int left = globalPayload; for (int i = payloads.length - 1; i >= 0; --i) { left -= payloads[i]; if (left <= pos) { return nums[i]; } } if (prevPayloads != null) { for (int i = prevPayloads.length - 1; i >= 0; --i) { left -= prevPayloads[i]; if (left <= pos) { return prevNums[i]; } } } return -1; } @Override public int fillBuffer(ByteBuffer dst) throws IOException { IntArrayList payloads = IntArrayList.createIntArrayList(); IntArrayList nums = IntArrayList.createIntArrayList(); int remaining = dst.remaining(); try { dst.put(NIOUtils.read(tsBuf, Math.min(dst.remaining(), tsBuf.remaining()))); while (dst.hasRemaining()) { if (!buf.hasRemaining()) { ByteBuffer dub = buf.duplicate(); dub.clear(); int read = ch.read(dub); if (read == -1) return dst.remaining() != remaining ? remaining - dst.remaining() : -1; dub.flip(); dub.limit(dub.limit() - (dub.limit() % 188)); buf = dub; } tsBuf = NIOUtils.read(buf, 188); Assert.assertEquals(0x47, tsBuf.get() & 0xff); ++tsNo; int guidFlags = ((tsBuf.get() & 0xff) << 8) | (tsBuf.get() & 0xff); int guid = (int) guidFlags & 0x1fff; if (guid != this.guid) continue; int payloadStart = (guidFlags >> 14) & 0x1; int b0 = tsBuf.get() & 0xff; int counter = b0 & 0xf; if ((b0 & 0x20) != 0) { NIOUtils.skip(tsBuf, tsBuf.get() & 0xff); } globalPayload += tsBuf.remaining(); payloads.add(tsBuf.remaining()); nums.add(tsNo - 1); dst.put(NIOUtils.read(tsBuf, Math.min(dst.remaining(), tsBuf.remaining()))); } } finally { this.prevPayloads = this.payloads; this.payloads = payloads.toArray(); this.prevNums = this.nums; this.nums = nums.toArray(); } return remaining - dst.remaining(); } }