www in docker support

This commit is contained in:
MaddoScientisto 2026-04-22 18:41:37 +02:00
commit c227fce036
2145 changed files with 399596 additions and 58 deletions

View file

@ -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);
}
}

View file

@ -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 } };
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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()));
}
}