package org.jcodec.codecs.mpeg12; import org.jcodec.common.Assert; import org.jcodec.common.io.NIOUtils; import org.jcodec.common.tools.MainUtils; import org.jcodec.common.tools.MainUtils.Cmd; import org.jcodec.containers.mps.psi.PATSection; import java.io.File; import java.io.IOException; import java.lang.System; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * This utility relocates PAT/PMT PSI packets from anywhere within a file to the * beginning of the file so that the file is playable * * @author The JCodec project * */ public class HLSRelocatePMT { private static final int TS_START_CODE = 0x47; private static final int CHUNK_SIZE_PKT = 1024; private static final int TS_PKT_SIZE = 188; public static void main1(String[] args) throws IOException { Cmd cmd = MainUtils.parseArguments(args); if (cmd.args.length < 2) { MainUtils.printHelpNoFlags("file _in", "file out"); return; } ReadableByteChannel _in = null; WritableByteChannel out = null; try { _in = NIOUtils.readableChannel(new File(cmd.args[0])); out = NIOUtils.writableChannel(new File(cmd.args[1])); System.err.println("Processed: " + replocatePMT(_in, out) + " packets."); } finally { NIOUtils.closeQuietly(_in); NIOUtils.closeQuietly(out); } } private static int replocatePMT(ReadableByteChannel _in, WritableByteChannel out) throws IOException { ByteBuffer buf = ByteBuffer.allocate(TS_PKT_SIZE * CHUNK_SIZE_PKT); Set<Integer> pmtPids = new HashSet<Integer>(); List<ByteBuffer> held = new ArrayList<ByteBuffer>(); ByteBuffer patPkt = null; ByteBuffer pmtPkt = null; int totalPkt = 0; while (_in.read(buf) != -1) { buf.flip(); buf.limit((buf.limit() / TS_PKT_SIZE) * TS_PKT_SIZE); while (buf.hasRemaining()) { ByteBuffer pkt = NIOUtils.read(buf, TS_PKT_SIZE); ByteBuffer pktRead = pkt.duplicate(); Assert.assertEquals(TS_START_CODE, pktRead.get() & 0xff); ++totalPkt; int guidFlags = ((pktRead.get() & 0xff) << 8) | (pktRead.get() & 0xff); int guid = (int) guidFlags & 0x1fff; int payloadStart = (guidFlags >> 14) & 0x1; int b0 = pktRead.get() & 0xff; int counter = b0 & 0xf; if ((b0 & 0x20) != 0) { NIOUtils.skip(pktRead, (pktRead.get() & 0xff)); } if (guid == 0 || pmtPids.contains(guid)) { if (payloadStart == 1) { NIOUtils.skip(pktRead, (pktRead.get() & 0xff)); } if (guid == 0) { patPkt = pkt; PATSection pat = PATSection.parsePAT(pktRead); int[] values = pat.getPrograms().values(); for (int i = 0; i < values.length; i++) { int pmtPid = values[i]; pmtPids.add(pmtPid); } } else if (pmtPids.contains(guid)) { pmtPkt = pkt; out.write(patPkt); out.write(pmtPkt); for (ByteBuffer heldPkt : held) { out.write(heldPkt); } held.clear(); } } else { if (pmtPkt == null) held.add(pkt); else out.write(pkt); } } buf.clear(); } return totalPkt; } }