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,92 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
import org.jcodec.common.model.Picture;
|
||||
|
||||
public class MPEG4BiRenderer {
|
||||
public static void renderBi(MPEG4DecodingContext ctx, Picture[] refs, int fcodeForward, int fcodeBackward, Macroblock mb) {
|
||||
switch (mb.mode) {
|
||||
case 0:
|
||||
case 4:
|
||||
renderBiDir(ctx, refs, mb, true);
|
||||
break;
|
||||
case 1:
|
||||
renderBiDir(ctx, refs, mb, false);
|
||||
break;
|
||||
case 2:
|
||||
MPEG4Renderer.renderInter(ctx, refs, mb, fcodeBackward, 0, true);
|
||||
break;
|
||||
case 3:
|
||||
MPEG4Renderer.renderInter(ctx, refs, mb, fcodeForward, 1, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderBiDir(MPEG4DecodingContext ctx, Picture[] refs, Macroblock mb, boolean direct) {
|
||||
int cbp = mb.cbp;
|
||||
MPEG4Renderer.validateVector(mb.mvs, ctx, mb.x, mb.y);
|
||||
MPEG4Renderer.validateVector(mb.bmvs, ctx, mb.x, mb.y);
|
||||
renderOneDir(ctx, mb, direct, refs[1], mb.mvs, 0);
|
||||
renderOneDir(ctx, mb, direct, refs[0], mb.bmvs, 3);
|
||||
mergePred(mb);
|
||||
if (cbp != 0)
|
||||
for (int i = 0; i < 6; i++) {
|
||||
short[] block = mb.block[i];
|
||||
if ((mb.cbp & 1 << 5 - i) != 0)
|
||||
MPEG4DCT.idctAdd(mb.pred, block, i, (ctx.interlacing && mb.fieldDCT));
|
||||
}
|
||||
}
|
||||
|
||||
private static void mergePred(Macroblock mb) {
|
||||
for (int i = 0; i < 256; i++)
|
||||
mb.pred[0][i] = (byte)(mb.pred[0][i] + mb.pred[3][i] + 1 >> 1);
|
||||
for (int pl = 1; pl < 3; pl++) {
|
||||
for (int j = 0; j < 64; j++)
|
||||
mb.pred[pl][j] = (byte)(mb.pred[pl][j] + mb.pred[pl + 3][j] + 1 >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderOneDir(MPEG4DecodingContext ctx, Macroblock mb, boolean direct, Picture forward, Macroblock.Vector[] mvs, int pred) {
|
||||
int mx_chr, my_chr;
|
||||
int mbX = 16 * mb.x;
|
||||
int mbY = 16 * mb.y;
|
||||
int codedW = ctx.mbWidth << 4;
|
||||
int codedH = ctx.mbHeight << 4;
|
||||
int codedWcr = ctx.mbWidth << 3;
|
||||
int codedHcr = ctx.mbHeight << 3;
|
||||
if (ctx.quarterPel) {
|
||||
if (!direct) {
|
||||
MPEG4Interpolator.interpolate16x16QP(mb.pred[pred], forward.getPlaneData(0), mbX, mbY, codedW, codedH, (mvs[0]).x, (mvs[0]).y,
|
||||
forward.getWidth(), false);
|
||||
} else {
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[pred], 0, forward.getPlaneData(0), mbX, mbY, codedW, codedH, (mvs[0]).x, (mvs[0]).y,
|
||||
forward.getWidth(), false);
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[pred], 8, forward.getPlaneData(0), mbX + 8, mbY, codedW, codedH, (mvs[1]).x, (mvs[1]).y,
|
||||
forward.getWidth(), false);
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[pred], 128, forward.getPlaneData(0), mbX, mbY + 8, codedW, codedH, (mvs[2]).x, (mvs[2]).y,
|
||||
forward.getWidth(), false);
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[pred], 136, forward.getPlaneData(0), mbX + 8, mbY + 8, codedW, codedH, (mvs[3]).x, (mvs[3]).y,
|
||||
forward.getWidth(), false);
|
||||
}
|
||||
} else {
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[pred], 0, 16, forward.getPlaneData(0), mbX, mbY, codedW, codedH, (mvs[0]).x, (mvs[0]).y,
|
||||
forward.getWidth(), false);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[pred], 8, 16, forward.getPlaneData(0), mbX + 8, mbY, codedW, codedH, (mvs[1]).x, (mvs[1]).y,
|
||||
forward.getWidth(), false);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[pred], 128, 16, forward.getPlaneData(0), mbX, mbY + 8, codedW, codedH, (mvs[2]).x, (mvs[2]).y,
|
||||
forward.getWidth(), false);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[pred], 136, 16, forward.getPlaneData(0), mbX + 8, mbY + 8, codedW, codedH, (mvs[3]).x, (mvs[3]).y,
|
||||
forward.getWidth(), false);
|
||||
}
|
||||
if (!direct) {
|
||||
mx_chr = MPEG4Renderer.calcChromaMv(ctx, (mvs[0]).x);
|
||||
my_chr = MPEG4Renderer.calcChromaMv(ctx, (mvs[0]).y);
|
||||
} else {
|
||||
mx_chr = MPEG4Renderer.calcChromaMvAvg(ctx, mvs, true);
|
||||
my_chr = MPEG4Renderer.calcChromaMvAvg(ctx, mvs, false);
|
||||
}
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[pred + 1], 0, 8, forward.getPlaneData(1), 8 * mb.x, 8 * mb.y, codedWcr, codedHcr, mx_chr, my_chr,
|
||||
forward.getPlaneWidth(1), false);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[pred + 2], 0, 8, forward.getPlaneData(2), 8 * mb.x, 8 * mb.y, codedWcr, codedHcr, mx_chr, my_chr,
|
||||
forward.getPlaneWidth(2), false);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,257 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
public class MPEG4Consts {
|
||||
static final Macroblock.Vector ZERO_MV = Macroblock.vec();
|
||||
|
||||
static final int BS_VERSION_BUGGY_DC_CLIP = 34;
|
||||
|
||||
static final int MODE_INTER = 0;
|
||||
|
||||
static final int MODE_INTER_Q = 1;
|
||||
|
||||
static final int MODE_INTER4V = 2;
|
||||
|
||||
static final int MODE_INTRA = 3;
|
||||
|
||||
static final int MODE_INTRA_Q = 4;
|
||||
|
||||
static final int MODE_NOT_CODED = 16;
|
||||
|
||||
static final int MODE_NOT_CODED_GMC = 17;
|
||||
|
||||
static final int MODE_DIRECT = 0;
|
||||
|
||||
static final int MODE_INTERPOLATE = 1;
|
||||
|
||||
static final int MODE_BACKWARD = 2;
|
||||
|
||||
static final int MODE_FORWARD = 3;
|
||||
|
||||
static final int MODE_DIRECT_NONE_MV = 4;
|
||||
|
||||
static final int MODE_DIRECT_NO4V = 5;
|
||||
|
||||
static final int[] ROUNDTAB_76 = new int[] {
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 1 };
|
||||
|
||||
static final int[] ROUNDTAB_79 = new int[] { 0, 1, 0, 0 };
|
||||
|
||||
static final int ALT_CHROMA_ROUNDING = 1;
|
||||
|
||||
static final int[] INTRA_DC_THRESHOLD_TABLE = new int[] { 32, 13, 15, 17, 19, 21, 23, 1 };
|
||||
|
||||
static final short[] DEFAULT_INTRA_MATRIX = new short[] {
|
||||
8, 17, 18, 19, 21, 23, 25, 27, 17, 18,
|
||||
19, 21, 23, 25, 27, 28, 20, 21, 22, 23,
|
||||
24, 26, 28, 30, 21, 22, 23, 24, 26, 28,
|
||||
30, 32, 22, 23, 24, 26, 28, 30, 32, 35,
|
||||
23, 24, 26, 28, 30, 32, 35, 38, 25, 26,
|
||||
28, 30, 32, 35, 38, 41, 27, 28, 30, 32,
|
||||
35, 38, 41, 45 };
|
||||
|
||||
static final short[] DEFAULT_INTER_MATRIX = new short[] {
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 18, 19, 20, 21,
|
||||
22, 23, 24, 25, 19, 20, 21, 22, 23, 24,
|
||||
26, 27, 20, 21, 22, 23, 25, 26, 27, 28,
|
||||
21, 22, 23, 24, 26, 27, 28, 30, 22, 23,
|
||||
24, 26, 27, 28, 30, 31, 23, 24, 25, 27,
|
||||
28, 30, 31, 33 };
|
||||
|
||||
static final int[][] MCBPC_INTRA_TABLE = new int[][] {
|
||||
new int[] { -1, 0 }, new int[] { 20, 6 }, new int[] { 36, 6 }, new int[] { 52, 6 }, new int[] { 4, 4 }, new int[] { 4, 4 }, new int[] { 4, 4 }, new int[] { 4, 4 }, new int[] { 19, 3 }, new int[] { 19, 3 },
|
||||
new int[] { 19, 3 }, new int[] { 19, 3 }, new int[] { 19, 3 }, new int[] { 19, 3 }, new int[] { 19, 3 }, new int[] { 19, 3 }, new int[] { 35, 3 }, new int[] { 35, 3 }, new int[] { 35, 3 }, new int[] { 35, 3 },
|
||||
new int[] { 35, 3 }, new int[] { 35, 3 }, new int[] { 35, 3 }, new int[] { 35, 3 }, new int[] { 51, 3 }, new int[] { 51, 3 }, new int[] { 51, 3 }, new int[] { 51, 3 }, new int[] { 51, 3 }, new int[] { 51, 3 },
|
||||
new int[] { 51, 3 }, new int[] { 51, 3 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 },
|
||||
new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 },
|
||||
new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 },
|
||||
new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 }, new int[] { 3, 1 } };
|
||||
|
||||
static final int[][] MCBPC_INTER_TABLE = new int[][] {
|
||||
new int[] { -1, 0 }, new int[] { 255, 9 }, new int[] { 52, 9 }, new int[] { 36, 9 }, new int[] { 20, 9 }, new int[] { 49, 9 }, new int[] { 35, 8 }, new int[] { 35, 8 }, new int[] { 19, 8 }, new int[] { 19, 8 },
|
||||
new int[] { 50, 8 }, new int[] { 50, 8 }, new int[] { 51, 7 }, new int[] { 51, 7 }, new int[] { 51, 7 }, new int[] { 51, 7 }, new int[] { 34, 7 }, new int[] { 34, 7 }, new int[] { 34, 7 }, new int[] { 34, 7 },
|
||||
new int[] { 18, 7 }, new int[] { 18, 7 }, new int[] { 18, 7 }, new int[] { 18, 7 }, new int[] { 33, 7 }, new int[] { 33, 7 }, new int[] { 33, 7 }, new int[] { 33, 7 }, new int[] { 17, 7 }, new int[] { 17, 7 },
|
||||
new int[] { 17, 7 }, new int[] { 17, 7 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 },
|
||||
new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 48, 6 }, new int[] { 3, 5 }, new int[] { 3, 5 },
|
||||
new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 },
|
||||
new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 3, 5 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 },
|
||||
new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 },
|
||||
new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 },
|
||||
new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 32, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 },
|
||||
new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 },
|
||||
new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 },
|
||||
new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 16, 4 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 2, 3 },
|
||||
new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 },
|
||||
new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 },
|
||||
new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 },
|
||||
new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 },
|
||||
new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 },
|
||||
new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 },
|
||||
new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 1, 3 }, new int[] { 0, 1 } };
|
||||
|
||||
static final int[][] CBPY_TABLE = new int[][] {
|
||||
new int[] { -1, 0 }, new int[] { -1, 0 }, new int[] { 6, 6 }, new int[] { 9, 6 }, new int[] { 8, 5 }, new int[] { 8, 5 }, new int[] { 4, 5 }, new int[] { 4, 5 }, new int[] { 2, 5 }, new int[] { 2, 5 },
|
||||
new int[] { 1, 5 }, new int[] { 1, 5 }, new int[] { 0, 4 }, new int[] { 0, 4 }, new int[] { 0, 4 }, new int[] { 0, 4 }, new int[] { 12, 4 }, new int[] { 12, 4 }, new int[] { 12, 4 }, new int[] { 12, 4 },
|
||||
new int[] { 10, 4 }, new int[] { 10, 4 }, new int[] { 10, 4 }, new int[] { 10, 4 }, new int[] { 14, 4 }, new int[] { 14, 4 }, new int[] { 14, 4 }, new int[] { 14, 4 }, new int[] { 5, 4 }, new int[] { 5, 4 },
|
||||
new int[] { 5, 4 }, new int[] { 5, 4 }, new int[] { 13, 4 }, new int[] { 13, 4 }, new int[] { 13, 4 }, new int[] { 13, 4 }, new int[] { 3, 4 }, new int[] { 3, 4 }, new int[] { 3, 4 }, new int[] { 3, 4 },
|
||||
new int[] { 11, 4 }, new int[] { 11, 4 }, new int[] { 11, 4 }, new int[] { 11, 4 }, new int[] { 7, 4 }, new int[] { 7, 4 }, new int[] { 7, 4 }, new int[] { 7, 4 }, new int[] { 15, 2 }, new int[] { 15, 2 },
|
||||
new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 },
|
||||
new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 }, new int[] { 15, 2 } };
|
||||
|
||||
static final int[][] TMNMV_TAB_0 = new int[][] {
|
||||
new int[] { 3, 4 }, new int[] { -3, 4 }, new int[] { 2, 3 }, new int[] { 2, 3 }, new int[] { -2, 3 }, new int[] { -2, 3 }, new int[] { 1, 2 }, new int[] { 1, 2 }, new int[] { 1, 2 }, new int[] { 1, 2 },
|
||||
new int[] { -1, 2 }, new int[] { -1, 2 }, new int[] { -1, 2 }, new int[] { -1, 2 } };
|
||||
|
||||
static final int[][] TMNMV_TAB_1 = new int[][] {
|
||||
new int[] { 12, 10 }, new int[] { -12, 10 }, new int[] { 11, 10 }, new int[] { -11, 10 }, new int[] { 10, 9 }, new int[] { 10, 9 }, new int[] { -10, 9 }, new int[] { -10, 9 }, new int[] { 9, 9 }, new int[] { 9, 9 },
|
||||
new int[] { -9, 9 }, new int[] { -9, 9 }, new int[] { 8, 9 }, new int[] { 8, 9 }, new int[] { -8, 9 }, new int[] { -8, 9 }, new int[] { 7, 7 }, new int[] { 7, 7 }, new int[] { 7, 7 }, new int[] { 7, 7 },
|
||||
new int[] { 7, 7 }, new int[] { 7, 7 }, new int[] { 7, 7 }, new int[] { 7, 7 }, new int[] { -7, 7 }, new int[] { -7, 7 }, new int[] { -7, 7 }, new int[] { -7, 7 }, new int[] { -7, 7 }, new int[] { -7, 7 },
|
||||
new int[] { -7, 7 }, new int[] { -7, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 }, new int[] { 6, 7 },
|
||||
new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { -6, 7 }, new int[] { 5, 7 }, new int[] { 5, 7 },
|
||||
new int[] { 5, 7 }, new int[] { 5, 7 }, new int[] { 5, 7 }, new int[] { 5, 7 }, new int[] { 5, 7 }, new int[] { 5, 7 }, new int[] { -5, 7 }, new int[] { -5, 7 }, new int[] { -5, 7 }, new int[] { -5, 7 },
|
||||
new int[] { -5, 7 }, new int[] { -5, 7 }, new int[] { -5, 7 }, new int[] { -5, 7 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 },
|
||||
new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 }, new int[] { 4, 6 },
|
||||
new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 },
|
||||
new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 }, new int[] { -4, 6 } };
|
||||
|
||||
static final int[][] TMNMV_TAB_2 = new int[][] {
|
||||
new int[] { 32, 12 }, new int[] { -32, 12 }, new int[] { 31, 12 }, new int[] { -31, 12 }, new int[] { 30, 11 }, new int[] { 30, 11 }, new int[] { -30, 11 }, new int[] { -30, 11 }, new int[] { 29, 11 }, new int[] { 29, 11 },
|
||||
new int[] { -29, 11 }, new int[] { -29, 11 }, new int[] { 28, 11 }, new int[] { 28, 11 }, new int[] { -28, 11 }, new int[] { -28, 11 }, new int[] { 27, 11 }, new int[] { 27, 11 }, new int[] { -27, 11 }, new int[] { -27, 11 },
|
||||
new int[] { 26, 11 }, new int[] { 26, 11 }, new int[] { -26, 11 }, new int[] { -26, 11 }, new int[] { 25, 11 }, new int[] { 25, 11 }, new int[] { -25, 11 }, new int[] { -25, 11 }, new int[] { 24, 10 }, new int[] { 24, 10 },
|
||||
new int[] { 24, 10 }, new int[] { 24, 10 }, new int[] { -24, 10 }, new int[] { -24, 10 }, new int[] { -24, 10 }, new int[] { -24, 10 }, new int[] { 23, 10 }, new int[] { 23, 10 }, new int[] { 23, 10 }, new int[] { 23, 10 },
|
||||
new int[] { -23, 10 }, new int[] { -23, 10 }, new int[] { -23, 10 }, new int[] { -23, 10 }, new int[] { 22, 10 }, new int[] { 22, 10 }, new int[] { 22, 10 }, new int[] { 22, 10 }, new int[] { -22, 10 }, new int[] { -22, 10 },
|
||||
new int[] { -22, 10 }, new int[] { -22, 10 }, new int[] { 21, 10 }, new int[] { 21, 10 }, new int[] { 21, 10 }, new int[] { 21, 10 }, new int[] { -21, 10 }, new int[] { -21, 10 }, new int[] { -21, 10 }, new int[] { -21, 10 },
|
||||
new int[] { 20, 10 }, new int[] { 20, 10 }, new int[] { 20, 10 }, new int[] { 20, 10 }, new int[] { -20, 10 }, new int[] { -20, 10 }, new int[] { -20, 10 }, new int[] { -20, 10 }, new int[] { 19, 10 }, new int[] { 19, 10 },
|
||||
new int[] { 19, 10 }, new int[] { 19, 10 }, new int[] { -19, 10 }, new int[] { -19, 10 }, new int[] { -19, 10 }, new int[] { -19, 10 }, new int[] { 18, 10 }, new int[] { 18, 10 }, new int[] { 18, 10 }, new int[] { 18, 10 },
|
||||
new int[] { -18, 10 }, new int[] { -18, 10 }, new int[] { -18, 10 }, new int[] { -18, 10 }, new int[] { 17, 10 }, new int[] { 17, 10 }, new int[] { 17, 10 }, new int[] { 17, 10 }, new int[] { -17, 10 }, new int[] { -17, 10 },
|
||||
new int[] { -17, 10 }, new int[] { -17, 10 }, new int[] { 16, 10 }, new int[] { 16, 10 }, new int[] { 16, 10 }, new int[] { 16, 10 }, new int[] { -16, 10 }, new int[] { -16, 10 }, new int[] { -16, 10 }, new int[] { -16, 10 },
|
||||
new int[] { 15, 10 }, new int[] { 15, 10 }, new int[] { 15, 10 }, new int[] { 15, 10 }, new int[] { -15, 10 }, new int[] { -15, 10 }, new int[] { -15, 10 }, new int[] { -15, 10 }, new int[] { 14, 10 }, new int[] { 14, 10 },
|
||||
new int[] { 14, 10 }, new int[] { 14, 10 }, new int[] { -14, 10 }, new int[] { -14, 10 }, new int[] { -14, 10 }, new int[] { -14, 10 }, new int[] { 13, 10 }, new int[] { 13, 10 }, new int[] { 13, 10 }, new int[] { 13, 10 },
|
||||
new int[] { -13, 10 }, new int[] { -13, 10 }, new int[] { -13, 10 }, new int[] { -13, 10 } };
|
||||
|
||||
static final byte[][][] MAX_LEVEL = new byte[][][] { new byte[][] { new byte[] {
|
||||
12, 6, 4, 3, 3, 3, 3, 2, 2, 2,
|
||||
2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 }, new byte[] {
|
||||
3, 2, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 } }, new byte[][] { new byte[] {
|
||||
27, 10, 5, 4, 3, 3, 3, 3, 2, 2,
|
||||
1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 }, new byte[] {
|
||||
8, 3, 2, 2, 2, 2, 2, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 } } };
|
||||
|
||||
static final byte[][][] MAX_RUN = new byte[][][] { new byte[][] { new byte[] {
|
||||
0, 26, 10, 6, 2, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 }, new byte[] {
|
||||
0, 40, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 } }, new byte[][] { new byte[] {
|
||||
0, 14, 9, 7, 3, 2, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 }, new byte[] {
|
||||
0, 20, 6, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0 } } };
|
||||
|
||||
static final int[][][] COEFF_TAB = new int[][][] { new int[][] {
|
||||
new int[] { 2, 2, 0, 0, 1 }, new int[] { 15, 4, 0, 0, 2 }, new int[] { 21, 6, 0, 0, 3 }, new int[] { 23, 7, 0, 0, 4 }, new int[] { 31, 8, 0, 0, 5 }, new int[] { 37, 9, 0, 0, 6 }, new int[] { 36, 9, 0, 0, 7 }, new int[] { 33, 10, 0, 0, 8 }, new int[] { 32, 10, 0, 0, 9 }, new int[] { 7, 11, 0, 0, 10 },
|
||||
new int[] { 6, 11, 0, 0, 11 }, new int[] { 32, 11, 0, 0, 12 }, new int[] { 6, 3, 0, 1, 1 }, new int[] { 20, 6, 0, 1, 2 }, new int[] { 30, 8, 0, 1, 3 }, new int[] { 15, 10, 0, 1, 4 }, new int[] { 33, 11, 0, 1, 5 }, new int[] { 80, 12, 0, 1, 6 }, new int[] { 14, 4, 0, 2, 1 }, new int[] { 29, 8, 0, 2, 2 },
|
||||
new int[] { 14, 10, 0, 2, 3 }, new int[] { 81, 12, 0, 2, 4 }, new int[] { 13, 5, 0, 3, 1 }, new int[] { 35, 9, 0, 3, 2 }, new int[] { 13, 10, 0, 3, 3 }, new int[] { 12, 5, 0, 4, 1 }, new int[] { 34, 9, 0, 4, 2 }, new int[] { 82, 12, 0, 4, 3 }, new int[] { 11, 5, 0, 5, 1 }, new int[] { 12, 10, 0, 5, 2 },
|
||||
new int[] { 83, 12, 0, 5, 3 }, new int[] { 19, 6, 0, 6, 1 }, new int[] { 11, 10, 0, 6, 2 }, new int[] { 84, 12, 0, 6, 3 }, new int[] { 18, 6, 0, 7, 1 }, new int[] { 10, 10, 0, 7, 2 }, new int[] { 17, 6, 0, 8, 1 }, new int[] { 9, 10, 0, 8, 2 }, new int[] { 16, 6, 0, 9, 1 }, new int[] { 8, 10, 0, 9, 2 },
|
||||
new int[] { 22, 7, 0, 10, 1 }, new int[] { 85, 12, 0, 10, 2 }, new int[] { 21, 7, 0, 11, 1 }, new int[] { 20, 7, 0, 12, 1 }, new int[] { 28, 8, 0, 13, 1 }, new int[] { 27, 8, 0, 14, 1 }, new int[] { 33, 9, 0, 15, 1 }, new int[] { 32, 9, 0, 16, 1 }, new int[] { 31, 9, 0, 17, 1 }, new int[] { 30, 9, 0, 18, 1 },
|
||||
new int[] { 29, 9, 0, 19, 1 }, new int[] { 28, 9, 0, 20, 1 }, new int[] { 27, 9, 0, 21, 1 }, new int[] { 26, 9, 0, 22, 1 }, new int[] { 34, 11, 0, 23, 1 }, new int[] { 35, 11, 0, 24, 1 }, new int[] { 86, 12, 0, 25, 1 }, new int[] { 87, 12, 0, 26, 1 }, new int[] { 7, 4, 1, 0, 1 }, new int[] { 25, 9, 1, 0, 2 },
|
||||
new int[] { 5, 11, 1, 0, 3 }, new int[] { 15, 6, 1, 1, 1 }, new int[] { 4, 11, 1, 1, 2 }, new int[] { 14, 6, 1, 2, 1 }, new int[] { 13, 6, 1, 3, 1 }, new int[] { 12, 6, 1, 4, 1 }, new int[] { 19, 7, 1, 5, 1 }, new int[] { 18, 7, 1, 6, 1 }, new int[] { 17, 7, 1, 7, 1 }, new int[] { 16, 7, 1, 8, 1 },
|
||||
new int[] { 26, 8, 1, 9, 1 }, new int[] { 25, 8, 1, 10, 1 }, new int[] { 24, 8, 1, 11, 1 }, new int[] { 23, 8, 1, 12, 1 }, new int[] { 22, 8, 1, 13, 1 }, new int[] { 21, 8, 1, 14, 1 }, new int[] { 20, 8, 1, 15, 1 }, new int[] { 19, 8, 1, 16, 1 }, new int[] { 24, 9, 1, 17, 1 }, new int[] { 23, 9, 1, 18, 1 },
|
||||
new int[] { 22, 9, 1, 19, 1 }, new int[] { 21, 9, 1, 20, 1 }, new int[] { 20, 9, 1, 21, 1 }, new int[] { 19, 9, 1, 22, 1 }, new int[] { 18, 9, 1, 23, 1 }, new int[] { 17, 9, 1, 24, 1 }, new int[] { 7, 10, 1, 25, 1 }, new int[] { 6, 10, 1, 26, 1 }, new int[] { 5, 10, 1, 27, 1 }, new int[] { 4, 10, 1, 28, 1 },
|
||||
new int[] { 36, 11, 1, 29, 1 }, new int[] { 37, 11, 1, 30, 1 }, new int[] { 38, 11, 1, 31, 1 }, new int[] { 39, 11, 1, 32, 1 }, new int[] { 88, 12, 1, 33, 1 }, new int[] { 89, 12, 1, 34, 1 }, new int[] { 90, 12, 1, 35, 1 }, new int[] { 91, 12, 1, 36, 1 }, new int[] { 92, 12, 1, 37, 1 }, new int[] { 93, 12, 1, 38, 1 },
|
||||
new int[] { 94, 12, 1, 39, 1 }, new int[] { 95, 12, 1, 40, 1 } }, new int[][] {
|
||||
new int[] { 2, 2, 0, 0, 1 }, new int[] { 15, 4, 0, 0, 3 }, new int[] { 21, 6, 0, 0, 6 }, new int[] { 23, 7, 0, 0, 9 }, new int[] { 31, 8, 0, 0, 10 }, new int[] { 37, 9, 0, 0, 13 }, new int[] { 36, 9, 0, 0, 14 }, new int[] { 33, 10, 0, 0, 17 }, new int[] { 32, 10, 0, 0, 18 }, new int[] { 7, 11, 0, 0, 21 },
|
||||
new int[] { 6, 11, 0, 0, 22 }, new int[] { 32, 11, 0, 0, 23 }, new int[] { 6, 3, 0, 0, 2 }, new int[] { 20, 6, 0, 1, 2 }, new int[] { 30, 8, 0, 0, 11 }, new int[] { 15, 10, 0, 0, 19 }, new int[] { 33, 11, 0, 0, 24 }, new int[] { 80, 12, 0, 0, 25 }, new int[] { 14, 4, 0, 1, 1 }, new int[] { 29, 8, 0, 0, 12 },
|
||||
new int[] { 14, 10, 0, 0, 20 }, new int[] { 81, 12, 0, 0, 26 }, new int[] { 13, 5, 0, 0, 4 }, new int[] { 35, 9, 0, 0, 15 }, new int[] { 13, 10, 0, 1, 7 }, new int[] { 12, 5, 0, 0, 5 }, new int[] { 34, 9, 0, 4, 2 }, new int[] { 82, 12, 0, 0, 27 }, new int[] { 11, 5, 0, 2, 1 }, new int[] { 12, 10, 0, 2, 4 },
|
||||
new int[] { 83, 12, 0, 1, 9 }, new int[] { 19, 6, 0, 0, 7 }, new int[] { 11, 10, 0, 3, 4 }, new int[] { 84, 12, 0, 6, 3 }, new int[] { 18, 6, 0, 0, 8 }, new int[] { 10, 10, 0, 4, 3 }, new int[] { 17, 6, 0, 3, 1 }, new int[] { 9, 10, 0, 8, 2 }, new int[] { 16, 6, 0, 4, 1 }, new int[] { 8, 10, 0, 5, 3 },
|
||||
new int[] { 22, 7, 0, 1, 3 }, new int[] { 85, 12, 0, 1, 10 }, new int[] { 21, 7, 0, 2, 2 }, new int[] { 20, 7, 0, 7, 1 }, new int[] { 28, 8, 0, 1, 4 }, new int[] { 27, 8, 0, 3, 2 }, new int[] { 33, 9, 0, 0, 16 }, new int[] { 32, 9, 0, 1, 5 }, new int[] { 31, 9, 0, 1, 6 }, new int[] { 30, 9, 0, 2, 3 },
|
||||
new int[] { 29, 9, 0, 3, 3 }, new int[] { 28, 9, 0, 5, 2 }, new int[] { 27, 9, 0, 6, 2 }, new int[] { 26, 9, 0, 7, 2 }, new int[] { 34, 11, 0, 1, 8 }, new int[] { 35, 11, 0, 9, 2 }, new int[] { 86, 12, 0, 2, 5 }, new int[] { 87, 12, 0, 7, 3 }, new int[] { 7, 4, 1, 0, 1 }, new int[] { 25, 9, 0, 11, 1 },
|
||||
new int[] { 5, 11, 1, 0, 6 }, new int[] { 15, 6, 1, 1, 1 }, new int[] { 4, 11, 1, 0, 7 }, new int[] { 14, 6, 1, 2, 1 }, new int[] { 13, 6, 0, 5, 1 }, new int[] { 12, 6, 1, 0, 2 }, new int[] { 19, 7, 1, 5, 1 }, new int[] { 18, 7, 0, 6, 1 }, new int[] { 17, 7, 1, 3, 1 }, new int[] { 16, 7, 1, 4, 1 },
|
||||
new int[] { 26, 8, 1, 9, 1 }, new int[] { 25, 8, 0, 8, 1 }, new int[] { 24, 8, 0, 9, 1 }, new int[] { 23, 8, 0, 10, 1 }, new int[] { 22, 8, 1, 0, 3 }, new int[] { 21, 8, 1, 6, 1 }, new int[] { 20, 8, 1, 7, 1 }, new int[] { 19, 8, 1, 8, 1 }, new int[] { 24, 9, 0, 12, 1 }, new int[] { 23, 9, 1, 0, 4 },
|
||||
new int[] { 22, 9, 1, 1, 2 }, new int[] { 21, 9, 1, 10, 1 }, new int[] { 20, 9, 1, 11, 1 }, new int[] { 19, 9, 1, 12, 1 }, new int[] { 18, 9, 1, 13, 1 }, new int[] { 17, 9, 1, 14, 1 }, new int[] { 7, 10, 0, 13, 1 }, new int[] { 6, 10, 1, 0, 5 }, new int[] { 5, 10, 1, 1, 3 }, new int[] { 4, 10, 1, 2, 2 },
|
||||
new int[] { 36, 11, 1, 3, 2 }, new int[] { 37, 11, 1, 4, 2 }, new int[] { 38, 11, 1, 15, 1 }, new int[] { 39, 11, 1, 16, 1 }, new int[] { 88, 12, 0, 14, 1 }, new int[] { 89, 12, 1, 0, 8 }, new int[] { 90, 12, 1, 5, 2 }, new int[] { 91, 12, 1, 6, 2 }, new int[] { 92, 12, 1, 17, 1 }, new int[] { 93, 12, 1, 18, 1 },
|
||||
new int[] { 94, 12, 1, 19, 1 }, new int[] { 95, 12, 1, 20, 1 } } };
|
||||
|
||||
static final short[][] SCAN_TABLES = new short[][] { new short[] {
|
||||
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 short[] {
|
||||
0, 1, 2, 3, 8, 9, 16, 17, 10, 11,
|
||||
4, 5, 6, 7, 15, 14, 13, 12, 19, 18,
|
||||
24, 25, 32, 33, 26, 27, 20, 21, 22, 23,
|
||||
28, 29, 30, 31, 34, 35, 40, 41, 48, 49,
|
||||
42, 43, 36, 37, 38, 39, 44, 45, 46, 47,
|
||||
50, 51, 56, 57, 58, 59, 52, 53, 54, 55,
|
||||
60, 61, 62, 63 }, new short[] {
|
||||
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 } };
|
||||
|
||||
static final short[] DEFAULT_ACDC_VALUES = new short[] {
|
||||
1024, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0 };
|
||||
|
||||
static final int[][] DC_LUM_TAB = new int[][] { new int[] { 0, 0 }, new int[] { 4, 3 }, new int[] { 3, 3 }, new int[] { 0, 3 }, new int[] { 2, 2 }, new int[] { 2, 2 }, new int[] { 1, 2 }, new int[] { 1, 2 } };
|
||||
|
||||
static final int[][] FILTER_TAB = new int[][] { new int[] { 14, 23, -7, 3, -1 }, new int[] { -3, 19, 20, -6, 3, -1 }, new int[] { 2, -6, 20, 20, -6, 3, -1 }, new int[] { -1, 3, -6, 20, 20, -6, 3, -1 } };
|
||||
|
||||
static final int[][] SPRITE_TRAJECTORY_LEN = new int[][] {
|
||||
new int[] { 0, 2 }, new int[] { 2, 3 }, new int[] { 3, 3 }, new int[] { 4, 3 }, new int[] { 5, 3 }, new int[] { 6, 3 }, new int[] { 14, 4 }, new int[] { 30, 5 }, new int[] { 62, 6 }, new int[] { 126, 7 },
|
||||
new int[] { 254, 8 }, new int[] { 510, 9 }, new int[] { 1022, 10 }, new int[] { 2046, 11 }, new int[] { 4094, 12 } };
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
import org.jcodec.common.tools.MathUtil;
|
||||
|
||||
public class MPEG4DCT {
|
||||
private static final int W1 = 2841;
|
||||
|
||||
private static final int W2 = 2676;
|
||||
|
||||
private static final int W3 = 2408;
|
||||
|
||||
private static final int W5 = 1609;
|
||||
|
||||
private static final int W6 = 1108;
|
||||
|
||||
private static final int W7 = 565;
|
||||
|
||||
public static void idctPut(byte[][] p, short[][] block, boolean interlacing) {
|
||||
idctRows(block[0]);
|
||||
idctRows(block[1]);
|
||||
idctRows(block[2]);
|
||||
idctRows(block[3]);
|
||||
idctRows(block[4]);
|
||||
idctRows(block[5]);
|
||||
int stride = 16;
|
||||
int stride2 = 8;
|
||||
int nextBlock = 128;
|
||||
if (interlacing) {
|
||||
nextBlock = stride;
|
||||
stride *= 2;
|
||||
}
|
||||
idctColumnsPut(block[0], p[0], 0, stride);
|
||||
idctColumnsPut(block[1], p[0], 8, stride);
|
||||
idctColumnsPut(block[2], p[0], nextBlock, stride);
|
||||
idctColumnsPut(block[3], p[0], nextBlock + 8, stride);
|
||||
idctColumnsPut(block[4], p[1], 0, stride2);
|
||||
idctColumnsPut(block[5], p[2], 0, stride2);
|
||||
}
|
||||
|
||||
public static void idctAdd(byte[][] p, short[] block, int index, boolean interlacing) {
|
||||
idctRows(block);
|
||||
switch (index) {
|
||||
case 0:
|
||||
idctColumnsAdd(block, p[0], 0, 16);
|
||||
break;
|
||||
case 1:
|
||||
idctColumnsAdd(block, p[0], 8, 16);
|
||||
break;
|
||||
case 2:
|
||||
if (interlacing) {
|
||||
idctColumnsAdd(block, p[0], 16, 32);
|
||||
} else {
|
||||
idctColumnsAdd(block, p[0], 128, 16);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (interlacing) {
|
||||
idctColumnsAdd(block, p[0], 24, 32);
|
||||
} else {
|
||||
idctColumnsAdd(block, p[0], 136, 16);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
idctColumnsAdd(block, p[1], 0, 8);
|
||||
break;
|
||||
case 5:
|
||||
idctColumnsAdd(block, p[2], 0, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte clamp255(int val) {
|
||||
val -= 255;
|
||||
val = -(255 + (val >> 31 & val));
|
||||
return (byte)(-(val >> 31 & val) - 128);
|
||||
}
|
||||
|
||||
public static void idctColumnsPut(short[] block, byte[] dst, int dstOffset, int stride) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int offset = dstOffset + i;
|
||||
int X1, X2, X3, X4, X5, X6, X7;
|
||||
if (((X1 = block[i + 32] << 8) | (X2 = block[i + 48]) | (X3 = block[i + 16]) | (X4 = block[i + 8]) | (X5 = block[i + 56]) | (X6 = block[i + 40]) | (X7 = block[i + 24])) == 0) {
|
||||
dst[offset + stride * 7] =
|
||||
|
||||
clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 6] = clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 5] = clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 4] = clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 3] = clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 2] = clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 1] = clamp255(block[i + 0] + 32 >> 6);
|
||||
dst[offset + stride * 0] = clamp255(block[i + 0] + 32 >> 6);
|
||||
} else {
|
||||
int X0 = (block[i + 0] << 8) + 8192;
|
||||
int X8 = 565 * (X4 + X5) + 4;
|
||||
X4 = X8 + 2276 * X4 >> 3;
|
||||
X5 = X8 - 3406 * X5 >> 3;
|
||||
X8 = 2408 * (X6 + X7) + 4;
|
||||
X6 = X8 - 799 * X6 >> 3;
|
||||
X7 = X8 - 4017 * X7 >> 3;
|
||||
X8 = X0 + X1;
|
||||
X0 -= X1;
|
||||
X1 = 1108 * (X3 + X2) + 4;
|
||||
X2 = X1 - 3784 * X2 >> 3;
|
||||
X3 = X1 + 1568 * X3 >> 3;
|
||||
X1 = X4 + X6;
|
||||
X4 -= X6;
|
||||
X6 = X5 + X7;
|
||||
X5 -= X7;
|
||||
X7 = X8 + X3;
|
||||
X8 -= X3;
|
||||
X3 = X0 + X2;
|
||||
X0 -= X2;
|
||||
X2 = 181 * (X4 + X5) + 128 >> 8;
|
||||
X4 = 181 * (X4 - X5) + 128 >> 8;
|
||||
dst[offset + stride * 0] = clamp255(X7 + X1 >> 14);
|
||||
dst[offset + stride * 1] = clamp255(X3 + X2 >> 14);
|
||||
dst[offset + stride * 2] = clamp255(X0 + X4 >> 14);
|
||||
dst[offset + stride * 3] = clamp255(X8 + X6 >> 14);
|
||||
dst[offset + stride * 4] = clamp255(X8 - X6 >> 14);
|
||||
dst[offset + stride * 5] = clamp255(X0 - X4 >> 14);
|
||||
dst[offset + stride * 6] = clamp255(X3 - X2 >> 14);
|
||||
dst[offset + stride * 7] = clamp255(X7 - X1 >> 14);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void idctColumnsAdd(short[] block, byte[] dst, int dstOffset, int stride) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int offset = dstOffset + i;
|
||||
int X1, X2, X3, X4, X5, X6, X7;
|
||||
if (((X1 = block[i + 32] << 8) | (X2 = block[i + 48]) | (X3 = block[i + 16]) | (X4 = block[i + 8]) | (X5 = block[i + 56]) | (X6 = block[i + 40]) | (X7 = block[i + 24])) == 0) {
|
||||
int pixel = block[i + 0] + 32 >> 6;
|
||||
dst[offset + stride * 0] = (byte)MathUtil.clip(dst[offset + stride * 0] + pixel, -128, 127);
|
||||
dst[offset + stride * 1] = (byte)MathUtil.clip(dst[offset + stride * 1] + pixel, -128, 127);
|
||||
dst[offset + stride * 2] = (byte)MathUtil.clip(dst[offset + stride * 2] + pixel, -128, 127);
|
||||
dst[offset + stride * 3] = (byte)MathUtil.clip(dst[offset + stride * 3] + pixel, -128, 127);
|
||||
dst[offset + stride * 4] = (byte)MathUtil.clip(dst[offset + stride * 4] + pixel, -128, 127);
|
||||
dst[offset + stride * 5] = (byte)MathUtil.clip(dst[offset + stride * 5] + pixel, -128, 127);
|
||||
dst[offset + stride * 6] = (byte)MathUtil.clip(dst[offset + stride * 6] + pixel, -128, 127);
|
||||
dst[offset + stride * 7] = (byte)MathUtil.clip(dst[offset + stride * 7] + pixel, -128, 127);
|
||||
} else {
|
||||
int X0 = (block[i + 0] << 8) + 8192;
|
||||
int X8 = 565 * (X4 + X5) + 4;
|
||||
X4 = X8 + 2276 * X4 >> 3;
|
||||
X5 = X8 - 3406 * X5 >> 3;
|
||||
X8 = 2408 * (X6 + X7) + 4;
|
||||
X6 = X8 - 799 * X6 >> 3;
|
||||
X7 = X8 - 4017 * X7 >> 3;
|
||||
X8 = X0 + X1;
|
||||
X0 -= X1;
|
||||
X1 = 1108 * (X3 + X2) + 4;
|
||||
X2 = X1 - 3784 * X2 >> 3;
|
||||
X3 = X1 + 1568 * X3 >> 3;
|
||||
X1 = X4 + X6;
|
||||
X4 -= X6;
|
||||
X6 = X5 + X7;
|
||||
X5 -= X7;
|
||||
X7 = X8 + X3;
|
||||
X8 -= X3;
|
||||
X3 = X0 + X2;
|
||||
X0 -= X2;
|
||||
X2 = 181 * (X4 + X5) + 128 >> 8;
|
||||
X4 = 181 * (X4 - X5) + 128 >> 8;
|
||||
dst[offset + stride * 0] = (byte)MathUtil.clip(dst[offset + stride * 0] + (X7 + X1 >> 14), -128, 127);
|
||||
dst[offset + stride * 1] = (byte)MathUtil.clip(dst[offset + stride * 1] + (X3 + X2 >> 14), -128, 127);
|
||||
dst[offset + stride * 2] = (byte)MathUtil.clip(dst[offset + stride * 2] + (X0 + X4 >> 14), -128, 127);
|
||||
dst[offset + stride * 3] = (byte)MathUtil.clip(dst[offset + stride * 3] + (X8 + X6 >> 14), -128, 127);
|
||||
dst[offset + stride * 4] = (byte)MathUtil.clip(dst[offset + stride * 4] + (X8 - X6 >> 14), -128, 127);
|
||||
dst[offset + stride * 5] = (byte)MathUtil.clip(dst[offset + stride * 5] + (X0 - X4 >> 14), -128, 127);
|
||||
dst[offset + stride * 6] = (byte)MathUtil.clip(dst[offset + stride * 6] + (X3 - X2 >> 14), -128, 127);
|
||||
dst[offset + stride * 7] = (byte)MathUtil.clip(dst[offset + stride * 7] + (X7 - X1 >> 14), -128, 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void idctRows(short[] block) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int offset = i << 3;
|
||||
int X1, X2, X3, X4, X5, X6, X7;
|
||||
if (((X1 = block[offset + 4] << 11) | (X2 = block[offset + 6]) | (X3 = block[offset + 2]) | (X4 = block[offset + 1]) | (X5 = block[offset + 7]) | (X6 = block[offset + 5]) | (X7 = block[offset + 3])) == 0) {
|
||||
block[offset + 7] = (short)(block[offset] << 3);
|
||||
block[offset + 6] = (short)(block[offset] << 3);
|
||||
block[offset + 5] = (short)(block[offset] << 3);
|
||||
block[offset + 4] = (short)(block[offset] << 3);
|
||||
block[offset + 3] = (short)(block[offset] << 3);
|
||||
block[offset + 2] = (short)(block[offset] << 3);
|
||||
block[offset + 1] = (short)(block[offset] << 3);
|
||||
block[offset] = (short)(block[offset] << 3);
|
||||
} else {
|
||||
int X0 = (block[offset] << 11) + 128;
|
||||
int X8 = 565 * (X4 + X5);
|
||||
X4 = X8 + 2276 * X4;
|
||||
X5 = X8 - 3406 * X5;
|
||||
X8 = 2408 * (X6 + X7);
|
||||
X6 = X8 - 799 * X6;
|
||||
X7 = X8 - 4017 * X7;
|
||||
X8 = X0 + X1;
|
||||
X0 -= X1;
|
||||
X1 = 1108 * (X3 + X2);
|
||||
X2 = X1 - 3784 * X2;
|
||||
X3 = X1 + 1568 * X3;
|
||||
X1 = X4 + X6;
|
||||
X4 -= X6;
|
||||
X6 = X5 + X7;
|
||||
X5 -= X7;
|
||||
X7 = X8 + X3;
|
||||
X8 -= X3;
|
||||
X3 = X0 + X2;
|
||||
X0 -= X2;
|
||||
X2 = 181 * (X4 + X5) + 128 >> 8;
|
||||
X4 = 181 * (X4 - X5) + 128 >> 8;
|
||||
block[offset] = (short)(X7 + X1 >> 8);
|
||||
block[offset + 1] = (short)(X3 + X2 >> 8);
|
||||
block[offset + 2] = (short)(X0 + X4 >> 8);
|
||||
block[offset + 3] = (short)(X8 + X6 >> 8);
|
||||
block[offset + 4] = (short)(X8 - X6 >> 8);
|
||||
block[offset + 5] = (short)(X0 - X4 >> 8);
|
||||
block[offset + 6] = (short)(X3 - X2 >> 8);
|
||||
block[offset + 7] = (short)(X7 - X1 >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.UsedViaReflection;
|
||||
import org.jcodec.common.VideoCodecMeta;
|
||||
import org.jcodec.common.VideoDecoder;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
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 MPEG4Decoder extends VideoDecoder {
|
||||
private Picture[] refs = new Picture[2];
|
||||
|
||||
private Macroblock[] prevMBs;
|
||||
|
||||
private Macroblock[] mbs;
|
||||
|
||||
private MPEG4DecodingContext ctx;
|
||||
|
||||
public Picture decodeFrame(ByteBuffer data, byte[][] buffer) {
|
||||
if (this.ctx == null)
|
||||
this.ctx = new MPEG4DecodingContext();
|
||||
if (!this.ctx.readHeaders(data))
|
||||
return null;
|
||||
this.ctx.fcodeForward = this.ctx.fcodeBackward = this.ctx.intraDCThreshold = 0;
|
||||
BitReader br = BitReader.createBitReader(data);
|
||||
if (!this.ctx.readVOPHeader(br))
|
||||
return null;
|
||||
this.mbs = new Macroblock[this.ctx.mbWidth * this.ctx.mbHeight];
|
||||
for (int i = 0; i < this.mbs.length; i++)
|
||||
this.mbs[i] = new Macroblock();
|
||||
Picture decoded = null;
|
||||
if (this.ctx.codingType != 2) {
|
||||
switch (this.ctx.codingType) {
|
||||
case 0:
|
||||
decoded = decodeIFrame(br, this.ctx, buffer);
|
||||
break;
|
||||
case 1:
|
||||
decoded = decodePFrame(br, this.ctx, buffer, this.ctx.fcodeForward);
|
||||
break;
|
||||
case 3:
|
||||
throw new RuntimeException("GMC not supported.");
|
||||
case 4:
|
||||
return null;
|
||||
}
|
||||
this.refs[1] = this.refs[0];
|
||||
this.refs[0] = decoded;
|
||||
this.prevMBs = this.mbs;
|
||||
} else {
|
||||
decoded = decodeBFrame(br, this.ctx, buffer, this.ctx.quant, this.ctx.fcodeForward, this.ctx.fcodeBackward);
|
||||
}
|
||||
br.terminate();
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private Picture decodeIFrame(BitReader br, MPEG4DecodingContext ctx, byte[][] buffer) {
|
||||
Picture p = new Picture(ctx.mbWidth << 4, ctx.mbHeight << 4, buffer, null, ColorSpace.YUV420, 0, new Rect(0, 0, ctx.width, ctx.height));
|
||||
int bound = 0;
|
||||
for (int y = 0; y < ctx.mbHeight; y++) {
|
||||
for (int x = 0; x < ctx.mbWidth; x++) {
|
||||
Macroblock mb = this.mbs[y * ctx.mbWidth + x];
|
||||
mb.reset(x, y, bound);
|
||||
MPEG4Bitstream.readIntraMode(br, ctx, mb);
|
||||
int index = x + y * ctx.mbWidth;
|
||||
Macroblock aboveMb = null;
|
||||
Macroblock aboveLeftMb = null;
|
||||
Macroblock leftMb = null;
|
||||
int apos = index - ctx.mbWidth;
|
||||
int lpos = index - 1;
|
||||
int alpos = index - 1 - ctx.mbWidth;
|
||||
if (apos >= bound)
|
||||
aboveMb = this.mbs[apos];
|
||||
if (alpos >= bound)
|
||||
aboveLeftMb = this.mbs[alpos];
|
||||
if (x > 0 && lpos >= bound)
|
||||
leftMb = this.mbs[lpos];
|
||||
MPEG4Bitstream.readCoeffIntra(br, ctx, mb, aboveMb, leftMb, aboveLeftMb);
|
||||
x = mb.x;
|
||||
y = mb.y;
|
||||
bound = mb.bound;
|
||||
MPEG4Renderer.renderIntra(mb, ctx);
|
||||
putPix(p, mb, x, y);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
Picture decodePFrame(BitReader br, MPEG4DecodingContext ctx, byte[][] buffers, int fcode) {
|
||||
int bound = 0;
|
||||
int mbWidth = ctx.mbWidth;
|
||||
int mbHeight = ctx.mbHeight;
|
||||
Picture p = new Picture(ctx.mbWidth << 4, ctx.mbHeight << 4, buffers, null, ColorSpace.YUV420, 0, new Rect(0, 0, ctx.width, ctx.height));
|
||||
for (int y = 0; y < mbHeight; y++) {
|
||||
for (int x = 0; x < mbWidth; x++) {
|
||||
while (br.checkNBit(10) == 1)
|
||||
br.skip(10);
|
||||
if (MPEG4Bitstream.checkResyncMarker(br, fcode - 1)) {
|
||||
bound = MPEG4Bitstream.readVideoPacketHeader(br, ctx, fcode - 1, true, false, true);
|
||||
x = bound % mbWidth;
|
||||
y = bound / mbWidth;
|
||||
}
|
||||
int index = x + y * ctx.mbWidth;
|
||||
Macroblock aboveMb = null;
|
||||
Macroblock aboveLeftMb = null;
|
||||
Macroblock leftMb = null;
|
||||
Macroblock aboveRightMb = null;
|
||||
int apos = index - ctx.mbWidth;
|
||||
int lpos = index - 1;
|
||||
int alpos = index - 1 - ctx.mbWidth;
|
||||
int arpos = index + 1 - ctx.mbWidth;
|
||||
if (apos >= bound)
|
||||
aboveMb = this.mbs[apos];
|
||||
if (alpos >= bound)
|
||||
aboveLeftMb = this.mbs[alpos];
|
||||
if (x > 0 && lpos >= bound)
|
||||
leftMb = this.mbs[lpos];
|
||||
if (arpos >= bound && x < ctx.mbWidth - 1)
|
||||
aboveRightMb = this.mbs[arpos];
|
||||
Macroblock mb = this.mbs[y * ctx.mbWidth + x];
|
||||
mb.reset(x, y, bound);
|
||||
MPEG4Bitstream.readInterModeCoeffs(br, ctx, fcode, mb, aboveMb, leftMb, aboveLeftMb, aboveRightMb);
|
||||
MPEG4Renderer.renderInter(ctx, this.refs, mb, fcode, 0, false);
|
||||
putPix(p, mb, x, y);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private Picture decodeBFrame(BitReader br, MPEG4DecodingContext ctx, byte[][] buffers, int quant, int fcodeForward, int fcodeBackward) {
|
||||
Picture p = new Picture(ctx.mbWidth << 4, ctx.mbHeight << 4, buffers, null, ColorSpace.YUV420, 0, new Rect(0, 0, ctx.width, ctx.height));
|
||||
Macroblock.Vector pFMV = Macroblock.vec(), pBMV = Macroblock.vec();
|
||||
int fcodeMax = (fcodeForward > fcodeBackward) ? fcodeForward : fcodeBackward;
|
||||
for (int y = 0; y < ctx.mbHeight; y++) {
|
||||
pBMV.x = pBMV.y = pFMV.x = pFMV.y = 0;
|
||||
for (int x = 0; x < ctx.mbWidth; x++) {
|
||||
Macroblock mb = this.mbs[y * ctx.mbWidth + x];
|
||||
Macroblock lastMB = this.prevMBs[y * ctx.mbWidth + x];
|
||||
if (MPEG4Bitstream.checkResyncMarker(br, fcodeMax - 1)) {
|
||||
int bound = MPEG4Bitstream.readVideoPacketHeader(br, ctx, fcodeMax - 1, (fcodeForward != 0), (fcodeBackward != 0), (ctx.intraDCThreshold != 0));
|
||||
x = bound % ctx.mbWidth;
|
||||
y = bound / ctx.mbWidth;
|
||||
pBMV.x = pBMV.y = pFMV.x = pFMV.y = 0;
|
||||
}
|
||||
mb.x = x;
|
||||
mb.y = y;
|
||||
mb.quant = quant;
|
||||
if (lastMB.mode == 16) {
|
||||
mb.cbp = 0;
|
||||
mb.mode = 3;
|
||||
MPEG4Bitstream.readInterCoeffs(br, ctx, mb);
|
||||
MPEG4Renderer.renderInter(ctx, this.refs, lastMB, fcodeForward, 1, true);
|
||||
putPix(p, lastMB, x, y);
|
||||
} else {
|
||||
MPEG4Bitstream.readBi(br, ctx, fcodeForward, fcodeBackward, mb, lastMB, pFMV, pBMV);
|
||||
MPEG4BiRenderer.renderBi(ctx, this.refs, fcodeForward, fcodeBackward, mb);
|
||||
putPix(p, mb, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public static void putPix(Picture p, Macroblock mb, int x, int y) {
|
||||
byte[] plane0 = p.getPlaneData(0);
|
||||
int dsto0 = (y << 4) * p.getWidth() + (x << 4);
|
||||
for (int row = 0, srco = 0; row < 16; row++, dsto0 += p.getWidth()) {
|
||||
for (int col = 0; col < 16; col++, srco++)
|
||||
plane0[dsto0 + col] = mb.pred[0][srco];
|
||||
}
|
||||
for (int pl = 1; pl < 3; pl++) {
|
||||
byte[] plane = p.getPlaneData(pl);
|
||||
int dsto = (y << 3) * p.getPlaneWidth(pl) + (x << 3);
|
||||
for (int i = 0, j = 0; i < 8; i++, dsto += p.getPlaneWidth(pl)) {
|
||||
for (int col = 0; col < 8; col++, j++)
|
||||
plane[dsto + col] = mb.pred[pl][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VideoCodecMeta getCodecMeta(ByteBuffer data) {
|
||||
MPEG4DecodingContext ctx = MPEG4DecodingContext.readFromHeaders(data.duplicate());
|
||||
if (ctx == null)
|
||||
return null;
|
||||
return VideoCodecMeta.createSimpleVideoCodecMeta(new Size(ctx.width, ctx.height), ColorSpace.YUV420J);
|
||||
}
|
||||
|
||||
@UsedViaReflection
|
||||
public static int probe(ByteBuffer data) {
|
||||
MPEG4DecodingContext ctx = MPEG4DecodingContext.readFromHeaders(data.duplicate());
|
||||
if (ctx == null)
|
||||
return 0;
|
||||
return Math.min((ctx.width > 320) ? ((ctx.width < 1280) ? 100 : 50) : 50,
|
||||
(ctx.height > 240) ? ((ctx.height < 720) ? 100 : 50) : 50);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,766 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import org.jcodec.common.io.BitReader;
|
||||
import org.jcodec.common.logging.Logger;
|
||||
import org.jcodec.common.tools.MathUtil;
|
||||
|
||||
public class MPEG4DecodingContext {
|
||||
public int width;
|
||||
|
||||
public int height;
|
||||
|
||||
public int horiz_mc_ref;
|
||||
|
||||
public int vert_mc_ref;
|
||||
|
||||
public short[] intraMpegQuantMatrix = new short[64];
|
||||
|
||||
public short[] interMpegQuantMatrix = new short[64];
|
||||
|
||||
public int[][] gmcWarps = new int[3][2];
|
||||
|
||||
public int mbWidth;
|
||||
|
||||
public int mbHeight;
|
||||
|
||||
public int spriteEnable;
|
||||
|
||||
public int shape;
|
||||
|
||||
public int quant;
|
||||
|
||||
public int quantBits;
|
||||
|
||||
public int timeIncrementBits;
|
||||
|
||||
public int intraDCThreshold;
|
||||
|
||||
public int spriteWarpingPoints;
|
||||
|
||||
public boolean reducedResolutionEnable;
|
||||
|
||||
public int fcodeForward;
|
||||
|
||||
public int fcodeBackward;
|
||||
|
||||
public boolean newPredEnable;
|
||||
|
||||
public boolean rounding;
|
||||
|
||||
public boolean quarterPel;
|
||||
|
||||
public boolean cartoonMode;
|
||||
|
||||
public int lastTimeBase;
|
||||
|
||||
public int timeBase;
|
||||
|
||||
public int time;
|
||||
|
||||
public int lastNonBTime;
|
||||
|
||||
public int pframeTs;
|
||||
|
||||
public int bframeTs;
|
||||
|
||||
public boolean topFieldFirst;
|
||||
|
||||
public boolean alternateVerticalScan;
|
||||
|
||||
int volVersionId;
|
||||
|
||||
int timestampMSB;
|
||||
|
||||
int timestampLSB;
|
||||
|
||||
boolean complexityEstimationDisable;
|
||||
|
||||
boolean interlacing;
|
||||
|
||||
boolean spriteBrightnessChange;
|
||||
|
||||
boolean scalability;
|
||||
|
||||
Estimation estimation = new Estimation();
|
||||
|
||||
private static final int VIDOBJ_START_CODE = 256;
|
||||
|
||||
private static final int VIDOBJLAY_START_CODE = 288;
|
||||
|
||||
private static final int VISOBJSEQ_START_CODE = 432;
|
||||
|
||||
private static final int VISOBJSEQ_STOP_CODE = 433;
|
||||
|
||||
private static final int USERDATA_START_CODE = 434;
|
||||
|
||||
private static final int GRPOFVOP_START_CODE = 435;
|
||||
|
||||
private static final int VISOBJ_START_CODE = 437;
|
||||
|
||||
private static final int VISOBJ_TYPE_VIDEO = 1;
|
||||
|
||||
private static final int VIDOBJLAY_AR_EXTPAR = 15;
|
||||
|
||||
private static final int VIDOBJLAY_SHAPE_RECTANGULAR = 0;
|
||||
|
||||
private static final int VIDOBJLAY_SHAPE_BINARY = 1;
|
||||
|
||||
private static final int VIDOBJLAY_SHAPE_BINARY_ONLY = 2;
|
||||
|
||||
private static final int VIDOBJLAY_SHAPE_GRAYSCALE = 3;
|
||||
|
||||
private static final int VOP_START_CODE = 438;
|
||||
|
||||
private static final int VIDOBJ_START_CODE_MASK = 31;
|
||||
|
||||
private static final int VIDOBJLAY_START_CODE_MASK = 15;
|
||||
|
||||
private static final int SPRITE_STATIC = 1;
|
||||
|
||||
private static final int SPRITE_GMC = 2;
|
||||
|
||||
private static final int VLC_CODE = 0;
|
||||
|
||||
private static final int VLC_LEN = 1;
|
||||
|
||||
private int timeIncrementResolution;
|
||||
|
||||
private boolean packedMode;
|
||||
|
||||
public int codingType;
|
||||
|
||||
public boolean quantType;
|
||||
|
||||
private static class Estimation {
|
||||
public int method;
|
||||
|
||||
public boolean opaque;
|
||||
|
||||
public boolean transparent;
|
||||
|
||||
public boolean intraCae;
|
||||
|
||||
public boolean interCae;
|
||||
|
||||
public boolean noUpdate;
|
||||
|
||||
public boolean upsampling;
|
||||
|
||||
public boolean intraBlocks;
|
||||
|
||||
public boolean interBlocks;
|
||||
|
||||
public boolean inter4vBlocks;
|
||||
|
||||
public boolean notCodedBlocks;
|
||||
|
||||
public boolean dctCoefs;
|
||||
|
||||
public boolean dctLines;
|
||||
|
||||
public boolean vlcSymbols;
|
||||
|
||||
public boolean vlcBits;
|
||||
|
||||
public boolean apm;
|
||||
|
||||
public boolean npm;
|
||||
|
||||
public boolean interpolateMcQ;
|
||||
|
||||
public boolean forwBackMcQ;
|
||||
|
||||
public boolean halfpel2;
|
||||
|
||||
public boolean halfpel4;
|
||||
|
||||
public boolean sadct;
|
||||
|
||||
public boolean quarterpel;
|
||||
}
|
||||
|
||||
public static MPEG4DecodingContext readFromHeaders(ByteBuffer bb) {
|
||||
MPEG4DecodingContext ret = new MPEG4DecodingContext();
|
||||
if (ret.readHeaders(bb))
|
||||
return ret;
|
||||
return null;
|
||||
}
|
||||
|
||||
public int bsVersion = 65535;
|
||||
|
||||
public static void getMatrix(BitReader br, short[] matrix) {
|
||||
int last;
|
||||
int value = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
last = value;
|
||||
value = br.readNBit(8);
|
||||
matrix[MPEG4Consts.SCAN_TABLES[0][i++]] = (short)value;
|
||||
} while (value != 0 && i < 64);
|
||||
i--;
|
||||
while (i < 64)
|
||||
matrix[MPEG4Consts.SCAN_TABLES[0][i++]] = (short)last;
|
||||
}
|
||||
|
||||
public boolean readHeaders(ByteBuffer bb) {
|
||||
bb.order(ByteOrder.BIG_ENDIAN);
|
||||
while (bb.remaining() >= 4) {
|
||||
int startCode = bb.getInt();
|
||||
while ((startCode & 0xFFFFFF00) != 256 && bb.hasRemaining()) {
|
||||
startCode <<= 8;
|
||||
startCode |= bb.get() & 0xFF;
|
||||
}
|
||||
if (startCode == 432) {
|
||||
byte b = bb.get();
|
||||
continue;
|
||||
}
|
||||
if (startCode == 433)
|
||||
continue;
|
||||
if (startCode == 437) {
|
||||
BitReader br = BitReader.createBitReader(bb);
|
||||
if (br.readBool()) {
|
||||
int verId = br.readNBit(4);
|
||||
br.skip(3);
|
||||
} else {
|
||||
int verId = 1;
|
||||
}
|
||||
int visual_object_type = br.readNBit(4);
|
||||
if (visual_object_type != 1)
|
||||
return false;
|
||||
if (br.readBool()) {
|
||||
br.skip(3);
|
||||
br.skip(1);
|
||||
if (br.readBool()) {
|
||||
br.skip(8);
|
||||
br.skip(8);
|
||||
br.skip(8);
|
||||
}
|
||||
}
|
||||
br.terminate();
|
||||
continue;
|
||||
}
|
||||
if ((startCode & 0xFFFFFFE0) == 256)
|
||||
continue;
|
||||
if ((startCode & 0xFFFFFFF0) == 288) {
|
||||
BitReader br = BitReader.createBitReader(bb);
|
||||
br.skip(1);
|
||||
br.skip(8);
|
||||
if (br.readBool()) {
|
||||
this.volVersionId = br.readNBit(4);
|
||||
br.skip(3);
|
||||
} else {
|
||||
this.volVersionId = 1;
|
||||
}
|
||||
int aspectRatio = br.readNBit(4);
|
||||
if (aspectRatio == 15) {
|
||||
br.readNBit(8);
|
||||
br.readNBit(8);
|
||||
}
|
||||
if (br.readBool()) {
|
||||
br.skip(2);
|
||||
boolean lowDelay = br.readBool();
|
||||
if (br.readBool()) {
|
||||
int bitrate = br.readNBit(15) << 15;
|
||||
br.skip(1);
|
||||
bitrate |= br.readNBit(15);
|
||||
br.skip(1);
|
||||
int bufferSize = br.readNBit(15) << 3;
|
||||
br.skip(1);
|
||||
bufferSize |= br.readNBit(3);
|
||||
int occupancy = br.readNBit(11) << 15;
|
||||
br.skip(1);
|
||||
occupancy |= br.readNBit(15);
|
||||
br.skip(1);
|
||||
}
|
||||
}
|
||||
this.shape = br.readNBit(2);
|
||||
if (this.shape != 0);
|
||||
if (this.shape == 3 && this.volVersionId != 1)
|
||||
br.skip(4);
|
||||
br.skip(1);
|
||||
this.timeIncrementResolution = br.readNBit(16);
|
||||
if (this.timeIncrementResolution > 0) {
|
||||
this.timeIncrementBits = Math.max(MathUtil.log2(this.timeIncrementResolution - 1) + 1, 1);
|
||||
} else {
|
||||
this.timeIncrementBits = 1;
|
||||
}
|
||||
br.skip(1);
|
||||
if (br.readBool())
|
||||
br.skip(this.timeIncrementBits);
|
||||
if (this.shape != 2) {
|
||||
if (this.shape == 0) {
|
||||
br.skip(1);
|
||||
this.width = br.readNBit(13);
|
||||
br.skip(1);
|
||||
this.height = br.readNBit(13);
|
||||
br.skip(1);
|
||||
calcSizes();
|
||||
}
|
||||
this.interlacing = br.readBool();
|
||||
if (!br.readBool());
|
||||
this.spriteEnable = br.readNBit((this.volVersionId == 1) ? 1 : 2);
|
||||
if (this.spriteEnable == 1 || this.spriteEnable == 2) {
|
||||
if (this.spriteEnable != 2) {
|
||||
br.readNBit(13);
|
||||
br.skip(1);
|
||||
br.readNBit(13);
|
||||
br.skip(1);
|
||||
br.readNBit(13);
|
||||
br.skip(1);
|
||||
br.readNBit(13);
|
||||
br.skip(1);
|
||||
}
|
||||
this.spriteWarpingPoints = br.readNBit(6);
|
||||
br.readNBit(2);
|
||||
this.spriteBrightnessChange = br.readBool();
|
||||
if (this.spriteEnable != 2)
|
||||
br.readNBit(1);
|
||||
}
|
||||
if (this.volVersionId != 1 && this.shape != 0)
|
||||
br.skip(1);
|
||||
if (br.readBool()) {
|
||||
this.quantBits = br.readNBit(4);
|
||||
br.skip(4);
|
||||
} else {
|
||||
this.quantBits = 5;
|
||||
}
|
||||
if (this.shape == 3) {
|
||||
br.skip(1);
|
||||
br.skip(1);
|
||||
br.skip(1);
|
||||
}
|
||||
this.quantType = br.readBool();
|
||||
if (this.quantType) {
|
||||
if (br.readBool()) {
|
||||
getMatrix(br, this.intraMpegQuantMatrix);
|
||||
} else {
|
||||
System.arraycopy(MPEG4Consts.DEFAULT_INTRA_MATRIX, 0, this.intraMpegQuantMatrix, 0, this.intraMpegQuantMatrix.length);
|
||||
}
|
||||
if (br.readBool()) {
|
||||
getMatrix(br, this.interMpegQuantMatrix);
|
||||
} else {
|
||||
System.arraycopy(MPEG4Consts.DEFAULT_INTER_MATRIX, 0, this.interMpegQuantMatrix, 0, this.interMpegQuantMatrix.length);
|
||||
}
|
||||
if (this.shape == 3)
|
||||
return false;
|
||||
}
|
||||
if (this.volVersionId != 1) {
|
||||
this.quarterPel = br.readBool();
|
||||
} else {
|
||||
this.quarterPel = false;
|
||||
}
|
||||
this.complexityEstimationDisable = br.readBool();
|
||||
if (!this.complexityEstimationDisable)
|
||||
readVolComplexityEstimationHeader(br, this.estimation);
|
||||
br.skip(1);
|
||||
if (br.readBool())
|
||||
br.skip(1);
|
||||
if (this.volVersionId != 1) {
|
||||
this.newPredEnable = br.readBool();
|
||||
if (this.newPredEnable) {
|
||||
br.skip(2);
|
||||
br.skip(1);
|
||||
}
|
||||
this.reducedResolutionEnable = br.readBool();
|
||||
} else {
|
||||
this.newPredEnable = false;
|
||||
this.reducedResolutionEnable = false;
|
||||
}
|
||||
this.scalability = br.readBool();
|
||||
if (this.scalability) {
|
||||
br.skip(1);
|
||||
br.skip(4);
|
||||
br.skip(1);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(1);
|
||||
if (this.shape == 1) {
|
||||
br.skip(1);
|
||||
br.skip(1);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (this.volVersionId != 1) {
|
||||
this.scalability = br.readBool();
|
||||
if (this.scalability) {
|
||||
br.skip(4);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
br.skip(5);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
br.skip(1);
|
||||
}
|
||||
br.terminate();
|
||||
continue;
|
||||
}
|
||||
if (startCode == 435) {
|
||||
BitReader br = BitReader.createBitReader(bb);
|
||||
int hours = br.readNBit(5);
|
||||
int minutes = br.readNBit(6);
|
||||
br.skip(1);
|
||||
int seconds = br.readNBit(6);
|
||||
br.skip(1);
|
||||
br.skip(1);
|
||||
br.terminate();
|
||||
continue;
|
||||
}
|
||||
if (startCode == 438)
|
||||
return true;
|
||||
if (startCode == 434) {
|
||||
byte[] tmp = new byte[256];
|
||||
int i = 0;
|
||||
tmp[i++] = bb.get();
|
||||
for (tmp[i] = bb.get(); bb.get() != 0; i++);
|
||||
bb.position(bb.position() - 1);
|
||||
String userData = new String(tmp, 0, i);
|
||||
if (userData.startsWith("XviD"))
|
||||
if (tmp[userData.length() - 1] == 67) {
|
||||
this.bsVersion = Integer.parseInt(userData.substring(4, userData.length() - 1));
|
||||
this.cartoonMode = true;
|
||||
} else {
|
||||
this.bsVersion = Integer.parseInt(userData.substring(4));
|
||||
}
|
||||
if (userData.startsWith("DivX")) {
|
||||
int buildIndex = userData.indexOf("Build");
|
||||
if (buildIndex == -1)
|
||||
buildIndex = userData.indexOf("b");
|
||||
try {
|
||||
int version = Integer.parseInt(userData.substring(4, buildIndex));
|
||||
int build = Integer.parseInt(userData.substring(buildIndex + 1, userData.length() - 1));
|
||||
char packed = userData.charAt(userData.length() - 1);
|
||||
this.packedMode = (packed == 'p');
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Logger.debug("Unknown");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void calcSizes() {
|
||||
this.mbWidth = (this.width + 15) / 16;
|
||||
this.mbHeight = (this.height + 15) / 16;
|
||||
}
|
||||
|
||||
private void readVolComplexityEstimationHeader(BitReader br, Estimation estimation) {
|
||||
estimation.method = br.readNBit(2);
|
||||
if (estimation.method == 0 || estimation.method == 1) {
|
||||
if (!br.readBool()) {
|
||||
estimation.opaque = br.readBool();
|
||||
estimation.transparent = br.readBool();
|
||||
estimation.intraCae = br.readBool();
|
||||
estimation.interCae = br.readBool();
|
||||
estimation.noUpdate = br.readBool();
|
||||
estimation.upsampling = br.readBool();
|
||||
}
|
||||
if (!br.readBool()) {
|
||||
estimation.intraBlocks = br.readBool();
|
||||
estimation.interBlocks = br.readBool();
|
||||
estimation.inter4vBlocks = br.readBool();
|
||||
estimation.notCodedBlocks = br.readBool();
|
||||
}
|
||||
}
|
||||
br.skip(1);
|
||||
if (!br.readBool()) {
|
||||
estimation.dctCoefs = br.readBool();
|
||||
estimation.dctLines = br.readBool();
|
||||
estimation.vlcSymbols = br.readBool();
|
||||
estimation.vlcBits = br.readBool();
|
||||
}
|
||||
if (!br.readBool()) {
|
||||
estimation.apm = br.readBool();
|
||||
estimation.npm = br.readBool();
|
||||
estimation.interpolateMcQ = br.readBool();
|
||||
estimation.forwBackMcQ = br.readBool();
|
||||
estimation.halfpel2 = br.readBool();
|
||||
estimation.halfpel4 = br.readBool();
|
||||
}
|
||||
br.skip(1);
|
||||
if (estimation.method == 1 &&
|
||||
!br.readBool()) {
|
||||
estimation.sadct = br.readBool();
|
||||
estimation.quarterpel = br.readBool();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean readVOPHeader(BitReader br) {
|
||||
this.rounding = false;
|
||||
this.quant = 2;
|
||||
this.codingType = br.readNBit(2);
|
||||
while (br.readBool())
|
||||
this.timestampMSB++;
|
||||
br.skip(1);
|
||||
if (getTimeIncrementBits() != 0)
|
||||
this.timestampLSB = br.readNBit(getTimeIncrementBits());
|
||||
br.skip(1);
|
||||
if (!br.readBool())
|
||||
return false;
|
||||
if (this.newPredEnable) {
|
||||
int vopId = br.readNBit(Math.min(getTimeIncrementBits() + 3, 15));
|
||||
if (br.readBool())
|
||||
int i = br.readNBit(Math.min(getTimeIncrementBits() + 3, 15));
|
||||
br.skip(1);
|
||||
}
|
||||
if (this.shape != 2 && (this.codingType == 1 || (this.codingType == 3 && this.spriteEnable == 2)))
|
||||
this.rounding = br.readBool();
|
||||
if (this.reducedResolutionEnable && this.shape == 0 && (this.codingType == 1 || this.codingType == 0))
|
||||
if (br.readBool());
|
||||
if (this.shape != 0) {
|
||||
if (this.spriteEnable != 1 || this.codingType != 0) {
|
||||
this.width = br.readNBit(13);
|
||||
br.skip(1);
|
||||
this.height = br.readNBit(13);
|
||||
br.skip(1);
|
||||
this.horiz_mc_ref = br.readNBit(13);
|
||||
br.skip(1);
|
||||
this.vert_mc_ref = br.readNBit(13);
|
||||
br.skip(1);
|
||||
calcSizes();
|
||||
}
|
||||
br.skip(1);
|
||||
if (br.readBool())
|
||||
br.skip(8);
|
||||
}
|
||||
Estimation estimation = new Estimation();
|
||||
if (this.shape != 2) {
|
||||
if (!this.complexityEstimationDisable)
|
||||
readVopComplexityEstimationHeader(br, estimation, this.spriteEnable, this.codingType);
|
||||
this.intraDCThreshold = MPEG4Consts.INTRA_DC_THRESHOLD_TABLE[br.readNBit(3)];
|
||||
if (this.interlacing) {
|
||||
this.topFieldFirst = br.readBool();
|
||||
this.alternateVerticalScan = br.readBool();
|
||||
}
|
||||
}
|
||||
if ((this.spriteEnable == 1 || this.spriteEnable == 2) && this.codingType == 3) {
|
||||
for (int i = 0; i < this.spriteWarpingPoints; i++) {
|
||||
int x = 0, y = 0;
|
||||
int length = getSpriteTrajectory(br);
|
||||
if (length > 0) {
|
||||
x = br.readNBit(length);
|
||||
if (x >> length - 1 == 0)
|
||||
x = -(x ^ (1 << length) - 1);
|
||||
}
|
||||
br.skip(1);
|
||||
length = getSpriteTrajectory(br);
|
||||
if (length > 0) {
|
||||
y = br.readNBit(length);
|
||||
if (y >> length - 1 == 0)
|
||||
y = -(y ^ (1 << length) - 1);
|
||||
}
|
||||
br.skip(1);
|
||||
this.gmcWarps[i][0] = x;
|
||||
this.gmcWarps[i][1] = y;
|
||||
}
|
||||
if (this.spriteBrightnessChange);
|
||||
if (this.spriteEnable == 1);
|
||||
}
|
||||
if ((this.quant = br.readNBit(this.quantBits)) < 1)
|
||||
this.quant = 1;
|
||||
if (this.codingType != 0)
|
||||
this.fcodeForward = br.readNBit(3);
|
||||
if (this.codingType == 2)
|
||||
this.fcodeBackward = br.readNBit(3);
|
||||
if (!this.scalability &&
|
||||
this.shape != 0 && this.codingType != 0)
|
||||
br.skip(1);
|
||||
if (this.codingType != 2) {
|
||||
this.lastTimeBase = this.timeBase;
|
||||
this.timeBase += this.timestampMSB;
|
||||
this.time = this.timeBase * getTimeIncrementResolution() + this.timestampLSB;
|
||||
this.pframeTs = this.time - this.lastNonBTime;
|
||||
this.lastNonBTime = this.time;
|
||||
} else {
|
||||
this.time = (this.lastTimeBase + this.timestampMSB) * getTimeIncrementResolution() + this.timestampLSB;
|
||||
this.bframeTs = this.pframeTs - (this.lastNonBTime - this.time);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getSpriteTrajectory(BitReader br) {
|
||||
for (int i = 0; i < 12; i++) {
|
||||
if (br.checkNBit(MPEG4Consts.SPRITE_TRAJECTORY_LEN[i][1]) == MPEG4Consts.SPRITE_TRAJECTORY_LEN[i][0]) {
|
||||
br.skip(MPEG4Consts.SPRITE_TRAJECTORY_LEN[i][1]);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void readVopComplexityEstimationHeader(BitReader br, Estimation estimation, int spriteEnable, int codingType) {
|
||||
if (estimation.method == 0 || estimation.method == 1) {
|
||||
if (codingType == 0) {
|
||||
if (estimation.opaque)
|
||||
br.skip(8);
|
||||
if (estimation.transparent)
|
||||
br.skip(8);
|
||||
if (estimation.intraCae)
|
||||
br.skip(8);
|
||||
if (estimation.interCae)
|
||||
br.skip(8);
|
||||
if (estimation.noUpdate)
|
||||
br.skip(8);
|
||||
if (estimation.upsampling)
|
||||
br.skip(8);
|
||||
if (estimation.intraBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.notCodedBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.dctCoefs)
|
||||
br.skip(8);
|
||||
if (estimation.dctLines)
|
||||
br.skip(8);
|
||||
if (estimation.vlcSymbols)
|
||||
br.skip(8);
|
||||
if (estimation.vlcBits)
|
||||
br.skip(8);
|
||||
if (estimation.sadct)
|
||||
br.skip(8);
|
||||
}
|
||||
if (codingType == 1) {
|
||||
if (estimation.opaque)
|
||||
br.skip(8);
|
||||
if (estimation.transparent)
|
||||
br.skip(8);
|
||||
if (estimation.intraCae)
|
||||
br.skip(8);
|
||||
if (estimation.interCae)
|
||||
br.skip(8);
|
||||
if (estimation.noUpdate)
|
||||
br.skip(8);
|
||||
if (estimation.upsampling)
|
||||
br.skip(8);
|
||||
if (estimation.intraBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.notCodedBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.dctCoefs)
|
||||
br.skip(8);
|
||||
if (estimation.dctLines)
|
||||
br.skip(8);
|
||||
if (estimation.vlcSymbols)
|
||||
br.skip(8);
|
||||
if (estimation.vlcBits)
|
||||
br.skip(8);
|
||||
if (estimation.interBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.inter4vBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.apm)
|
||||
br.skip(8);
|
||||
if (estimation.npm)
|
||||
br.skip(8);
|
||||
if (estimation.forwBackMcQ)
|
||||
br.skip(8);
|
||||
if (estimation.halfpel2)
|
||||
br.skip(8);
|
||||
if (estimation.halfpel4)
|
||||
br.skip(8);
|
||||
if (estimation.sadct)
|
||||
br.skip(8);
|
||||
if (estimation.quarterpel)
|
||||
br.skip(8);
|
||||
}
|
||||
if (codingType == 2) {
|
||||
if (estimation.opaque)
|
||||
br.skip(8);
|
||||
if (estimation.transparent)
|
||||
br.skip(8);
|
||||
if (estimation.intraCae)
|
||||
br.skip(8);
|
||||
if (estimation.interCae)
|
||||
br.skip(8);
|
||||
if (estimation.noUpdate)
|
||||
br.skip(8);
|
||||
if (estimation.upsampling)
|
||||
br.skip(8);
|
||||
if (estimation.intraBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.notCodedBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.dctCoefs)
|
||||
br.skip(8);
|
||||
if (estimation.dctLines)
|
||||
br.skip(8);
|
||||
if (estimation.vlcSymbols)
|
||||
br.skip(8);
|
||||
if (estimation.vlcBits)
|
||||
br.skip(8);
|
||||
if (estimation.interBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.inter4vBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.apm)
|
||||
br.skip(8);
|
||||
if (estimation.npm)
|
||||
br.skip(8);
|
||||
if (estimation.forwBackMcQ)
|
||||
br.skip(8);
|
||||
if (estimation.halfpel2)
|
||||
br.skip(8);
|
||||
if (estimation.halfpel4)
|
||||
br.skip(8);
|
||||
if (estimation.interpolateMcQ)
|
||||
br.skip(8);
|
||||
if (estimation.sadct)
|
||||
br.skip(8);
|
||||
if (estimation.quarterpel)
|
||||
br.skip(8);
|
||||
}
|
||||
if (codingType == 3 && spriteEnable == 1) {
|
||||
if (estimation.intraBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.notCodedBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.dctCoefs)
|
||||
br.skip(8);
|
||||
if (estimation.dctLines)
|
||||
br.skip(8);
|
||||
if (estimation.vlcSymbols)
|
||||
br.skip(8);
|
||||
if (estimation.vlcBits)
|
||||
br.skip(8);
|
||||
if (estimation.interBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.inter4vBlocks)
|
||||
br.skip(8);
|
||||
if (estimation.apm)
|
||||
br.skip(8);
|
||||
if (estimation.npm)
|
||||
br.skip(8);
|
||||
if (estimation.forwBackMcQ)
|
||||
br.skip(8);
|
||||
if (estimation.halfpel2)
|
||||
br.skip(8);
|
||||
if (estimation.halfpel4)
|
||||
br.skip(8);
|
||||
if (estimation.interpolateMcQ)
|
||||
br.skip(8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getPackedMode() {
|
||||
return this.packedMode;
|
||||
}
|
||||
|
||||
public int getTimeIncrementBits() {
|
||||
return this.timeIncrementBits;
|
||||
}
|
||||
|
||||
public int getTimeIncrementResolution() {
|
||||
return this.timeIncrementResolution;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,543 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
import org.jcodec.common.tools.MathUtil;
|
||||
|
||||
public class MPEG4Interpolator {
|
||||
private static byte[] qpi = new byte[272];
|
||||
|
||||
public static final void fulpel8x8(byte[] dst, int dstOff, int dstStride, byte[] src, int srcCol, int srcRow, int srcWidth, int srcHeight, int srcStride) {
|
||||
if (srcCol < 0 || srcRow < 0 || srcCol > srcWidth - 8 || srcRow > srcHeight - 8) {
|
||||
for (int j = 0; j < 8; j++, dstOff += dstStride) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int y = MathUtil.clip(srcRow + j, 0, srcHeight - 1);
|
||||
int x = MathUtil.clip(srcCol + i, 0, srcWidth - 1);
|
||||
dst[dstOff + i] = src[srcStride * y + x];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int srcOffset = srcRow * srcStride + srcCol;
|
||||
for (int j = 0; j < 8; j++, dstOff += dstStride, srcOffset += srcStride) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
dst[dstOff + i] = src[srcOffset + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final void fulpel16x16(byte[] dst, byte[] src, int srcCol, int srcRow, int srcWidth, int srcHeight, int srcStride) {
|
||||
if (srcCol < 0 || srcRow < 0 || srcCol > srcWidth - 16 || srcRow > srcHeight - 16) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int y = MathUtil.clip(srcRow + j, 0, srcHeight - 1);
|
||||
int x = MathUtil.clip(srcCol + i, 0, srcWidth - 1);
|
||||
dst[(j << 4) + i] = src[srcStride * y + x];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int srcOffset = srcRow * srcStride + srcCol;
|
||||
for (int j = 0; j < 16; j++) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
dst[(j << 4) + i] = src[srcOffset + j * srcStride + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final void interpolate16x16QP(byte[] dst, byte[] ref, int x, int y, int w, int h, int dx, int dy, int refs, boolean rounding) {
|
||||
int xRef = x * 4 + dx;
|
||||
int yRef = y * 4 + dy;
|
||||
int location = dx & 0x3 | (dy & 0x3) << 2;
|
||||
int xFull = xRef / 4;
|
||||
if (xRef < 0 && (xRef & 0x3) != 0)
|
||||
xFull--;
|
||||
int yFull = yRef / 4;
|
||||
if (yRef < 0 && (yRef & 0x3) != 0)
|
||||
yFull--;
|
||||
switch (location) {
|
||||
case 0:
|
||||
fulpel16x16(dst, ref, xFull, yFull, w, h, refs);
|
||||
break;
|
||||
case 1:
|
||||
horzMiddle16(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
qOff(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 2:
|
||||
horzMiddle16(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 3:
|
||||
horzMiddle16(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
qOff(dst, ref, xFull + 1, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 4:
|
||||
vertMiddle16(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
qOff(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 5:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
qOff(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
qOffSafe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 6:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
qOffSafe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 7:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
qOff(qpi, ref, xFull + 1, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
qOffSafe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 8:
|
||||
vertMiddle16(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 9:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
qOff(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 10:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 11:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
qOff(qpi, ref, xFull + 1, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 12:
|
||||
vertMiddle16(dst, ref, xFull, yFull, w, h, 16, refs, rounding ? 1 : 0);
|
||||
qOff(dst, ref, xFull, yFull + 1, w, h, 16, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 13:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
qOff(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
qOffSafe(dst, qpi, 16, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 14:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
qOffSafe(dst, qpi, 16, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 15:
|
||||
horzMiddle16(qpi, ref, xFull, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
qOff(qpi, ref, xFull + 1, yFull, w, h, 17, refs, rounding ? 1 : 0);
|
||||
vertMiddle16Safe(dst, qpi, 0, 16, 16, rounding ? 1 : 0);
|
||||
qOffSafe(dst, qpi, 16, 16, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void qOffSafe(byte[] dst, byte[] src, int srcOffset, int height, int srcStride, int round) {
|
||||
for (int row = 0, dstOff = 0; row < height; row++, srcOffset += srcStride) {
|
||||
for (int col = 0; col < 16; col++, dstOff++)
|
||||
dst[dstOff] = (byte)(dst[dstOff] + src[srcOffset + col] + 1 >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void qOff(byte[] dst, byte[] src, int x, int y, int w, int h, int height, int srcStride, int round) {
|
||||
if (x < 0 || y < 0 || x > w - 16 || y > h - height) {
|
||||
for (int row = 0, dstOff = 0; row < height; row++) {
|
||||
int o0 = MathUtil.clip(y + row, 0, h - 1) * srcStride;
|
||||
for (int col = 0; col < 16; col++, dstOff++) {
|
||||
int srcOffset = o0 + MathUtil.clip(x + col, 0, w - 1);
|
||||
dst[dstOff] = (byte)(dst[dstOff] + src[srcOffset] + 1 >> 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qOffSafe(dst, src, y * srcStride + x, height, srcStride, round);
|
||||
}
|
||||
}
|
||||
|
||||
private static void qOff8x8Safe(byte[] dst, int dstOff, byte[] src, int srcOffset, int height, int srcStride, int round) {
|
||||
for (int row = 0; row < height; row++, srcOffset += srcStride, dstOff += 8) {
|
||||
for (int col = 0; col < 8; col++, dstOff++)
|
||||
dst[dstOff] = (byte)(dst[dstOff] + src[srcOffset + col] + 1 >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void qOff8x8(byte[] dst, int dstOff, byte[] src, int x, int y, int w, int h, int height, int srcStride, int round) {
|
||||
if (x < 0 || y < 0 || x > w - 8 || y > h - height) {
|
||||
for (int row = 0; row < height; row++, dstOff += 8) {
|
||||
int o0 = MathUtil.clip(y + row, 0, h - 1) * srcStride;
|
||||
for (int col = 0; col < 8; col++, dstOff++) {
|
||||
int srcOffset = o0 + MathUtil.clip(x + col, 0, w - 1);
|
||||
dst[dstOff] = (byte)(dst[dstOff] + src[srcOffset] + 1 >> 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qOff8x8Safe(dst, dstOff, src, y * srcStride + x, height, srcStride, round);
|
||||
}
|
||||
}
|
||||
|
||||
public static final void interpolate8x8QP(byte[] dst, int dstO, byte[] ref, int x, int y, int w, int h, int dx, int dy, int refs, boolean rounding) {
|
||||
int xRef = x * 4 + dx;
|
||||
int yRef = y * 4 + dy;
|
||||
int quads = dx & 0x3 | (dy & 0x3) << 2;
|
||||
int xInt = xRef / 4;
|
||||
if (xRef < 0 && xRef % 4 != 0)
|
||||
xInt--;
|
||||
int yInt = yRef / 4;
|
||||
if (yRef < 0 && yRef % 4 != 0)
|
||||
yInt--;
|
||||
switch (quads) {
|
||||
case 0:
|
||||
fulpel8x8(dst, dstO, 16, ref, xInt, yInt, w, h, refs);
|
||||
break;
|
||||
case 1:
|
||||
horzMiddle8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
qOff8x8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 2:
|
||||
horzMiddle8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 3:
|
||||
horzMiddle8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
qOff8x8(dst, dstO, ref, xInt + 1, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 4:
|
||||
vertMiddle8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
qOff8x8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 5:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
qOff8x8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
qOff8x8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 6:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
qOff8x8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 7:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
qOff8x8(qpi, 0, ref, xInt + 1, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
qOff8x8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 8:
|
||||
vertMiddle8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 9:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
qOff8x8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 10:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 11:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
qOff8x8(qpi, 0, ref, xInt + 1, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 12:
|
||||
vertMiddle8(dst, dstO, ref, xInt, yInt, w, h, 8, refs, rounding ? 1 : 0);
|
||||
qOff8x8(dst, dstO, ref, xInt, yInt + 1, w, h, 8, refs, rounding ? 1 : 0);
|
||||
break;
|
||||
case 13:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
qOff8x8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
qOff8x8Safe(dst, dstO, qpi, 16, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 14:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
qOff8x8Safe(dst, dstO, qpi, 16, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
case 15:
|
||||
horzMiddle8(qpi, 0, ref, xInt, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
qOff8x8(qpi, 0, ref, xInt + 1, yInt, w, h, 9, refs, rounding ? 1 : 0);
|
||||
vertMiddle8Safe(dst, dstO, qpi, 0, 8, 16, rounding ? 1 : 0);
|
||||
qOff8x8Safe(dst, dstO, qpi, 16, 8, 16, rounding ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final void horzMiddle8(byte[] dst, int dstOffset, byte[] src, int x, int y, int w, int h, int height, int srcStride, int rounding) {
|
||||
if (x < 0 || y < 0 || x > w - 9 || y > h - height) {
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
int o0 = MathUtil.clip(y + row, 0, h - 1) * srcStride;
|
||||
for (int k = 0; k < 5 + i; k++) {
|
||||
int o1 = MathUtil.clip(x + k, 0, w - 1);
|
||||
int o2 = MathUtil.clip(x + 8 - k, 0, w - 1);
|
||||
sum0 += MPEG4Consts.FILTER_TAB[i][k] * src[o0 + o1];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[i][k] * src[o0 + o2];
|
||||
}
|
||||
dst[dstOffset + i] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstOffset + 7 - i] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
dstOffset += 16;
|
||||
}
|
||||
} else {
|
||||
int srcOffset = y * srcStride + x;
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
for (int k = 0; k < 5 + i; k++) {
|
||||
sum0 += MPEG4Consts.FILTER_TAB[i][k] * src[srcOffset + k];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[i][k] * src[srcOffset + 8 - k];
|
||||
}
|
||||
dst[dstOffset + i] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstOffset + 7 - i] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
srcOffset += srcStride;
|
||||
dstOffset += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void horzMiddle16(byte[] dst, byte[] src, int x, int y, int w, int h, int height, int srcStride, int rounding) {
|
||||
if (x < 0 || y < 0 || x > w - 17 || y > h - height) {
|
||||
int dstOffset = 0;
|
||||
for (int row = 0; row < height; row++) {
|
||||
int o0 = MathUtil.clip(y + row, 0, h - 1) * srcStride;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
for (int k = 0; k < 5 + j; k++) {
|
||||
int srcOffset0 = o0 + MathUtil.clip(x + k, 0, w - 1);
|
||||
int srcOffset1 = o0 + MathUtil.clip(x + 16 - k, 0, w - 1);
|
||||
sum0 += MPEG4Consts.FILTER_TAB[j][k] * src[srcOffset0];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[j][k] * src[srcOffset1];
|
||||
}
|
||||
dst[dstOffset + j] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstOffset + 15 - j] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int sum = 0;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
int srcOffset = o0 + MathUtil.clip(x + k + i + 1, 0, w - 1);
|
||||
sum += MPEG4Consts.FILTER_TAB[3][k] * src[srcOffset];
|
||||
}
|
||||
dst[dstOffset + i + 4] = (byte)MathUtil.clip(sum + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
dstOffset += 16;
|
||||
}
|
||||
} else {
|
||||
int srcOffset = y * srcStride + x;
|
||||
int dstOffset = 0;
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
for (int k = 0; k < 5 + j; k++) {
|
||||
sum0 += MPEG4Consts.FILTER_TAB[j][k] * src[srcOffset + k];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[j][k] * src[srcOffset + 16 - k];
|
||||
}
|
||||
dst[dstOffset + j] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstOffset + 15 - j] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int sum = 0;
|
||||
for (int k = 0; k < 8; k++)
|
||||
sum += MPEG4Consts.FILTER_TAB[3][k] * src[srcOffset + k + i + 1];
|
||||
dst[dstOffset + i + 4] = (byte)MathUtil.clip(sum + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
srcOffset += srcStride;
|
||||
dstOffset += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void vertMiddle16Safe(byte[] dst, byte[] src, int srcOffset, int width, int srcStride, int rounding) {
|
||||
int dstOffset = 0;
|
||||
for (int col = 0; col < width; col++) {
|
||||
int dstStart = dstOffset, dstEnd = dstOffset + 240;
|
||||
for (int i = 0; i < 4; i++, dstStart += 16, dstEnd -= 16) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
int ss = srcOffset;
|
||||
int es = srcOffset + (srcStride << 4);
|
||||
for (int k = 0; k < 5 + i; k++) {
|
||||
sum0 += MPEG4Consts.FILTER_TAB[i][k] * src[ss];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[i][k] * src[es];
|
||||
ss += srcStride;
|
||||
es -= srcStride;
|
||||
}
|
||||
dst[dstStart] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstEnd] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
dstStart = dstOffset + 64;
|
||||
int srcCoeff0Pos = srcOffset + srcStride;
|
||||
for (int j = 0; j < 8; j++, dstStart += 16, srcCoeff0Pos += srcStride) {
|
||||
int sum = 0;
|
||||
int srcPos = srcCoeff0Pos;
|
||||
for (int k = 0; k < 8; k++, srcPos += srcStride)
|
||||
sum += MPEG4Consts.FILTER_TAB[3][k] * src[srcPos];
|
||||
dst[dstStart] = (byte)MathUtil.clip(sum + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
srcOffset++;
|
||||
dstOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
private static final void vertMiddle16(byte[] dst, byte[] src, int x, int y, int w, int h, int width, int srcStride, int rounding) {
|
||||
if (x < 0 || y < 0 || x > w - width || y > h - 17) {
|
||||
int dstOffset = 0;
|
||||
for (int col = 0; col < width; col++) {
|
||||
int dstStart = dstOffset, dstEnd = dstOffset + 240;
|
||||
for (int j = 0; j < 4; j++, dstStart += 16, dstEnd -= 16) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
for (int k = 0; k < 5 + j; k++) {
|
||||
int ss = MathUtil.clip(y + k, 0, h - 1) * srcStride + MathUtil.clip(x + col, 0, w - 1);
|
||||
int es = MathUtil.clip(y - k + 16, 0, h - 1) * srcStride + MathUtil.clip(x + col, 0, w - 1);
|
||||
sum0 += MPEG4Consts.FILTER_TAB[j][k] * src[ss];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[j][k] * src[es];
|
||||
}
|
||||
dst[dstStart] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstEnd] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
dstStart = dstOffset + 64;
|
||||
for (int i = 0; i < 8; i++, dstStart += 16) {
|
||||
int sum = 0;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
int srcPos = MathUtil.clip(y + i + k + 1, 0, h - 1) * srcStride +
|
||||
MathUtil.clip(x + col, 0, w - 1);
|
||||
sum += MPEG4Consts.FILTER_TAB[3][k] * src[srcPos];
|
||||
}
|
||||
dst[dstStart] = (byte)MathUtil.clip(sum + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
dstOffset++;
|
||||
}
|
||||
} else {
|
||||
vertMiddle16Safe(dst, src, y * srcStride + x, width, srcStride, rounding);
|
||||
}
|
||||
}
|
||||
|
||||
private static final void vertMiddle8Safe(byte[] dst, int dstOffset, byte[] src, int srcOffset, int width, int srcStride, int rounding) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
int os = srcOffset;
|
||||
int of = srcOffset + (srcStride << 3);
|
||||
for (int k = 0; k < 5 + i; k++) {
|
||||
sum0 += MPEG4Consts.FILTER_TAB[i][k] * src[os];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[i][k] * src[of];
|
||||
os += srcStride;
|
||||
of -= srcStride;
|
||||
}
|
||||
dst[dstOffset + i * 16] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstOffset + (7 - i) * 16] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
srcOffset++;
|
||||
dstOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
private static final void vertMiddle8(byte[] dst, int dstOffset, byte[] src, int x, int y, int w, int h, int width, int srcStride, int rounding) {
|
||||
if (x < 0 || y < 0 || x > w - width || y > h - 9) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int sum0 = 0;
|
||||
int sum1 = 0;
|
||||
for (int k = 0; k < 5 + i; k++) {
|
||||
int os = MathUtil.clip(y + k, 0, h - 1) * srcStride + MathUtil.clip(x + col, 0, w - 1);
|
||||
int of = MathUtil.clip(y + 8 - k, 0, h - 1) * srcStride + MathUtil.clip(x + col, 0, w - 1);
|
||||
sum0 += MPEG4Consts.FILTER_TAB[i][k] * src[os];
|
||||
sum1 += MPEG4Consts.FILTER_TAB[i][k] * src[of];
|
||||
}
|
||||
dst[dstOffset + i * 16] = (byte)MathUtil.clip(sum0 + 16 - rounding >> 5, -128, 127);
|
||||
dst[dstOffset + (7 - i) * 16] = (byte)MathUtil.clip(sum1 + 16 - rounding >> 5, -128, 127);
|
||||
}
|
||||
dstOffset++;
|
||||
}
|
||||
} else {
|
||||
vertMiddle8Safe(dst, dstOffset, src, y * srcStride + x, width, srcStride, rounding);
|
||||
}
|
||||
}
|
||||
|
||||
public static final void interpolate16x16Planar(byte[] dst, byte[] refn, int x, int y, int w, int h, int dx, int dy, int stride, boolean rounding) {
|
||||
interpolate8x8Planar(dst, 0, 16, refn, x, y, w, h, dx, dy, stride, rounding);
|
||||
interpolate8x8Planar(dst, 8, 16, refn, x + 8, y, w, h, dx, dy, stride, rounding);
|
||||
interpolate8x8Planar(dst, 128, 16, refn, x, y + 8, w, h, dx, dy, stride, rounding);
|
||||
interpolate8x8Planar(dst, 136, 16, refn, x + 8, y + 8, w, h, dx, dy, stride, rounding);
|
||||
}
|
||||
|
||||
public static final void interpolate8x8Planar(byte[] dst, int dstOff, int dstStride, byte[] refn, int x, int y, int w, int h, int dx, int dy, int stride, boolean rounding) {
|
||||
int x_ = x + (dx >> 1);
|
||||
int y_ = y + (dy >> 1);
|
||||
switch (((dx & 0x1) << 1) + (dy & 0x1)) {
|
||||
case 0:
|
||||
fulpel8x8(dst, dstOff, dstStride, refn, x_, y_, w, h, stride);
|
||||
break;
|
||||
case 1:
|
||||
interpolate8PlanarVer(dst, dstOff, dstStride, refn, x_, y_, w, h, stride, rounding);
|
||||
break;
|
||||
case 2:
|
||||
interpolate8x8PlanarHor(dst, dstOff, dstStride, refn, x_, y_, w, h, stride, rounding);
|
||||
break;
|
||||
default:
|
||||
interpolate8x8PlanarBoth(dst, dstOff, dstStride, refn, x_, y_, w, h, stride, rounding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final void interpolate8x8PlanarHor(byte[] dst, int dstOffset, int dstStride, byte[] src, int x, int y, int w, int h, int stride, boolean rounding) {
|
||||
int rnd = rounding ? 0 : 1;
|
||||
if (x < 0 || y < 0 || x > w - 9 || y > h - 8) {
|
||||
for (int j = 0, d = dstOffset; j < 8; j++, d += dstStride) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int srcOffset0 = MathUtil.clip(y + j, 0, h - 1) * stride + MathUtil.clip(x + i, 0, w - 1);
|
||||
int srcOffset1 = MathUtil.clip(y + j, 0, h - 1) * stride + MathUtil.clip(x + i + 1, 0, w - 1);
|
||||
dst[d + i] = (byte)(src[srcOffset0] + src[srcOffset1] + rnd >> 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int srcOffset = y * stride + x;
|
||||
for (int j = 0, d = dstOffset; j < 8 * stride; j += stride, d += dstStride) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
dst[d + i] = (byte)(src[srcOffset + j + i] + src[srcOffset + j + i + 1] + rnd >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void interpolate8PlanarVer(byte[] dst, int dstOff, int dstStride, byte[] src, int x, int y, int w, int h, int stride, boolean rounding) {
|
||||
int rnd = rounding ? 0 : 1;
|
||||
if (x < 0 || y < 0 || x > w - 8 || y > h - 9) {
|
||||
for (int j = 0, d = dstOff; j < 8; j++, d += dstStride) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int srcOffset0 = MathUtil.clip(y + j, 0, h - 1) * stride + MathUtil.clip(x + i, 0, w - 1);
|
||||
int srcOffset1 = MathUtil.clip(y + j + 1, 0, h - 1) * stride + MathUtil.clip(x + i, 0, w - 1);
|
||||
dst[d + i] = (byte)(src[srcOffset0] + src[srcOffset1] + rnd >> 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int srcOffset = y * stride + x;
|
||||
for (int j = 0, d = dstOff; j < 8 * stride; j += stride, d += dstStride) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
dst[d + i] = (byte)(src[srcOffset + j + i] + src[srcOffset + j + stride + i] + rnd >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void interpolate8x8PlanarBoth(byte[] dst, int dstOff, int dstStride, byte[] src, int x, int y, int w, int h, int stride, boolean rounding) {
|
||||
int rnd = rounding ? 1 : 2;
|
||||
if (x < 0 || y < 0 || x > w - 9 || y > h - 9) {
|
||||
for (int j = 0, d = dstOff; j < 8; j++, d += dstStride) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int srcOffset0 = MathUtil.clip(y + j, 0, h - 1) * stride + MathUtil.clip(x + i, 0, w - 1);
|
||||
int srcOffset1 = MathUtil.clip(y + j, 0, h - 1) * stride + MathUtil.clip(x + i + 1, 0, w - 1);
|
||||
int srcOffset2 = MathUtil.clip(y + j + 1, 0, h - 1) * stride + MathUtil.clip(x + i, 0, w - 1);
|
||||
int srcOffset3 = MathUtil.clip(y + j + 1, 0, h - 1) * stride + MathUtil.clip(x + i + 1, 0, w - 1);
|
||||
dst[d + i] = (byte)(src[srcOffset0] + src[srcOffset1] + src[srcOffset2] + src[srcOffset3] + rnd >> 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int srcOffset = y * stride + x;
|
||||
for (int j = 0, d = dstOff; j < 8 * stride; j += stride, d += dstStride) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
dst[d + i] = (byte)(src[srcOffset + j + i] + src[srcOffset + j + i + 1] + src[srcOffset + j + stride + i] + src[srcOffset + j + stride + i + 1] + rnd >> 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
import org.jcodec.common.model.Picture;
|
||||
|
||||
public class MPEG4Renderer {
|
||||
private static void checkMV(Macroblock.Vector mv, int xHigh, int xLow, int yHigh, int yLow) {
|
||||
if (mv.x > xHigh) {
|
||||
mv.x = xHigh;
|
||||
} else if (mv.x < xLow) {
|
||||
mv.x = xLow;
|
||||
}
|
||||
if (mv.y > yHigh) {
|
||||
mv.y = yHigh;
|
||||
} else if (mv.y < yLow) {
|
||||
mv.y = yLow;
|
||||
}
|
||||
}
|
||||
|
||||
static void validateVector(Macroblock.Vector[] mvs, MPEG4DecodingContext ctx, int xPos, int yPos) {
|
||||
int shift = 5 + (ctx.quarterPel ? 1 : 0);
|
||||
int xHigh = ctx.mbWidth - xPos << shift;
|
||||
int xLow = -xPos - 1 << shift;
|
||||
int yHigh = ctx.mbHeight - yPos << shift;
|
||||
int yLow = -yPos - 1 << shift;
|
||||
checkMV(mvs[0], xHigh, xLow, yHigh, yLow);
|
||||
checkMV(mvs[1], xHigh, xLow, yHigh, yLow);
|
||||
checkMV(mvs[2], xHigh, xLow, yHigh, yLow);
|
||||
checkMV(mvs[3], xHigh, xLow, yHigh, yLow);
|
||||
}
|
||||
|
||||
public static void renderIntra(Macroblock mb, MPEG4DecodingContext ctx) {
|
||||
MPEG4DCT.idctPut(mb.pred, mb.block, (ctx.interlacing && mb.fieldDCT));
|
||||
}
|
||||
|
||||
public static void renderInter(MPEG4DecodingContext ctx, Picture[] refs, Macroblock mb, int fcode, int ref, boolean bvop) {
|
||||
if (mb.coded) {
|
||||
if (mb.mcsel)
|
||||
throw new RuntimeException("GMC");
|
||||
if (mb.mode == 0 || mb.mode == 1 || mb.mode == 2) {
|
||||
if (!mb.fieldPred) {
|
||||
renderMBInter(ctx, refs, mb, ref, bvop);
|
||||
} else {
|
||||
throw new RuntimeException("interlaced");
|
||||
}
|
||||
} else {
|
||||
renderIntra(mb, ctx);
|
||||
}
|
||||
} else {
|
||||
renderMBInter(ctx, refs, mb, ref, bvop);
|
||||
}
|
||||
}
|
||||
|
||||
static void renderMBInter(MPEG4DecodingContext ctx, Picture[] refs, Macroblock mb, int ref, boolean bvop) {
|
||||
int uv_dx, uv_dy;
|
||||
Macroblock.Vector[] mv = new Macroblock.Vector[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
mv[i] = new Macroblock.Vector((mb.mvs[i]).x, (mb.mvs[i]).y);
|
||||
validateVector(mv, ctx, mb.x, mb.y);
|
||||
int mbX = mb.x << 4;
|
||||
int mbY = mb.y << 4;
|
||||
int codedW = ctx.mbWidth << 4;
|
||||
int codedH = ctx.mbHeight << 4;
|
||||
int codedWcr = ctx.mbWidth << 3;
|
||||
int codedHcr = ctx.mbHeight << 3;
|
||||
if (mb.mode != 2 || bvop) {
|
||||
Picture backward = refs[ref];
|
||||
uv_dx = calcChromaMv(ctx, (mv[0]).x);
|
||||
uv_dy = calcChromaMv(ctx, (mv[0]).y);
|
||||
if (ctx.quarterPel) {
|
||||
MPEG4Interpolator.interpolate16x16QP(mb.pred[0], backward.getPlaneData(0), mbX, mbY, codedW, codedH, (mv[0]).x, (mv[0]).y,
|
||||
backward.getWidth(), ctx.rounding);
|
||||
} else {
|
||||
MPEG4Interpolator.interpolate16x16Planar(mb.pred[0], backward.getPlaneData(0), mbX, mbY, codedW, codedH, (mv[0]).x, (mv[0]).y,
|
||||
backward.getWidth(), ctx.rounding);
|
||||
}
|
||||
} else {
|
||||
uv_dx = calcChromaMvAvg(ctx, mv, true);
|
||||
uv_dy = calcChromaMvAvg(ctx, mv, false);
|
||||
Picture backward = refs[0];
|
||||
byte[] lumaPlane = backward.getPlaneData(0);
|
||||
int lumaStride = backward.getWidth();
|
||||
if (ctx.quarterPel) {
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[0], 0, lumaPlane, mbX, mbY, codedW, codedH, (mv[0]).x, (mv[0]).y, lumaStride, ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[0], 8, lumaPlane, mbX + 8, mbY, codedW, codedH, (mv[1]).x, (mv[1]).y, lumaStride, ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[0], 128, lumaPlane, mbX, mbY + 8, codedW, codedH, (mv[2]).x, (mv[2]).y, lumaStride, ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8QP(mb.pred[0], 136, lumaPlane, mbX + 8, mbY + 8, codedW, codedH, (mv[3]).x, (mv[3]).y, lumaStride, ctx.rounding);
|
||||
} else {
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[0], 0, 16, lumaPlane, mbX, mbY, codedW, codedH, (mv[0]).x, (mv[0]).y, lumaStride, ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[0], 8, 16, lumaPlane, mbX + 8, mbY, codedW, codedH, (mv[1]).x, (mv[1]).y, lumaStride, ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[0], 128, 16, lumaPlane, mbX, mbY + 8, codedW, codedH, (mv[2]).x, (mv[2]).y, lumaStride, ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[0], 136, 16, lumaPlane, mbX + 8, mbY + 8, codedW, codedH, (mv[3]).x, (mv[3]).y, lumaStride, ctx.rounding);
|
||||
}
|
||||
}
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[1], 0, 8, refs[ref].getPlaneData(1), 8 * mb.x, 8 * mb.y, codedWcr, codedHcr, uv_dx, uv_dy, refs[ref]
|
||||
.getPlaneWidth(1), ctx.rounding);
|
||||
MPEG4Interpolator.interpolate8x8Planar(mb.pred[2], 0, 8, refs[ref].getPlaneData(2), 8 * mb.x, 8 * mb.y, codedWcr, codedHcr, uv_dx, uv_dy, refs[ref]
|
||||
.getPlaneWidth(2), ctx.rounding);
|
||||
if (mb.cbp != 0)
|
||||
for (int j = 0; j < 6; j++) {
|
||||
short[] block = mb.block[j];
|
||||
if ((mb.cbp & 1 << 5 - j) != 0)
|
||||
MPEG4DCT.idctAdd(mb.pred, block, j, (ctx.interlacing && mb.fieldDCT));
|
||||
}
|
||||
}
|
||||
|
||||
static int calcChromaMv(MPEG4DecodingContext ctx, int ret) {
|
||||
if (ctx.quarterPel)
|
||||
if (ctx.bsVersion <= 1) {
|
||||
ret = ret >> 1 | ret & 0x1;
|
||||
} else {
|
||||
ret /= 2;
|
||||
}
|
||||
return (ret >> 1) + MPEG4Consts.ROUNDTAB_79[ret & 0x3];
|
||||
}
|
||||
|
||||
static int calcChromaMvAvg(MPEG4DecodingContext ctx, Macroblock.Vector[] mv, boolean x) {
|
||||
if (ctx.quarterPel) {
|
||||
if (ctx.bsVersion <= 1) {
|
||||
ret = 0;
|
||||
for (int z = 0; z < 4; z++) {
|
||||
if (x) {
|
||||
ret += (mv[z]).x >> 1 | (mv[z]).x & 0x1;
|
||||
} else {
|
||||
ret += (mv[z]).y >> 1 | (mv[z]).y & 0x1;
|
||||
}
|
||||
}
|
||||
} else if (x) {
|
||||
ret = (mv[0]).x / 2 + (mv[1]).x / 2 + (mv[2]).x / 2 + (mv[3]).x / 2;
|
||||
} else {
|
||||
ret = (mv[0]).y / 2 + (mv[1]).y / 2 + (mv[2]).y / 2 + (mv[3]).y / 2;
|
||||
}
|
||||
} else if (x) {
|
||||
ret = (mv[0]).x + (mv[1]).x + (mv[2]).x + (mv[3]).x;
|
||||
} else {
|
||||
ret = (mv[0]).y + (mv[1]).y + (mv[2]).y + (mv[3]).y;
|
||||
}
|
||||
int ret = (ret >> 3) + MPEG4Consts.ROUNDTAB_76[ret & 0xF];
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static final int sanitize(int value, boolean quarterPel, int fcode) {
|
||||
int length = 1 << fcode + 4;
|
||||
if (value < -length)
|
||||
return -length;
|
||||
if (value >= length)
|
||||
return length - 1;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package org.jcodec.codecs.mpeg4;
|
||||
|
||||
public class Macroblock {
|
||||
public static final int MBPRED_SIZE = 15;
|
||||
|
||||
public Vector[] mvs;
|
||||
|
||||
public short[][] predValues;
|
||||
|
||||
public int[] acpredDirections;
|
||||
|
||||
public int mode;
|
||||
|
||||
public int quant;
|
||||
|
||||
public boolean fieldDCT;
|
||||
|
||||
public boolean fieldPred;
|
||||
|
||||
public boolean fieldForTop;
|
||||
|
||||
public boolean fieldForBottom;
|
||||
|
||||
private Vector[] pmvs;
|
||||
|
||||
private Vector[] qmvs;
|
||||
|
||||
public int cbp;
|
||||
|
||||
public Vector[] bmvs;
|
||||
|
||||
public Vector[] bqmvs;
|
||||
|
||||
public Vector amv;
|
||||
|
||||
public Vector mvsAvg;
|
||||
|
||||
public int x;
|
||||
|
||||
public int y;
|
||||
|
||||
public int bound;
|
||||
|
||||
public boolean acpredFlag;
|
||||
|
||||
public short[] predictors;
|
||||
|
||||
public short[][] block;
|
||||
|
||||
public boolean coded;
|
||||
|
||||
public boolean mcsel;
|
||||
|
||||
public byte[][] pred;
|
||||
|
||||
public static Vector vec() {
|
||||
return new Vector(0, 0);
|
||||
}
|
||||
|
||||
public static class Vector {
|
||||
public int x;
|
||||
|
||||
public int y;
|
||||
|
||||
public Vector(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
public Macroblock() {
|
||||
this.mvs = new Vector[4];
|
||||
this.pmvs = new Vector[4];
|
||||
this.qmvs = new Vector[4];
|
||||
this.bmvs = new Vector[4];
|
||||
this.bqmvs = new Vector[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
this.mvs[i] = vec();
|
||||
this.pmvs[i] = vec();
|
||||
this.qmvs[i] = vec();
|
||||
this.bmvs[i] = vec();
|
||||
this.bqmvs[i] = vec();
|
||||
}
|
||||
this.pred = new byte[][] { new byte[256], new byte[64], new byte[64], new byte[256], new byte[64], new byte[64] };
|
||||
this.predValues = new short[6][15];
|
||||
this.acpredDirections = new int[6];
|
||||
this.amv = vec();
|
||||
this.predictors = new short[8];
|
||||
this.block = new short[6][64];
|
||||
}
|
||||
|
||||
public void reset(int x2, int y2, int bound2) {
|
||||
this.x = x2;
|
||||
this.y = y2;
|
||||
this.bound = bound2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
|
||||
public class DecoderConfig extends NodeDescriptor {
|
||||
private int objectType;
|
||||
|
||||
private int bufSize;
|
||||
|
||||
private int maxBitrate;
|
||||
|
||||
private int avgBitrate;
|
||||
|
||||
public DecoderConfig(int objectType, int bufSize, int maxBitrate, int avgBitrate, Collection<Descriptor> children) {
|
||||
super(tag(), children);
|
||||
this.objectType = objectType;
|
||||
this.bufSize = bufSize;
|
||||
this.maxBitrate = maxBitrate;
|
||||
this.avgBitrate = avgBitrate;
|
||||
}
|
||||
|
||||
protected void doWrite(ByteBuffer out) {
|
||||
out.put((byte)this.objectType);
|
||||
out.put((byte)21);
|
||||
out.put((byte)(this.bufSize >> 16));
|
||||
out.putShort((short)this.bufSize);
|
||||
out.putInt(this.maxBitrate);
|
||||
out.putInt(this.avgBitrate);
|
||||
super.doWrite(out);
|
||||
}
|
||||
|
||||
public static int tag() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public int getObjectType() {
|
||||
return this.objectType;
|
||||
}
|
||||
|
||||
public int getBufSize() {
|
||||
return this.bufSize;
|
||||
}
|
||||
|
||||
public int getMaxBitrate() {
|
||||
return this.maxBitrate;
|
||||
}
|
||||
|
||||
public int getAvgBitrate() {
|
||||
return this.avgBitrate;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
|
||||
public class DecoderSpecific extends Descriptor {
|
||||
private ByteBuffer data;
|
||||
|
||||
public DecoderSpecific(ByteBuffer data) {
|
||||
super(tag(), 0);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
protected void doWrite(ByteBuffer out) {
|
||||
NIOUtils.write(out, this.data);
|
||||
}
|
||||
|
||||
public static int tag() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public ByteBuffer getData() {
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jcodec.common.JCodecUtil2;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
|
||||
public abstract class Descriptor {
|
||||
private int _tag;
|
||||
|
||||
private int size;
|
||||
|
||||
public Descriptor(int tag, int size) {
|
||||
this._tag = tag;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void write(ByteBuffer out) {
|
||||
ByteBuffer fork = out.duplicate();
|
||||
NIOUtils.skip(out, 5);
|
||||
doWrite(out);
|
||||
int length = out.position() - fork.position() - 5;
|
||||
fork.put((byte)this._tag);
|
||||
JCodecUtil2.writeBER32(fork, length);
|
||||
}
|
||||
|
||||
protected abstract void doWrite(ByteBuffer paramByteBuffer);
|
||||
|
||||
int getTag() {
|
||||
return this._tag;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.jcodec.common.JCodecUtil2;
|
||||
import org.jcodec.common.Preconditions;
|
||||
import org.jcodec.common.UsedViaReflection;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
|
||||
public class DescriptorParser {
|
||||
private static final int ES_TAG = 3;
|
||||
|
||||
private static final int DC_TAG = 4;
|
||||
|
||||
private static final int DS_TAG = 5;
|
||||
|
||||
private static final int SL_TAG = 6;
|
||||
|
||||
public static Descriptor read(ByteBuffer input) {
|
||||
if (input.remaining() < 2)
|
||||
return null;
|
||||
int tag = input.get() & 0xFF;
|
||||
int size = JCodecUtil2.readBER32(input);
|
||||
ByteBuffer byteBuffer = NIOUtils.read(input, size);
|
||||
switch (tag) {
|
||||
case 3:
|
||||
return parseES(byteBuffer);
|
||||
case 6:
|
||||
return parseSL(byteBuffer);
|
||||
case 4:
|
||||
return parseDecoderConfig(byteBuffer);
|
||||
case 5:
|
||||
return parseDecoderSpecific(byteBuffer);
|
||||
}
|
||||
throw new RuntimeException("unknown tag " + tag);
|
||||
}
|
||||
|
||||
@UsedViaReflection
|
||||
private static NodeDescriptor parseNodeDesc(ByteBuffer input) {
|
||||
Collection<Descriptor> children = new ArrayList<>();
|
||||
while (true) {
|
||||
Descriptor d = read(input);
|
||||
if (d != null)
|
||||
children.add(d);
|
||||
if (d == null)
|
||||
return new NodeDescriptor(0, children);
|
||||
}
|
||||
}
|
||||
|
||||
private static ES parseES(ByteBuffer input) {
|
||||
int trackId = input.getShort();
|
||||
input.get();
|
||||
NodeDescriptor node = parseNodeDesc(input);
|
||||
return new ES(trackId, node.getChildren());
|
||||
}
|
||||
|
||||
private static SL parseSL(ByteBuffer input) {
|
||||
Preconditions.checkState((2 == (input.get() & 0xFF)));
|
||||
return new SL();
|
||||
}
|
||||
|
||||
private static DecoderSpecific parseDecoderSpecific(ByteBuffer input) {
|
||||
ByteBuffer data = NIOUtils.readBuf(input);
|
||||
return new DecoderSpecific(data);
|
||||
}
|
||||
|
||||
private static DecoderConfig parseDecoderConfig(ByteBuffer input) {
|
||||
int objectType = input.get() & 0xFF;
|
||||
input.get();
|
||||
int bufSize = (input.get() & 0xFF) << 16 | input.getShort() & 0xFFFF;
|
||||
int maxBitrate = input.getInt();
|
||||
int avgBitrate = input.getInt();
|
||||
NodeDescriptor node = parseNodeDesc(input);
|
||||
return new DecoderConfig(objectType, bufSize, maxBitrate, avgBitrate, node.getChildren());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ES extends NodeDescriptor {
|
||||
private int trackId;
|
||||
|
||||
public ES(int trackId, Collection<Descriptor> children) {
|
||||
super(tag(), children);
|
||||
this.trackId = trackId;
|
||||
}
|
||||
|
||||
public static int tag() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
protected void doWrite(ByteBuffer out) {
|
||||
out.putShort((short)this.trackId);
|
||||
out.put((byte)0);
|
||||
super.doWrite(out);
|
||||
}
|
||||
|
||||
public int getTrackId() {
|
||||
return this.trackId;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
|
||||
public class NodeDescriptor extends Descriptor {
|
||||
private Collection<Descriptor> children;
|
||||
|
||||
public NodeDescriptor(int tag, Collection<Descriptor> children) {
|
||||
super(tag, 0);
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
protected void doWrite(ByteBuffer out) {
|
||||
for (Descriptor descr : this.children)
|
||||
descr.write(out);
|
||||
}
|
||||
|
||||
public Collection<Descriptor> getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
public static <T> T findByTag(Descriptor es, int tag) {
|
||||
if (es.getTag() == tag)
|
||||
return (T)es;
|
||||
if (es instanceof NodeDescriptor)
|
||||
for (Descriptor descriptor : ((NodeDescriptor)es).getChildren()) {
|
||||
T res = findByTag(descriptor, tag);
|
||||
if (res != null)
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package org.jcodec.codecs.mpeg4.es;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class SL extends Descriptor {
|
||||
public SL() {
|
||||
super(tag(), 0);
|
||||
}
|
||||
|
||||
protected void doWrite(ByteBuffer out) {
|
||||
out.put((byte)2);
|
||||
}
|
||||
|
||||
public static int tag() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package org.jcodec.codecs.mpeg4.mp4;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import org.jcodec.codecs.aac.ADTSParser;
|
||||
import org.jcodec.codecs.mpeg4.es.DecoderConfig;
|
||||
import org.jcodec.codecs.mpeg4.es.DecoderSpecific;
|
||||
import org.jcodec.codecs.mpeg4.es.Descriptor;
|
||||
import org.jcodec.codecs.mpeg4.es.DescriptorParser;
|
||||
import org.jcodec.codecs.mpeg4.es.ES;
|
||||
import org.jcodec.codecs.mpeg4.es.NodeDescriptor;
|
||||
import org.jcodec.codecs.mpeg4.es.SL;
|
||||
import org.jcodec.containers.mp4.boxes.FullBox;
|
||||
import org.jcodec.containers.mp4.boxes.Header;
|
||||
|
||||
public class EsdsBox extends FullBox {
|
||||
private ByteBuffer streamInfo;
|
||||
|
||||
private int objectType;
|
||||
|
||||
private int bufSize;
|
||||
|
||||
private int maxBitrate;
|
||||
|
||||
private int avgBitrate;
|
||||
|
||||
private int trackId;
|
||||
|
||||
public static String fourcc() {
|
||||
return "esds";
|
||||
}
|
||||
|
||||
public EsdsBox(Header atom) {
|
||||
super(atom);
|
||||
}
|
||||
|
||||
protected void doWrite(ByteBuffer out) {
|
||||
super.doWrite(out);
|
||||
if (this.streamInfo != null && this.streamInfo.remaining() > 0) {
|
||||
ArrayList<Descriptor> l = new ArrayList<>();
|
||||
ArrayList<Descriptor> l1 = new ArrayList<>();
|
||||
l1.add(new DecoderSpecific(this.streamInfo));
|
||||
l.add(new DecoderConfig(this.objectType, this.bufSize, this.maxBitrate, this.avgBitrate, l1));
|
||||
l.add(new SL());
|
||||
new ES(this.trackId, l).write(out);
|
||||
} else {
|
||||
ArrayList<Descriptor> l = new ArrayList<>();
|
||||
l.add(new DecoderConfig(this.objectType, this.bufSize, this.maxBitrate, this.avgBitrate, new ArrayList<>()));
|
||||
l.add(new SL());
|
||||
new ES(this.trackId, l).write(out);
|
||||
}
|
||||
}
|
||||
|
||||
public int estimateSize() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
public void parse(ByteBuffer input) {
|
||||
super.parse(input);
|
||||
ES es = (ES)DescriptorParser.read(input);
|
||||
this.trackId = es.getTrackId();
|
||||
DecoderConfig decoderConfig = NodeDescriptor.<DecoderConfig>findByTag(es, DecoderConfig.tag());
|
||||
this.objectType = decoderConfig.getObjectType();
|
||||
this.bufSize = decoderConfig.getBufSize();
|
||||
this.maxBitrate = decoderConfig.getMaxBitrate();
|
||||
this.avgBitrate = decoderConfig.getAvgBitrate();
|
||||
DecoderSpecific decoderSpecific = NodeDescriptor.<DecoderSpecific>findByTag(decoderConfig, DecoderSpecific.tag());
|
||||
this.streamInfo = decoderSpecific.getData();
|
||||
}
|
||||
|
||||
public ByteBuffer getStreamInfo() {
|
||||
return this.streamInfo;
|
||||
}
|
||||
|
||||
public int getObjectType() {
|
||||
return this.objectType;
|
||||
}
|
||||
|
||||
public int getBufSize() {
|
||||
return this.bufSize;
|
||||
}
|
||||
|
||||
public int getMaxBitrate() {
|
||||
return this.maxBitrate;
|
||||
}
|
||||
|
||||
public int getAvgBitrate() {
|
||||
return this.avgBitrate;
|
||||
}
|
||||
|
||||
public int getTrackId() {
|
||||
return this.trackId;
|
||||
}
|
||||
|
||||
public static EsdsBox fromADTS(ADTSParser.Header hdr) {
|
||||
return createEsdsBox(ADTSParser.adtsToStreamInfo(hdr), hdr.getObjectType() << 5, 0, 210750, 133350, 2);
|
||||
}
|
||||
|
||||
public static EsdsBox createEsdsBox(ByteBuffer streamInfo, int objectType, int bufSize, int maxBitrate, int avgBitrate, int trackId) {
|
||||
EsdsBox esds = new EsdsBox(new Header(fourcc()));
|
||||
esds.objectType = objectType;
|
||||
esds.bufSize = bufSize;
|
||||
esds.maxBitrate = maxBitrate;
|
||||
esds.avgBitrate = avgBitrate;
|
||||
esds.trackId = trackId;
|
||||
esds.streamInfo = streamInfo;
|
||||
return esds;
|
||||
}
|
||||
|
||||
public static EsdsBox newEsdsBox() {
|
||||
return new EsdsBox(new Header(fourcc()));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue