Пример #1
0
 public MobiEncoder(int Quantizer, int Width, int Height)
 {
     if (Width % 16 != 0 || Height % 16 != 0) throw new Exception();
     if (Quantizer < 0xC) Quantizer = 0xC;
     if (Quantizer > 0x34) Quantizer = 0x34;
     this.Quantizer = Quantizer;
     this.Width = Width;
     this.Height = Height;
     Stride = 1024;
     if (Width <= 256) Stride = 256;
     else if (Width <= 512) Stride = 512;
     YDec = new byte[Stride * Height];
     UVDec = new byte[Stride * Height / 2];
     MacroBlocks = new MacroBlock[Height / 16][];
     for (int i = 0; i < Height / 16; i++)
     {
         MacroBlocks[i] = new MacroBlock[Width / 16];
     }
     LastFrameType = FrameType.None;
     SetupQuantizationTables();
 }
Пример #2
0
 private unsafe byte[] EncodePrediction(Bitmap Frame)
 {
     //We'll just look if there are blocks that are 100% the same first
     BitmapData d = Frame.LockBits(new Rectangle(0, 0, Frame.Width, Frame.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
     BitmapData prev = PastFrames[1].LockBits(new Rectangle(0, 0, Frame.Width, Frame.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
     for (int y = 0; y < Height; y += 16)
     {
         for (int x = 0; x < Width; x += 16)
         {
             MacroBlocks[y / 16][x / 16] = new MacroBlock(d, x, y);
             bool same = true;
             for (int y2 = 0; y2 < 16; y2++)
             {
                 ulong* pA = (ulong*)(((byte*)d.Scan0) + (y + y2) * d.Stride + x * 4);
                 ulong* pB = (ulong*)(((byte*)prev.Scan0) + (y + y2) * prev.Stride + x * 4);
                 for (int x2 = 0; x2 < 16; x2+=2)
                 {
                     ulong color = *pA++;
                     ulong color2 = *pB++;
                     if (color != color2)
                     {
                         same = false;
                         break;
                     }
                 }
                 if (!same) break;
             }
             if (same) MacroBlocks[y / 16][x / 16].Predict = true;
             else
             {
                 Analyzer.ConfigureBlockY(this, MacroBlocks[y / 16][x / 16]);
                 int blocktype2 = Analyzer.AnalyzeBlockUV(this, MacroBlocks[y / 16][x / 16]);
                 MacroBlocks[y / 16][x / 16].UVPredictionMode = blocktype2;
                 MacroBlocks[y / 16][x / 16].UVUseComplex8x8[0] = true;
                 MacroBlocks[y / 16][x / 16].UVUseComplex8x8[1] = true;
                 MacroBlocks[y / 16][x / 16].SetupDCTs(this);
             }
         }
     }
     Frame.UnlockBits(d);
     PastFrames[1].UnlockBits(prev);
     BitWriter b = new BitWriter();
     b.WriteBits(0, 1);//Interframe
     b.WriteVarIntSigned(0);
     for (int y = 0; y < Height; y += 16)
     {
         for (int x = 0; x < Width; x += 16)
         {
             MacroBlock curblock = MacroBlocks[y / 16][x / 16];
             if (curblock.Predict)
             {
                 b.WriteBits(1, 1);
                 b.WriteVarIntUnsigned(0);
             }
             else
             {
                 b.WriteBits(0xE >> 1, 5);
                 EncodeBlockIntra(curblock, b);
             }
         }
     }
     b.WriteBits(0, 16);
     b.Flush();
     byte[] result = b.ToArray();
     return result;
 }
Пример #3
0
 private void EncodeBlockIntra(MacroBlock Block, BitWriter b)
 {
     uint dctmask =
                (Block.YUseComplex8x8[0] ? 1u : 0) |
                ((Block.YUseComplex8x8[1] ? 1u : 0) << 1) |
                ((Block.YUseComplex8x8[2] ? 1u : 0) << 2) |
                ((Block.YUseComplex8x8[3] ? 1u : 0) << 3) |
                ((Block.UVUseComplex8x8[0] ? 1u : 0) << 4) |
                ((Block.UVUseComplex8x8[1] ? 1u : 0) << 5);
     b.WriteVarIntUnsigned(REV_byte_115FC4[dctmask]);
     b.WriteBits((uint)Block.YPredictionMode, 3);//Block type
     for (int y2 = 0; y2 < 2; y2++)
     {
         for (int x2 = 0; x2 < 2; x2++)
         {
             if (Block.YUseComplex8x8[x2 + y2 * 2] && !Block.YUse4x4[x2 + y2 * 2])
             {
                 b.WriteBits(1, 1);//Don't use 4x4 blocks
                 EncodeDCT(Block.YDCT8x8[x2 + y2 * 2], 0, b);
             }
             else if (Block.YUseComplex8x8[x2 + y2 * 2] && Block.YUse4x4[x2 + y2 * 2])
             {
                 uint dctmask2 =
                     (Block.YUseDCT4x4[x2 + y2 * 2][0] ? 1u : 0) |
                     ((Block.YUseDCT4x4[x2 + y2 * 2][1] ? 1u : 0) << 1) |
                     ((Block.YUseDCT4x4[x2 + y2 * 2][2] ? 1u : 0) << 2) |
                     ((Block.YUseDCT4x4[x2 + y2 * 2][3] ? 1u : 0) << 3);
                 b.WriteVarIntUnsigned(REV_byte_1164F4[dctmask2]);
                 for (int y3 = 0; y3 < 2; y3++)
                 {
                     for (int x3 = 0; x3 < 2; x3++)
                     {
                         if (Block.YUseDCT4x4[x2 + y2 * 2][x3 + y3 * 2])
                             EncodeDCT(Block.YDCT4x4[x2 + y2 * 2][x3 + y3 * 2], 0, b);
                     }
                 }
             }
         }
     }
     b.WriteBits((uint)Block.UVPredictionMode, 3);//Block type
     for (int q = 0; q < 2; q++)
     {
         if (Block.UVUseComplex8x8[q] && !Block.UVUse4x4[q])
         {
             b.WriteBits(1, 1);//Don't use 4x4 blocks
             EncodeDCT(Block.UVDCT8x8[q], 0, b);
         }
     }
 }
Пример #4
0
        private byte[] EncodeIntra(Bitmap Frame)
        {
            BitmapData d = Frame.LockBits(new Rectangle(0, 0, Frame.Width, Frame.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            //Setup the macroblocks
            for (int y = 0; y < Height; y += 16)
            {
                for (int x = 0; x < Width; x += 16)
                {
                    MacroBlocks[y / 16][x / 16] = new MacroBlock(d, x, y);
                    Analyzer.ConfigureBlockY(this, MacroBlocks[y / 16][x / 16]);
                    int blocktype2 = Analyzer.AnalyzeBlockUV(this, MacroBlocks[y / 16][x / 16]);
                    MacroBlocks[y / 16][x / 16].UVPredictionMode = blocktype2;
                    MacroBlocks[y / 16][x / 16].UVUseComplex8x8[0] = true;
                    MacroBlocks[y / 16][x / 16].UVUseComplex8x8[1] = true;
                    MacroBlocks[y / 16][x / 16].SetupDCTs(this);
                }
            }
            Frame.UnlockBits(d);
            BitWriter b = new BitWriter();
            b.WriteBits(1, 1);//Interframe
            b.WriteBits(1, 1);//YUV format
            //TODO: determine table (when we actually use it...)
            b.WriteBits(0, 1);//Table
            b.WriteBits((uint)Quantizer, 6);//Quantizer
            for (int y = 0; y < Height; y += 16)
            {
                for (int x = 0; x < Width; x += 16)
                {
                    MacroBlock curblock = MacroBlocks[y / 16][x / 16];

                    //Todo use predicted prediction mode
                    /*if (x > 0 && y > 0)
                    {
                        int r12 = MacroBlocks[y / 16 - 1][x / 16].YPredictionMode;
                        int r6 = MacroBlocks[y / 16][x / 16 - 1].YPredictionMode;
                        if (r12 > r6) r12 = r6;
                        if (r12 == 9) r12 = 3;
                        r6 = r3 >> 28;
                        if (r6 >= r12) r6++;
                        int r7;
                        if (r6 < 9)
                        {
                            r12 = r6;
                            r7 = 4;
                        }
                        else r7 = 1;
                        r3 <<= r7;
                        nrBitsRemaining -= r7;
                    }*/


                    b.WriteBits(0, 1);//Func
                    EncodeBlockIntra(curblock, b);
                }
            }
            b.WriteBits(0, 16);
            b.Flush();
            byte[] result = b.ToArray();
            return result;
        }
Пример #5
0
 //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;
             }
         }
     }
 }
Пример #6
0
 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;
 }