//MobiclipDecoder d; public void AddFrame(Bitmap Frame) { if (mEncoder == null) { mEncoder = new MobiEncoder(18, Frame.Width, Frame.Height); //d = new MobiclipDecoder((uint)Frame.Width, (uint)Frame.Height, MobiclipDecoder.MobiclipVersion.Moflex3DS); } byte[] data = mEncoder.EncodeFrame(Frame); //d.Data = data; //d.Offset = 0; //Bitmap test = d.DecodeFrame(); if (data.Length <= (0x1000 - 0x80))//safe margin { WriteDataBlock(); WriteEp(0, data, 0, data.Length, true); WriteEp(0, null, 0, 0); } else { int pos = 0; int left = data.Length; while (left >= (0x1000 - 0x80)) { WriteDataBlock(); WriteEp(0, data, pos, 0x1000 - 0x80, left == (0x1000 - 0x80)); WriteEp(0, null, 0, 0); pos += 0x1000 - 0x80; left -= 0x1000 - 0x80; } if (left > 0) { WriteDataBlock(); WriteEp(0, data, pos, left, true); WriteEp(0, null, 0, 0); } } }
public bool Predict { get; set; }//Just assume previous frame, no compensation data public void SetupDCTs(MobiEncoder Context) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { if (YUseComplex8x8[x + y * 2] && !YUse4x4[x + y * 2]) { int[] Block2 = new int[64]; byte[] CompVals = GetCompvals8x8(YPredictionMode, Context.YDec, X + x * 8, Y + y * 8, Context.Stride, 0); for (int i = 0; i < 64; i++) { Block2[i] = YData8x8[x + y * 2][i] - CompVals[i]; } int[] dct = MobiEncoder.DCT64(Block2); YDCT8x8[x + y * 2] = new int[64]; for (int i = 0; i < 64; i++) { YDCT8x8[x + y * 2][MobiConst.ZigZagTable8x8[i]] = (int)Math.Round(dct[i] / Context.QTable8x8[i]); } int lastnonzero = 0; for (int i = 0; i < 64; i++) { if (YDCT8x8[x + y * 2][i] != 0) lastnonzero = i; } if (lastnonzero == 0 && YDCT8x8[x + y * 2][0] == 0) YUseComplex8x8[x + y * 2] = false; byte[] decresult; if (YUseComplex8x8[x + y * 2]) { int[] realdct = new int[64]; for (int i = 0; i < 64; i++) { realdct[i] = (int)Math.Round(dct[i] / Context.QTable8x8[i]); realdct[i] = realdct[i] * (int)Context.QTable8x8[i]; } decresult = MobiEncoder.IDCT64(realdct, CompVals); } else decresult = CompVals; Set8x8BlockPixels(Context.YDec, X + x * 8, Y + y * 8, Context.Stride, 0, decresult); } else if (YUseComplex8x8[x + y * 2] && YUse4x4[x + y * 2]) { for (int y2 = 0; y2 < 2; y2++) { for (int x2 = 0; x2 < 2; x2++) { if (YUseDCT4x4[x + y * 2][x2 + y2 * 2]) { int[] Block2 = new int[16]; byte[] CompVals = GetCompvals4x4(10 + YPredictionMode, Context.YDec, X + x * 8 + x2 * 4, Y + y * 8 + y2 * 4, Context.Stride, 0); for (int i = 0; i < 16; i++) { Block2[i] = YData4x4[x + y * 2][x2 + y2 * 2][i] - CompVals[i]; } int[] dct = MobiEncoder.DCT16(Block2); YDCT4x4[x + y * 2][x2 + y2 * 2] = new int[16]; for (int i = 0; i < 16; i++) { YDCT4x4[x + y * 2][x2 + y2 * 2][MobiConst.ZigZagTable4x4[i]] = (int)Math.Round(dct[i] / Context.QTable4x4[i]); } int lastnonzero = 0; for (int i = 0; i < 16; i++) { if (YDCT4x4[x + y * 2][x2 + y2 * 2][i] != 0) lastnonzero = i; } if (lastnonzero == 0 && YDCT4x4[x + y * 2][x2 + y2 * 2][0] == 0) YUseDCT4x4[x + y * 2][x2 + y2 * 2] = false; byte[] decresult; if (YUseDCT4x4[x + y * 2][x2 + y2 * 2]) { int[] realdct = new int[16]; for (int i = 0; i < 16; i++) { realdct[i] = (int)Math.Round(dct[i] / Context.QTable4x4[i]); realdct[i] = realdct[i] * (int)Context.QTable4x4[i]; } decresult = MobiEncoder.IDCT16(realdct, CompVals); } else decresult = CompVals; Set4x4BlockPixels(Context.YDec, X + x * 8 + x2 * 4, Y + y * 8 + y2 * 4, Context.Stride, 0, decresult); } } } } } } if (UVUseComplex8x8[0] && !UVUse4x4[0]) { int[] Block2 = new int[64]; byte[] CompVals = GetCompvals8x8(UVPredictionMode, Context.UVDec, X / 2, Y / 2, Context.Stride, 0); for (int i = 0; i < 64; i++) { Block2[i] = UData[i] - CompVals[i]; } int[] dct = MobiEncoder.DCT64(Block2); UVDCT8x8[0] = new int[64]; for (int i = 0; i < 64; i++) { UVDCT8x8[0][MobiConst.ZigZagTable8x8[i]] = (int)Math.Round(dct[i] / Context.QTable8x8[i]); } int lastnonzero = 0; for (int i = 0; i < 64; i++) { if (UVDCT8x8[0][i] != 0) lastnonzero = i; } if (lastnonzero == 0 && UVDCT8x8[0][0] == 0) UVUseComplex8x8[0] = false; byte[] decresult; if (UVUseComplex8x8[0]) { int[] realdct = new int[64]; for (int i = 0; i < 64; i++) { realdct[i] = (int)Math.Round(dct[i] / Context.QTable8x8[i]); realdct[i] = realdct[i] * (int)Context.QTable8x8[i]; } decresult = MobiEncoder.IDCT64(realdct, CompVals); } else decresult = CompVals; Set8x8BlockPixels(Context.UVDec, X / 2, Y / 2, Context.Stride, 0, decresult); } if (UVUseComplex8x8[1] && !UVUse4x4[1]) { int[] Block2 = new int[64]; byte[] CompVals = GetCompvals8x8(UVPredictionMode, Context.UVDec, X / 2, Y / 2, Context.Stride, Context.Stride / 2); for (int i = 0; i < 64; i++) { Block2[i] = VData[i] - CompVals[i]; } int[] dct = MobiEncoder.DCT64(Block2); UVDCT8x8[1] = new int[64]; for (int i = 0; i < 64; i++) { UVDCT8x8[1][MobiConst.ZigZagTable8x8[i]] = (int)Math.Round(dct[i] / Context.QTable8x8[i]); } int lastnonzero = 0; for (int i = 0; i < 64; i++) { if (UVDCT8x8[1][i] != 0) lastnonzero = i; } if (lastnonzero == 0 && UVDCT8x8[1][0] == 0) UVUseComplex8x8[1] = false; byte[] decresult; if (UVUseComplex8x8[1]) { int[] realdct = new int[64]; for (int i = 0; i < 64; i++) { realdct[i] = (int)Math.Round(dct[i] / Context.QTable8x8[i]); realdct[i] = realdct[i] * (int)Context.QTable8x8[i]; } decresult = MobiEncoder.IDCT64(realdct, CompVals); } else decresult = CompVals; Set8x8BlockPixels(Context.UVDec, X / 2, Y / 2, Context.Stride, Context.Stride / 2, decresult); } }
//This analyzer should determine the best block configuration for a macro block (mb) public static void ConfigureBlockY(MobiEncoder Encoder, MacroBlock Block) { List<BlockScore> scores = new List<BlockScore>(); //8x8 if (Block.Y >= 8) { int score = 0; score += GetScore8x8(Block.YData8x8[0], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[0], Encoder.YDec, Block.X, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, 0)); score += GetScore8x8(Block.YData8x8[1], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[1], Encoder.YDec, Block.X + 8, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, 0)); score += GetScore8x8(Block.YData8x8[2], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[2], Encoder.YDec, Block.X, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, 0)); score += GetScore8x8(Block.YData8x8[3], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[3], Encoder.YDec, Block.X + 8, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, 0)); scores.Add(new BlockScore() { BlockConfigId = 0, Score = score }); score = 0; int b = 0; for (int y = 0; y < 16; y += 8) { for (int x = 0; x < 16; x += 8) { int b2 = 0; for (int y2 = 0; y2 < 8; y2 += 4) { for (int x2 = 0; x2 < 8; x2 += 4) { score += GetScore4x4(Block.YData4x4[b][b2], MacroBlock.EncodeDecode4x4Block(Block.YData4x4[b][b2], Encoder.YDec, Block.X + x + x2, Block.Y + y + y2, Encoder.Stride, 0, Encoder.QTable4x4, 10 + 0)); b2++; } } b++; } } scores.Add(new BlockScore() { BlockConfigId = 0 | (1 << 5), Score = score }); } if (Block.X >= 8) { int score = 0; score += GetScore8x8(Block.YData8x8[0], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[0], Encoder.YDec, Block.X, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, 1)); score += GetScore8x8(Block.YData8x8[1], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[1], Encoder.YDec, Block.X + 8, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, 1)); score += GetScore8x8(Block.YData8x8[2], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[2], Encoder.YDec, Block.X, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, 1)); score += GetScore8x8(Block.YData8x8[3], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[3], Encoder.YDec, Block.X + 8, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, 1)); scores.Add(new BlockScore() { BlockConfigId = 1, Score = score }); score = 0; int b = 0; for (int y = 0; y < 16; y += 8) { for (int x = 0; x < 16; x += 8) { int b2 = 0; for (int y2 = 0; y2 < 8; y2 += 4) { for (int x2 = 0; x2 < 8; x2 += 4) { score += GetScore4x4(Block.YData4x4[b][b2], MacroBlock.EncodeDecode4x4Block(Block.YData4x4[b][b2], Encoder.YDec, Block.X + x + x2, Block.Y + y + y2, Encoder.Stride, 0, Encoder.QTable4x4, 10 + 1)); b2++; } } b++; } } scores.Add(new BlockScore() { BlockConfigId = 1 | (1 << 5), Score = score }); } //TODO: block type2 //Block type 3 { int score = 0; score += GetScore8x8(Block.YData8x8[0], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[0], Encoder.YDec, Block.X, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, 3)); score += GetScore8x8(Block.YData8x8[1], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[1], Encoder.YDec, Block.X + 8, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, 3)); score += GetScore8x8(Block.YData8x8[2], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[2], Encoder.YDec, Block.X, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, 3)); score += GetScore8x8(Block.YData8x8[3], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[3], Encoder.YDec, Block.X + 8, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, 3)); scores.Add(new BlockScore() { BlockConfigId = 3, Score = score }); score = 0; int b = 0; for (int y = 0; y < 16; y += 8) { for (int x = 0; x < 16; x += 8) { int b2 = 0; for (int y2 = 0; y2 < 8; y2 += 4) { for (int x2 = 0; x2 < 8; x2 += 4) { score += GetScore4x4(Block.YData4x4[b][b2], MacroBlock.EncodeDecode4x4Block(Block.YData4x4[b][b2], Encoder.YDec, Block.X + x + x2, Block.Y + y + y2, Encoder.Stride, 0, Encoder.QTable4x4, 10 + 3)); b2++; } } b++; } } scores.Add(new BlockScore() { BlockConfigId = 3 | (1 << 5), Score = score }); } if (Block.X >= 8 && Block.Y >= 8) { for (int i = 4; i <= 7; i++) { int score = 0; score += GetScore8x8(Block.YData8x8[0], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[0], Encoder.YDec, Block.X, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, i)); score += GetScore8x8(Block.YData8x8[1], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[1], Encoder.YDec, Block.X + 8, Block.Y, Encoder.Stride, 0, Encoder.QTable8x8, i)); score += GetScore8x8(Block.YData8x8[2], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[2], Encoder.YDec, Block.X, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, i)); score += GetScore8x8(Block.YData8x8[3], MacroBlock.EncodeDecode8x8Block(Block.YData8x8[3], Encoder.YDec, Block.X + 8, Block.Y + 8, Encoder.Stride, 0, Encoder.QTable8x8, i)); scores.Add(new BlockScore() { BlockConfigId = i, Score = score }); score = 0; int b = 0; for (int y = 0; y < 16; y += 8) { for (int x = 0; x < 16; x += 8) { int b2 = 0; for (int y2 = 0; y2 < 8; y2 += 4) { for (int x2 = 0; x2 < 8; x2 += 4) { score += GetScore4x4(Block.YData4x4[b][b2], MacroBlock.EncodeDecode4x4Block(Block.YData4x4[b][b2], Encoder.YDec, Block.X + x + x2, Block.Y + y + y2, Encoder.Stride, 0, Encoder.QTable4x4, 10 + i)); b2++; } } b++; } } scores.Add(new BlockScore() { BlockConfigId = i | (1 << 5), Score = score }); } } BlockScore best = null; foreach (BlockScore s in scores) { if (best == null || s.Score < best.Score || (s.Score == best.Score && (s.BlockConfigId & 0x20) == 0 && (best.BlockConfigId & 0x20) != 0)) best = s; } Block.YPredictionMode = best.BlockConfigId & 0x1F; Block.YUseComplex8x8[0] = true; Block.YUseComplex8x8[1] = true; Block.YUseComplex8x8[2] = true; Block.YUseComplex8x8[3] = true; if (((best.BlockConfigId >> 5) & 1) == 1) { Block.YUse4x4[0] = true; Block.YUse4x4[1] = true; Block.YUse4x4[2] = true; Block.YUse4x4[3] = true; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { Block.YUseDCT4x4[i][j] = true; } } } }
public static int AnalyzeBlockUV(MobiEncoder Encoder, MacroBlock Block) { List<BlockScore> scores = new List<BlockScore>(); //8x8 if (Block.Y >= 8) { int score = 0; score += GetScore8x8(Block.UData, MacroBlock.EncodeDecode8x8Block(Block.UData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, 0, Encoder.QTable8x8, 0)); score += GetScore8x8(Block.VData, MacroBlock.EncodeDecode8x8Block(Block.VData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, Encoder.Stride / 2, Encoder.QTable8x8, 0)); scores.Add(new BlockScore() { BlockConfigId = 0, Score = score }); } if (Block.X >= 8) { int score = 0; score += GetScore8x8(Block.UData, MacroBlock.EncodeDecode8x8Block(Block.UData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, 0, Encoder.QTable8x8, 1)); score += GetScore8x8(Block.VData, MacroBlock.EncodeDecode8x8Block(Block.VData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, Encoder.Stride / 2, Encoder.QTable8x8, 1)); scores.Add(new BlockScore() { BlockConfigId = 1, Score = score }); } //TODO: block type2 //Block type 3 { int score = 0; score += GetScore8x8(Block.UData, MacroBlock.EncodeDecode8x8Block(Block.UData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, 0, Encoder.QTable8x8, 3)); score += GetScore8x8(Block.VData, MacroBlock.EncodeDecode8x8Block(Block.VData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, Encoder.Stride / 2, Encoder.QTable8x8, 3)); scores.Add(new BlockScore() { BlockConfigId = 3, Score = score }); } if (Block.X >= 8 && Block.Y >= 8) { for (int i = 4; i <= 7; i++) { int score = 0; score += GetScore8x8(Block.UData, MacroBlock.EncodeDecode8x8Block(Block.UData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, 0, Encoder.QTable8x8, i)); score += GetScore8x8(Block.VData, MacroBlock.EncodeDecode8x8Block(Block.VData, Encoder.UVDec, Block.X / 2, Block.Y / 2, Encoder.Stride, Encoder.Stride / 2, Encoder.QTable8x8, i)); scores.Add(new BlockScore() { BlockConfigId = i, Score = score }); } } BlockScore best = null; foreach (BlockScore s in scores) { if (best == null || s.Score < best.Score) best = s; } return best.BlockConfigId; }