package org.jcodec.codecs.mpeg12;
import org.jcodec.common.io.FileChannelWrapper;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.containers.mps.MTSUtils;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
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 abstract class FixTimestamp {
public void fix(File file) throws IOException {
RandomAccessFile ra = null;
try {
ra = new RandomAccessFile(file, "rw");
SeekableByteChannel ch = new FileChannelWrapper(ra.getChannel());
final FixTimestamp self = this;
new MTSUtils.TSReader(true) {
@Override
public boolean onPkt(int guid, boolean payloadStart, ByteBuffer bb, long filePos,
boolean sectionSyntax, ByteBuffer fullPkt) {
return self.processPacket(payloadStart, bb, sectionSyntax, fullPkt);
}
}.readTsFile(ch);
} finally {
if (ra != null)
ra.close();
}
}
private boolean processPacket(boolean payloadStart, ByteBuffer bb, boolean sectionSyntax, ByteBuffer fullPkt) {
if (!payloadStart || sectionSyntax)
return true;
int streamId = bb.getInt();
if (streamId == 0x1bd || streamId >= 0x1c0 && streamId < 0x1ef) {
int len = bb.getShort();
int b0 = bb.get() & 0xff;
bb.position(bb.position() - 1);
if ((b0 & 0xc0) == 0x80)
fixMpeg2(streamId & 0xff, bb);
else
fixMpeg1(streamId & 0xff, bb);
}
return true;
}
public void fixMpeg1(int streamId, ByteBuffer is) {
int c = is.getInt() & 0xff;
while (c == 0xff) {
c = is.get() & 0xff;
}
if ((c & 0xc0) == 0x40) {
is.get();
c = is.get() & 0xff;
}
if ((c & 0xf0) == 0x20) {
is.position(is.position() - 1);
fixTs(streamId, is, true);
} else if ((c & 0xf0) == 0x30) {
is.position(is.position() - 1);
fixTs(streamId, is, true);
fixTs(streamId, is, false);
} else {
if (c != 0x0f)
throw new RuntimeException("Invalid data");
}
}
public long fixTs(int streamId, ByteBuffer is, boolean isPts) {
byte b0 = is.get();
byte b1 = is.get();
byte b2 = is.get();
byte b3 = is.get();
byte b4 = is.get();
long pts = (((long) b0 & 0x0e) << 29) | ((b1 & 0xff) << 22) | (((b2 & 0xff) >> 1) << 15) | ((b3 & 0xff) << 7)
| ((b4 & 0xff) >> 1);
pts = doWithTimestamp(streamId, pts, isPts);
is.position(is.position() - 5);
is.put((byte) ((b0 & 0xf0) | (pts >>> 29) | 1));
is.put((byte) (pts >>> 22));
is.put((byte) ((pts >>> 14) | 1));
is.put((byte) (pts >>> 7));
is.put((byte) ((pts << 1) | 1));
return pts;
}
public void fixMpeg2(int streamId, ByteBuffer is) {
int flags1 = is.get() & 0xff;
int flags2 = is.get() & 0xff;
int header_len = is.get() & 0xff;
if ((flags2 & 0xc0) == 0x80) {
fixTs(streamId, is, true);
} else if ((flags2 & 0xc0) == 0xc0) {
fixTs(streamId, is, true);
fixTs(streamId, is, false);
}
}
public boolean isVideo(int streamId) {
return streamId >= 0xe0 && streamId <= 0xef;
}
public boolean isAudio(int streamId) {
return streamId >= 0xbf && streamId <= 0xdf;
}
protected abstract long doWithTimestamp(int streamId, long pts, boolean isPts);
}