package org.jcodec.codecs.mpeg12;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import org.jcodec.common.Assert;
import org.jcodec.common.NIOUtils;
/**
* 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");
byte[] tsPkt = new byte[188];
while (ra.read(tsPkt) == 188) {
Assert.assertEquals(0x47, tsPkt[0] & 0xff);
int guidFlags = ((tsPkt[1] & 0xff) << 8) | (tsPkt[2] & 0xff);
int guid = (int) guidFlags & 0x1fff;
int payloadStart = (guidFlags >> 14) & 0x1;
if (payloadStart == 0 || guid == 0)
continue;
ByteBuffer bb = ByteBuffer.wrap(tsPkt, 4, 184);
if ((tsPkt[3] & 0x20) != 0) {
NIOUtils.skip(bb, bb.get() & 0xff);
}
int streamId = 0xffffffff;
while (bb.hasRemaining() && !(streamId >= 0x1bf && streamId < 0x1ef)) {
streamId <<= 8;
streamId |= bb.get() & 0xff;
}
if (streamId >= 0x1bf && 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);
ra.seek(ra.getFilePointer() - 188);
ra.write(tsPkt);
}
}
} finally {
if (ra != null)
ra.close();
}
}
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);
}