www in docker support
This commit is contained in:
parent
539a848e95
commit
c227fce036
2145 changed files with 399596 additions and 58 deletions
|
|
@ -0,0 +1,44 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FixHLSTimestamps extends FixTimestamp {
|
||||
private long[] lastPts = new long[256];
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
String wildCard = args[0];
|
||||
int startIdx = Integer.parseInt(args[1]);
|
||||
new FixHLSTimestamps().doIt(wildCard, startIdx);
|
||||
}
|
||||
|
||||
private void doIt(String wildCard, int startIdx) throws IOException {
|
||||
Arrays.fill(this.lastPts, -1L);
|
||||
for (int i = startIdx;; i++) {
|
||||
File file = new File(String.format(wildCard, i));
|
||||
System.out.println(file.getAbsolutePath());
|
||||
if (!file.exists())
|
||||
break;
|
||||
fix(file);
|
||||
}
|
||||
}
|
||||
|
||||
protected long doWithTimestamp(int streamId, long pts, boolean isPts) {
|
||||
if (!isPts)
|
||||
return pts;
|
||||
if (this.lastPts[streamId] == -1L) {
|
||||
this.lastPts[streamId] = pts;
|
||||
return pts;
|
||||
}
|
||||
if (isVideo(streamId)) {
|
||||
this.lastPts[streamId] = this.lastPts[streamId] + 3003L;
|
||||
return this.lastPts[streamId];
|
||||
}
|
||||
if (isAudio(streamId)) {
|
||||
this.lastPts[streamId] = this.lastPts[streamId] + 1920L;
|
||||
return this.lastPts[streamId];
|
||||
}
|
||||
throw new RuntimeException("Unexpected!!!");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
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.io.FileChannelWrapper;
|
||||
import org.jcodec.common.io.SeekableByteChannel;
|
||||
import org.jcodec.containers.mps.MTSUtils;
|
||||
|
||||
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) {
|
||||
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 == 445 || (streamId >= 448 && streamId < 495)) {
|
||||
int len = bb.getShort();
|
||||
int b0 = bb.get() & 0xFF;
|
||||
bb.position(bb.position() - 1);
|
||||
if ((b0 & 0xC0) == 128) {
|
||||
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 == 255)
|
||||
c = is.get() & 0xFF;
|
||||
if ((c & 0xC0) == 64) {
|
||||
is.get();
|
||||
c = is.get() & 0xFF;
|
||||
}
|
||||
if ((c & 0xF0) == 32) {
|
||||
is.position(is.position() - 1);
|
||||
fixTs(streamId, is, true);
|
||||
} else if ((c & 0xF0) == 48) {
|
||||
is.position(is.position() - 1);
|
||||
fixTs(streamId, is, true);
|
||||
fixTs(streamId, is, false);
|
||||
} else if (c != 15) {
|
||||
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 & 0xEL) << 29L | (long)((b1 & 0xFF) << 22) | (long)((b2 & 0xFF) >> 1 << 15) | (long)((b3 & 0xFF) << 7) | (long)((b4 & 0xFF) >> 1);
|
||||
pts = doWithTimestamp(streamId, pts, isPts);
|
||||
is.position(is.position() - 5);
|
||||
is.put((byte)(int)((long)(b0 & 0xF0) | pts >>> 29L | 0x1L));
|
||||
is.put((byte)(int)(pts >>> 22L));
|
||||
is.put((byte)(int)(pts >>> 14L | 0x1L));
|
||||
is.put((byte)(int)(pts >>> 7L));
|
||||
is.put((byte)(int)(pts << 1L | 0x1L));
|
||||
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) == 128) {
|
||||
fixTs(streamId, is, true);
|
||||
} else if ((flags2 & 0xC0) == 192) {
|
||||
fixTs(streamId, is, true);
|
||||
fixTs(streamId, is, false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVideo(int streamId) {
|
||||
return (streamId >= 224 && streamId <= 239);
|
||||
}
|
||||
|
||||
public boolean isAudio(int streamId) {
|
||||
return (streamId >= 191 && streamId <= 223);
|
||||
}
|
||||
|
||||
protected abstract long doWithTimestamp(int paramInt, long paramLong, boolean paramBoolean);
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.CRC32;
|
||||
import org.jcodec.common.Preconditions;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
import org.jcodec.containers.mps.MTSUtils;
|
||||
|
||||
public class HLSFixPMT {
|
||||
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) {
|
||||
Preconditions.checkState((71 == (tsPkt[0] & 0xFF)));
|
||||
int guidFlags = (tsPkt[1] & 0xFF) << 8 | tsPkt[2] & 0xFF;
|
||||
int guid = guidFlags & 0x1FFF;
|
||||
int payloadStart = guidFlags >> 14 & 0x1;
|
||||
int b0 = tsPkt[3] & 0xFF;
|
||||
int counter = b0 & 0xF;
|
||||
int payloadOff = 0;
|
||||
if ((b0 & 0x20) != 0)
|
||||
payloadOff = (tsPkt[4 + payloadOff] & 0xFF) + 1;
|
||||
if (payloadStart == 1)
|
||||
payloadOff += (tsPkt[4 + payloadOff] & 0xFF) + 1;
|
||||
if (guid == 0) {
|
||||
if (payloadStart == 0)
|
||||
throw new RuntimeException("PAT spans multiple TS packets, not supported!!!!!!");
|
||||
ByteBuffer bb = ByteBuffer.wrap(tsPkt, 4 + payloadOff, 184 - payloadOff);
|
||||
fixPAT(bb);
|
||||
ra.seek(ra.getFilePointer() - 188L);
|
||||
ra.write(tsPkt);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (ra != null)
|
||||
ra.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void fixPAT(ByteBuffer data) {
|
||||
ByteBuffer table = data.duplicate();
|
||||
MTSUtils.parseSection(data);
|
||||
ByteBuffer newPmt = data.duplicate();
|
||||
while (data.remaining() > 4) {
|
||||
short num = data.getShort();
|
||||
short pid = data.getShort();
|
||||
if (num != 0) {
|
||||
newPmt.putShort(num);
|
||||
newPmt.putShort(pid);
|
||||
}
|
||||
}
|
||||
if (newPmt.position() != data.position()) {
|
||||
ByteBuffer section = table.duplicate();
|
||||
section.get();
|
||||
int sectionLen = newPmt.position() - table.position() + 1;
|
||||
section.putShort((short)(sectionLen & 0xFFF | 0xB000));
|
||||
CRC32 crc32 = new CRC32();
|
||||
table.limit(newPmt.position());
|
||||
crc32.update(NIOUtils.toArray(table));
|
||||
newPmt.putInt((int)crc32.getValue());
|
||||
while (newPmt.hasRemaining())
|
||||
newPmt.put((byte)-1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
if (args.length < 1)
|
||||
exit("Please specify package location");
|
||||
File hlsPkg = new File(args[0]);
|
||||
if (!hlsPkg.isDirectory())
|
||||
exit("Not an HLS package, expected a folder");
|
||||
File[] listFiles = hlsPkg.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".ts");
|
||||
}
|
||||
});
|
||||
HLSFixPMT fix = new HLSFixPMT();
|
||||
for (int i = 0; i < listFiles.length; i++) {
|
||||
File file = listFiles[i];
|
||||
System.err.println("Processing: " + file.getName());
|
||||
fix.fix(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void exit(String message) {
|
||||
System.err.println("Syntax: hls_fixpmt <hls package location>");
|
||||
System.err.println(message);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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;
|
||||
import org.jcodec.common.Preconditions;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
import org.jcodec.common.tools.MainUtils;
|
||||
import org.jcodec.containers.mps.psi.PATSection;
|
||||
|
||||
public class HLSRelocatePMT {
|
||||
private static final int TS_START_CODE = 71;
|
||||
|
||||
private static final int CHUNK_SIZE_PKT = 1024;
|
||||
|
||||
private static final int TS_PKT_SIZE = 188;
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
MainUtils.Cmd cmd = MainUtils.parseArguments(args, new MainUtils.Flag[0]);
|
||||
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(192512);
|
||||
Set<Integer> pmtPids = new HashSet<>();
|
||||
List<ByteBuffer> held = new ArrayList<>();
|
||||
ByteBuffer patPkt = null;
|
||||
ByteBuffer pmtPkt = null;
|
||||
int totalPkt = 0;
|
||||
while (_in.read(buf) != -1) {
|
||||
buf.flip();
|
||||
buf.limit(buf.limit() / 188 * 188);
|
||||
while (buf.hasRemaining()) {
|
||||
ByteBuffer pkt = NIOUtils.read(buf, 188);
|
||||
ByteBuffer pktRead = pkt.duplicate();
|
||||
Preconditions.checkState((71 == (pktRead.get() & 0xFF)));
|
||||
totalPkt++;
|
||||
int guidFlags = (pktRead.get() & 0xFF) << 8 | pktRead.get() & 0xFF;
|
||||
int guid = 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(Integer.valueOf(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(Integer.valueOf(pmtPid));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pmtPids.contains(Integer.valueOf(guid))) {
|
||||
pmtPkt = pkt;
|
||||
out.write(patPkt);
|
||||
out.write(pmtPkt);
|
||||
for (ByteBuffer heldPkt : held)
|
||||
out.write(heldPkt);
|
||||
held.clear();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pmtPkt == null) {
|
||||
held.add(pkt);
|
||||
continue;
|
||||
}
|
||||
out.write(pkt);
|
||||
}
|
||||
buf.clear();
|
||||
}
|
||||
return totalPkt;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,435 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import org.jcodec.common.io.VLC;
|
||||
import org.jcodec.common.io.VLCBuilder;
|
||||
|
||||
public class MPEGConst {
|
||||
public static final int PICTURE_START_CODE = 0;
|
||||
|
||||
public static final int SLICE_START_CODE_FIRST = 1;
|
||||
|
||||
public static final int SLICE_START_CODE_LAST = 175;
|
||||
|
||||
public static final int USER_DATA_START_CODE = 178;
|
||||
|
||||
public static final int SEQUENCE_HEADER_CODE = 179;
|
||||
|
||||
public static final int SEQUENCE_ERROR_CODE = 180;
|
||||
|
||||
public static final int EXTENSION_START_CODE = 181;
|
||||
|
||||
public static final int SEQUENCE_END_CODE = 183;
|
||||
|
||||
public static final int GROUP_START_CODE = 184;
|
||||
|
||||
public static class MBType {
|
||||
public int macroblock_quant;
|
||||
|
||||
public int macroblock_motion_forward;
|
||||
|
||||
public int macroblock_motion_backward;
|
||||
|
||||
public int macroblock_pattern;
|
||||
|
||||
public int macroblock_intra;
|
||||
|
||||
public int spatial_temporal_weight_code_flag;
|
||||
|
||||
public int permitted_spatial_temporal_weight_classes;
|
||||
|
||||
MBType(int macroblock_quant, int macroblock_motion_forward, int macroblock_motion_backward, int macroblock_pattern, int macroblock_intra, int spatial_temporal_weight_code_flag, int permitted_spatial_temporal_weight_classes) {
|
||||
this.macroblock_quant = macroblock_quant;
|
||||
this.macroblock_motion_forward = macroblock_motion_forward;
|
||||
this.macroblock_motion_backward = macroblock_motion_backward;
|
||||
this.macroblock_pattern = macroblock_pattern;
|
||||
this.macroblock_intra = macroblock_intra;
|
||||
this.spatial_temporal_weight_code_flag = spatial_temporal_weight_code_flag;
|
||||
this.permitted_spatial_temporal_weight_classes = permitted_spatial_temporal_weight_classes;
|
||||
}
|
||||
}
|
||||
|
||||
public static final VLC vlcAddressIncrement = VLC.createVLC(new String[] {
|
||||
"1", "011", "010", "0011", "0010", "00011", "00010", "0000111", "0000110", "00001011",
|
||||
"00001010", "00001001", "00001000", "00000111", "00000110", "0000010111", "0000010110", "0000010101", "0000010100", "0000010011",
|
||||
"0000010010", "00000100011", "00000100010", "00000100001", "00000100000", "00000011111", "00000011110", "00000011101", "00000011100", "00000011011",
|
||||
"00000011010", "00000011001", "00000011000" });
|
||||
|
||||
public static final VLC vlcMBTypeI = VLC.createVLC(new String[] { "1", "01" });
|
||||
|
||||
public static final MBType[] mbTypeValI = new MBType[] { new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(1, 0, 0, 0, 1, 0, 0) };
|
||||
|
||||
public static final VLC vlcMBTypeP = VLC.createVLC(new String[] { "1", "01", "001", "00011", "00010", "00001", "000001" });
|
||||
|
||||
public static final MBType[] mbTypeValP = new MBType[] { new MBType(0, 1, 0, 1, 0, 0, 0), new MBType(0, 0, 0, 1, 0, 0, 0), new MBType(0, 1, 0, 0, 0, 0, 0), new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(1, 1, 0, 1, 0, 0, 0), new MBType(1, 0, 0, 1, 0, 0, 0), new MBType(1, 0, 0, 0, 1, 0, 0) };
|
||||
|
||||
public static final VLC vlcMBTypeB = VLC.createVLC(new String[] {
|
||||
"10", "11", "010", "011", "0010", "0011", "00011", "00010", "000011", "000010",
|
||||
"000001" });
|
||||
|
||||
public static final MBType[] mbTypeValB = new MBType[] {
|
||||
new MBType(0, 1, 1, 0, 0, 0, 0), new MBType(0, 1, 1, 1, 0, 0, 0), new MBType(0, 0, 1, 0, 0, 0, 0), new MBType(0, 0, 1, 1, 0, 0, 0), new MBType(0, 1, 0, 0, 0, 0, 0), new MBType(0, 1, 0, 1, 0, 0, 0), new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(1, 1, 1, 1, 0, 0, 0), new MBType(1, 1, 0, 1, 0, 0, 0), new MBType(1, 0, 1, 1, 0, 0, 0),
|
||||
new MBType(1, 0, 0, 0, 1, 0, 0) };
|
||||
|
||||
public static final VLC vlcMBTypeISpat = VLC.createVLC(new String[] { "1", "01", "0011", "0010", "0001" });
|
||||
|
||||
public static final MBType[] mbTypeValISpat = new MBType[] { new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(1, 0, 0, 0, 1, 0, 0), new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(1, 0, 0, 0, 1, 0, 0), new MBType(0, 0, 0, 0, 0, 0, 0) };
|
||||
|
||||
public static final VLC vlcMBTypePSpat = VLC.createVLC(new String[] {
|
||||
"10", "011", "0000100", "000111", "0010", "0000111", "0011", "010", "000100", "0000110",
|
||||
"11", "000101", "000110", "0000101", "0000010", "0000011" });
|
||||
|
||||
public static final MBType[] mbTypeValPSpat = new MBType[] {
|
||||
new MBType(0, 1, 0, 1, 0, 0, 0), new MBType(0, 1, 0, 1, 0, 1, 0), new MBType(0, 0, 0, 1, 0, 0, 0), new MBType(0, 0, 0, 1, 0, 1, 0), new MBType(0, 1, 0, 0, 0, 0, 0), new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(0, 1, 0, 0, 0, 1, 0), new MBType(1, 1, 0, 1, 0, 0, 0), new MBType(1, 0, 0, 1, 0, 0, 0), new MBType(1, 0, 0, 0, 1, 0, 0),
|
||||
new MBType(1, 1, 0, 1, 0, 1, 0), new MBType(1, 0, 0, 1, 0, 1, 0), new MBType(0, 0, 0, 0, 0, 1, 0), new MBType(0, 0, 0, 1, 0, 0, 0), new MBType(1, 0, 0, 1, 0, 0, 0), new MBType(0, 0, 0, 0, 0, 0, 0) };
|
||||
|
||||
public static final VLC vlcMBTypeBSpat = VLC.createVLC(new String[] {
|
||||
"10", "11", "010", "011", "0010", "0011", "000110", "000111", "000100", "000101",
|
||||
"0000110", "0000111", "0000100", "0000101", "00000100", "00000101", "000001100", "000001110", "000001101", "000001111" });
|
||||
|
||||
public static final MBType[] mbTypeValBSpat = new MBType[] {
|
||||
new MBType(0, 1, 1, 0, 0, 0, 0), new MBType(0, 1, 1, 1, 0, 0, 0), new MBType(0, 0, 1, 0, 0, 0, 0), new MBType(0, 0, 1, 1, 0, 0, 0), new MBType(0, 1, 0, 0, 0, 0, 0), new MBType(0, 1, 0, 1, 0, 0, 0), new MBType(0, 0, 1, 0, 0, 1, 0), new MBType(0, 0, 1, 1, 0, 1, 0), new MBType(0, 1, 0, 0, 0, 1, 0), new MBType(0, 1, 0, 1, 0, 1, 0),
|
||||
new MBType(0, 0, 0, 0, 1, 0, 0), new MBType(1, 1, 1, 1, 0, 0, 0), new MBType(1, 1, 0, 1, 0, 0, 0), new MBType(1, 0, 1, 1, 0, 0, 0), new MBType(1, 0, 0, 0, 1, 0, 0), new MBType(1, 1, 0, 1, 0, 1, 0), new MBType(1, 0, 1, 1, 0, 1, 0), new MBType(0, 0, 0, 0, 0, 0, 0), new MBType(1, 0, 0, 1, 0, 0, 0), new MBType(0, 0, 0, 1, 0, 0, 0) };
|
||||
|
||||
public static final VLC vlcMBTypeSNR = VLC.createVLC(new String[] { "1", "01", "001" });
|
||||
|
||||
public static final MBType[] mbTypeValSNR = new MBType[] { new MBType(0, 0, 0, 1, 0, 0, 0), new MBType(1, 0, 0, 1, 0, 0, 0), new MBType(0, 0, 0, 0, 0, 0, 0) };
|
||||
|
||||
public static final VLC vlcCBP = VLC.createVLC(new String[] {
|
||||
"000000001", "01011", "01001", "001101", "1101", "0010111", "0010011", "00011111", "1100", "0010110",
|
||||
"0010010", "00011110", "10011", "00011011", "00010111", "00010011", "1011", "0010101", "0010001", "00011101",
|
||||
"10001", "00011001", "00010101", "00010001", "001111", "00001111", "00001101", "000000011", "01111", "00001011",
|
||||
"00000111", "000000111", "1010", "0010100", "0010000", "00011100", "001110", "00001110", "00001100", "000000010",
|
||||
"10000", "00011000", "00010100", "00010000", "01110", "00001010", "00000110", "000000110", "10010", "00011010",
|
||||
"00010110", "00010010", "01101", "00001001", "00000101", "000000101", "01100", "00001000", "00000100", "000000100",
|
||||
"111", "01010", "01000", "001100" });
|
||||
|
||||
public static final VLC vlcMotionCode = VLC.createVLC(new String[] {
|
||||
"1", "01", "001", "0001", "000011", "0000101", "0000100", "0000011", "000001011", "000001010",
|
||||
"000001001", "0000010001", "0000010000", "0000001111", "0000001110", "0000001101", "0000001100" });
|
||||
|
||||
public static final VLC vlcDualPrime = VLC.createVLC(new String[] { "11", "0", "10" });
|
||||
|
||||
public static final VLC vlcDCSizeLuma = VLC.createVLC(new String[] {
|
||||
"100", "00", "01", "101", "110", "1110", "11110", "111110", "1111110", "11111110",
|
||||
"111111110", "111111111" });
|
||||
|
||||
public static final VLC vlcDCSizeChroma = VLC.createVLC(new String[] {
|
||||
"00", "01", "10", "110", "1110", "11110", "111110", "1111110", "11111110", "111111110",
|
||||
"1111111110", "1111111111" });
|
||||
|
||||
public static final VLC vlcCoeff0;
|
||||
|
||||
public static final VLC vlcCoeff1;
|
||||
|
||||
public static final int CODE_ESCAPE = 2049;
|
||||
|
||||
public static final int CODE_END = 2048;
|
||||
|
||||
static {
|
||||
VLCBuilder vlcCoeffBldr = new VLCBuilder();
|
||||
vlcCoeffBldr.set(2049, "000001");
|
||||
vlcCoeffBldr.set(2048, "10");
|
||||
vlcCoeffBldr.set(1, "11");
|
||||
vlcCoeffBldr.set(65, "011");
|
||||
vlcCoeffBldr.set(2, "0100");
|
||||
vlcCoeffBldr.set(129, "0101");
|
||||
vlcCoeffBldr.set(3, "00101");
|
||||
vlcCoeffBldr.set(193, "00111");
|
||||
vlcCoeffBldr.set(257, "00110");
|
||||
vlcCoeffBldr.set(66, "000110");
|
||||
vlcCoeffBldr.set(321, "000111");
|
||||
vlcCoeffBldr.set(385, "000101");
|
||||
vlcCoeffBldr.set(449, "000100");
|
||||
vlcCoeffBldr.set(4, "0000110");
|
||||
vlcCoeffBldr.set(130, "0000100");
|
||||
vlcCoeffBldr.set(513, "0000111");
|
||||
vlcCoeffBldr.set(577, "0000101");
|
||||
vlcCoeffBldr.set(5, "00100110");
|
||||
vlcCoeffBldr.set(6, "00100001");
|
||||
vlcCoeffBldr.set(67, "00100101");
|
||||
vlcCoeffBldr.set(194, "00100100");
|
||||
vlcCoeffBldr.set(641, "00100111");
|
||||
vlcCoeffBldr.set(705, "00100011");
|
||||
vlcCoeffBldr.set(769, "00100010");
|
||||
vlcCoeffBldr.set(833, "00100000");
|
||||
vlcCoeffBldr.set(7, "0000001010");
|
||||
vlcCoeffBldr.set(68, "0000001100");
|
||||
vlcCoeffBldr.set(131, "0000001011");
|
||||
vlcCoeffBldr.set(258, "0000001111");
|
||||
vlcCoeffBldr.set(322, "0000001001");
|
||||
vlcCoeffBldr.set(897, "0000001110");
|
||||
vlcCoeffBldr.set(961, "0000001101");
|
||||
vlcCoeffBldr.set(1025, "0000001000");
|
||||
vlcCoeffBldr.set(8, "000000011101");
|
||||
vlcCoeffBldr.set(9, "000000011000");
|
||||
vlcCoeffBldr.set(10, "000000010011");
|
||||
vlcCoeffBldr.set(11, "000000010000");
|
||||
vlcCoeffBldr.set(69, "000000011011");
|
||||
vlcCoeffBldr.set(132, "000000010100");
|
||||
vlcCoeffBldr.set(195, "000000011100");
|
||||
vlcCoeffBldr.set(259, "000000010010");
|
||||
vlcCoeffBldr.set(386, "000000011110");
|
||||
vlcCoeffBldr.set(450, "000000010101");
|
||||
vlcCoeffBldr.set(514, "000000010001");
|
||||
vlcCoeffBldr.set(1089, "000000011111");
|
||||
vlcCoeffBldr.set(1153, "000000011010");
|
||||
vlcCoeffBldr.set(1217, "000000011001");
|
||||
vlcCoeffBldr.set(1281, "000000010111");
|
||||
vlcCoeffBldr.set(1345, "000000010110");
|
||||
vlcCoeffBldr.set(12, "0000000011010");
|
||||
vlcCoeffBldr.set(13, "0000000011001");
|
||||
vlcCoeffBldr.set(14, "0000000011000");
|
||||
vlcCoeffBldr.set(15, "0000000010111");
|
||||
vlcCoeffBldr.set(70, "0000000010110");
|
||||
vlcCoeffBldr.set(71, "0000000010101");
|
||||
vlcCoeffBldr.set(133, "0000000010100");
|
||||
vlcCoeffBldr.set(196, "0000000010011");
|
||||
vlcCoeffBldr.set(323, "0000000010010");
|
||||
vlcCoeffBldr.set(578, "0000000010001");
|
||||
vlcCoeffBldr.set(642, "0000000010000");
|
||||
vlcCoeffBldr.set(1409, "0000000011111");
|
||||
vlcCoeffBldr.set(1473, "0000000011110");
|
||||
vlcCoeffBldr.set(1537, "0000000011101");
|
||||
vlcCoeffBldr.set(1601, "0000000011100");
|
||||
vlcCoeffBldr.set(1665, "0000000011011");
|
||||
vlcCoeffBldr.set(16, "00000000011111");
|
||||
vlcCoeffBldr.set(17, "00000000011110");
|
||||
vlcCoeffBldr.set(18, "00000000011101");
|
||||
vlcCoeffBldr.set(19, "00000000011100");
|
||||
vlcCoeffBldr.set(20, "00000000011011");
|
||||
vlcCoeffBldr.set(21, "00000000011010");
|
||||
vlcCoeffBldr.set(22, "00000000011001");
|
||||
vlcCoeffBldr.set(23, "00000000011000");
|
||||
vlcCoeffBldr.set(24, "00000000010111");
|
||||
vlcCoeffBldr.set(25, "00000000010110");
|
||||
vlcCoeffBldr.set(26, "00000000010101");
|
||||
vlcCoeffBldr.set(27, "00000000010100");
|
||||
vlcCoeffBldr.set(28, "00000000010011");
|
||||
vlcCoeffBldr.set(29, "00000000010010");
|
||||
vlcCoeffBldr.set(30, "00000000010001");
|
||||
vlcCoeffBldr.set(31, "00000000010000");
|
||||
vlcCoeffBldr.set(32, "000000000011000");
|
||||
vlcCoeffBldr.set(33, "000000000010111");
|
||||
vlcCoeffBldr.set(34, "000000000010110");
|
||||
vlcCoeffBldr.set(35, "000000000010101");
|
||||
vlcCoeffBldr.set(36, "000000000010100");
|
||||
vlcCoeffBldr.set(37, "000000000010011");
|
||||
vlcCoeffBldr.set(38, "000000000010010");
|
||||
vlcCoeffBldr.set(39, "000000000010001");
|
||||
vlcCoeffBldr.set(40, "000000000010000");
|
||||
vlcCoeffBldr.set(72, "000000000011111");
|
||||
vlcCoeffBldr.set(73, "000000000011110");
|
||||
vlcCoeffBldr.set(74, "000000000011101");
|
||||
vlcCoeffBldr.set(75, "000000000011100");
|
||||
vlcCoeffBldr.set(76, "000000000011011");
|
||||
vlcCoeffBldr.set(77, "000000000011010");
|
||||
vlcCoeffBldr.set(78, "000000000011001");
|
||||
vlcCoeffBldr.set(79, "0000000000010011");
|
||||
vlcCoeffBldr.set(80, "0000000000010010");
|
||||
vlcCoeffBldr.set(81, "0000000000010001");
|
||||
vlcCoeffBldr.set(82, "0000000000010000");
|
||||
vlcCoeffBldr.set(387, "0000000000010100");
|
||||
vlcCoeffBldr.set(706, "0000000000011010");
|
||||
vlcCoeffBldr.set(770, "0000000000011001");
|
||||
vlcCoeffBldr.set(834, "0000000000011000");
|
||||
vlcCoeffBldr.set(898, "0000000000010111");
|
||||
vlcCoeffBldr.set(962, "0000000000010110");
|
||||
vlcCoeffBldr.set(1026, "0000000000010101");
|
||||
vlcCoeffBldr.set(1729, "0000000000011111");
|
||||
vlcCoeffBldr.set(1793, "0000000000011110");
|
||||
vlcCoeffBldr.set(1857, "0000000000011101");
|
||||
vlcCoeffBldr.set(1921, "0000000000011100");
|
||||
vlcCoeffBldr.set(1985, "0000000000011011");
|
||||
vlcCoeff0 = vlcCoeffBldr.getVLC();
|
||||
vlcCoeffBldr = new VLCBuilder();
|
||||
vlcCoeffBldr.set(2049, "000001");
|
||||
vlcCoeffBldr.set(2048, "0110");
|
||||
vlcCoeffBldr.set(1, "10");
|
||||
vlcCoeffBldr.set(65, "010");
|
||||
vlcCoeffBldr.set(2, "110");
|
||||
vlcCoeffBldr.set(129, "00101");
|
||||
vlcCoeffBldr.set(3, "0111");
|
||||
vlcCoeffBldr.set(193, "00111");
|
||||
vlcCoeffBldr.set(257, "000110");
|
||||
vlcCoeffBldr.set(66, "00110");
|
||||
vlcCoeffBldr.set(321, "000111");
|
||||
vlcCoeffBldr.set(385, "0000110");
|
||||
vlcCoeffBldr.set(449, "0000100");
|
||||
vlcCoeffBldr.set(4, "11100");
|
||||
vlcCoeffBldr.set(130, "0000111");
|
||||
vlcCoeffBldr.set(513, "0000101");
|
||||
vlcCoeffBldr.set(577, "1111000");
|
||||
vlcCoeffBldr.set(5, "11101");
|
||||
vlcCoeffBldr.set(6, "000101");
|
||||
vlcCoeffBldr.set(67, "1111001");
|
||||
vlcCoeffBldr.set(194, "00100110");
|
||||
vlcCoeffBldr.set(641, "1111010");
|
||||
vlcCoeffBldr.set(705, "00100001");
|
||||
vlcCoeffBldr.set(769, "00100101");
|
||||
vlcCoeffBldr.set(833, "00100100");
|
||||
vlcCoeffBldr.set(7, "000100");
|
||||
vlcCoeffBldr.set(68, "00100111");
|
||||
vlcCoeffBldr.set(131, "11111100");
|
||||
vlcCoeffBldr.set(258, "11111101");
|
||||
vlcCoeffBldr.set(322, "000000100");
|
||||
vlcCoeffBldr.set(897, "000000101");
|
||||
vlcCoeffBldr.set(961, "000000111");
|
||||
vlcCoeffBldr.set(1025, "0000001101");
|
||||
vlcCoeffBldr.set(8, "1111011");
|
||||
vlcCoeffBldr.set(9, "1111100");
|
||||
vlcCoeffBldr.set(10, "00100011");
|
||||
vlcCoeffBldr.set(11, "00100010");
|
||||
vlcCoeffBldr.set(69, "00100000");
|
||||
vlcCoeffBldr.set(132, "0000001100");
|
||||
vlcCoeffBldr.set(195, "000000011100");
|
||||
vlcCoeffBldr.set(259, "000000010010");
|
||||
vlcCoeffBldr.set(386, "000000011110");
|
||||
vlcCoeffBldr.set(450, "000000010101");
|
||||
vlcCoeffBldr.set(514, "000000010001");
|
||||
vlcCoeffBldr.set(1089, "000000011111");
|
||||
vlcCoeffBldr.set(1153, "000000011010");
|
||||
vlcCoeffBldr.set(1217, "000000011001");
|
||||
vlcCoeffBldr.set(1281, "000000010111");
|
||||
vlcCoeffBldr.set(1345, "000000010110");
|
||||
vlcCoeffBldr.set(12, "11111010");
|
||||
vlcCoeffBldr.set(13, "11111011");
|
||||
vlcCoeffBldr.set(14, "11111110");
|
||||
vlcCoeffBldr.set(15, "11111111");
|
||||
vlcCoeffBldr.set(70, "0000000010110");
|
||||
vlcCoeffBldr.set(71, "0000000010101");
|
||||
vlcCoeffBldr.set(133, "0000000010100");
|
||||
vlcCoeffBldr.set(196, "0000000010011");
|
||||
vlcCoeffBldr.set(323, "0000000010010");
|
||||
vlcCoeffBldr.set(578, "0000000010001");
|
||||
vlcCoeffBldr.set(642, "0000000010000");
|
||||
vlcCoeffBldr.set(1409, "0000000011111");
|
||||
vlcCoeffBldr.set(1473, "0000000011110");
|
||||
vlcCoeffBldr.set(1537, "0000000011101");
|
||||
vlcCoeffBldr.set(1601, "0000000011100");
|
||||
vlcCoeffBldr.set(1665, "0000000011011");
|
||||
vlcCoeffBldr.set(16, "00000000011111");
|
||||
vlcCoeffBldr.set(17, "00000000011110");
|
||||
vlcCoeffBldr.set(18, "00000000011101");
|
||||
vlcCoeffBldr.set(19, "00000000011100");
|
||||
vlcCoeffBldr.set(20, "00000000011011");
|
||||
vlcCoeffBldr.set(21, "00000000011010");
|
||||
vlcCoeffBldr.set(22, "00000000011001");
|
||||
vlcCoeffBldr.set(23, "00000000011000");
|
||||
vlcCoeffBldr.set(24, "00000000010111");
|
||||
vlcCoeffBldr.set(25, "00000000010110");
|
||||
vlcCoeffBldr.set(26, "00000000010101");
|
||||
vlcCoeffBldr.set(27, "00000000010100");
|
||||
vlcCoeffBldr.set(28, "00000000010011");
|
||||
vlcCoeffBldr.set(29, "00000000010010");
|
||||
vlcCoeffBldr.set(30, "00000000010001");
|
||||
vlcCoeffBldr.set(31, "00000000010000");
|
||||
vlcCoeffBldr.set(32, "000000000011000");
|
||||
vlcCoeffBldr.set(33, "000000000010111");
|
||||
vlcCoeffBldr.set(34, "000000000010110");
|
||||
vlcCoeffBldr.set(35, "000000000010101");
|
||||
vlcCoeffBldr.set(36, "000000000010100");
|
||||
vlcCoeffBldr.set(37, "000000000010011");
|
||||
vlcCoeffBldr.set(38, "000000000010010");
|
||||
vlcCoeffBldr.set(39, "000000000010001");
|
||||
vlcCoeffBldr.set(40, "000000000010000");
|
||||
vlcCoeffBldr.set(72, "000000000011111");
|
||||
vlcCoeffBldr.set(73, "000000000011110");
|
||||
vlcCoeffBldr.set(74, "000000000011101");
|
||||
vlcCoeffBldr.set(75, "000000000011100");
|
||||
vlcCoeffBldr.set(76, "000000000011011");
|
||||
vlcCoeffBldr.set(77, "000000000011010");
|
||||
vlcCoeffBldr.set(78, "000000000011001");
|
||||
vlcCoeffBldr.set(79, "0000000000010011");
|
||||
vlcCoeffBldr.set(80, "0000000000010010");
|
||||
vlcCoeffBldr.set(81, "0000000000010001");
|
||||
vlcCoeffBldr.set(82, "0000000000010000");
|
||||
vlcCoeffBldr.set(387, "0000000000010100");
|
||||
vlcCoeffBldr.set(706, "0000000000011010");
|
||||
vlcCoeffBldr.set(770, "0000000000011001");
|
||||
vlcCoeffBldr.set(834, "0000000000011000");
|
||||
vlcCoeffBldr.set(898, "0000000000010111");
|
||||
vlcCoeffBldr.set(962, "0000000000010110");
|
||||
vlcCoeffBldr.set(1026, "0000000000010101");
|
||||
vlcCoeffBldr.set(1729, "0000000000011111");
|
||||
vlcCoeffBldr.set(1793, "0000000000011110");
|
||||
vlcCoeffBldr.set(1857, "0000000000011101");
|
||||
vlcCoeffBldr.set(1921, "0000000000011100");
|
||||
vlcCoeffBldr.set(1985, "0000000000011011");
|
||||
vlcCoeff1 = vlcCoeffBldr.getVLC();
|
||||
}
|
||||
|
||||
public static final int[] qScaleTab1 = new int[] {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
|
||||
20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
|
||||
40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
|
||||
60, 62 };
|
||||
|
||||
public static final int[] qScaleTab2 = new int[] {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
|
||||
12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
|
||||
40, 44, 48, 52, 56, 64, 72, 80, 88, 96,
|
||||
104, 112 };
|
||||
|
||||
public static final int[] defaultQMatIntra = new int[] {
|
||||
8, 16, 19, 22, 26, 27, 29, 34, 16, 16,
|
||||
22, 24, 27, 29, 34, 37, 19, 22, 26, 27,
|
||||
29, 34, 34, 38, 22, 22, 26, 27, 29, 34,
|
||||
37, 40, 22, 26, 27, 29, 32, 35, 40, 48,
|
||||
26, 27, 29, 32, 35, 40, 48, 58, 26, 27,
|
||||
29, 34, 38, 46, 56, 69, 27, 29, 35, 38,
|
||||
46, 56, 69, 83 };
|
||||
|
||||
public static final int[] defaultQMatInter = new int[] {
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16 };
|
||||
|
||||
public static final int[][] scan = new int[][] { new int[] {
|
||||
0, 1, 8, 16, 9, 2, 3, 10, 17, 24,
|
||||
32, 25, 18, 11, 4, 5, 12, 19, 26, 33,
|
||||
40, 48, 41, 34, 27, 20, 13, 6, 7, 14,
|
||||
21, 28, 35, 42, 49, 56, 57, 50, 43, 36,
|
||||
29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
|
||||
52, 45, 38, 31, 39, 46, 53, 60, 61, 54,
|
||||
47, 55, 62, 63 }, new int[] {
|
||||
0, 8, 16, 24, 1, 9, 2, 10, 17, 25,
|
||||
32, 40, 48, 56, 57, 49, 41, 33, 26, 18,
|
||||
3, 11, 4, 12, 19, 27, 34, 42, 50, 58,
|
||||
35, 43, 51, 59, 20, 28, 5, 13, 6, 14,
|
||||
21, 29, 36, 44, 52, 60, 37, 45, 53, 61,
|
||||
22, 30, 7, 15, 23, 31, 38, 46, 54, 62,
|
||||
39, 47, 55, 63 } };
|
||||
|
||||
public static final int[] BLOCK_TO_CC = new int[] {
|
||||
0, 0, 0, 0, 1, 2, 1, 2, 1, 2,
|
||||
1, 2 };
|
||||
|
||||
public static final int[] BLOCK_POS_X = new int[] {
|
||||
0, 8, 0, 8, 0, 0, 0, 0, 8, 8,
|
||||
8, 8, 0, 0, 0, 0, 0, 8, 0, 8,
|
||||
0, 0, 0, 0, 8, 8, 8, 8 };
|
||||
|
||||
public static final int[] BLOCK_POS_Y = new int[] {
|
||||
0, 0, 8, 8, 0, 0, 8, 8, 0, 0,
|
||||
8, 8, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 1 };
|
||||
|
||||
public static final int[] STEP_Y = new int[] {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
public static final int[] SQUEEZE_X = new int[] { 0, 1, 1, 0 };
|
||||
|
||||
public static final int[] SQUEEZE_Y = new int[] { 0, 1, 0, 0 };
|
||||
|
||||
public static final int IntraCoded = 1;
|
||||
|
||||
public static final int PredictiveCoded = 2;
|
||||
|
||||
public static final int BiPredictiveCoded = 3;
|
||||
}
|
||||
|
|
@ -0,0 +1,611 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.GOPHeader;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.PictureHeader;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.SequenceHeader;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.SequenceScalableExtension;
|
||||
import org.jcodec.common.Preconditions;
|
||||
import org.jcodec.common.UsedViaReflection;
|
||||
import org.jcodec.common.VideoCodecMeta;
|
||||
import org.jcodec.common.VideoDecoder;
|
||||
import org.jcodec.common.dct.SparseIDCT;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.VLC;
|
||||
import org.jcodec.common.model.ColorSpace;
|
||||
import org.jcodec.common.model.Picture;
|
||||
import org.jcodec.common.model.Rect;
|
||||
import org.jcodec.common.model.Size;
|
||||
|
||||
public class MPEGDecoder extends VideoDecoder {
|
||||
protected SequenceHeader sh;
|
||||
|
||||
protected GOPHeader gh;
|
||||
|
||||
private Picture[] refFrames = new Picture[2];
|
||||
|
||||
private Picture[] refFields = new Picture[2];
|
||||
|
||||
public static class Context {
|
||||
int[] intra_dc_predictor = new int[3];
|
||||
|
||||
public int mbWidth;
|
||||
|
||||
int mbNo;
|
||||
|
||||
public int codedWidth;
|
||||
|
||||
public int codedHeight;
|
||||
|
||||
public int mbHeight;
|
||||
|
||||
public ColorSpace color;
|
||||
|
||||
public MPEGConst.MBType lastPredB;
|
||||
|
||||
public int[][] qMats;
|
||||
|
||||
public int[] scan;
|
||||
|
||||
public int picWidth;
|
||||
|
||||
public int picHeight;
|
||||
}
|
||||
|
||||
public Picture decodeFrame(ByteBuffer buffer, byte[][] buf) {
|
||||
PictureHeader ph = readHeader(buffer);
|
||||
if ((this.refFrames[0] == null && ph.picture_coding_type > 1) || (this.refFrames[1] == null && ph.picture_coding_type > 2))
|
||||
throw new RuntimeException("Not enough references to decode " + (
|
||||
(ph.picture_coding_type == 1) ? "P" : "B") + " frame");
|
||||
Context context = initContext(this.sh, ph);
|
||||
Picture pic = new Picture(context.codedWidth, context.codedHeight, buf, null, context.color, 0, new Rect(0, 0, context.picWidth, context.picHeight));
|
||||
if (ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure != 3) {
|
||||
decodePicture(context, ph, buffer, buf, ph.pictureCodingExtension.picture_structure - 1, 1);
|
||||
ph = readHeader(buffer);
|
||||
context = initContext(this.sh, ph);
|
||||
decodePicture(context, ph, buffer, buf, ph.pictureCodingExtension.picture_structure - 1, 1);
|
||||
} else {
|
||||
decodePicture(context, ph, buffer, buf, 0, 0);
|
||||
}
|
||||
if (ph.picture_coding_type == 1 || ph.picture_coding_type == 2) {
|
||||
Picture unused = this.refFrames[1];
|
||||
this.refFrames[1] = this.refFrames[0];
|
||||
this.refFrames[0] = copyAndCreateIfNeeded(pic, unused);
|
||||
}
|
||||
return pic;
|
||||
}
|
||||
|
||||
private Picture copyAndCreateIfNeeded(Picture src, Picture dst) {
|
||||
if (dst == null || !dst.compatible(src))
|
||||
dst = src.createCompatible();
|
||||
dst.copyFrom(src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
private PictureHeader readHeader(ByteBuffer buffer) {
|
||||
assert false : "Decompilation failed at line #134 -> offsets [0]";
|
||||
assert false : "Decompilation failed at line #136 -> offsets [2]";
|
||||
assert false : "Decompilation failed at line #138 -> offsets [8]";
|
||||
assert false : "Decompilation failed at line #139 -> offsets [18]";
|
||||
assert false : "Decompilation failed at line #140 -> offsets [28]";
|
||||
assert false : "Decompilation failed at line #141 -> offsets [36]";
|
||||
assert false : "Decompilation failed at line #142 -> offsets [42]";
|
||||
assert false : "Decompilation failed at line #143 -> offsets [49]";
|
||||
assert false : "Decompilation failed at line #145 -> offsets [58]";
|
||||
assert false : "Decompilation failed at line #146 -> offsets [64]";
|
||||
assert false : "Decompilation failed at line #147 -> offsets [75]";
|
||||
assert false : "Decompilation failed at line #148 -> offsets [86]";
|
||||
assert false : "Decompilation failed at line #149 -> offsets [91]";
|
||||
assert false : "Decompilation failed at line #150 -> offsets [99]";
|
||||
assert false : "Decompilation failed at line #151 -> offsets [107]";
|
||||
assert false : "Decompilation failed at line #152 -> offsets [116]";
|
||||
assert false : "Decompilation failed at line #155 -> offsets [134]";
|
||||
assert false : "Decompilation failed at line #157 -> offsets [145]";
|
||||
assert false : "Decompilation failed at line #158 -> offsets [154]";
|
||||
assert false : "Decompilation failed at line #163 -> offsets [165]";
|
||||
assert false : "Decompilation failed at line #164 -> offsets [175]";
|
||||
assert false : "Decompilation failed at line #165 -> offsets [178]";
|
||||
}
|
||||
|
||||
protected Context initContext(SequenceHeader sh, PictureHeader ph) {
|
||||
Context context = new Context();
|
||||
context.codedWidth = sh.horizontal_size + 15 & 0xFFFFFFF0;
|
||||
context.codedHeight = getCodedHeight(sh, ph);
|
||||
context.mbWidth = sh.horizontal_size + 15 >> 4;
|
||||
context.mbHeight = sh.vertical_size + 15 >> 4;
|
||||
context.picWidth = sh.horizontal_size;
|
||||
context.picHeight = sh.vertical_size;
|
||||
int chromaFormat = 1;
|
||||
if (sh.sequenceExtension != null)
|
||||
chromaFormat = sh.sequenceExtension.chroma_format;
|
||||
context.color = getColor(chromaFormat);
|
||||
context.scan = MPEGConst.scan[(ph.pictureCodingExtension == null) ? 0 : ph.pictureCodingExtension.alternate_scan];
|
||||
int[] inter = (sh.non_intra_quantiser_matrix == null) ? zigzag(MPEGConst.defaultQMatInter, context.scan) :
|
||||
sh.non_intra_quantiser_matrix;
|
||||
int[] intra = (sh.intra_quantiser_matrix == null) ? zigzag(MPEGConst.defaultQMatIntra, context.scan) :
|
||||
sh.intra_quantiser_matrix;
|
||||
context.qMats = new int[][] { inter, inter, intra, intra };
|
||||
if (ph.quantMatrixExtension != null) {
|
||||
if (ph.quantMatrixExtension.non_intra_quantiser_matrix != null)
|
||||
context.qMats[0] = ph.quantMatrixExtension.non_intra_quantiser_matrix;
|
||||
if (ph.quantMatrixExtension.chroma_non_intra_quantiser_matrix != null)
|
||||
context.qMats[1] = ph.quantMatrixExtension.chroma_non_intra_quantiser_matrix;
|
||||
if (ph.quantMatrixExtension.intra_quantiser_matrix != null)
|
||||
context.qMats[2] = ph.quantMatrixExtension.intra_quantiser_matrix;
|
||||
if (ph.quantMatrixExtension.chroma_intra_quantiser_matrix != null)
|
||||
context.qMats[3] = ph.quantMatrixExtension.chroma_intra_quantiser_matrix;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private int[] zigzag(int[] array, int[] scan) {
|
||||
int[] result = new int[64];
|
||||
for (int i = 0; i < scan.length; i++)
|
||||
result[i] = array[scan[i]];
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int getCodedHeight(SequenceHeader sh, PictureHeader ph) {
|
||||
int field = (ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure != 3) ? 1 : 0;
|
||||
return ((sh.vertical_size >> field) + 15 & 0xFFFFFFF0) << field;
|
||||
}
|
||||
|
||||
public Picture decodePicture(Context context, PictureHeader ph, ByteBuffer buffer, byte[][] buf, int vertOff, int vertStep) {
|
||||
int planeSize = context.codedWidth * context.codedHeight;
|
||||
if (buf.length < 3 || (buf[0]).length < planeSize || (buf[1]).length < planeSize || (buf[2]).length < planeSize)
|
||||
throw new RuntimeException("ByteBuffer too small to hold output picture [" + context.codedWidth + "x" + context.codedHeight + "]");
|
||||
try {
|
||||
ByteBuffer segment;
|
||||
while ((segment = MPEGUtil.nextSegment(buffer)) != null) {
|
||||
int startCode = segment.get(3) & 0xFF;
|
||||
if (startCode >= 1 && startCode <= 175) {
|
||||
doDecodeSlice(context, ph, buf, vertOff, vertStep, segment);
|
||||
continue;
|
||||
}
|
||||
if (startCode >= 179 && startCode != 182 && startCode != 183)
|
||||
throw new RuntimeException("Unexpected start code " + startCode);
|
||||
if (startCode == 0) {
|
||||
buffer.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Picture pic = Picture.createPicture(context.codedWidth, context.codedHeight, buf, context.color);
|
||||
if ((ph.picture_coding_type == 1 || ph.picture_coding_type == 2) && ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure != 3)
|
||||
this.refFields[ph.pictureCodingExtension.picture_structure - 1] = copyAndCreateIfNeeded(pic, this.refFields[ph.pictureCodingExtension.picture_structure - 1]);
|
||||
return pic;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void doDecodeSlice(Context context, PictureHeader ph, byte[][] buf, int vertOff, int vertStep, ByteBuffer segment) throws IOException {
|
||||
int startCode = segment.get(3) & 0xFF;
|
||||
ByteBuffer dup = segment.duplicate();
|
||||
dup.position(4);
|
||||
try {
|
||||
decodeSlice(ph, startCode, context, buf, BitReader.createBitReader(dup), vertOff, vertStep);
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private ColorSpace getColor(int chromaFormat) {
|
||||
switch (chromaFormat) {
|
||||
case 1:
|
||||
return ColorSpace.YUV420;
|
||||
case 2:
|
||||
return ColorSpace.YUV422;
|
||||
case 3:
|
||||
return ColorSpace.YUV444;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void decodeSlice(PictureHeader ph, int verticalPos, Context context, byte[][] buf, BitReader _in, int vertOff, int vertStep) throws IOException {
|
||||
int stride = context.codedWidth;
|
||||
resetDCPredictors(context, ph);
|
||||
int mbRow = verticalPos - 1;
|
||||
if (this.sh.vertical_size > 2800)
|
||||
mbRow += _in.readNBit(3) << 7;
|
||||
if (this.sh.sequenceScalableExtension != null && this.sh.sequenceScalableExtension.scalable_mode == 0)
|
||||
int i = _in.readNBit(7);
|
||||
int qScaleCode = _in.readNBit(5);
|
||||
if (_in.read1Bit() == 1) {
|
||||
int intraSlice = _in.read1Bit();
|
||||
_in.skip(7);
|
||||
while (_in.read1Bit() == 1)
|
||||
_in.readNBit(8);
|
||||
}
|
||||
MPEGPred pred = new MPEGPred(
|
||||
(ph.pictureCodingExtension != null) ? ph.pictureCodingExtension.f_code :
|
||||
new int[][] { new int[] { ph.forward_f_code, ph.forward_f_code }, , new int[] { ph.backward_f_code, ph.backward_f_code }, }, (this.sh.sequenceExtension != null) ? this.sh.sequenceExtension.chroma_format : 1,
|
||||
!(ph.pictureCodingExtension != null && ph.pictureCodingExtension.top_field_first == 0));
|
||||
int[] ctx = { qScaleCode };
|
||||
for (int prevAddr = mbRow * context.mbWidth - 1; _in.checkNBit(23) != 0; ) {
|
||||
prevAddr = decodeMacroblock(ph, context, prevAddr, ctx, buf, stride, _in, vertOff, vertStep, pred);
|
||||
context.mbNo++;
|
||||
}
|
||||
}
|
||||
|
||||
private void resetDCPredictors(Context context, PictureHeader ph) {
|
||||
int rval = 128;
|
||||
if (ph.pictureCodingExtension != null)
|
||||
rval = 1 << 7 + ph.pictureCodingExtension.intra_dc_precision;
|
||||
context.intra_dc_predictor[2] = rval;
|
||||
context.intra_dc_predictor[1] = rval;
|
||||
context.intra_dc_predictor[0] = rval;
|
||||
}
|
||||
|
||||
public int decodeMacroblock(PictureHeader ph, Context context, int prevAddr, int[] qScaleCode, byte[][] buf, int stride, BitReader bits, int vertOff, int vertStep, MPEGPred pred) {
|
||||
int mbAddr = prevAddr;
|
||||
while (bits.checkNBit(11) == 8) {
|
||||
bits.skip(11);
|
||||
mbAddr += 33;
|
||||
}
|
||||
mbAddr += MPEGConst.vlcAddressIncrement.readVLC(bits) + 1;
|
||||
int chromaFormat = 1;
|
||||
if (this.sh.sequenceExtension != null)
|
||||
chromaFormat = this.sh.sequenceExtension.chroma_format;
|
||||
for (int i = prevAddr + 1; i < mbAddr; i++) {
|
||||
int[][] arrayOfInt = { new int[256], new int[1 << chromaFormat + 5], new int[1 << chromaFormat + 5] };
|
||||
int k = i % context.mbWidth;
|
||||
int m = i / context.mbWidth;
|
||||
if (ph.picture_coding_type == 2)
|
||||
pred.reset();
|
||||
mvZero(context, ph, pred, k, m, arrayOfInt);
|
||||
put(arrayOfInt, buf, stride, chromaFormat, k, m, context.codedWidth, context.codedHeight >> vertStep, vertOff, vertStep);
|
||||
}
|
||||
VLC vlcMBType = SequenceScalableExtension.vlcMBType(ph.picture_coding_type, this.sh.sequenceScalableExtension);
|
||||
MPEGConst.MBType[] mbTypeVal = SequenceScalableExtension.mbTypeVal(ph.picture_coding_type, this.sh.sequenceScalableExtension);
|
||||
MPEGConst.MBType mbType = mbTypeVal[vlcMBType.readVLC(bits)];
|
||||
if (mbType.macroblock_intra != 1 || mbAddr - prevAddr > 1)
|
||||
resetDCPredictors(context, ph);
|
||||
int spatial_temporal_weight_code = 0;
|
||||
if (mbType.spatial_temporal_weight_code_flag == 1 && ph.pictureSpatialScalableExtension != null && ph.pictureSpatialScalableExtension.spatial_temporal_weight_code_table_index != 0)
|
||||
spatial_temporal_weight_code = bits.readNBit(2);
|
||||
int motion_type = -1;
|
||||
if (mbType.macroblock_motion_forward != 0 || mbType.macroblock_motion_backward != 0)
|
||||
if (ph.pictureCodingExtension == null || (ph.pictureCodingExtension.picture_structure == 3 && ph.pictureCodingExtension.frame_pred_frame_dct == 1)) {
|
||||
motion_type = 2;
|
||||
} else {
|
||||
motion_type = bits.readNBit(2);
|
||||
}
|
||||
int dctType = 0;
|
||||
if (ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure == 3 && ph.pictureCodingExtension.frame_pred_frame_dct == 0 && (mbType.macroblock_intra != 0 || mbType.macroblock_pattern != 0))
|
||||
dctType = bits.read1Bit();
|
||||
if (mbType.macroblock_quant != 0)
|
||||
qScaleCode[0] = bits.readNBit(5);
|
||||
boolean concealmentMv = (ph.pictureCodingExtension != null && ph.pictureCodingExtension.concealment_motion_vectors != 0);
|
||||
int[][] predFwd = null;
|
||||
int mbX = mbAddr % context.mbWidth;
|
||||
int mbY = mbAddr / context.mbWidth;
|
||||
if (mbType.macroblock_intra == 1) {
|
||||
if (!concealmentMv)
|
||||
pred.reset();
|
||||
} else if (mbType.macroblock_motion_forward != 0) {
|
||||
int refIdx = (ph.picture_coding_type == 2) ? 0 : 1;
|
||||
predFwd = new int[][] { new int[256], new int[1 << chromaFormat + 5], new int[1 << chromaFormat + 5] };
|
||||
if (ph.pictureCodingExtension == null || ph.pictureCodingExtension.picture_structure == 3) {
|
||||
pred.predictInFrame(this.refFrames[refIdx], mbX << 4, mbY << 4, predFwd, bits, motion_type, 0, spatial_temporal_weight_code);
|
||||
} else if (ph.picture_coding_type == 2) {
|
||||
pred.predictInField(this.refFields, mbX << 4, mbY << 4, predFwd, bits, motion_type, 0, ph.pictureCodingExtension.picture_structure - 1);
|
||||
} else {
|
||||
pred.predictInField(new Picture[] { this.refFrames[refIdx], this.refFrames[refIdx] }, mbX << 4, mbY << 4, predFwd, bits, motion_type, 0, ph.pictureCodingExtension.picture_structure - 1);
|
||||
}
|
||||
} else if (ph.picture_coding_type == 2) {
|
||||
predFwd = new int[][] { new int[256], new int[1 << chromaFormat + 5], new int[1 << chromaFormat + 5] };
|
||||
pred.reset();
|
||||
mvZero(context, ph, pred, mbX, mbY, predFwd);
|
||||
}
|
||||
int[][] predBack = null;
|
||||
if (mbType.macroblock_motion_backward != 0) {
|
||||
predBack = new int[][] { new int[256], new int[1 << chromaFormat + 5], new int[1 << chromaFormat + 5] };
|
||||
if (ph.pictureCodingExtension == null || ph.pictureCodingExtension.picture_structure == 3) {
|
||||
pred.predictInFrame(this.refFrames[0], mbX << 4, mbY << 4, predBack, bits, motion_type, 1, spatial_temporal_weight_code);
|
||||
} else {
|
||||
pred.predictInField(new Picture[] { this.refFrames[0], this.refFrames[0] }, mbX << 4, mbY << 4, predBack, bits, motion_type, 1, ph.pictureCodingExtension.picture_structure - 1);
|
||||
}
|
||||
}
|
||||
context.lastPredB = mbType;
|
||||
int[][] pp = (mbType.macroblock_intra == 1) ?
|
||||
new int[][] { new int[256], new int[1 << chromaFormat + 5], new int[1 << chromaFormat + 5] } : buildPred(predFwd, predBack);
|
||||
if (mbType.macroblock_intra != 0 && concealmentMv)
|
||||
Preconditions.checkState((1 == bits.read1Bit()));
|
||||
int cbp = (mbType.macroblock_intra == 1) ? 4095 : 0;
|
||||
if (mbType.macroblock_pattern != 0)
|
||||
cbp = readCbPattern(bits);
|
||||
VLC vlcCoeff = MPEGConst.vlcCoeff0;
|
||||
if (ph.pictureCodingExtension != null && mbType.macroblock_intra == 1 && ph.pictureCodingExtension.intra_vlc_format == 1)
|
||||
vlcCoeff = MPEGConst.vlcCoeff1;
|
||||
int[] qScaleTab = (ph.pictureCodingExtension != null && ph.pictureCodingExtension.q_scale_type == 1) ?
|
||||
MPEGConst.qScaleTab2 : MPEGConst.qScaleTab1;
|
||||
int qScale = qScaleTab[qScaleCode[0]];
|
||||
int intra_dc_mult = 8;
|
||||
if (ph.pictureCodingExtension != null)
|
||||
intra_dc_mult = 8 >> ph.pictureCodingExtension.intra_dc_precision;
|
||||
int blkCount = 6 + ((chromaFormat == 1) ? 0 : ((chromaFormat == 2) ? 2 : 6));
|
||||
int[] block = new int[64];
|
||||
for (int j = 0, cbpMask = 1 << blkCount - 1; j < blkCount; j++, cbpMask >>= 1) {
|
||||
if ((cbp & cbpMask) != 0) {
|
||||
int[] qmat = context.qMats[((j >= 4) ? 1 : 0) + (mbType.macroblock_intra << 1)];
|
||||
if (mbType.macroblock_intra == 1) {
|
||||
blockIntra(bits, vlcCoeff, block, context.intra_dc_predictor, j, context.scan, (
|
||||
this.sh.hasExtensions() || ph.hasExtensions()) ? 12 : 8, intra_dc_mult, qScale, qmat);
|
||||
} else {
|
||||
blockInter(bits, vlcCoeff, block, context.scan, (this.sh.hasExtensions() || ph.hasExtensions()) ? 12 : 8, qScale, qmat);
|
||||
}
|
||||
mapBlock(block, pp[MPEGConst.BLOCK_TO_CC[j]], j, dctType, chromaFormat);
|
||||
}
|
||||
}
|
||||
put(pp, buf, stride, chromaFormat, mbX, mbY, context.codedWidth, context.codedHeight >> vertStep, vertOff, vertStep);
|
||||
return mbAddr;
|
||||
}
|
||||
|
||||
protected void mapBlock(int[] block, int[] out, int blkIdx, int dctType, int chromaFormat) {
|
||||
int stepVert = (chromaFormat == 1 && (blkIdx == 4 || blkIdx == 5)) ? 0 : dctType;
|
||||
int log2stride = (blkIdx < 4) ? 4 : (4 - MPEGConst.SQUEEZE_X[chromaFormat]);
|
||||
int blkIdxExt = blkIdx + (dctType << 4);
|
||||
int x = MPEGConst.BLOCK_POS_X[blkIdxExt];
|
||||
int y = MPEGConst.BLOCK_POS_Y[blkIdxExt];
|
||||
int off = (y << log2stride) + x, stride = 1 << log2stride + stepVert;
|
||||
for (int i = 0, coeff = 0; i < 8; i++, coeff += 8) {
|
||||
out[off] = out[off] + block[coeff];
|
||||
out[off + 1] = out[off + 1] + block[coeff + 1];
|
||||
out[off + 2] = out[off + 2] + block[coeff + 2];
|
||||
out[off + 3] = out[off + 3] + block[coeff + 3];
|
||||
out[off + 4] = out[off + 4] + block[coeff + 4];
|
||||
out[off + 5] = out[off + 5] + block[coeff + 5];
|
||||
out[off + 6] = out[off + 6] + block[coeff + 6];
|
||||
out[off + 7] = out[off + 7] + block[coeff + 7];
|
||||
off += stride;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int[][] buildPred(int[][] predFwd, int[][] predBack) {
|
||||
if (predFwd != null && predBack != null) {
|
||||
avgPred(predFwd, predBack);
|
||||
return predFwd;
|
||||
}
|
||||
if (predFwd != null)
|
||||
return predFwd;
|
||||
if (predBack != null)
|
||||
return predBack;
|
||||
throw new RuntimeException("Omited pred _in B-frames --> invalid");
|
||||
}
|
||||
|
||||
private static final void avgPred(int[][] predFwd, int[][] predBack) {
|
||||
for (int i = 0; i < predFwd.length; i++) {
|
||||
for (int j = 0; j < (predFwd[i]).length; j += 4) {
|
||||
predFwd[i][j] = predFwd[i][j] + predBack[i][j] + 1 >> 1;
|
||||
predFwd[i][j + 1] = predFwd[i][j + 1] + predBack[i][j + 1] + 1 >> 1;
|
||||
predFwd[i][j + 2] = predFwd[i][j + 2] + predBack[i][j + 2] + 1 >> 1;
|
||||
predFwd[i][j + 3] = predFwd[i][j + 3] + predBack[i][j + 3] + 1 >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mvZero(Context context, PictureHeader ph, MPEGPred pred, int mbX, int mbY, int[][] mbPix) {
|
||||
if (ph.picture_coding_type == 2) {
|
||||
pred.predict16x16NoMV(this.refFrames[0], mbX << 4, mbY << 4,
|
||||
(ph.pictureCodingExtension == null) ? 3 : ph.pictureCodingExtension.picture_structure, 0, mbPix);
|
||||
} else {
|
||||
int[][] pp = mbPix;
|
||||
if (context.lastPredB.macroblock_motion_backward == 1) {
|
||||
pred.predict16x16NoMV(this.refFrames[0], mbX << 4, mbY << 4,
|
||||
(ph.pictureCodingExtension == null) ? 3 : ph.pictureCodingExtension.picture_structure, 1, pp);
|
||||
pp = new int[][] { new int[(mbPix[0]).length], new int[(mbPix[1]).length], new int[(mbPix[2]).length] };
|
||||
}
|
||||
if (context.lastPredB.macroblock_motion_forward == 1) {
|
||||
pred.predict16x16NoMV(this.refFrames[1], mbX << 4, mbY << 4,
|
||||
(ph.pictureCodingExtension == null) ? 3 : ph.pictureCodingExtension.picture_structure, 0, pp);
|
||||
if (mbPix != pp)
|
||||
avgPred(mbPix, pp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void put(int[][] mbPix, byte[][] buf, int stride, int chromaFormat, int mbX, int mbY, int width, int height, int vertOff, int vertStep) {
|
||||
int chromaStride = stride + (1 << MPEGConst.SQUEEZE_X[chromaFormat]) - 1 >> MPEGConst.SQUEEZE_X[chromaFormat];
|
||||
int chromaMBW = 4 - MPEGConst.SQUEEZE_X[chromaFormat];
|
||||
int chromaMBH = 4 - MPEGConst.SQUEEZE_Y[chromaFormat];
|
||||
putSub(buf[0], (mbY << 4) * (stride << vertStep) + vertOff * stride + (mbX << 4), stride << vertStep, mbPix[0], 4, 4);
|
||||
putSub(buf[1], (mbY << chromaMBH) * (chromaStride << vertStep) + vertOff * chromaStride + (mbX << chromaMBW), chromaStride << vertStep, mbPix[1], chromaMBW, chromaMBH);
|
||||
putSub(buf[2], (mbY << chromaMBH) * (chromaStride << vertStep) + vertOff * chromaStride + (mbX << chromaMBW), chromaStride << vertStep, mbPix[2], chromaMBW, chromaMBH);
|
||||
}
|
||||
|
||||
protected void putSub(byte[] big, int off, int stride, int[] block, int mbW, int mbH) {
|
||||
int blOff = 0;
|
||||
if (mbW == 3) {
|
||||
for (int i = 0; i < 1 << mbH; i++) {
|
||||
big[off] = clipTo8Bit(block[blOff]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 1]);
|
||||
big[off + 2] = clipTo8Bit(block[blOff + 2]);
|
||||
big[off + 3] = clipTo8Bit(block[blOff + 3]);
|
||||
big[off + 4] = clipTo8Bit(block[blOff + 4]);
|
||||
big[off + 5] = clipTo8Bit(block[blOff + 5]);
|
||||
big[off + 6] = clipTo8Bit(block[blOff + 6]);
|
||||
big[off + 7] = clipTo8Bit(block[blOff + 7]);
|
||||
blOff += 8;
|
||||
off += stride;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 1 << mbH; i++) {
|
||||
big[off] = clipTo8Bit(block[blOff]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 1]);
|
||||
big[off + 2] = clipTo8Bit(block[blOff + 2]);
|
||||
big[off + 3] = clipTo8Bit(block[blOff + 3]);
|
||||
big[off + 4] = clipTo8Bit(block[blOff + 4]);
|
||||
big[off + 5] = clipTo8Bit(block[blOff + 5]);
|
||||
big[off + 6] = clipTo8Bit(block[blOff + 6]);
|
||||
big[off + 7] = clipTo8Bit(block[blOff + 7]);
|
||||
big[off + 8] = clipTo8Bit(block[blOff + 8]);
|
||||
big[off + 9] = clipTo8Bit(block[blOff + 9]);
|
||||
big[off + 10] = clipTo8Bit(block[blOff + 10]);
|
||||
big[off + 11] = clipTo8Bit(block[blOff + 11]);
|
||||
big[off + 12] = clipTo8Bit(block[blOff + 12]);
|
||||
big[off + 13] = clipTo8Bit(block[blOff + 13]);
|
||||
big[off + 14] = clipTo8Bit(block[blOff + 14]);
|
||||
big[off + 15] = clipTo8Bit(block[blOff + 15]);
|
||||
blOff += 16;
|
||||
off += stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static final byte clipTo8Bit(int val) {
|
||||
return (byte)(((val < 0) ? 0 : ((val > 255) ? 255 : val)) - 128);
|
||||
}
|
||||
|
||||
protected static final int clip(int val) {
|
||||
return (val < 0) ? 0 : ((val > 255) ? 255 : val);
|
||||
}
|
||||
|
||||
protected static final int quantInter(int level, int quant) {
|
||||
return ((level << 1) + 1) * quant >> 5;
|
||||
}
|
||||
|
||||
protected static final int quantInterSigned(int level, int quant) {
|
||||
return (level >= 0) ? quantInter(level, quant) : -quantInter(-level, quant);
|
||||
}
|
||||
|
||||
protected void blockIntra(BitReader bits, VLC vlcCoeff, int[] block, int[] intra_dc_predictor, int blkIdx, int[] scan, int escSize, int intra_dc_mult, int qScale, int[] qmat) {
|
||||
int cc = MPEGConst.BLOCK_TO_CC[blkIdx];
|
||||
int size = ((cc == 0) ? MPEGConst.vlcDCSizeLuma : MPEGConst.vlcDCSizeChroma).readVLC(bits);
|
||||
int delta = (size != 0) ? mpegSigned(bits, size) : 0;
|
||||
intra_dc_predictor[cc] = intra_dc_predictor[cc] + delta;
|
||||
int dc = intra_dc_predictor[cc] * intra_dc_mult;
|
||||
SparseIDCT.start(block, dc);
|
||||
for (int idx = 0; idx < 64; ) {
|
||||
int level;
|
||||
int readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
level = twosSigned(bits, escSize) * qScale * qmat[idx];
|
||||
level = (level >= 0) ? (level >> 4) : -(-level >> 4);
|
||||
} else {
|
||||
idx += (readVLC >> 6) + 1;
|
||||
level = toSigned((readVLC & 0x3F) * qScale * qmat[idx] >> 4, bits.read1Bit());
|
||||
}
|
||||
SparseIDCT.coeff(block, scan[idx], level);
|
||||
}
|
||||
SparseIDCT.finish(block);
|
||||
}
|
||||
|
||||
protected void blockInter(BitReader bits, VLC vlcCoeff, int[] block, int[] scan, int escSize, int qScale, int[] qmat) {
|
||||
int idx = -1;
|
||||
if (vlcCoeff == MPEGConst.vlcCoeff0 && bits.checkNBit(1) == 1) {
|
||||
bits.read1Bit();
|
||||
int dc = toSigned(quantInter(1, qScale * qmat[0]), bits.read1Bit());
|
||||
SparseIDCT.start(block, dc);
|
||||
idx++;
|
||||
} else {
|
||||
SparseIDCT.start(block, 0);
|
||||
}
|
||||
while (idx < 64) {
|
||||
int ac;
|
||||
int readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
ac = quantInterSigned(twosSigned(bits, escSize), qScale * qmat[idx]);
|
||||
} else {
|
||||
idx += (readVLC >> 6) + 1;
|
||||
ac = toSigned(quantInter(readVLC & 0x3F, qScale * qmat[idx]), bits.read1Bit());
|
||||
}
|
||||
SparseIDCT.coeff(block, scan[idx], ac);
|
||||
}
|
||||
SparseIDCT.finish(block);
|
||||
}
|
||||
|
||||
public static final int twosSigned(BitReader bits, int size) {
|
||||
int shift = 32 - size;
|
||||
return bits.readNBit(size) << shift >> shift;
|
||||
}
|
||||
|
||||
public static final int mpegSigned(BitReader bits, int size) {
|
||||
int val = bits.readNBit(size);
|
||||
int sign = val >>> size - 1 ^ 0x1;
|
||||
return val + sign - (sign << size);
|
||||
}
|
||||
|
||||
public static final int toSigned(int val, int s) {
|
||||
int sign = s << 31 >> 31;
|
||||
return (val ^ sign) - sign;
|
||||
}
|
||||
|
||||
private final int readCbPattern(BitReader bits) {
|
||||
int cbp420 = MPEGConst.vlcCBP.readVLC(bits);
|
||||
if (this.sh.sequenceExtension == null || this.sh.sequenceExtension.chroma_format == 1)
|
||||
return cbp420;
|
||||
if (this.sh.sequenceExtension.chroma_format == 2)
|
||||
return cbp420 << 2 | bits.readNBit(2);
|
||||
if (this.sh.sequenceExtension.chroma_format == 3)
|
||||
return cbp420 << 6 | bits.readNBit(6);
|
||||
throw new RuntimeException("Unsupported chroma format: " + this.sh.sequenceExtension.chroma_format);
|
||||
}
|
||||
|
||||
@UsedViaReflection
|
||||
public static int probe(ByteBuffer data) {
|
||||
data = data.duplicate();
|
||||
data.order(ByteOrder.BIG_ENDIAN);
|
||||
for (int i = 0; i < 2 &&
|
||||
MPEGUtil.gotoNextMarker(data) != null; i++) {
|
||||
if (!data.hasRemaining())
|
||||
break;
|
||||
int marker = data.getInt();
|
||||
if (marker == 256 || (marker >= 432 && marker <= 440))
|
||||
return 50 - i * 10;
|
||||
if (marker > 256 && marker < 432)
|
||||
return 20 - i * 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static ByteBuffer getSequenceHeader(ByteBuffer data) {
|
||||
ByteBuffer segment = MPEGUtil.nextSegment(data);
|
||||
while (segment != null) {
|
||||
int marker = segment.getInt();
|
||||
if (marker == 435)
|
||||
return segment;
|
||||
segment = MPEGUtil.nextSegment(data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ByteBuffer getRawPictureHeader(ByteBuffer data) {
|
||||
ByteBuffer segment = MPEGUtil.nextSegment(data);
|
||||
while (segment != null) {
|
||||
int marker = segment.getInt();
|
||||
if (marker == 256)
|
||||
return segment;
|
||||
segment = MPEGUtil.nextSegment(data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getSequenceNumber(ByteBuffer data) {
|
||||
PictureHeader ph = getPictureHeader(data);
|
||||
if (ph == null)
|
||||
return -1;
|
||||
return ph.temporal_reference;
|
||||
}
|
||||
|
||||
public static PictureHeader getPictureHeader(ByteBuffer data) {
|
||||
ByteBuffer bb = getRawPictureHeader(data);
|
||||
if (bb == null)
|
||||
return null;
|
||||
PictureHeader ph = PictureHeader.read(bb);
|
||||
return ph;
|
||||
}
|
||||
|
||||
public VideoCodecMeta getCodecMeta(ByteBuffer data) {
|
||||
ByteBuffer codecPrivate = getSequenceHeader(data.duplicate());
|
||||
SequenceHeader sh = SequenceHeader.read(codecPrivate.duplicate());
|
||||
return VideoCodecMeta.createSimpleVideoCodecMeta(new Size(sh.horizontal_size, sh.vertical_size), ColorSpace.YUV420);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import org.jcodec.containers.mps.MPEGPacket;
|
||||
|
||||
public class MPEGES extends SegmentReader {
|
||||
private int frameNo;
|
||||
|
||||
public long lastKnownDuration;
|
||||
|
||||
public MPEGES(ReadableByteChannel channel, int fetchSize) throws IOException {
|
||||
super(channel, fetchSize);
|
||||
}
|
||||
|
||||
public MPEGPacket frame(ByteBuffer buffer) throws IOException {
|
||||
assert false : "Decompilation failed at line #44 -> offsets [0]";
|
||||
assert false : "Decompilation failed at line #46 -> offsets [5]";
|
||||
assert false : "Decompilation failed at line #47 -> offsets [32]";
|
||||
assert false : "Decompilation failed at line #49 -> offsets [35]";
|
||||
assert false : "Decompilation failed at line #50 -> offsets [53]";
|
||||
assert false : "Decompilation failed at line #52 -> offsets [56]";
|
||||
assert false : "Decompilation failed at line #54 -> offsets [62]";
|
||||
assert false : "Decompilation failed at line #55 -> offsets [90]";
|
||||
assert false : "Decompilation failed at line #57 -> offsets [93]";
|
||||
assert false : "Decompilation failed at line #59 -> offsets [98]";
|
||||
assert false : "Decompilation failed at line #61 -> offsets [106, 159]";
|
||||
assert false : "Decompilation failed at line #62 -> offsets [134]";
|
||||
}
|
||||
|
||||
public MPEGPacket getFrame() throws IOException {
|
||||
assert false : "Decompilation failed at line #73 -> offsets [0]";
|
||||
assert false : "Decompilation failed at line #74 -> offsets [27]";
|
||||
assert false : "Decompilation failed at line #76 -> offsets [30]";
|
||||
assert false : "Decompilation failed at line #79 -> offsets [38]";
|
||||
assert false : "Decompilation failed at line #80 -> offsets [55]";
|
||||
assert false : "Decompilation failed at line #83 -> offsets [63]";
|
||||
assert false : "Decompilation failed at line #87 -> offsets [68]";
|
||||
assert false : "Decompilation failed at line #88 -> offsets [95]";
|
||||
assert false : "Decompilation failed at line #90 -> offsets [103]";
|
||||
assert false : "Decompilation failed at line #91 -> offsets [108]";
|
||||
assert false : "Decompilation failed at line #93 -> offsets [116, 169]";
|
||||
assert false : "Decompilation failed at line #94 -> offsets [144]";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
public class MPEGEncoder {}
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.model.Picture;
|
||||
import org.jcodec.common.tools.MathUtil;
|
||||
|
||||
public class MPEGPred {
|
||||
protected int[][][] mvPred;
|
||||
|
||||
protected int chromaFormat;
|
||||
|
||||
protected int[][] fCode;
|
||||
|
||||
protected boolean topFieldFirst;
|
||||
|
||||
public MPEGPred(int[][] fCode, int chromaFormat, boolean topFieldFirst) {
|
||||
this.mvPred = new int[2][2][2];
|
||||
this.fCode = fCode;
|
||||
this.chromaFormat = chromaFormat;
|
||||
this.topFieldFirst = topFieldFirst;
|
||||
}
|
||||
|
||||
public void predictFullXFullYSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int offRef = ((refY << refVertStep) + refVertOff) * refW + refX, offTgt = tgtW * tgtY, lfRef = (refW << refVertStep) - tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
for (int j = 0; j < tgtW; j++)
|
||||
tgt[offTgt++] = ref[offRef++] + 128;
|
||||
offRef += lfRef;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictEvenOddSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int offRef = ((refY << refVertStep) + refVertOff) * refW + refX, offTgt = tgtW * tgtY, lfRef = (refW << refVertStep) - tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
for (int j = 0; j < tgtW; j++) {
|
||||
tgt[offTgt++] = (ref[offRef] + ref[offRef + 1] + 1 >> 1) + 128;
|
||||
offRef++;
|
||||
}
|
||||
offRef += lfRef;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictOddEvenSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int offRef = ((refY << refVertStep) + refVertOff) * refW + refX, offTgt = tgtW * tgtY, lfRef = (refW << refVertStep) - tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW, stride = refW << refVertStep;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
for (int j = 0; j < tgtW; j++) {
|
||||
tgt[offTgt++] = (ref[offRef] + ref[offRef + stride] + 1 >> 1) + 128;
|
||||
offRef++;
|
||||
}
|
||||
offRef += lfRef;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictOddOddSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int offRef = ((refY << refVertStep) + refVertOff) * refW + refX, offTgt = tgtW * tgtY, lfRef = (refW << refVertStep) - tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW, stride = refW << refVertStep;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
for (int j = 0; j < tgtW; j++) {
|
||||
tgt[offTgt++] = (ref[offRef] + ref[offRef + 1] + ref[offRef + stride] + ref[offRef + stride + 1] + 3 >> 2) + 128;
|
||||
offRef++;
|
||||
}
|
||||
offRef += lfRef;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
protected final int getPix1(byte[] ref, int refW, int refH, int x, int y, int refVertStep, int refVertOff) {
|
||||
x = MathUtil.clip(x, 0, refW - 1);
|
||||
y = MathUtil.clip(y, 0, refH - (1 << refVertStep) + refVertOff);
|
||||
return ref[y * refW + x] + 128;
|
||||
}
|
||||
|
||||
protected final int getPix2(byte[] ref, int refW, int refH, int x1, int y1, int x2, int y2, int refVertStep, int refVertOff) {
|
||||
x1 = MathUtil.clip(x1, 0, refW - 1);
|
||||
int lastLine = refH - (1 << refVertStep) + refVertOff;
|
||||
y1 = MathUtil.clip(y1, 0, lastLine);
|
||||
x2 = MathUtil.clip(x2, 0, refW - 1);
|
||||
y2 = MathUtil.clip(y2, 0, lastLine);
|
||||
return (ref[y1 * refW + x1] + ref[y2 * refW + x2] + 1 >> 1) + 128;
|
||||
}
|
||||
|
||||
protected final int getPix4(byte[] ref, int refW, int refH, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int refVertStep, int refVertOff) {
|
||||
int lastLine = refH - (1 << refVertStep) + refVertOff;
|
||||
x1 = MathUtil.clip(x1, 0, refW - 1);
|
||||
y1 = MathUtil.clip(y1, 0, lastLine);
|
||||
x2 = MathUtil.clip(x2, 0, refW - 1);
|
||||
y2 = MathUtil.clip(y2, 0, lastLine);
|
||||
x3 = MathUtil.clip(x3, 0, refW - 1);
|
||||
y3 = MathUtil.clip(y3, 0, lastLine);
|
||||
x4 = MathUtil.clip(x4, 0, refW - 1);
|
||||
y4 = MathUtil.clip(y4, 0, lastLine);
|
||||
return (ref[y1 * refW + x1] + ref[y2 * refW + x2] + ref[y3 * refW + x3] + ref[y4 * refW + x4] + 3 >> 2) + 128;
|
||||
}
|
||||
|
||||
public void predictFullXFullYUnSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int tgtOff = tgtW * tgtY, jump = tgtVertStep * tgtW;
|
||||
for (int j = 0; j < tgtH; j++) {
|
||||
int y = (j + refY << refVertStep) + refVertOff;
|
||||
for (int i = 0; i < tgtW; i++)
|
||||
tgt[tgtOff++] = getPix1(ref, refW, refH, i + refX, y, refVertStep, refVertOff);
|
||||
tgtOff += jump;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictEvenOddUnSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int tgtOff = tgtW * tgtY, jump = tgtVertStep * tgtW;
|
||||
for (int j = 0; j < tgtH; j++) {
|
||||
int y = (j + refY << refVertStep) + refVertOff;
|
||||
for (int i = 0; i < tgtW; i++)
|
||||
tgt[tgtOff++] = getPix2(ref, refW, refH, i + refX, y, i + refX + 1, y, refVertStep, refVertOff);
|
||||
tgtOff += jump;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictOddEvenUnSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int tgtOff = tgtW * tgtY, jump = tgtVertStep * tgtW;
|
||||
for (int j = 0; j < tgtH; j++) {
|
||||
int y1 = (j + refY << refVertStep) + refVertOff;
|
||||
int y2 = (j + refY + 1 << refVertStep) + refVertOff;
|
||||
for (int i = 0; i < tgtW; i++)
|
||||
tgt[tgtOff++] = getPix2(ref, refW, refH, i + refX, y1, i + refX, y2, refVertStep, refVertOff);
|
||||
tgtOff += jump;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictOddOddUnSafe(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int tgtOff = tgtW * tgtY, jump = tgtVertStep * tgtW;
|
||||
for (int j = 0; j < tgtH; j++) {
|
||||
int y1 = (j + refY << refVertStep) + refVertOff;
|
||||
int y2 = (j + refY + 1 << refVertStep) + refVertOff;
|
||||
for (int i = 0; i < tgtW; i++) {
|
||||
int ptX = i + refX;
|
||||
tgt[tgtOff++] = getPix4(ref, refW, refH, ptX, y1, ptX + 1, y1, ptX, y2, ptX + 1, y2, refVertStep, refVertOff);
|
||||
}
|
||||
tgtOff += jump;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictPlane(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int rx = refX >> 1, ry = refY >> 1;
|
||||
boolean safe = (rx >= 0 && ry >= 0 && rx + tgtW < refW && ry + tgtH << refVertStep < refH);
|
||||
if ((refX & 0x1) == 0) {
|
||||
if ((refY & 0x1) == 0) {
|
||||
if (safe) {
|
||||
predictFullXFullYSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictFullXFullYUnSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
} else if (safe) {
|
||||
predictOddEvenSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictOddEvenUnSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
} else if ((refY & 0x1) == 0) {
|
||||
if (safe) {
|
||||
predictEvenOddSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictEvenOddUnSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
} else if (safe) {
|
||||
predictOddOddSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictOddOddUnSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
}
|
||||
|
||||
public void predictInField(Picture[] reference, int x, int y, int[][] mbPix, BitReader bits, int motionType, int backward, int fieldNo) {
|
||||
switch (motionType) {
|
||||
case 1:
|
||||
predict16x16Field(reference, x, y, bits, backward, mbPix);
|
||||
break;
|
||||
case 2:
|
||||
predict16x8MC(reference, x, y, bits, backward, mbPix, 0, 0);
|
||||
predict16x8MC(reference, x, y, bits, backward, mbPix, 8, 1);
|
||||
break;
|
||||
case 3:
|
||||
predict16x16DualPrimeField(reference, x, y, bits, mbPix, fieldNo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void predictInFrame(Picture reference, int x, int y, int[][] mbPix, BitReader _in, int motionType, int backward, int spatial_temporal_weight_code) {
|
||||
Picture[] refs = { reference, reference };
|
||||
switch (motionType) {
|
||||
case 1:
|
||||
predictFieldInFrame(reference, x, y, mbPix, _in, backward, spatial_temporal_weight_code);
|
||||
break;
|
||||
case 2:
|
||||
predict16x16Frame(reference, x, y, _in, backward, mbPix);
|
||||
break;
|
||||
case 3:
|
||||
predict16x16DualPrimeFrame(refs, x, y, _in, backward, mbPix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void predict16x16DualPrimeField(Picture[] reference, int x, int y, BitReader bits, int[][] mbPix, int fieldNo) {
|
||||
int vect1X = mvectDecode(bits, this.fCode[0][0], this.mvPred[0][0][0]);
|
||||
int dmX = MPEGConst.vlcDualPrime.readVLC(bits) - 1;
|
||||
int vect1Y = mvectDecode(bits, this.fCode[0][1], this.mvPred[0][0][1]);
|
||||
int dmY = MPEGConst.vlcDualPrime.readVLC(bits) - 1;
|
||||
int vect2X = dpXField(vect1X, dmX, 1 - fieldNo);
|
||||
int vect2Y = dpYField(vect1Y, dmY, 1 - fieldNo);
|
||||
int ch = (this.chromaFormat == 1) ? 1 : 0;
|
||||
int cw = (this.chromaFormat == 3) ? 0 : 1;
|
||||
int sh = (this.chromaFormat == 1) ? 2 : 1;
|
||||
int sw = (this.chromaFormat == 3) ? 1 : 2;
|
||||
int[][] mbPix1 = new int[3][256], mbPix2 = new int[3][256];
|
||||
int refX1 = (x << 1) + vect1X;
|
||||
int refY1 = (y << 1) + vect1Y;
|
||||
int refX1Chr = (x << 1 >> cw) + vect1X / sw;
|
||||
int refY1Chr = (y << 1 >> ch) + vect1Y / sh;
|
||||
predictPlane(reference[fieldNo].getPlaneData(0), refX1, refY1, reference[fieldNo].getPlaneWidth(0), reference[fieldNo]
|
||||
.getPlaneHeight(0), 1, fieldNo, mbPix1[0], 0, 16, 16, 0);
|
||||
predictPlane(reference[fieldNo].getPlaneData(1), refX1Chr, refY1Chr, reference[fieldNo].getPlaneWidth(1), reference[fieldNo]
|
||||
.getPlaneHeight(1), 1, fieldNo, mbPix1[1], 0, 16 >> cw, 16 >> ch, 0);
|
||||
predictPlane(reference[fieldNo].getPlaneData(2), refX1Chr, refY1Chr, reference[fieldNo].getPlaneWidth(2), reference[fieldNo]
|
||||
.getPlaneHeight(2), 1, fieldNo, mbPix1[2], 0, 16 >> cw, 16 >> ch, 0);
|
||||
int refX2 = (x << 1) + vect2X;
|
||||
int refY2 = (y << 1) + vect2Y;
|
||||
int refX2Chr = (x << 1 >> cw) + vect2X / sw;
|
||||
int refY2Chr = (y << 1 >> ch) + vect2Y / sh;
|
||||
int opposite = 1 - fieldNo;
|
||||
predictPlane(reference[opposite].getPlaneData(0), refX2, refY2, reference[opposite].getPlaneWidth(0), reference[opposite]
|
||||
.getPlaneHeight(0), 1, opposite, mbPix2[0], 0, 16, 16, 0);
|
||||
predictPlane(reference[opposite].getPlaneData(1), refX2Chr, refY2Chr, reference[opposite].getPlaneWidth(1), reference[opposite]
|
||||
.getPlaneHeight(1), 1, opposite, mbPix2[1], 0, 16 >> cw, 16 >> ch, 0);
|
||||
predictPlane(reference[opposite].getPlaneData(2), refX2Chr, refY2Chr, reference[opposite].getPlaneWidth(2), reference[opposite]
|
||||
.getPlaneHeight(2), 1, opposite, mbPix2[2], 0, 16 >> cw, 16 >> ch, 0);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < (mbPix[i]).length; j++)
|
||||
mbPix[i][j] = mbPix1[i][j] + mbPix2[i][j] + 1 >> 1;
|
||||
}
|
||||
this.mvPred[0][0][0] = vect1X;
|
||||
this.mvPred[1][0][0] = vect1X;
|
||||
this.mvPred[0][0][1] = vect1Y;
|
||||
this.mvPred[1][0][1] = vect1Y;
|
||||
}
|
||||
|
||||
private final int dpYField(int vect1y, int dmY, int topField) {
|
||||
return (vect1y + ((vect1y > 0) ? 1 : 0) >> 1) + 1 - (topField << 1) + dmY;
|
||||
}
|
||||
|
||||
private final int dpXField(int vect1x, int dmX, int topField) {
|
||||
return (vect1x + ((vect1x > 0) ? 1 : 0) >> 1) + dmX;
|
||||
}
|
||||
|
||||
private void predict16x8MC(Picture[] reference, int x, int y, BitReader bits, int backward, int[][] mbPix, int vertPos, int vectIdx) {
|
||||
int field = bits.read1Bit();
|
||||
predictGeneric(reference[field], x, y + vertPos, bits, backward, mbPix, vertPos, 16, 8, 1, field, 0, vectIdx, 0);
|
||||
}
|
||||
|
||||
protected void predict16x16Field(Picture[] reference, int x, int y, BitReader bits, int backward, int[][] mbPix) {
|
||||
int field = bits.read1Bit();
|
||||
predictGeneric(reference[field], x, y, bits, backward, mbPix, 0, 16, 16, 1, field, 0, 0, 0);
|
||||
this.mvPred[1][backward][0] = this.mvPred[0][backward][0];
|
||||
this.mvPred[1][backward][1] = this.mvPred[0][backward][1];
|
||||
}
|
||||
|
||||
private void predict16x16DualPrimeFrame(Picture[] reference, int x, int y, BitReader bits, int backward, int[][] mbPix) {
|
||||
int vect1X = mvectDecode(bits, this.fCode[0][0], this.mvPred[0][0][0]);
|
||||
int dmX = MPEGConst.vlcDualPrime.readVLC(bits) - 1;
|
||||
int vect1Y = mvectDecode(bits, this.fCode[0][1], this.mvPred[0][0][1] >> 1);
|
||||
int dmY = MPEGConst.vlcDualPrime.readVLC(bits) - 1;
|
||||
int m = this.topFieldFirst ? 1 : 3;
|
||||
int vect2X = (vect1X * m + ((vect1X > 0) ? 1 : 0) >> 1) + dmX;
|
||||
int vect2Y = (vect1Y * m + ((vect1Y > 0) ? 1 : 0) >> 1) + dmY - 1;
|
||||
m = 4 - m;
|
||||
int vect3X = (vect1X * m + ((vect1X > 0) ? 1 : 0) >> 1) + dmX;
|
||||
int vect3Y = (vect1Y * m + ((vect1Y > 0) ? 1 : 0) >> 1) + dmY + 1;
|
||||
int ch = (this.chromaFormat == 1) ? 1 : 0;
|
||||
int cw = (this.chromaFormat == 3) ? 0 : 1;
|
||||
int sh = (this.chromaFormat == 1) ? 2 : 1;
|
||||
int sw = (this.chromaFormat == 3) ? 1 : 2;
|
||||
int[][] mbPix1 = new int[3][256], mbPix2 = new int[3][256];
|
||||
int refX1 = (x << 1) + vect1X;
|
||||
int refY1 = y + vect1Y;
|
||||
int refX1Chr = (x << 1 >> cw) + vect1X / sw;
|
||||
int refY1Chr = (y >> ch) + vect1Y / sh;
|
||||
predictPlane(reference[0].getPlaneData(0), refX1, refY1, reference[0].getPlaneWidth(0), reference[0]
|
||||
.getPlaneHeight(0), 1, 0, mbPix1[0], 0, 16, 8, 1);
|
||||
predictPlane(reference[0].getPlaneData(1), refX1Chr, refY1Chr, reference[0].getPlaneWidth(1), reference[0]
|
||||
.getPlaneHeight(1), 1, 0, mbPix1[1], 0, 16 >> cw, 8 >> ch, 1);
|
||||
predictPlane(reference[0].getPlaneData(2), refX1Chr, refY1Chr, reference[0].getPlaneWidth(2), reference[0]
|
||||
.getPlaneHeight(2), 1, 0, mbPix1[2], 0, 16 >> cw, 8 >> ch, 1);
|
||||
predictPlane(reference[1].getPlaneData(0), refX1, refY1, reference[1].getPlaneWidth(0), reference[1]
|
||||
.getPlaneHeight(0), 1, 1, mbPix1[0], 1, 16, 8, 1);
|
||||
predictPlane(reference[1].getPlaneData(1), refX1Chr, refY1Chr, reference[1].getPlaneWidth(1), reference[1]
|
||||
.getPlaneHeight(1), 1, 1, mbPix1[1], 1, 16 >> cw, 8 >> ch, 1);
|
||||
predictPlane(reference[1].getPlaneData(2), refX1Chr, refY1Chr, reference[1].getPlaneWidth(2), reference[1]
|
||||
.getPlaneHeight(2), 1, 1, mbPix1[2], 1, 16 >> cw, 8 >> ch, 1);
|
||||
int refX2 = (x << 1) + vect2X;
|
||||
int refY2 = y + vect2Y;
|
||||
int refX2Chr = (x << 1 >> cw) + vect2X / sw;
|
||||
int refY2Chr = (y >> ch) + vect2Y / sh;
|
||||
predictPlane(reference[1].getPlaneData(0), refX2, refY2, reference[1].getPlaneWidth(0), reference[1]
|
||||
.getPlaneHeight(0), 1, 1, mbPix2[0], 0, 16, 8, 1);
|
||||
predictPlane(reference[1].getPlaneData(1), refX2Chr, refY2Chr, reference[1].getPlaneWidth(1), reference[1]
|
||||
.getPlaneHeight(1), 1, 1, mbPix2[1], 0, 16 >> cw, 8 >> ch, 1);
|
||||
predictPlane(reference[1].getPlaneData(2), refX2Chr, refY2Chr, reference[1].getPlaneWidth(2), reference[1]
|
||||
.getPlaneHeight(2), 1, 1, mbPix2[2], 0, 16 >> cw, 8 >> ch, 1);
|
||||
int refX3 = (x << 1) + vect3X;
|
||||
int refY3 = y + vect3Y;
|
||||
int refX3Chr = (x << 1 >> cw) + vect3X / sw;
|
||||
int refY3Chr = (y >> ch) + vect3Y / sh;
|
||||
predictPlane(reference[0].getPlaneData(0), refX3, refY3, reference[0].getPlaneWidth(0), reference[0]
|
||||
.getPlaneHeight(0), 1, 0, mbPix2[0], 1, 16, 8, 1);
|
||||
predictPlane(reference[0].getPlaneData(1), refX3Chr, refY3Chr, reference[0].getPlaneWidth(1), reference[0]
|
||||
.getPlaneHeight(1), 1, 0, mbPix2[1], 1, 16 >> cw, 8 >> ch, 1);
|
||||
predictPlane(reference[0].getPlaneData(2), refX3Chr, refY3Chr, reference[0].getPlaneWidth(2), reference[0]
|
||||
.getPlaneHeight(2), 1, 0, mbPix2[2], 1, 16 >> cw, 8 >> ch, 1);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < (mbPix[i]).length; j++)
|
||||
mbPix[i][j] = mbPix1[i][j] + mbPix2[i][j] + 1 >> 1;
|
||||
}
|
||||
this.mvPred[0][0][0] = vect1X;
|
||||
this.mvPred[1][0][0] = vect1X;
|
||||
this.mvPred[0][0][1] = vect1Y << 1;
|
||||
this.mvPred[1][0][1] = vect1Y << 1;
|
||||
}
|
||||
|
||||
protected void predict16x16Frame(Picture reference, int x, int y, BitReader bits, int backward, int[][] mbPix) {
|
||||
predictGeneric(reference, x, y, bits, backward, mbPix, 0, 16, 16, 0, 0, 0, 0, 0);
|
||||
this.mvPred[1][backward][0] = this.mvPred[0][backward][0];
|
||||
this.mvPred[1][backward][1] = this.mvPred[0][backward][1];
|
||||
}
|
||||
|
||||
private final int mvectDecode(BitReader bits, int fcode, int pred) {
|
||||
int code = MPEGConst.vlcMotionCode.readVLC(bits);
|
||||
if (code == 0)
|
||||
return pred;
|
||||
if (code < 0)
|
||||
return 65535;
|
||||
int sign = bits.read1Bit();
|
||||
int shift = fcode - 1;
|
||||
int val = code;
|
||||
if (shift > 0) {
|
||||
val = val - 1 << shift;
|
||||
val |= bits.readNBit(shift);
|
||||
val++;
|
||||
}
|
||||
if (sign != 0)
|
||||
val = -val;
|
||||
val += pred;
|
||||
return sign_extend(val, 5 + shift);
|
||||
}
|
||||
|
||||
private final int sign_extend(int val, int bits) {
|
||||
int shift = 32 - bits;
|
||||
return val << shift >> shift;
|
||||
}
|
||||
|
||||
protected void predictGeneric(Picture reference, int x, int y, BitReader bits, int backward, int[][] mbPix, int tgtY, int blkW, int blkH, int isSrcField, int srcField, int isDstField, int vectIdx, int predScale) {
|
||||
int vectX = mvectDecode(bits, this.fCode[backward][0], this.mvPred[vectIdx][backward][0]);
|
||||
int vectY = mvectDecode(bits, this.fCode[backward][1], this.mvPred[vectIdx][backward][1] >> predScale);
|
||||
predictMB(reference, x << 1, vectX, y << 1, vectY, blkW, blkH, isSrcField, srcField, mbPix, tgtY, isDstField);
|
||||
this.mvPred[vectIdx][backward][0] = vectX;
|
||||
this.mvPred[vectIdx][backward][1] = vectY << predScale;
|
||||
}
|
||||
|
||||
private void predictFieldInFrame(Picture reference, int x, int y, int[][] mbPix, BitReader bits, int backward, int spatial_temporal_weight_code) {
|
||||
y >>= 1;
|
||||
int field = bits.read1Bit();
|
||||
predictGeneric(reference, x, y, bits, backward, mbPix, 0, 16, 8, 1, field, 1, 0, 1);
|
||||
if (spatial_temporal_weight_code == 0 || spatial_temporal_weight_code == 1) {
|
||||
field = bits.read1Bit();
|
||||
predictGeneric(reference, x, y, bits, backward, mbPix, 1, 16, 8, 1, field, 1, 1, 1);
|
||||
} else {
|
||||
this.mvPred[1][backward][0] = this.mvPred[0][backward][0];
|
||||
this.mvPred[1][backward][1] = this.mvPred[0][backward][1];
|
||||
predictMB(reference, this.mvPred[1][backward][0], 0, this.mvPred[1][backward][1], 0, 16, 8, 1, 1 - field, mbPix, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void predictMB(Picture ref, int refX, int vectX, int refY, int vectY, int blkW, int blkH, int refVertStep, int refVertOff, int[][] tgt, int tgtY, int tgtVertStep) {
|
||||
int ch = (this.chromaFormat == 1) ? 1 : 0;
|
||||
int cw = (this.chromaFormat == 3) ? 0 : 1;
|
||||
int sh = (this.chromaFormat == 1) ? 2 : 1;
|
||||
int sw = (this.chromaFormat == 3) ? 1 : 2;
|
||||
predictPlane(ref.getPlaneData(0), refX + vectX, refY + vectY, ref.getPlaneWidth(0), ref.getPlaneHeight(0), refVertStep, refVertOff, tgt[0], tgtY, blkW, blkH, tgtVertStep);
|
||||
predictPlane(ref.getPlaneData(1), (refX >> cw) + vectX / sw, (refY >> ch) + vectY / sh, ref.getPlaneWidth(1),
|
||||
ref.getPlaneHeight(1), refVertStep, refVertOff, tgt[1], tgtY, blkW >> cw, blkH >> ch, tgtVertStep);
|
||||
predictPlane(ref.getPlaneData(2), (refX >> cw) + vectX / sw, (refY >> ch) + vectY / sh, ref.getPlaneWidth(2),
|
||||
ref.getPlaneHeight(2), refVertStep, refVertOff, tgt[2], tgtY, blkW >> cw, blkH >> ch, tgtVertStep);
|
||||
}
|
||||
|
||||
public void predict16x16NoMV(Picture picture, int x, int y, int pictureStructure, int backward, int[][] mbPix) {
|
||||
if (pictureStructure == 3) {
|
||||
predictMB(picture, x << 1, this.mvPred[0][backward][0], y << 1, this.mvPred[0][backward][1], 16, 16, 0, 0, mbPix, 0, 0);
|
||||
} else {
|
||||
predictMB(picture, x << 1, this.mvPred[0][backward][0], y << 1, this.mvPred[0][backward][1], 16, 16, 1, pictureStructure - 1, mbPix, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.mvPred[1][1][1] = 0;
|
||||
this.mvPred[1][1][0] = 0;
|
||||
this.mvPred[1][0][1] = 0;
|
||||
this.mvPred[1][0][0] = 0;
|
||||
this.mvPred[0][1][1] = 0;
|
||||
this.mvPred[0][1][0] = 0;
|
||||
this.mvPred[0][0][1] = 0;
|
||||
this.mvPred[0][0][0] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
public class MPEGPredDbl extends MPEGPredOct {
|
||||
public MPEGPredDbl(MPEGPred other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
public void predictPlane(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
super.predictPlane(ref, refX << 1, refY << 1, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW << 2, tgtH << 2, tgtVertStep);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import org.jcodec.common.tools.MathUtil;
|
||||
|
||||
public class MPEGPredOct extends MPEGPred {
|
||||
private int[] tmp;
|
||||
|
||||
private static final int[][] COEFF = new int[][] { new int[] { 0, 0, 128, 0, 0, 0 }, new int[] { 0, -6, 123, 12, -1, 0 }, new int[] { 2, -11, 108, 36, -8, 1 }, new int[] { 0, -9, 93, 50, -6, 0 }, new int[] { 3, -16, 77, 77, -16, 3 }, new int[] { 0, -6, 50, 93, -9, 0 }, new int[] { 1, -8, 36, 108, -11, 2 }, new int[] { 0, -1, 12, 123, -6, 0 } };
|
||||
|
||||
public MPEGPredOct(MPEGPred other) {
|
||||
super(other.fCode, other.chromaFormat, other.topFieldFirst);
|
||||
this.tmp = new int[336];
|
||||
}
|
||||
|
||||
public void predictPlane(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int rx = refX >> 3, ry = refY >> 3;
|
||||
tgtW >>= 3;
|
||||
tgtH >>= 3;
|
||||
boolean safe = (rx >= 2 && ry >= 2 && rx + tgtW + 3 < refW && ry + tgtH + 3 << refVertStep < refH);
|
||||
if ((refX & 0x7) == 0) {
|
||||
if ((refY & 0x7) == 0) {
|
||||
if (safe) {
|
||||
predictFullXFullYSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictFullXFullYUnSafe(ref, rx, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
} else if (safe) {
|
||||
predictFullXSubYSafe(ref, rx, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictFullXSubYUnSafe(ref, rx, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
} else if ((refY & 0x7) == 0) {
|
||||
if (safe) {
|
||||
predictSubXFullYSafe(ref, rx, refX & 0x7, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictSubXFullYUnSafe(ref, rx, refX & 0x7, ry, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
} else if (safe) {
|
||||
predictSubXSubYSafe(ref, rx, refX & 0x7, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
} else {
|
||||
predictSubXSubYUnSafe(ref, rx, refX & 0x7, ry, refY & 0x7, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW, tgtH, tgtVertStep);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getPix6(byte[] ref, int refW, int refH, int x, int y, int refVertStep, int refVertOff, int[] coeff) {
|
||||
int lastLine = refH - (1 << refVertStep) + refVertOff;
|
||||
int x0 = MathUtil.clip(x - 2, 0, refW - 1);
|
||||
int x1 = MathUtil.clip(x - 1, 0, refW - 1);
|
||||
int x2 = MathUtil.clip(x, 0, refW - 1);
|
||||
int x3 = MathUtil.clip(x + 1, 0, refW - 1);
|
||||
int x4 = MathUtil.clip(x + 2, 0, refW - 1);
|
||||
int x5 = MathUtil.clip(x + 3, 0, refW - 1);
|
||||
int off = MathUtil.clip(y, refVertOff, lastLine) * refW;
|
||||
return ref[off + x0] * coeff[0] + ref[off + x1] * coeff[1] + ref[off + x2] * coeff[2] + ref[off + x3] * coeff[3] + ref[off + x4] * coeff[4] + ref[off + x5] * coeff[5] + 16384;
|
||||
}
|
||||
|
||||
protected int getPix6Vert(byte[] ref, int refW, int refH, int x, int y, int refVertStep, int refVertOff, int[] coeff) {
|
||||
int lastLine = refH - (1 << refVertStep) + refVertOff;
|
||||
int y0 = MathUtil.clip(y - (2 << refVertStep), refVertOff, lastLine);
|
||||
int y1 = MathUtil.clip(y - (1 << refVertStep), refVertOff, lastLine);
|
||||
int y2 = MathUtil.clip(y, 0, lastLine);
|
||||
int y3 = MathUtil.clip(y + (1 << refVertStep), refVertOff, lastLine);
|
||||
int y4 = MathUtil.clip(y + (2 << refVertStep), refVertOff, lastLine);
|
||||
int y5 = MathUtil.clip(y + (3 << refVertStep), refVertOff, lastLine);
|
||||
x = MathUtil.clip(x, 0, refW - 1);
|
||||
return ref[y0 * refW + x] * coeff[0] + ref[y1 * refW + x] * coeff[1] + ref[y2 * refW + x] * coeff[2] + ref[y3 * refW + x] * coeff[3] + ref[y4 * refW + x] * coeff[4] + ref[y5 * refW + x] * coeff[5] + 16384;
|
||||
}
|
||||
|
||||
private void predictSubXSubYUnSafe(byte[] ref, int rx, int ix, int ry, int iy, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int offTgt = tgtW * tgtY;
|
||||
int dblTgtW = tgtW << 1;
|
||||
int tripleTgtW = dblTgtW + tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
int[] coeff = COEFF[ix];
|
||||
for (int j = -2, k = 0; j < tgtH + 3; j++) {
|
||||
int y = (j + ry << refVertStep) + refVertOff;
|
||||
for (int m = 0; m < tgtW; m++, k++)
|
||||
this.tmp[k] = getPix6(ref, refW, refH, m + rx, y, refVertStep, refVertOff, coeff);
|
||||
}
|
||||
coeff = COEFF[iy];
|
||||
for (int i = 0, offTmp = dblTgtW; i < tgtH; i++) {
|
||||
for (int m = 0; m < tgtW; m++, offTmp++, offTgt++)
|
||||
tgt[offTgt] = this.tmp[offTmp - dblTgtW] * coeff[0] + this.tmp[offTmp - tgtW] * coeff[1] + this.tmp[offTmp] * coeff[2] + this.tmp[offTmp + tgtW] * coeff[3] + this.tmp[offTmp + dblTgtW] * coeff[4] + this.tmp[offTmp + tripleTgtW] * coeff[5] + 8192 >> 14;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
private void predictSubXSubYSafe(byte[] ref, int rx, int ix, int ry, int iy, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int[] coeff = COEFF[ix];
|
||||
int offRef = ((ry - 2 << refVertStep) + refVertOff) * refW + rx;
|
||||
int offTgt = tgtW * tgtY;
|
||||
int lfRef = (refW << refVertStep) - tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
int dblTgtW = tgtW << 1;
|
||||
int tripleTgtW = dblTgtW + tgtW;
|
||||
for (int j = 0, k = 0; j < tgtH + 5; j++) {
|
||||
for (int m = 0; m < tgtW; m++, k++, offRef++)
|
||||
this.tmp[k] = ref[offRef - 2] * coeff[0] + ref[offRef - 1] * coeff[1] + ref[offRef] * coeff[2] + ref[offRef + 1] * coeff[3] + ref[offRef + 2] * coeff[4] + ref[offRef + 3] * coeff[5];
|
||||
offRef += lfRef;
|
||||
}
|
||||
coeff = COEFF[iy];
|
||||
for (int i = 0, offTmp = dblTgtW; i < tgtH; i++) {
|
||||
for (int m = 0; m < tgtW; m++, offTmp++, offTgt++)
|
||||
tgt[offTgt] = (this.tmp[offTmp - dblTgtW] * coeff[0] + this.tmp[offTmp - tgtW] * coeff[1] + this.tmp[offTmp] * coeff[2] + this.tmp[offTmp + tgtW] * coeff[3] + this.tmp[offTmp + dblTgtW] * coeff[4] + this.tmp[offTmp + tripleTgtW] * coeff[5] + 8192 >> 14) + 128;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
private void predictSubXFullYUnSafe(byte[] ref, int rx, int ix, int ry, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int[] coeff = COEFF[ix];
|
||||
int tgtOff = tgtW * tgtY;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
int y = (i + ry << refVertStep) + refVertOff;
|
||||
for (int j = 0; j < tgtW; j++)
|
||||
tgt[tgtOff++] = getPix6(ref, refW, refH, j + rx, y, refVertStep, refVertOff, coeff) + 64 >> 7;
|
||||
tgtOff += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
private void predictSubXFullYSafe(byte[] ref, int rx, int ix, int ry, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int[] coeff = COEFF[ix];
|
||||
int offRef = ((ry << refVertStep) + refVertOff) * refW + rx;
|
||||
int offTgt = tgtW * tgtY;
|
||||
int lfRef = (refW << refVertStep) - tgtW;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
for (int j = 0; j < tgtW; j++, offRef++)
|
||||
tgt[offTgt++] = (ref[offRef - 2] * coeff[0] + ref[offRef - 1] * coeff[1] + ref[offRef] * coeff[2] + ref[offRef + 1] * coeff[3] + ref[offRef + 2] * coeff[4] + ref[offRef + 3] * coeff[5] + 64 >> 7) + 128;
|
||||
offRef += lfRef;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
private void predictFullXSubYUnSafe(byte[] ref, int rx, int ry, int iy, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int[] coeff = COEFF[iy];
|
||||
int tgtOff = tgtW * tgtY;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
int y = (i + ry << refVertStep) + refVertOff;
|
||||
for (int j = 0; j < tgtW; j++)
|
||||
tgt[tgtOff++] = getPix6Vert(ref, refW, refH, j + rx, y, refVertStep, refVertOff, coeff) + 64 >> 7;
|
||||
tgtOff += lfTgt;
|
||||
}
|
||||
}
|
||||
|
||||
private void predictFullXSubYSafe(byte[] ref, int rx, int ry, int iy, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
int[] coeff = COEFF[iy];
|
||||
int offTgt = tgtW * tgtY;
|
||||
int offRef = ((ry << refVertStep) + refVertOff) * refW + rx;
|
||||
int singleRefW = refW << refVertStep;
|
||||
int dblRefW = refW << 1 + refVertStep;
|
||||
int tripleRefW = dblRefW + singleRefW;
|
||||
int lfTgt = tgtVertStep * tgtW;
|
||||
int lfRef = (refW << refVertStep) - tgtW;
|
||||
for (int i = 0; i < tgtH; i++) {
|
||||
for (int j = 0; j < tgtW; j++, offTgt++, offRef++)
|
||||
tgt[offTgt] = (ref[offRef - dblRefW] * coeff[0] + ref[offRef - singleRefW] * coeff[1] + ref[offRef] * coeff[2] + ref[offRef + singleRefW] * coeff[3] + ref[offRef + dblRefW] * coeff[4] + ref[offRef + tripleRefW] * coeff[5] + 64 >> 7) + 128;
|
||||
offRef += lfRef;
|
||||
offTgt += lfTgt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
public class MPEGPredQuad extends MPEGPredOct {
|
||||
public MPEGPredQuad(MPEGPred other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
public void predictPlane(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff, int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
|
||||
super.predictPlane(ref, refX, refY, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW << 1, tgtH << 1, tgtVertStep);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class MPEGUtil {
|
||||
public static final ByteBuffer gotoNextMarker(ByteBuffer buf) {
|
||||
return gotoMarker(buf, 0, 256, 511);
|
||||
}
|
||||
|
||||
public static final ByteBuffer gotoMarker(ByteBuffer buf, int n, int mmin, int mmax) {
|
||||
if (!buf.hasRemaining())
|
||||
return null;
|
||||
int from = buf.position();
|
||||
ByteBuffer result = buf.slice();
|
||||
result.order(ByteOrder.BIG_ENDIAN);
|
||||
int val = -1;
|
||||
while (buf.hasRemaining()) {
|
||||
val = val << 8 | buf.get() & 0xFF;
|
||||
if (val >= mmin && val <= mmax) {
|
||||
if (n == 0) {
|
||||
buf.position(buf.position() - 4);
|
||||
result.limit(buf.position() - from);
|
||||
break;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final ByteBuffer nextSegment(ByteBuffer buf) {
|
||||
gotoMarker(buf, 0, 256, 511);
|
||||
return gotoMarker(buf, 1, 256, 511);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jcodec.common.AudioFormat;
|
||||
import org.jcodec.common.Codec;
|
||||
import org.jcodec.common.IntArrayList;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
import org.jcodec.common.io.SeekableByteChannel;
|
||||
import org.jcodec.common.logging.Logger;
|
||||
import org.jcodec.common.model.ChannelLabel;
|
||||
import org.jcodec.common.model.Rational;
|
||||
import org.jcodec.common.model.Size;
|
||||
import org.jcodec.containers.mps.MPSUtils;
|
||||
|
||||
public class MPSMediaInfo extends MPSUtils.PESReader {
|
||||
private Map<Integer, MPEGTrackMetadata> infos = new HashMap<>();
|
||||
|
||||
private int pesTried;
|
||||
|
||||
private PSM psm;
|
||||
|
||||
public static class MPEGTimecodeMetadata {
|
||||
public String getNumFrames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String isDropFrame() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getStartCounter() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MPEGTrackMetadata {
|
||||
int streamId;
|
||||
|
||||
Codec codec;
|
||||
|
||||
ByteBuffer probeData;
|
||||
|
||||
public MPEGTrackMetadata(int streamId) {
|
||||
this.streamId = streamId;
|
||||
}
|
||||
|
||||
public AudioFormat getAudioFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChannelLabel[] getChannelLables() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Size getDisplaySize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Size getCodedSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public float getFps() {
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
public float getDuration() {
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
public String getFourcc() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Rational getFpsR() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getNumFrames() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public MPSMediaInfo.MPEGTimecodeMetadata getTimecode() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<MPEGTrackMetadata> getMediaInfo(File f) throws IOException {
|
||||
try {
|
||||
new NIOUtils.FileReader() {
|
||||
protected void data(ByteBuffer data, long filePos) {
|
||||
MPSMediaInfo.this.analyseBuffer(data, filePos);
|
||||
}
|
||||
|
||||
protected void done() {}
|
||||
}.readFile(f, 65536, null);
|
||||
} catch (MediaInfoDone e) {
|
||||
Logger.info("Media info done");
|
||||
}
|
||||
return getInfos();
|
||||
}
|
||||
|
||||
public static class MediaInfoDone extends RuntimeException {}
|
||||
|
||||
protected void pes(ByteBuffer pesBuffer, long start, int pesLen, int stream) {
|
||||
if (!MPSUtils.mediaStream(stream))
|
||||
return;
|
||||
MPEGTrackMetadata info = this.infos.get(Integer.valueOf(stream));
|
||||
if (info == null) {
|
||||
info = new MPEGTrackMetadata(stream);
|
||||
this.infos.put(Integer.valueOf(stream), info);
|
||||
}
|
||||
if (info.probeData == null)
|
||||
info.probeData = NIOUtils.cloneBuffer(pesBuffer);
|
||||
if (++this.pesTried >= 100) {
|
||||
deriveMediaInfo();
|
||||
throw new MediaInfoDone();
|
||||
}
|
||||
}
|
||||
|
||||
private void deriveMediaInfo() {
|
||||
Collection<MPEGTrackMetadata> values = this.infos.values();
|
||||
for (MPEGTrackMetadata stream : values) {
|
||||
int streamId = 0x100 | stream.streamId;
|
||||
if (streamId >= 448 && streamId <= 479) {
|
||||
stream.codec = Codec.MP2;
|
||||
continue;
|
||||
}
|
||||
if (streamId == 445) {
|
||||
ByteBuffer dup = stream.probeData.duplicate();
|
||||
MPSUtils.readPESHeader(dup, 0L);
|
||||
int type = dup.get() & 0xFF;
|
||||
if (type >= 128 && type <= 135) {
|
||||
stream.codec = Codec.AC3;
|
||||
continue;
|
||||
}
|
||||
if ((type >= 136 && type <= 143) || (type >= 152 && type <= 159)) {
|
||||
stream.codec = Codec.DTS;
|
||||
continue;
|
||||
}
|
||||
if (type >= 160 && type <= 175) {
|
||||
stream.codec = Codec.PCM_DVD;
|
||||
continue;
|
||||
}
|
||||
if (type >= 176 && type <= 191) {
|
||||
stream.codec = Codec.TRUEHD;
|
||||
continue;
|
||||
}
|
||||
if (type >= 192 && type <= 207)
|
||||
stream.codec = Codec.AC3;
|
||||
continue;
|
||||
}
|
||||
if (streamId >= 480 && streamId <= 495)
|
||||
stream.codec = Codec.MPEG2;
|
||||
}
|
||||
}
|
||||
|
||||
private int[] parseSystem(ByteBuffer pesBuffer) {
|
||||
NIOUtils.skip(pesBuffer, 12);
|
||||
IntArrayList result = IntArrayList.createIntArrayList();
|
||||
while (pesBuffer.remaining() >= 3 && (pesBuffer.get(pesBuffer.position()) & 0x80) == 128) {
|
||||
result.add(pesBuffer.get() & 0xFF);
|
||||
pesBuffer.getShort();
|
||||
}
|
||||
return result.toArray();
|
||||
}
|
||||
|
||||
public static class PSM {}
|
||||
|
||||
private PSM parsePSM(ByteBuffer pesBuffer) {
|
||||
pesBuffer.getInt();
|
||||
short psmLen = pesBuffer.getShort();
|
||||
if (psmLen > 1018)
|
||||
throw new RuntimeException("Invalid PSM");
|
||||
byte b0 = pesBuffer.get();
|
||||
byte b1 = pesBuffer.get();
|
||||
if ((b1 & 0x1) != 1)
|
||||
throw new RuntimeException("Invalid PSM");
|
||||
short psiLen = pesBuffer.getShort();
|
||||
ByteBuffer psi = NIOUtils.read(pesBuffer, psiLen & 0xFFFF);
|
||||
short elStreamLen = pesBuffer.getShort();
|
||||
parseElStreams(NIOUtils.read(pesBuffer, elStreamLen & 0xFFFF));
|
||||
int crc = pesBuffer.getInt();
|
||||
return new PSM();
|
||||
}
|
||||
|
||||
private void parseElStreams(ByteBuffer buf) {
|
||||
while (buf.hasRemaining()) {
|
||||
byte streamType = buf.get();
|
||||
byte streamId = buf.get();
|
||||
short strInfoLen = buf.getShort();
|
||||
ByteBuffer byteBuffer = NIOUtils.read(buf, strInfoLen & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
public List<MPEGTrackMetadata> getInfos() {
|
||||
return new ArrayList<>(this.infos.values());
|
||||
}
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
new MPSMediaInfo().getMediaInfo(new File(args[0]));
|
||||
}
|
||||
|
||||
public static MPSMediaInfo extract(SeekableByteChannel input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<MPEGTrackMetadata> getAudioTracks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public MPEGTrackMetadata getVideoTrack() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jcodec.common.io.FileChannelWrapper;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
import org.jcodec.common.io.SeekableByteChannel;
|
||||
import org.jcodec.containers.mps.MTSUtils;
|
||||
import org.jcodec.containers.mps.psi.PMTSection;
|
||||
|
||||
public class MTSMediaInfo {
|
||||
public List<MPSMediaInfo.MPEGTrackMetadata> getMediaInfo(File f) throws IOException {
|
||||
FileChannelWrapper ch = null;
|
||||
final List<PMTSection> pmtSections = new ArrayList<>();
|
||||
final Map<Integer, MPSMediaInfo> pids = new HashMap<>();
|
||||
final List<MPSMediaInfo.MPEGTrackMetadata> result = new ArrayList<>();
|
||||
try {
|
||||
ch = NIOUtils.readableChannel(f);
|
||||
new MTSUtils.TSReader(false) {
|
||||
private ByteBuffer pmtBuffer;
|
||||
|
||||
private int pmtPid = -1;
|
||||
|
||||
private boolean pmtDone;
|
||||
|
||||
protected boolean onPkt(int guid, boolean payloadStart, ByteBuffer tsBuf, long filePos, boolean sectionSyntax, ByteBuffer fullPkt) {
|
||||
if (guid == 0) {
|
||||
this.pmtPid = MTSUtils.parsePAT(tsBuf);
|
||||
} else if (guid == this.pmtPid && !this.pmtDone) {
|
||||
if (this.pmtBuffer == null) {
|
||||
this.pmtBuffer = ByteBuffer.allocate((tsBuf.duplicate().getInt() >> 8 & 0x3FF) + 3);
|
||||
} else if (this.pmtBuffer.hasRemaining()) {
|
||||
NIOUtils.writeL(this.pmtBuffer, tsBuf, Math.min(this.pmtBuffer.remaining(), tsBuf.remaining()));
|
||||
}
|
||||
if (!this.pmtBuffer.hasRemaining()) {
|
||||
this.pmtBuffer.flip();
|
||||
PMTSection pmt = MTSUtils.parsePMT(this.pmtBuffer);
|
||||
pmtSections.add(pmt);
|
||||
PMTSection.PMTStream[] streams = pmt.getStreams();
|
||||
for (int i = 0; i < streams.length; i++) {
|
||||
PMTSection.PMTStream stream = streams[i];
|
||||
if (!pids.containsKey(Integer.valueOf(stream.getPid())))
|
||||
pids.put(Integer.valueOf(stream.getPid()), new MPSMediaInfo());
|
||||
}
|
||||
this.pmtDone = (pmt.getSectionNumber() == pmt.getLastSectionNumber());
|
||||
this.pmtBuffer = null;
|
||||
}
|
||||
} else if (pids.containsKey(Integer.valueOf(guid))) {
|
||||
try {
|
||||
((MPSMediaInfo)pids.get(Integer.valueOf(guid))).analyseBuffer(tsBuf, filePos);
|
||||
} catch (MPSMediaInfo.MediaInfoDone e) {
|
||||
result.addAll(((MPSMediaInfo)pids.get(Integer.valueOf(guid))).getInfos());
|
||||
pids.remove(Integer.valueOf(guid));
|
||||
if (pids.size() == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}.readTsFile(ch);
|
||||
} finally {
|
||||
NIOUtils.closeQuietly(ch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
List<MPSMediaInfo.MPEGTrackMetadata> info = new MTSMediaInfo().getMediaInfo(new File(args[0]));
|
||||
for (MPSMediaInfo.MPEGTrackMetadata stream : info)
|
||||
System.out.println(stream.codec);
|
||||
}
|
||||
|
||||
public static MTSMediaInfo extract(SeekableByteChannel input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public MPSMediaInfo.MPEGTrackMetadata getVideoTrack() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<MPSMediaInfo.MPEGTrackMetadata> getAudioTracks() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import org.jcodec.codecs.mpeg12.bitstream.PictureHeader;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.SequenceHeader;
|
||||
import org.jcodec.common.dct.IDCT2x2;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.VLC;
|
||||
|
||||
public class Mpeg2Thumb2x2 extends MPEGDecoder {
|
||||
private MPEGPred localPred;
|
||||
|
||||
private MPEGPred oldPred;
|
||||
|
||||
protected void blockIntra(BitReader bits, VLC vlcCoeff, int[] block, int[] intra_dc_predictor, int blkIdx, int[] scan, int escSize, int intra_dc_mult, int qScale, int[] qmat) {
|
||||
int cc = MPEGConst.BLOCK_TO_CC[blkIdx];
|
||||
int size = ((cc == 0) ? MPEGConst.vlcDCSizeLuma : MPEGConst.vlcDCSizeChroma).readVLC(bits);
|
||||
int delta = (size != 0) ? mpegSigned(bits, size) : 0;
|
||||
intra_dc_predictor[cc] = intra_dc_predictor[cc] + delta;
|
||||
block[0] = intra_dc_predictor[cc] * intra_dc_mult;
|
||||
block[3] = 0;
|
||||
block[2] = 0;
|
||||
block[1] = 0;
|
||||
int readVLC = 0;
|
||||
int idx;
|
||||
for (idx = 0; idx < 6; ) {
|
||||
int level;
|
||||
readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
level = twosSigned(bits, escSize) * qScale * qmat[idx];
|
||||
level = (level >= 0) ? (level >> 4) : -(-level >> 4);
|
||||
} else {
|
||||
idx += (readVLC >> 6) + 1;
|
||||
level = toSigned((readVLC & 0x3F) * qScale * qmat[idx] >> 4, bits.read1Bit());
|
||||
}
|
||||
block[scan[idx]] = level;
|
||||
}
|
||||
if (readVLC != 2048)
|
||||
finishOff(bits, idx, vlcCoeff, escSize);
|
||||
IDCT2x2.idct(block, 0);
|
||||
}
|
||||
|
||||
private void finishOff(BitReader bits, int idx, VLC vlcCoeff, int escSize) {
|
||||
while (idx < 64) {
|
||||
int readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
bits.readNBit(escSize);
|
||||
continue;
|
||||
}
|
||||
bits.read1Bit();
|
||||
}
|
||||
}
|
||||
|
||||
protected void blockInter(BitReader bits, VLC vlcCoeff, int[] block, int[] scan, int escSize, int qScale, int[] qmat) {
|
||||
block[3] = 0;
|
||||
block[2] = 0;
|
||||
block[1] = 0;
|
||||
int idx = -1;
|
||||
if (vlcCoeff == MPEGConst.vlcCoeff0 && bits.checkNBit(1) == 1) {
|
||||
bits.read1Bit();
|
||||
block[0] = toSigned(quantInter(1, qScale * qmat[0]), bits.read1Bit());
|
||||
idx++;
|
||||
} else {
|
||||
block[0] = 0;
|
||||
}
|
||||
int readVLC = 0;
|
||||
while (idx < 6) {
|
||||
int ac;
|
||||
readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
ac = quantInterSigned(twosSigned(bits, escSize), qScale * qmat[idx]);
|
||||
} else {
|
||||
idx += (readVLC >> 6) + 1;
|
||||
ac = toSigned(quantInter(readVLC & 0x3F, qScale * qmat[idx]), bits.read1Bit());
|
||||
}
|
||||
block[scan[idx]] = ac;
|
||||
}
|
||||
if (readVLC != 2048)
|
||||
finishOff(bits, idx, vlcCoeff, escSize);
|
||||
IDCT2x2.idct(block, 0);
|
||||
}
|
||||
|
||||
public int decodeMacroblock(PictureHeader ph, MPEGDecoder.Context context, int prevAddr, int[] qScaleCode, byte[][] buf, int stride, BitReader bits, int vertOff, int vertStep, MPEGPred pred) {
|
||||
if (this.localPred == null || this.oldPred != pred) {
|
||||
this.localPred = new MPEGPredQuad(pred);
|
||||
this.oldPred = pred;
|
||||
}
|
||||
return super.decodeMacroblock(ph, context, prevAddr, qScaleCode, buf, stride, bits, vertOff, vertStep, this.localPred);
|
||||
}
|
||||
|
||||
public static int[] BLOCK_POS_X = new int[] {
|
||||
0, 2, 0, 2, 0, 0, 0, 0, 2, 2,
|
||||
2, 2, 0, 0, 0, 0, 0, 2, 0, 2,
|
||||
0, 0, 0, 0, 2, 2, 2, 2 };
|
||||
|
||||
public static int[] BLOCK_POS_Y = new int[] {
|
||||
0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
|
||||
2, 2, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 1 };
|
||||
|
||||
protected void mapBlock(int[] block, int[] out, int blkIdx, int dctType, int chromaFormat) {
|
||||
int stepVert = (chromaFormat == 1 && (blkIdx == 4 || blkIdx == 5)) ? 0 : dctType;
|
||||
int log2stride = (blkIdx < 4) ? 2 : (2 - MPEGConst.SQUEEZE_X[chromaFormat]);
|
||||
int blkIdxExt = blkIdx + (dctType << 4);
|
||||
int x = BLOCK_POS_X[blkIdxExt];
|
||||
int y = BLOCK_POS_Y[blkIdxExt];
|
||||
int off = (y << log2stride) + x, stride = 1 << log2stride + stepVert;
|
||||
out[off] = out[off] + block[0];
|
||||
out[off + 1] = out[off + 1] + block[1];
|
||||
out[off + stride] = out[off + stride] + block[2];
|
||||
out[off + stride + 1] = out[off + stride + 1] + block[3];
|
||||
}
|
||||
|
||||
protected void put(int[][] mbPix, byte[][] buf, int stride, int chromaFormat, int mbX, int mbY, int width, int height, int vertOff, int vertStep) {
|
||||
int chromaStride = stride + (1 << MPEGConst.SQUEEZE_X[chromaFormat]) - 1 >> MPEGConst.SQUEEZE_X[chromaFormat];
|
||||
int chromaMBW = 2 - MPEGConst.SQUEEZE_X[chromaFormat];
|
||||
int chromaMBH = 2 - MPEGConst.SQUEEZE_Y[chromaFormat];
|
||||
putSub(buf[0], (mbY << 2) * (stride << vertStep) + vertOff * stride + (mbX << 2), stride << vertStep, mbPix[0], 2, 2);
|
||||
putSub(buf[1], (mbY << chromaMBH) * (chromaStride << vertStep) + vertOff * chromaStride + (mbX << chromaMBW), chromaStride << vertStep, mbPix[1], chromaMBW, chromaMBH);
|
||||
putSub(buf[2], (mbY << chromaMBH) * (chromaStride << vertStep) + vertOff * chromaStride + (mbX << chromaMBW), chromaStride << vertStep, mbPix[2], chromaMBW, chromaMBH);
|
||||
}
|
||||
|
||||
protected void putSub(byte[] big, int off, int stride, int[] block, int mbW, int mbH) {
|
||||
int blOff = 0;
|
||||
if (mbW == 1) {
|
||||
big[off] = clipTo8Bit(block[blOff]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 1]);
|
||||
big[off + stride] = clipTo8Bit(block[blOff + 2]);
|
||||
big[off + stride + 1] = clipTo8Bit(block[blOff + 3]);
|
||||
if (mbH == 2) {
|
||||
off += stride << 1;
|
||||
big[off] = clipTo8Bit(block[blOff + 4]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 5]);
|
||||
big[off + stride] = clipTo8Bit(block[blOff + 6]);
|
||||
big[off + stride + 1] = clipTo8Bit(block[blOff + 7]);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
big[off] = clipTo8Bit(block[blOff]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 1]);
|
||||
big[off + 2] = clipTo8Bit(block[blOff + 2]);
|
||||
big[off + 3] = clipTo8Bit(block[blOff + 3]);
|
||||
off += stride;
|
||||
blOff += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int[][] scan2x2 = new int[][] { new int[] {
|
||||
0, 1, 2, 4, 3, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4 }, new int[] {
|
||||
0, 2, 4, 4, 1, 3, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4 } };
|
||||
|
||||
protected MPEGDecoder.Context initContext(SequenceHeader sh, PictureHeader ph) {
|
||||
MPEGDecoder.Context context = super.initContext(sh, ph);
|
||||
context.codedWidth >>= 2;
|
||||
context.codedHeight >>= 2;
|
||||
context.picWidth >>= 2;
|
||||
context.picHeight >>= 2;
|
||||
context.scan = scan2x2[(ph.pictureCodingExtension == null) ? 0 : ph.pictureCodingExtension.alternate_scan];
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.PictureHeader;
|
||||
import org.jcodec.codecs.mpeg12.bitstream.SequenceHeader;
|
||||
import org.jcodec.common.dct.IDCT4x4;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.VLC;
|
||||
|
||||
public class Mpeg2Thumb4x4 extends MPEGDecoder {
|
||||
private MPEGPred localPred;
|
||||
|
||||
private MPEGPred oldPred;
|
||||
|
||||
protected void blockIntra(BitReader bits, VLC vlcCoeff, int[] block, int[] intra_dc_predictor, int blkIdx, int[] scan, int escSize, int intra_dc_mult, int qScale, int[] qmat) {
|
||||
int cc = MPEGConst.BLOCK_TO_CC[blkIdx];
|
||||
int size = ((cc == 0) ? MPEGConst.vlcDCSizeLuma : MPEGConst.vlcDCSizeChroma).readVLC(bits);
|
||||
int delta = (size != 0) ? mpegSigned(bits, size) : 0;
|
||||
intra_dc_predictor[cc] = intra_dc_predictor[cc] + delta;
|
||||
Arrays.fill(block, 1, 16, 0);
|
||||
block[0] = intra_dc_predictor[cc] * intra_dc_mult;
|
||||
int readVLC = 0;
|
||||
int idx = 0;
|
||||
while (true) {
|
||||
if (idx < 19 + ((scan == scan4x4[1]) ? 7 : 0)) {
|
||||
int level;
|
||||
readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
level = twosSigned(bits, escSize) * qScale * qmat[idx];
|
||||
level = (level >= 0) ? (level >> 4) : -(-level >> 4);
|
||||
} else {
|
||||
idx += (readVLC >> 6) + 1;
|
||||
level = toSigned((readVLC & 0x3F) * qScale * qmat[idx] >> 4, bits.read1Bit());
|
||||
}
|
||||
block[scan[idx]] = level;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (readVLC != 2048)
|
||||
finishOff(bits, idx, vlcCoeff, escSize);
|
||||
IDCT4x4.idct(block, 0);
|
||||
}
|
||||
|
||||
private void finishOff(BitReader bits, int idx, VLC vlcCoeff, int escSize) {
|
||||
while (idx < 64) {
|
||||
int readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
bits.readNBit(escSize);
|
||||
continue;
|
||||
}
|
||||
bits.read1Bit();
|
||||
}
|
||||
}
|
||||
|
||||
protected void blockInter(BitReader bits, VLC vlcCoeff, int[] block, int[] scan, int escSize, int qScale, int[] qmat) {
|
||||
Arrays.fill(block, 1, 16, 0);
|
||||
int idx = -1;
|
||||
if (vlcCoeff == MPEGConst.vlcCoeff0 && bits.checkNBit(1) == 1) {
|
||||
bits.read1Bit();
|
||||
block[0] = toSigned(quantInter(1, qScale * qmat[0]), bits.read1Bit());
|
||||
idx++;
|
||||
} else {
|
||||
block[0] = 0;
|
||||
}
|
||||
int readVLC = 0;
|
||||
while (true) {
|
||||
if (idx < 19 + ((scan == scan4x4[1]) ? 7 : 0)) {
|
||||
int ac;
|
||||
readVLC = vlcCoeff.readVLC(bits);
|
||||
if (readVLC == 2048)
|
||||
break;
|
||||
if (readVLC == 2049) {
|
||||
idx += bits.readNBit(6) + 1;
|
||||
ac = quantInterSigned(twosSigned(bits, escSize), qScale * qmat[idx]);
|
||||
} else {
|
||||
idx += (readVLC >> 6) + 1;
|
||||
ac = toSigned(quantInter(readVLC & 0x3F, qScale * qmat[idx]), bits.read1Bit());
|
||||
}
|
||||
block[scan[idx]] = ac;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (readVLC != 2048)
|
||||
finishOff(bits, idx, vlcCoeff, escSize);
|
||||
IDCT4x4.idct(block, 0);
|
||||
}
|
||||
|
||||
public int decodeMacroblock(PictureHeader ph, MPEGDecoder.Context context, int prevAddr, int[] qScaleCode, byte[][] buf, int stride, BitReader bits, int vertOff, int vertStep, MPEGPred pred) {
|
||||
if (this.localPred == null || this.oldPred != pred) {
|
||||
this.localPred = new MPEGPredDbl(pred);
|
||||
this.oldPred = pred;
|
||||
}
|
||||
return super.decodeMacroblock(ph, context, prevAddr, qScaleCode, buf, stride, bits, vertOff, vertStep, this.localPred);
|
||||
}
|
||||
|
||||
public static int[] BLOCK_POS_X = new int[] {
|
||||
0, 4, 0, 4, 0, 0, 0, 0, 4, 4,
|
||||
4, 4, 0, 0, 0, 0, 0, 4, 0, 4,
|
||||
0, 0, 0, 0, 4, 4, 4, 4 };
|
||||
|
||||
public static int[] BLOCK_POS_Y = new int[] {
|
||||
0, 0, 4, 4, 0, 0, 4, 4, 0, 0,
|
||||
4, 4, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 1 };
|
||||
|
||||
protected void mapBlock(int[] block, int[] out, int blkIdx, int dctType, int chromaFormat) {
|
||||
int stepVert = (chromaFormat == 1 && (blkIdx == 4 || blkIdx == 5)) ? 0 : dctType;
|
||||
int log2stride = (blkIdx < 4) ? 3 : (3 - MPEGConst.SQUEEZE_X[chromaFormat]);
|
||||
int blkIdxExt = blkIdx + (dctType << 4);
|
||||
int x = BLOCK_POS_X[blkIdxExt];
|
||||
int y = BLOCK_POS_Y[blkIdxExt];
|
||||
int off = (y << log2stride) + x, stride = 1 << log2stride + stepVert;
|
||||
for (int i = 0; i < 16; i += 4, off += stride) {
|
||||
out[off] = out[off] + block[i];
|
||||
out[off + 1] = out[off + 1] + block[i + 1];
|
||||
out[off + 2] = out[off + 2] + block[i + 2];
|
||||
out[off + 3] = out[off + 3] + block[i + 3];
|
||||
}
|
||||
}
|
||||
|
||||
protected void put(int[][] mbPix, byte[][] buf, int stride, int chromaFormat, int mbX, int mbY, int width, int height, int vertOff, int vertStep) {
|
||||
int chromaStride = stride + (1 << MPEGConst.SQUEEZE_X[chromaFormat]) - 1 >> MPEGConst.SQUEEZE_X[chromaFormat];
|
||||
int chromaMBW = 3 - MPEGConst.SQUEEZE_X[chromaFormat];
|
||||
int chromaMBH = 3 - MPEGConst.SQUEEZE_Y[chromaFormat];
|
||||
putSub(buf[0], (mbY << 3) * (stride << vertStep) + vertOff * stride + (mbX << 3), stride << vertStep, mbPix[0], 3, 3);
|
||||
putSub(buf[1], (mbY << chromaMBH) * (chromaStride << vertStep) + vertOff * chromaStride + (mbX << chromaMBW), chromaStride << vertStep, mbPix[1], chromaMBW, chromaMBH);
|
||||
putSub(buf[2], (mbY << chromaMBH) * (chromaStride << vertStep) + vertOff * chromaStride + (mbX << chromaMBW), chromaStride << vertStep, mbPix[2], chromaMBW, chromaMBH);
|
||||
}
|
||||
|
||||
protected void putSub(byte[] big, int off, int stride, int[] block, int mbW, int mbH) {
|
||||
int blOff = 0;
|
||||
if (mbW == 2) {
|
||||
for (int i = 0; i < 1 << mbH; i++) {
|
||||
big[off] = clipTo8Bit(block[blOff]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 1]);
|
||||
big[off + 2] = clipTo8Bit(block[blOff + 2]);
|
||||
big[off + 3] = clipTo8Bit(block[blOff + 3]);
|
||||
blOff += 4;
|
||||
off += stride;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 1 << mbH; i++) {
|
||||
big[off] = clipTo8Bit(block[blOff]);
|
||||
big[off + 1] = clipTo8Bit(block[blOff + 1]);
|
||||
big[off + 2] = clipTo8Bit(block[blOff + 2]);
|
||||
big[off + 3] = clipTo8Bit(block[blOff + 3]);
|
||||
big[off + 4] = clipTo8Bit(block[blOff + 4]);
|
||||
big[off + 5] = clipTo8Bit(block[blOff + 5]);
|
||||
big[off + 6] = clipTo8Bit(block[blOff + 6]);
|
||||
big[off + 7] = clipTo8Bit(block[blOff + 7]);
|
||||
blOff += 8;
|
||||
off += stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int[][] scan4x4 = new int[][] { new int[] {
|
||||
0, 1, 4, 8, 5, 2, 3, 6, 9, 12,
|
||||
16, 13, 10, 7, 16, 16, 16, 11, 14, 16,
|
||||
16, 16, 16, 16, 15, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16 }, new int[] {
|
||||
0, 4, 8, 12, 1, 5, 2, 6, 9, 13,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 14, 10,
|
||||
3, 7, 16, 16, 11, 15, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16 } };
|
||||
|
||||
protected MPEGDecoder.Context initContext(SequenceHeader sh, PictureHeader ph) {
|
||||
MPEGDecoder.Context context = super.initContext(sh, ph);
|
||||
context.codedWidth >>= 1;
|
||||
context.codedHeight >>= 1;
|
||||
context.picWidth >>= 1;
|
||||
context.picHeight >>= 1;
|
||||
context.scan = scan4x4[(ph.pictureCodingExtension == null) ? 0 : ph.pictureCodingExtension.alternate_scan];
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
|
||||
public class SegmentReader {
|
||||
private ReadableByteChannel channel;
|
||||
|
||||
private ByteBuffer buf;
|
||||
|
||||
protected int curMarker;
|
||||
|
||||
private int fetchSize;
|
||||
|
||||
protected boolean done;
|
||||
|
||||
private long pos;
|
||||
|
||||
private int bytesInMarker;
|
||||
|
||||
private int bufferIncrement = 32768;
|
||||
|
||||
public SegmentReader(ReadableByteChannel channel, int fetchSize) throws IOException {
|
||||
this.channel = channel;
|
||||
this.fetchSize = fetchSize;
|
||||
this.buf = NIOUtils.fetchFromChannel(channel, 4);
|
||||
this.pos = (long)this.buf.remaining();
|
||||
this.curMarker = this.buf.getInt();
|
||||
this.bytesInMarker = 4;
|
||||
}
|
||||
|
||||
public int getBufferIncrement() {
|
||||
return this.bufferIncrement;
|
||||
}
|
||||
|
||||
public void setBufferIncrement(int bufferIncrement) {
|
||||
this.bufferIncrement = bufferIncrement;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
MORE_DATA, DONE, STOP;
|
||||
}
|
||||
|
||||
public final State readToNextMarkerPartial(ByteBuffer out) throws IOException {
|
||||
if (this.done)
|
||||
return State.STOP;
|
||||
int skipOneMarker = (this.curMarker >= 256 && this.curMarker <= 511) ? 1 : 0;
|
||||
int written = out.position();
|
||||
do {
|
||||
while (this.buf.hasRemaining()) {
|
||||
if (this.curMarker >= 256 && this.curMarker <= 511) {
|
||||
if (skipOneMarker == 0)
|
||||
return State.DONE;
|
||||
skipOneMarker--;
|
||||
}
|
||||
if (!out.hasRemaining())
|
||||
return State.MORE_DATA;
|
||||
out.put((byte)(this.curMarker >>> 24));
|
||||
this.curMarker = this.curMarker << 8 | this.buf.get() & 0xFF;
|
||||
}
|
||||
this.buf = NIOUtils.fetchFromChannel(this.channel, this.fetchSize);
|
||||
this.pos += (long)this.buf.remaining();
|
||||
} while (this.buf.hasRemaining());
|
||||
written = out.position() - written;
|
||||
if (written > 0 && this.curMarker >= 256 && this.curMarker <= 511)
|
||||
return State.DONE;
|
||||
while (this.bytesInMarker > 0 && out.hasRemaining()) {
|
||||
out.put((byte)(this.curMarker >>> 24));
|
||||
this.curMarker <<= 8;
|
||||
this.bytesInMarker--;
|
||||
if (this.curMarker >= 256 && this.curMarker <= 511)
|
||||
return State.DONE;
|
||||
}
|
||||
if (this.bytesInMarker == 0) {
|
||||
this.done = true;
|
||||
return State.STOP;
|
||||
}
|
||||
return State.MORE_DATA;
|
||||
}
|
||||
|
||||
public ByteBuffer readToNextMarkerNewBuffer() throws IOException {
|
||||
if (this.done)
|
||||
return null;
|
||||
List<ByteBuffer> buffers = new ArrayList<>();
|
||||
readToNextMarkerBuffers(buffers);
|
||||
return NIOUtils.combineBuffers(buffers);
|
||||
}
|
||||
|
||||
public void readToNextMarkerBuffers(List<ByteBuffer> buffers) throws IOException {
|
||||
State state;
|
||||
do {
|
||||
ByteBuffer curBuffer = ByteBuffer.allocate(this.bufferIncrement);
|
||||
state = readToNextMarkerPartial(curBuffer);
|
||||
curBuffer.flip();
|
||||
buffers.add(curBuffer);
|
||||
} while (state == State.MORE_DATA);
|
||||
}
|
||||
|
||||
public final boolean readToNextMarker(ByteBuffer out) throws IOException {
|
||||
State state = readToNextMarkerPartial(out);
|
||||
if (state == State.MORE_DATA)
|
||||
throw new BufferOverflowException();
|
||||
return (state == State.DONE);
|
||||
}
|
||||
|
||||
public final boolean skipToMarker() throws IOException {
|
||||
if (this.done)
|
||||
return false;
|
||||
while (true) {
|
||||
while (this.buf.hasRemaining()) {
|
||||
this.curMarker = this.curMarker << 8 | this.buf.get() & 0xFF;
|
||||
if (this.curMarker >= 256 && this.curMarker <= 511)
|
||||
return true;
|
||||
}
|
||||
this.buf = NIOUtils.fetchFromChannel(this.channel, this.fetchSize);
|
||||
this.pos += (long)this.buf.remaining();
|
||||
if (!this.buf.hasRemaining()) {
|
||||
this.done = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean read(ByteBuffer out, int length) throws IOException {
|
||||
if (this.done)
|
||||
return false;
|
||||
while (true) {
|
||||
while (this.buf.hasRemaining()) {
|
||||
if (length-- == 0)
|
||||
return true;
|
||||
out.put((byte)(this.curMarker >>> 24));
|
||||
this.curMarker = this.curMarker << 8 | this.buf.get() & 0xFF;
|
||||
}
|
||||
this.buf = NIOUtils.fetchFromChannel(this.channel, this.fetchSize);
|
||||
this.pos += (long)this.buf.remaining();
|
||||
if (!this.buf.hasRemaining()) {
|
||||
out.putInt(this.curMarker);
|
||||
this.done = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final long curPos() {
|
||||
return this.pos - (long)this.buf.remaining() - 4L;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SetBaseTimestamp extends FixTimestamp {
|
||||
private int baseTs;
|
||||
|
||||
private long firstPts = -1L;
|
||||
|
||||
private boolean video;
|
||||
|
||||
public SetBaseTimestamp(boolean video, int baseTs) {
|
||||
this.video = video;
|
||||
this.baseTs = baseTs;
|
||||
}
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
File file = new File(args[0]);
|
||||
new SetBaseTimestamp("video".equalsIgnoreCase(args[1]), Integer.parseInt(args[2])).fix(file);
|
||||
}
|
||||
|
||||
protected long doWithTimestamp(int streamId, long pts, boolean isPts) {
|
||||
if ((this.video && isVideo(streamId)) || (!this.video && isAudio(streamId))) {
|
||||
if (this.firstPts == -1L)
|
||||
this.firstPts = pts;
|
||||
return pts - this.firstPts + (long)this.baseTs;
|
||||
}
|
||||
return pts;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package org.jcodec.codecs.mpeg12;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import org.jcodec.common.io.IOUtils;
|
||||
import org.jcodec.common.model.RationalLarge;
|
||||
import org.jcodec.common.tools.MainUtils;
|
||||
|
||||
public class TimestampUtil {
|
||||
private static final String STREAM_ALL = "all";
|
||||
|
||||
private static final String STREAM_AUDIO = "audio";
|
||||
|
||||
private static final String STRAM_VIDEO = "video";
|
||||
|
||||
private static final MainUtils.Flag FLAG_STREAM = MainUtils.Flag.flag("stream", "s", "A stream to shift, i.e. 'video' or 'audio' or 'all' [default]");
|
||||
|
||||
private static final MainUtils.Flag[] ALL_FLAGS = new MainUtils.Flag[] { FLAG_STREAM };
|
||||
|
||||
private static final String COMMAND_SHIFT = "shift";
|
||||
|
||||
private static final String COMMAND_SCALE = "scale";
|
||||
|
||||
private static final String COMMAND_ROUND = "round";
|
||||
|
||||
public static void main1(String[] args) throws IOException {
|
||||
MainUtils.Cmd cmd = MainUtils.parseArguments(args, ALL_FLAGS);
|
||||
if (cmd.args.length < 3) {
|
||||
System.out.println("A utility to tweak MPEG TS timestamps.");
|
||||
MainUtils.printHelp(ALL_FLAGS, Arrays.asList("command", "arg", "in name", "?out file"));
|
||||
System.out.println("Where command is:\n\tshift\tShift timestamps of selected stream by arg.\n\tscale\tScale timestams of selected stream by arg [num:den].\n\tround\tRound timestamps of selected stream to multiples of arg.");
|
||||
return;
|
||||
}
|
||||
File src = new File(cmd.getArg(2));
|
||||
if (cmd.argsLength() > 3) {
|
||||
File dst = new File(cmd.getArg(3));
|
||||
IOUtils.copyFile(src, dst);
|
||||
src = dst;
|
||||
}
|
||||
String command = cmd.getArg(0);
|
||||
String stream = cmd.getStringFlagD(FLAG_STREAM, "all");
|
||||
if ("shift".equalsIgnoreCase(command)) {
|
||||
final long shift = Long.parseLong(cmd.getArg(1));
|
||||
new BaseCommand(stream) {
|
||||
protected long withTimestamp(long pts, boolean isPts) {
|
||||
return Math.max(pts + shift, 0L);
|
||||
}
|
||||
}.fix(src);
|
||||
} else if ("scale".equalsIgnoreCase(command)) {
|
||||
final RationalLarge scale = RationalLarge.parse(cmd.getArg(1));
|
||||
new BaseCommand(stream) {
|
||||
protected long withTimestamp(long pts, boolean isPts) {
|
||||
return scale.multiplyS(pts);
|
||||
}
|
||||
}.fix(src);
|
||||
} else if ("round".equalsIgnoreCase(command)) {
|
||||
final int precision = Integer.parseInt(cmd.getArg(1));
|
||||
new BaseCommand(stream) {
|
||||
protected long withTimestamp(long pts, boolean isPts) {
|
||||
return Math.round((double)pts / (double)precision) * (long)precision;
|
||||
}
|
||||
}.fix(src);
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class BaseCommand extends FixTimestamp {
|
||||
private String streamSelector;
|
||||
|
||||
public BaseCommand(String stream) {
|
||||
this.streamSelector = stream;
|
||||
}
|
||||
|
||||
protected long doWithTimestamp(int streamId, long pts, boolean isPts) {
|
||||
if ("all".equals(this.streamSelector) || ("video".equals(this.streamSelector) && isVideo(streamId)) || ("audio"
|
||||
.equals(this.streamSelector) && isAudio(streamId)))
|
||||
return withTimestamp(pts, isPts);
|
||||
return pts;
|
||||
}
|
||||
|
||||
protected abstract long withTimestamp(long param1Long, boolean param1Boolean);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class CopyrightExtension implements MPEGHeader {
|
||||
public int copyright_flag;
|
||||
|
||||
public int copyright_identifier;
|
||||
|
||||
public int original_or_copy;
|
||||
|
||||
public int copyright_number_1;
|
||||
|
||||
public int copyright_number_2;
|
||||
|
||||
public int copyright_number_3;
|
||||
|
||||
public static final int Copyright_Extension = 4;
|
||||
|
||||
public static CopyrightExtension read(BitReader _in) {
|
||||
CopyrightExtension ce = new CopyrightExtension();
|
||||
ce.copyright_flag = _in.read1Bit();
|
||||
ce.copyright_identifier = _in.readNBit(8);
|
||||
ce.original_or_copy = _in.read1Bit();
|
||||
_in.skip(7);
|
||||
_in.read1Bit();
|
||||
ce.copyright_number_1 = _in.readNBit(20);
|
||||
_in.read1Bit();
|
||||
ce.copyright_number_2 = _in.readNBit(22);
|
||||
_in.read1Bit();
|
||||
ce.copyright_number_3 = _in.readNBit(22);
|
||||
return ce;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(4, 4);
|
||||
bw.write1Bit(this.copyright_flag);
|
||||
bw.writeNBit(this.copyright_identifier, 8);
|
||||
bw.write1Bit(this.original_or_copy);
|
||||
bw.writeNBit(0, 7);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.copyright_number_1, 20);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.copyright_number_2, 22);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.copyright_number_3, 22);
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
import org.jcodec.common.model.TapeTimecode;
|
||||
|
||||
public class GOPHeader implements MPEGHeader {
|
||||
private TapeTimecode timeCode;
|
||||
|
||||
private boolean closedGop;
|
||||
|
||||
private boolean brokenLink;
|
||||
|
||||
public GOPHeader(TapeTimecode timeCode, boolean closedGop, boolean brokenLink) {
|
||||
this.timeCode = timeCode;
|
||||
this.closedGop = closedGop;
|
||||
this.brokenLink = brokenLink;
|
||||
}
|
||||
|
||||
public static GOPHeader read(ByteBuffer bb) {
|
||||
BitReader _in = BitReader.createBitReader(bb);
|
||||
boolean dropFrame = (_in.read1Bit() == 1);
|
||||
short hours = (short)_in.readNBit(5);
|
||||
byte minutes = (byte)_in.readNBit(6);
|
||||
_in.skip(1);
|
||||
byte seconds = (byte)_in.readNBit(6);
|
||||
byte frames = (byte)_in.readNBit(6);
|
||||
boolean closedGop = (_in.read1Bit() == 1);
|
||||
boolean brokenLink = (_in.read1Bit() == 1);
|
||||
return new GOPHeader(new TapeTimecode(hours, minutes, seconds, frames, dropFrame, 0), closedGop, brokenLink);
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
if (this.timeCode == null) {
|
||||
bw.writeNBit(0, 25);
|
||||
} else {
|
||||
bw.write1Bit(this.timeCode.isDropFrame() ? 1 : 0);
|
||||
bw.writeNBit(this.timeCode.getHour(), 5);
|
||||
bw.writeNBit(this.timeCode.getMinute(), 6);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.timeCode.getSecond(), 6);
|
||||
bw.writeNBit(this.timeCode.getFrame(), 6);
|
||||
}
|
||||
bw.write1Bit(this.closedGop ? 1 : 0);
|
||||
bw.write1Bit(this.brokenLink ? 1 : 0);
|
||||
bw.flush();
|
||||
}
|
||||
|
||||
public TapeTimecode getTimeCode() {
|
||||
return this.timeCode;
|
||||
}
|
||||
|
||||
public boolean isClosedGop() {
|
||||
return this.closedGop;
|
||||
}
|
||||
|
||||
public boolean isBrokenLink() {
|
||||
return this.brokenLink;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface MPEGHeader {
|
||||
void write(ByteBuffer paramByteBuffer);
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class PictureCodingExtension implements MPEGHeader {
|
||||
public static final int Top_Field = 1;
|
||||
|
||||
public static final int Bottom_Field = 2;
|
||||
|
||||
public static final int Frame = 3;
|
||||
|
||||
public int[][] f_code = new int[2][2];
|
||||
|
||||
public int intra_dc_precision;
|
||||
|
||||
public int picture_structure;
|
||||
|
||||
public int top_field_first;
|
||||
|
||||
public int frame_pred_frame_dct;
|
||||
|
||||
public int concealment_motion_vectors;
|
||||
|
||||
public int q_scale_type;
|
||||
|
||||
public int intra_vlc_format;
|
||||
|
||||
public int alternate_scan;
|
||||
|
||||
public int repeat_first_field;
|
||||
|
||||
public int chroma_420_type;
|
||||
|
||||
public int progressive_frame;
|
||||
|
||||
public CompositeDisplay compositeDisplay;
|
||||
|
||||
public static final int Picture_Coding_Extension = 8;
|
||||
|
||||
public static class CompositeDisplay {
|
||||
public int v_axis;
|
||||
|
||||
public int field_sequence;
|
||||
|
||||
public int sub_carrier;
|
||||
|
||||
public int burst_amplitude;
|
||||
|
||||
public int sub_carrier_phase;
|
||||
|
||||
public static CompositeDisplay read(BitReader _in) {
|
||||
CompositeDisplay cd = new CompositeDisplay();
|
||||
cd.v_axis = _in.read1Bit();
|
||||
cd.field_sequence = _in.readNBit(3);
|
||||
cd.sub_carrier = _in.read1Bit();
|
||||
cd.burst_amplitude = _in.readNBit(7);
|
||||
cd.sub_carrier_phase = _in.readNBit(8);
|
||||
return cd;
|
||||
}
|
||||
|
||||
public void write(BitWriter out) {
|
||||
out.write1Bit(this.v_axis);
|
||||
out.writeNBit(this.field_sequence, 3);
|
||||
out.write1Bit(this.sub_carrier);
|
||||
out.writeNBit(this.burst_amplitude, 7);
|
||||
out.writeNBit(this.sub_carrier_phase, 8);
|
||||
}
|
||||
}
|
||||
|
||||
public static PictureCodingExtension read(BitReader _in) {
|
||||
PictureCodingExtension pce = new PictureCodingExtension();
|
||||
pce.f_code[0][0] = _in.readNBit(4);
|
||||
pce.f_code[0][1] = _in.readNBit(4);
|
||||
pce.f_code[1][0] = _in.readNBit(4);
|
||||
pce.f_code[1][1] = _in.readNBit(4);
|
||||
pce.intra_dc_precision = _in.readNBit(2);
|
||||
pce.picture_structure = _in.readNBit(2);
|
||||
pce.top_field_first = _in.read1Bit();
|
||||
pce.frame_pred_frame_dct = _in.read1Bit();
|
||||
pce.concealment_motion_vectors = _in.read1Bit();
|
||||
pce.q_scale_type = _in.read1Bit();
|
||||
pce.intra_vlc_format = _in.read1Bit();
|
||||
pce.alternate_scan = _in.read1Bit();
|
||||
pce.repeat_first_field = _in.read1Bit();
|
||||
pce.chroma_420_type = _in.read1Bit();
|
||||
pce.progressive_frame = _in.read1Bit();
|
||||
if (_in.read1Bit() != 0)
|
||||
pce.compositeDisplay = CompositeDisplay.read(_in);
|
||||
return pce;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(8, 4);
|
||||
bw.writeNBit(this.f_code[0][0], 4);
|
||||
bw.writeNBit(this.f_code[0][1], 4);
|
||||
bw.writeNBit(this.f_code[1][0], 4);
|
||||
bw.writeNBit(this.f_code[1][1], 4);
|
||||
bw.writeNBit(this.intra_dc_precision, 2);
|
||||
bw.writeNBit(this.picture_structure, 2);
|
||||
bw.write1Bit(this.top_field_first);
|
||||
bw.write1Bit(this.frame_pred_frame_dct);
|
||||
bw.write1Bit(this.concealment_motion_vectors);
|
||||
bw.write1Bit(this.q_scale_type);
|
||||
bw.write1Bit(this.intra_vlc_format);
|
||||
bw.write1Bit(this.alternate_scan);
|
||||
bw.write1Bit(this.repeat_first_field);
|
||||
bw.write1Bit(this.chroma_420_type);
|
||||
bw.write1Bit(this.progressive_frame);
|
||||
bw.write1Bit((this.compositeDisplay != null) ? 1 : 0);
|
||||
if (this.compositeDisplay != null)
|
||||
this.compositeDisplay.write(bw);
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
import org.jcodec.common.model.Point;
|
||||
|
||||
public class PictureDisplayExtension implements MPEGHeader {
|
||||
public Point[] frame_centre_offsets;
|
||||
|
||||
public static final int Picture_Display_Extension = 7;
|
||||
|
||||
public static PictureDisplayExtension read(BitReader bits, SequenceExtension se, PictureCodingExtension pce) {
|
||||
PictureDisplayExtension pde = new PictureDisplayExtension();
|
||||
pde.frame_centre_offsets = new Point[numberOfFrameCentreOffsets(se, pce)];
|
||||
for (int i = 0; i < pde.frame_centre_offsets.length; i++) {
|
||||
int frame_centre_horizontal_offset = bits.readNBit(16);
|
||||
bits.read1Bit();
|
||||
int frame_centre_vertical_offset = bits.readNBit(16);
|
||||
bits.read1Bit();
|
||||
pde.frame_centre_offsets[i] = new Point(frame_centre_horizontal_offset, frame_centre_vertical_offset);
|
||||
}
|
||||
return pde;
|
||||
}
|
||||
|
||||
private static int numberOfFrameCentreOffsets(SequenceExtension se, PictureCodingExtension pce) {
|
||||
if (se == null || pce == null)
|
||||
throw new IllegalArgumentException("PictureDisplayExtension requires SequenceExtension and PictureCodingExtension to be present");
|
||||
if (se.progressive_sequence == 1) {
|
||||
if (pce.repeat_first_field == 1) {
|
||||
if (pce.top_field_first == 1)
|
||||
return 3;
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (pce.picture_structure != 3)
|
||||
return 1;
|
||||
if (pce.repeat_first_field == 1)
|
||||
return 3;
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(7, 4);
|
||||
for (int i = 0; i < this.frame_centre_offsets.length; i++) {
|
||||
Point point = this.frame_centre_offsets[i];
|
||||
bw.writeNBit(point.getX(), 16);
|
||||
bw.writeNBit(point.getY(), 16);
|
||||
}
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class PictureHeader implements MPEGHeader {
|
||||
public int temporal_reference;
|
||||
|
||||
public int picture_coding_type;
|
||||
|
||||
public int vbv_delay;
|
||||
|
||||
public int full_pel_forward_vector;
|
||||
|
||||
public int forward_f_code;
|
||||
|
||||
public int full_pel_backward_vector;
|
||||
|
||||
public int backward_f_code;
|
||||
|
||||
public QuantMatrixExtension quantMatrixExtension;
|
||||
|
||||
public CopyrightExtension copyrightExtension;
|
||||
|
||||
public PictureDisplayExtension pictureDisplayExtension;
|
||||
|
||||
public PictureCodingExtension pictureCodingExtension;
|
||||
|
||||
public PictureSpatialScalableExtension pictureSpatialScalableExtension;
|
||||
|
||||
public PictureTemporalScalableExtension pictureTemporalScalableExtension;
|
||||
|
||||
private boolean _hasExtensions;
|
||||
|
||||
public static PictureHeader createPictureHeader(int temporal_reference, int picture_coding_type, int vbv_delay, int full_pel_forward_vector, int forward_f_code, int full_pel_backward_vector, int backward_f_code) {
|
||||
PictureHeader p = new PictureHeader();
|
||||
p.temporal_reference = temporal_reference;
|
||||
p.picture_coding_type = picture_coding_type;
|
||||
p.vbv_delay = vbv_delay;
|
||||
p.full_pel_forward_vector = full_pel_forward_vector;
|
||||
p.forward_f_code = forward_f_code;
|
||||
p.full_pel_backward_vector = full_pel_backward_vector;
|
||||
p.backward_f_code = backward_f_code;
|
||||
return p;
|
||||
}
|
||||
|
||||
public static PictureHeader read(ByteBuffer bb) {
|
||||
BitReader _in = BitReader.createBitReader(bb);
|
||||
PictureHeader ph = new PictureHeader();
|
||||
ph.temporal_reference = _in.readNBit(10);
|
||||
ph.picture_coding_type = _in.readNBit(3);
|
||||
ph.vbv_delay = _in.readNBit(16);
|
||||
if (ph.picture_coding_type == 2 || ph.picture_coding_type == 3) {
|
||||
ph.full_pel_forward_vector = _in.read1Bit();
|
||||
ph.forward_f_code = _in.readNBit(3);
|
||||
}
|
||||
if (ph.picture_coding_type == 3) {
|
||||
ph.full_pel_backward_vector = _in.read1Bit();
|
||||
ph.backward_f_code = _in.readNBit(3);
|
||||
}
|
||||
while (_in.read1Bit() == 1)
|
||||
_in.readNBit(8);
|
||||
return ph;
|
||||
}
|
||||
|
||||
public static void readExtension(ByteBuffer bb, PictureHeader ph, SequenceHeader sh) {
|
||||
ph._hasExtensions = true;
|
||||
BitReader _in = BitReader.createBitReader(bb);
|
||||
int extType = _in.readNBit(4);
|
||||
switch (extType) {
|
||||
case 3:
|
||||
ph.quantMatrixExtension = QuantMatrixExtension.read(_in);
|
||||
break;
|
||||
case 4:
|
||||
ph.copyrightExtension = CopyrightExtension.read(_in);
|
||||
break;
|
||||
case 7:
|
||||
ph.pictureDisplayExtension = PictureDisplayExtension.read(_in, sh.sequenceExtension, ph.pictureCodingExtension);
|
||||
break;
|
||||
case 8:
|
||||
ph.pictureCodingExtension = PictureCodingExtension.read(_in);
|
||||
break;
|
||||
case 9:
|
||||
ph.pictureSpatialScalableExtension = PictureSpatialScalableExtension.read(_in);
|
||||
break;
|
||||
case 16:
|
||||
ph.pictureTemporalScalableExtension = PictureTemporalScalableExtension.read(_in);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unsupported extension: " + extType);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(ByteBuffer os) {
|
||||
BitWriter out = new BitWriter(os);
|
||||
out.writeNBit(this.temporal_reference, 10);
|
||||
out.writeNBit(this.picture_coding_type, 3);
|
||||
out.writeNBit(this.vbv_delay, 16);
|
||||
if (this.picture_coding_type == 2 || this.picture_coding_type == 3) {
|
||||
out.write1Bit(this.full_pel_forward_vector);
|
||||
out.write1Bit(this.forward_f_code);
|
||||
}
|
||||
if (this.picture_coding_type == 3) {
|
||||
out.write1Bit(this.full_pel_backward_vector);
|
||||
out.writeNBit(this.backward_f_code, 3);
|
||||
}
|
||||
out.write1Bit(0);
|
||||
out.flush();
|
||||
writeExtensions(os);
|
||||
}
|
||||
|
||||
private void writeExtensions(ByteBuffer out) {
|
||||
if (this.quantMatrixExtension != null) {
|
||||
out.putInt(181);
|
||||
this.quantMatrixExtension.write(out);
|
||||
}
|
||||
if (this.copyrightExtension != null) {
|
||||
out.putInt(181);
|
||||
this.copyrightExtension.write(out);
|
||||
}
|
||||
if (this.pictureCodingExtension != null) {
|
||||
out.putInt(181);
|
||||
this.pictureCodingExtension.write(out);
|
||||
}
|
||||
if (this.pictureDisplayExtension != null) {
|
||||
out.putInt(181);
|
||||
this.pictureDisplayExtension.write(out);
|
||||
}
|
||||
if (this.pictureSpatialScalableExtension != null) {
|
||||
out.putInt(181);
|
||||
this.pictureSpatialScalableExtension.write(out);
|
||||
}
|
||||
if (this.pictureTemporalScalableExtension != null) {
|
||||
out.putInt(181);
|
||||
this.pictureTemporalScalableExtension.write(out);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasExtensions() {
|
||||
return this._hasExtensions;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class PictureSpatialScalableExtension implements MPEGHeader {
|
||||
public int lower_layer_temporal_reference;
|
||||
|
||||
public int lower_layer_horizontal_offset;
|
||||
|
||||
public int lower_layer_vertical_offset;
|
||||
|
||||
public int spatial_temporal_weight_code_table_index;
|
||||
|
||||
public int lower_layer_progressive_frame;
|
||||
|
||||
public int lower_layer_deinterlaced_field_select;
|
||||
|
||||
public static final int Picture_Spatial_Scalable_Extension = 9;
|
||||
|
||||
public static PictureSpatialScalableExtension read(BitReader _in) {
|
||||
PictureSpatialScalableExtension psse = new PictureSpatialScalableExtension();
|
||||
psse.lower_layer_temporal_reference = _in.readNBit(10);
|
||||
_in.read1Bit();
|
||||
psse.lower_layer_horizontal_offset = _in.readNBit(15);
|
||||
_in.read1Bit();
|
||||
psse.lower_layer_vertical_offset = _in.readNBit(15);
|
||||
psse.spatial_temporal_weight_code_table_index = _in.readNBit(2);
|
||||
psse.lower_layer_progressive_frame = _in.read1Bit();
|
||||
psse.lower_layer_deinterlaced_field_select = _in.read1Bit();
|
||||
return psse;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(9, 4);
|
||||
bw.writeNBit(this.lower_layer_temporal_reference, 10);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.lower_layer_horizontal_offset, 15);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.lower_layer_vertical_offset, 15);
|
||||
bw.writeNBit(this.spatial_temporal_weight_code_table_index, 2);
|
||||
bw.write1Bit(this.lower_layer_progressive_frame);
|
||||
bw.write1Bit(this.lower_layer_deinterlaced_field_select);
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class PictureTemporalScalableExtension implements MPEGHeader {
|
||||
public int reference_select_code;
|
||||
|
||||
public int forward_temporal_reference;
|
||||
|
||||
public int backward_temporal_reference;
|
||||
|
||||
public static final int Picture_Temporal_Scalable_Extension = 16;
|
||||
|
||||
public static PictureTemporalScalableExtension read(BitReader _in) {
|
||||
PictureTemporalScalableExtension ptse = new PictureTemporalScalableExtension();
|
||||
ptse.reference_select_code = _in.readNBit(2);
|
||||
ptse.forward_temporal_reference = _in.readNBit(10);
|
||||
_in.read1Bit();
|
||||
ptse.backward_temporal_reference = _in.readNBit(10);
|
||||
return ptse;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(16, 4);
|
||||
bw.writeNBit(this.reference_select_code, 2);
|
||||
bw.writeNBit(this.forward_temporal_reference, 10);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.backward_temporal_reference, 10);
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class QuantMatrixExtension implements MPEGHeader {
|
||||
public int[] intra_quantiser_matrix;
|
||||
|
||||
public int[] non_intra_quantiser_matrix;
|
||||
|
||||
public int[] chroma_intra_quantiser_matrix;
|
||||
|
||||
public int[] chroma_non_intra_quantiser_matrix;
|
||||
|
||||
public static final int Quant_Matrix_Extension = 3;
|
||||
|
||||
public static QuantMatrixExtension read(BitReader _in) {
|
||||
QuantMatrixExtension qme = new QuantMatrixExtension();
|
||||
if (_in.read1Bit() != 0)
|
||||
qme.intra_quantiser_matrix = readQMat(_in);
|
||||
if (_in.read1Bit() != 0)
|
||||
qme.non_intra_quantiser_matrix = readQMat(_in);
|
||||
if (_in.read1Bit() != 0)
|
||||
qme.chroma_intra_quantiser_matrix = readQMat(_in);
|
||||
if (_in.read1Bit() != 0)
|
||||
qme.chroma_non_intra_quantiser_matrix = readQMat(_in);
|
||||
return qme;
|
||||
}
|
||||
|
||||
private static int[] readQMat(BitReader _in) {
|
||||
int[] qmat = new int[64];
|
||||
for (int i = 0; i < 64; i++)
|
||||
qmat[i] = _in.readNBit(8);
|
||||
return qmat;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(3, 4);
|
||||
bw.write1Bit((this.intra_quantiser_matrix != null) ? 1 : 0);
|
||||
if (this.intra_quantiser_matrix != null)
|
||||
writeQMat(this.intra_quantiser_matrix, bw);
|
||||
bw.write1Bit((this.non_intra_quantiser_matrix != null) ? 1 : 0);
|
||||
if (this.non_intra_quantiser_matrix != null)
|
||||
writeQMat(this.non_intra_quantiser_matrix, bw);
|
||||
bw.write1Bit((this.chroma_intra_quantiser_matrix != null) ? 1 : 0);
|
||||
if (this.chroma_intra_quantiser_matrix != null)
|
||||
writeQMat(this.chroma_intra_quantiser_matrix, bw);
|
||||
bw.write1Bit((this.chroma_non_intra_quantiser_matrix != null) ? 1 : 0);
|
||||
if (this.chroma_non_intra_quantiser_matrix != null)
|
||||
writeQMat(this.chroma_non_intra_quantiser_matrix, bw);
|
||||
bw.flush();
|
||||
}
|
||||
|
||||
private void writeQMat(int[] matrix, BitWriter ob) {
|
||||
for (int i = 0; i < 64; i++)
|
||||
ob.writeNBit(matrix[i], 8);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class SequenceDisplayExtension implements MPEGHeader {
|
||||
public int video_format;
|
||||
|
||||
public int display_horizontal_size;
|
||||
|
||||
public int display_vertical_size;
|
||||
|
||||
public ColorDescription colorDescription;
|
||||
|
||||
public static final int Sequence_Display_Extension = 2;
|
||||
|
||||
public static class ColorDescription {
|
||||
int colour_primaries;
|
||||
|
||||
int transfer_characteristics;
|
||||
|
||||
int matrix_coefficients;
|
||||
|
||||
public static ColorDescription read(BitReader _in) {
|
||||
ColorDescription cd = new ColorDescription();
|
||||
cd.colour_primaries = _in.readNBit(8);
|
||||
cd.transfer_characteristics = _in.readNBit(8);
|
||||
cd.matrix_coefficients = _in.readNBit(8);
|
||||
return cd;
|
||||
}
|
||||
|
||||
public void write(BitWriter out) {
|
||||
out.writeNBit(this.colour_primaries, 8);
|
||||
out.writeNBit(this.transfer_characteristics, 8);
|
||||
out.writeNBit(this.matrix_coefficients, 8);
|
||||
}
|
||||
}
|
||||
|
||||
public static SequenceDisplayExtension read(BitReader _in) {
|
||||
SequenceDisplayExtension sde = new SequenceDisplayExtension();
|
||||
sde.video_format = _in.readNBit(3);
|
||||
if (_in.read1Bit() == 1)
|
||||
sde.colorDescription = ColorDescription.read(_in);
|
||||
sde.display_horizontal_size = _in.readNBit(14);
|
||||
_in.read1Bit();
|
||||
sde.display_vertical_size = _in.readNBit(14);
|
||||
return sde;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(2, 4);
|
||||
bw.writeNBit(this.video_format, 3);
|
||||
bw.write1Bit((this.colorDescription != null) ? 1 : 0);
|
||||
if (this.colorDescription != null)
|
||||
this.colorDescription.write(bw);
|
||||
bw.writeNBit(this.display_horizontal_size, 14);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.display_vertical_size, 14);
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class SequenceExtension implements MPEGHeader {
|
||||
public static final int Chroma420 = 1;
|
||||
|
||||
public static final int Chroma422 = 2;
|
||||
|
||||
public static final int Chroma444 = 3;
|
||||
|
||||
public int profile_and_level;
|
||||
|
||||
public int progressive_sequence;
|
||||
|
||||
public int chroma_format;
|
||||
|
||||
public int horizontal_size_extension;
|
||||
|
||||
public int vertical_size_extension;
|
||||
|
||||
public int bit_rate_extension;
|
||||
|
||||
public int vbv_buffer_size_extension;
|
||||
|
||||
public int low_delay;
|
||||
|
||||
public int frame_rate_extension_n;
|
||||
|
||||
public int frame_rate_extension_d;
|
||||
|
||||
public static final int Sequence_Extension = 1;
|
||||
|
||||
public static SequenceExtension createSequenceExtension(int profile_and_level, int progressive_sequence, int chroma_format, int horizontal_size_extension, int vertical_size_extension, int bit_rate_extension, int vbv_buffer_size_extension, int low_delay, int frame_rate_extension_n, int frame_rate_extension_d) {
|
||||
SequenceExtension se = new SequenceExtension();
|
||||
se.profile_and_level = profile_and_level;
|
||||
se.progressive_sequence = progressive_sequence;
|
||||
se.chroma_format = chroma_format;
|
||||
se.horizontal_size_extension = horizontal_size_extension;
|
||||
se.vertical_size_extension = vertical_size_extension;
|
||||
se.bit_rate_extension = bit_rate_extension;
|
||||
se.vbv_buffer_size_extension = vbv_buffer_size_extension;
|
||||
se.low_delay = low_delay;
|
||||
se.frame_rate_extension_n = frame_rate_extension_n;
|
||||
se.frame_rate_extension_d = frame_rate_extension_d;
|
||||
return se;
|
||||
}
|
||||
|
||||
public static SequenceExtension read(BitReader _in) {
|
||||
SequenceExtension se = new SequenceExtension();
|
||||
se.profile_and_level = _in.readNBit(8);
|
||||
se.progressive_sequence = _in.read1Bit();
|
||||
se.chroma_format = _in.readNBit(2);
|
||||
se.horizontal_size_extension = _in.readNBit(2);
|
||||
se.vertical_size_extension = _in.readNBit(2);
|
||||
se.bit_rate_extension = _in.readNBit(12);
|
||||
se.vbv_buffer_size_extension = _in.readNBit(8);
|
||||
se.low_delay = _in.read1Bit();
|
||||
se.frame_rate_extension_n = _in.readNBit(2);
|
||||
se.frame_rate_extension_d = _in.readNBit(5);
|
||||
return se;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(1, 4);
|
||||
bw.writeNBit(this.profile_and_level, 8);
|
||||
bw.write1Bit(this.progressive_sequence);
|
||||
bw.writeNBit(this.chroma_format, 2);
|
||||
bw.writeNBit(this.horizontal_size_extension, 2);
|
||||
bw.writeNBit(this.vertical_size_extension, 2);
|
||||
bw.writeNBit(this.bit_rate_extension, 12);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.vbv_buffer_size_extension, 8);
|
||||
bw.write1Bit(this.low_delay);
|
||||
bw.writeNBit(this.frame_rate_extension_n, 2);
|
||||
bw.writeNBit(this.frame_rate_extension_d, 5);
|
||||
bw.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
|
||||
public class SequenceHeader implements MPEGHeader {
|
||||
private static boolean _hasExtensions;
|
||||
|
||||
public int horizontal_size;
|
||||
|
||||
public int vertical_size;
|
||||
|
||||
public int aspect_ratio_information;
|
||||
|
||||
public int frame_rate_code;
|
||||
|
||||
public int bit_rate;
|
||||
|
||||
public int vbv_buffer_size_value;
|
||||
|
||||
public int constrained_parameters_flag;
|
||||
|
||||
public int[] intra_quantiser_matrix;
|
||||
|
||||
public int[] non_intra_quantiser_matrix;
|
||||
|
||||
public SequenceExtension sequenceExtension;
|
||||
|
||||
public SequenceScalableExtension sequenceScalableExtension;
|
||||
|
||||
public SequenceDisplayExtension sequenceDisplayExtension;
|
||||
|
||||
public static SequenceHeader createSequenceHeader(int horizontal_size, int vertical_size, int aspect_ratio_information, int frame_rate_code, int bit_rate, int vbv_buffer_size_value, int constrained_parameters_flag, int[] intra_quantiser_matrix, int[] non_intra_quantiser_matrix) {
|
||||
SequenceHeader sh = new SequenceHeader();
|
||||
sh.horizontal_size = horizontal_size;
|
||||
sh.vertical_size = vertical_size;
|
||||
sh.aspect_ratio_information = aspect_ratio_information;
|
||||
sh.frame_rate_code = frame_rate_code;
|
||||
sh.bit_rate = bit_rate;
|
||||
sh.vbv_buffer_size_value = vbv_buffer_size_value;
|
||||
sh.constrained_parameters_flag = constrained_parameters_flag;
|
||||
sh.intra_quantiser_matrix = intra_quantiser_matrix;
|
||||
sh.non_intra_quantiser_matrix = non_intra_quantiser_matrix;
|
||||
return sh;
|
||||
}
|
||||
|
||||
public static SequenceHeader read(ByteBuffer bb) {
|
||||
BitReader _in = BitReader.createBitReader(bb);
|
||||
SequenceHeader sh = new SequenceHeader();
|
||||
sh.horizontal_size = _in.readNBit(12);
|
||||
sh.vertical_size = _in.readNBit(12);
|
||||
sh.aspect_ratio_information = _in.readNBit(4);
|
||||
sh.frame_rate_code = _in.readNBit(4);
|
||||
sh.bit_rate = _in.readNBit(18);
|
||||
_in.read1Bit();
|
||||
sh.vbv_buffer_size_value = _in.readNBit(10);
|
||||
sh.constrained_parameters_flag = _in.read1Bit();
|
||||
if (_in.read1Bit() != 0) {
|
||||
sh.intra_quantiser_matrix = new int[64];
|
||||
for (int i = 0; i < 64; i++)
|
||||
sh.intra_quantiser_matrix[i] = _in.readNBit(8);
|
||||
}
|
||||
if (_in.read1Bit() != 0) {
|
||||
sh.non_intra_quantiser_matrix = new int[64];
|
||||
for (int i = 0; i < 64; i++)
|
||||
sh.non_intra_quantiser_matrix[i] = _in.readNBit(8);
|
||||
}
|
||||
return sh;
|
||||
}
|
||||
|
||||
public static void readExtension(ByteBuffer bb, SequenceHeader sh) {
|
||||
_hasExtensions = true;
|
||||
BitReader _in = BitReader.createBitReader(bb);
|
||||
int extType = _in.readNBit(4);
|
||||
switch (extType) {
|
||||
case 1:
|
||||
sh.sequenceExtension = SequenceExtension.read(_in);
|
||||
break;
|
||||
case 5:
|
||||
sh.sequenceScalableExtension = SequenceScalableExtension.read(_in);
|
||||
break;
|
||||
case 2:
|
||||
sh.sequenceDisplayExtension = SequenceDisplayExtension.read(_in);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unsupported extension: " + extType);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(this.horizontal_size, 12);
|
||||
bw.writeNBit(this.vertical_size, 12);
|
||||
bw.writeNBit(this.aspect_ratio_information, 4);
|
||||
bw.writeNBit(this.frame_rate_code, 4);
|
||||
bw.writeNBit(this.bit_rate, 18);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.vbv_buffer_size_value, 10);
|
||||
bw.write1Bit(this.constrained_parameters_flag);
|
||||
bw.write1Bit((this.intra_quantiser_matrix != null) ? 1 : 0);
|
||||
if (this.intra_quantiser_matrix != null)
|
||||
for (int i = 0; i < 64; i++)
|
||||
bw.writeNBit(this.intra_quantiser_matrix[i], 8);
|
||||
bw.write1Bit((this.non_intra_quantiser_matrix != null) ? 1 : 0);
|
||||
if (this.non_intra_quantiser_matrix != null)
|
||||
for (int i = 0; i < 64; i++)
|
||||
bw.writeNBit(this.non_intra_quantiser_matrix[i], 8);
|
||||
bw.flush();
|
||||
writeExtensions(bb);
|
||||
}
|
||||
|
||||
private void writeExtensions(ByteBuffer out) {
|
||||
if (this.sequenceExtension != null) {
|
||||
out.putInt(181);
|
||||
this.sequenceExtension.write(out);
|
||||
}
|
||||
if (this.sequenceScalableExtension != null) {
|
||||
out.putInt(181);
|
||||
this.sequenceScalableExtension.write(out);
|
||||
}
|
||||
if (this.sequenceDisplayExtension != null) {
|
||||
out.putInt(181);
|
||||
this.sequenceDisplayExtension.write(out);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasExtensions() {
|
||||
return _hasExtensions;
|
||||
}
|
||||
|
||||
public void copyExtensions(SequenceHeader sh) {
|
||||
this.sequenceExtension = sh.sequenceExtension;
|
||||
this.sequenceScalableExtension = sh.sequenceScalableExtension;
|
||||
this.sequenceDisplayExtension = sh.sequenceDisplayExtension;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package org.jcodec.codecs.mpeg12.bitstream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.codecs.mpeg12.MPEGConst;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.io.BitWriter;
|
||||
import org.jcodec.common.io.VLC;
|
||||
|
||||
public class SequenceScalableExtension implements MPEGHeader {
|
||||
public static final int DATA_PARTITIONING = 0;
|
||||
|
||||
public static final int SPATIAL_SCALABILITY = 1;
|
||||
|
||||
public static final int SNR_SCALABILITY = 2;
|
||||
|
||||
public static final int TEMPORAL_SCALABILITY = 3;
|
||||
|
||||
public int scalable_mode;
|
||||
|
||||
public int layer_id;
|
||||
|
||||
public int lower_layer_prediction_horizontal_size;
|
||||
|
||||
public int lower_layer_prediction_vertical_size;
|
||||
|
||||
public int horizontal_subsampling_factor_m;
|
||||
|
||||
public int horizontal_subsampling_factor_n;
|
||||
|
||||
public int vertical_subsampling_factor_m;
|
||||
|
||||
public int vertical_subsampling_factor_n;
|
||||
|
||||
public int picture_mux_enable;
|
||||
|
||||
public int mux_to_progressive_sequence;
|
||||
|
||||
public int picture_mux_order;
|
||||
|
||||
public int picture_mux_factor;
|
||||
|
||||
public static final int Sequence_Scalable_Extension = 5;
|
||||
|
||||
public static SequenceScalableExtension read(BitReader _in) {
|
||||
SequenceScalableExtension sse = new SequenceScalableExtension();
|
||||
sse.scalable_mode = _in.readNBit(2);
|
||||
sse.layer_id = _in.readNBit(4);
|
||||
if (sse.scalable_mode == 1) {
|
||||
sse.lower_layer_prediction_horizontal_size = _in.readNBit(14);
|
||||
_in.read1Bit();
|
||||
sse.lower_layer_prediction_vertical_size = _in.readNBit(14);
|
||||
sse.horizontal_subsampling_factor_m = _in.readNBit(5);
|
||||
sse.horizontal_subsampling_factor_n = _in.readNBit(5);
|
||||
sse.vertical_subsampling_factor_m = _in.readNBit(5);
|
||||
sse.vertical_subsampling_factor_n = _in.readNBit(5);
|
||||
}
|
||||
if (sse.scalable_mode == 3) {
|
||||
sse.picture_mux_enable = _in.read1Bit();
|
||||
if (sse.picture_mux_enable != 0)
|
||||
sse.mux_to_progressive_sequence = _in.read1Bit();
|
||||
sse.picture_mux_order = _in.readNBit(3);
|
||||
sse.picture_mux_factor = _in.readNBit(3);
|
||||
}
|
||||
return sse;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer bb) {
|
||||
BitWriter bw = new BitWriter(bb);
|
||||
bw.writeNBit(5, 4);
|
||||
bw.writeNBit(this.scalable_mode, 2);
|
||||
bw.writeNBit(this.layer_id, 4);
|
||||
if (this.scalable_mode == 1) {
|
||||
bw.writeNBit(this.lower_layer_prediction_horizontal_size, 14);
|
||||
bw.write1Bit(1);
|
||||
bw.writeNBit(this.lower_layer_prediction_vertical_size, 14);
|
||||
bw.writeNBit(this.horizontal_subsampling_factor_m, 5);
|
||||
bw.writeNBit(this.horizontal_subsampling_factor_n, 5);
|
||||
bw.writeNBit(this.vertical_subsampling_factor_m, 5);
|
||||
bw.writeNBit(this.vertical_subsampling_factor_n, 5);
|
||||
}
|
||||
if (this.scalable_mode == 3) {
|
||||
bw.write1Bit(this.picture_mux_enable);
|
||||
if (this.picture_mux_enable != 0)
|
||||
bw.write1Bit(this.mux_to_progressive_sequence);
|
||||
bw.writeNBit(this.picture_mux_order, 3);
|
||||
bw.writeNBit(this.picture_mux_factor, 3);
|
||||
}
|
||||
bw.flush();
|
||||
}
|
||||
|
||||
public static MPEGConst.MBType[] mbTypeVal(int picture_coding_type, SequenceScalableExtension sse) {
|
||||
if (sse != null && sse.scalable_mode == 2)
|
||||
return MPEGConst.mbTypeValSNR;
|
||||
if (sse != null && sse.scalable_mode == 1)
|
||||
return (picture_coding_type == 1) ? MPEGConst.mbTypeValISpat : (
|
||||
(picture_coding_type == 2) ? MPEGConst.mbTypeValPSpat : MPEGConst.mbTypeValBSpat);
|
||||
return (picture_coding_type == 1) ? MPEGConst.mbTypeValI : (
|
||||
(picture_coding_type == 2) ? MPEGConst.mbTypeValP : MPEGConst.mbTypeValB);
|
||||
}
|
||||
|
||||
public static VLC vlcMBType(int picture_coding_type, SequenceScalableExtension sse) {
|
||||
if (sse != null && sse.scalable_mode == 2)
|
||||
return MPEGConst.vlcMBTypeSNR;
|
||||
if (sse != null && sse.scalable_mode == 1)
|
||||
return (picture_coding_type == 1) ? MPEGConst.vlcMBTypeISpat : (
|
||||
(picture_coding_type == 2) ? MPEGConst.vlcMBTypePSpat : MPEGConst.vlcMBTypeBSpat);
|
||||
return (picture_coding_type == 1) ? MPEGConst.vlcMBTypeI : (
|
||||
(picture_coding_type == 2) ? MPEGConst.vlcMBTypeP : MPEGConst.vlcMBTypeB);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue