Example #1
0
        public static byte[] Decompress(byte[] input, SnmVideoFrame video, Blocky16Context context)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            if (video == null)
            {
                throw new ArgumentNullException(nameof(video));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (video.Sequence == 0)
            {
                context.Clear(video.BackgroundColor);
            }

            switch (video.SubcodecId)
            {
            case 0:
                Array.Copy(input, 0, context.Buffer0, 0, context.BufferSize);
                break;

            case 1:
                throw new NotImplementedException("SubcodecId 1");

            case 2:
            {
                int hblocks = (int)((video.Height + 7) & 0xFFFFFFF8);
                int wblocks = (int)((video.Width + 7) & 0xFFFFFFF8);

                int inputPos = 0;

                for (int cy = 0; cy < hblocks; cy += 8)
                {
                    for (int cx = 0; cx < wblocks; cx += 8)
                    {
                        Level(8, input, ref inputPos, video, context, cx, cy);
                    }
                }

                break;
            }

            case 3:
                Array.Copy(context.Buffer2, 0, context.Buffer0, 0, context.BufferSize);
                break;

            case 4:
                Array.Copy(context.Buffer1, 0, context.Buffer0, 0, context.BufferSize);
                break;

            case 5:
                for (int pos = 0, inputPos = 0; pos < video.RleOutputSize;)
                {
                    byte code = input[inputPos];
                    inputPos++;

                    int length = (code >> 1) + 1;

                    if ((code & 1) != 0)
                    {
                        byte color = input[inputPos];
                        inputPos++;

                        for (int i = 0; i < length; i++)
                        {
                            context.Buffer0[pos + i] = color;
                        }
                    }
                    else
                    {
                        Array.Copy(input, inputPos, context.Buffer0, pos, length);
                        inputPos += length;
                    }

                    pos += length;
                }

                break;

            case 6:
                for (int pos = 0, inputPos = 0; pos < context.BufferSize; pos += 2)
                {
                    byte index = input[inputPos];
                    inputPos++;

                    ushort color = video.Codebook[index];
                    context.Buffer0[pos]     = (byte)color;
                    context.Buffer0[pos + 1] = (byte)(color >> 8);
                }

                break;

            case 7:
                throw new NotImplementedException("SubcodecId 7");

            case 8:
                for (int pos = 0, inputPos = 0; pos < video.RleOutputSize;)
                {
                    byte code = input[inputPos];
                    inputPos++;

                    int length2 = ((code >> 1) + 1) * 2;

                    if ((code & 1) != 0)
                    {
                        byte index = input[inputPos];
                        inputPos++;

                        ushort color = video.Codebook[index];

                        for (int i = 0; i < length2; i += 2)
                        {
                            context.Buffer0[pos + i]     = (byte)color;
                            context.Buffer0[pos + i + 1] = (byte)(color >> 8);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < length2; i += 2)
                        {
                            byte index = input[inputPos];
                            inputPos++;

                            ushort color = video.Codebook[index];
                            context.Buffer0[pos + i]     = (byte)color;
                            context.Buffer0[pos + i + 1] = (byte)(color >> 8);
                        }
                    }

                    pos += length2;
                }

                break;

            default:
                throw new NotSupportedException();
            }

            byte[] output = context.Buffer0;
            context.RotateBuffers(video.DiffBufferRotateCode);

            return(output);
        }
Example #2
0
        private static void Level(int param, byte[] input, ref int inputPos, SnmVideoFrame video, Blocky16Context context, int cx, int cy)
        {
            byte opcode = input[inputPos];

            inputPos++;

            int stride = video.Width * 2;
            int pos    = cy * stride + cx * 2;

            if (opcode <= 0xF4)
            {
                int x = _motion_vectors[opcode * 2];
                int y = _motion_vectors[opcode * 2 + 1];

                int offset = y * stride + x * 2;

                for (int i = 0; i < param; i++)
                {
                    if (pos + offset + param * 2 > context.BufferSize)
                    {
                        break;
                    }

                    Array.Copy(context.Buffer2, pos + offset, context.Buffer0, pos, param * 2);
                    pos += stride;
                }
            }
            else if (opcode == 0xF5)
            {
                int motion_vector = BitConverter.ToInt16(input, inputPos);
                inputPos += 2;

                int x = motion_vector % video.Width;
                int y = motion_vector / video.Width;

                int offset = y * stride + x * 2;

                for (int i = 0; i < param; i++)
                {
                    if (pos + offset + param * 2 > context.BufferSize)
                    {
                        break;
                    }

                    Array.Copy(context.Buffer2, pos + offset, context.Buffer0, pos, param * 2);
                    pos += stride;
                }
            }
            else if (opcode == 0xF6)
            {
                for (int i = 0; i < param; i++)
                {
                    if (pos + param * 2 > context.BufferSize)
                    {
                        break;
                    }

                    Array.Copy(context.Buffer1, pos, context.Buffer0, pos, param * 2);
                    pos += stride;
                }
            }
            else if (opcode == 0xF7)
            {
                if (param > 2)
                {
                    byte   glyph_index = input[inputPos++];
                    byte   fg_index    = input[inputPos++];
                    byte   bg_index    = input[inputPos++];
                    ushort fg_color    = video.Codebook[fg_index];
                    ushort bg_color    = video.Codebook[bg_index];

                    byte[] glyph;
                    int    glyphWidth;

                    if (param == 8)
                    {
                        glyph      = _glyph8_cb[glyph_index];
                        glyphWidth = 8;
                    }
                    else
                    {
                        glyph      = _glyph4_cb[glyph_index];
                        glyphWidth = 4;
                    }

                    byte bgLow  = (byte)bg_color;
                    byte bgHigh = (byte)(bg_color >> 8);

                    byte fgLow  = (byte)fg_color;
                    byte fgHigh = (byte)(fg_color >> 8);

                    for (int i = 0; i < param; i++)
                    {
                        for (int j = 0; j < param; j++)
                        {
                            if (glyph[i * glyphWidth + j] == 0)
                            {
                                context.Buffer0[pos + j * 2]     = bgLow;
                                context.Buffer0[pos + j * 2 + 1] = bgHigh;
                            }
                            else
                            {
                                context.Buffer0[pos + j * 2]     = fgLow;
                                context.Buffer0[pos + j * 2 + 1] = fgHigh;
                            }
                        }

                        pos += stride;
                    }
                }
                else
                {
                    for (int i = 0; i < 2; i++)
                    {
                        for (int j = 0; j < 2 * 2; j += 2)
                        {
                            byte   index = input[inputPos++];
                            ushort color = video.Codebook[index];
                            context.Buffer0[pos + j]     = (byte)color;
                            context.Buffer0[pos + j + 1] = (byte)(color >> 8);
                        }

                        pos += stride;
                    }
                }
            }
            else if (opcode == 0xF8)
            {
                if (param > 2)
                {
                    byte   glyph_index = input[inputPos++];
                    ushort fg_color    = BitConverter.ToUInt16(input, inputPos);
                    inputPos += 2;
                    ushort bg_color = BitConverter.ToUInt16(input, inputPos);
                    inputPos += 2;

                    byte[] glyph;
                    int    glyphWidth;

                    if (param == 8)
                    {
                        glyph      = _glyph8_cb[glyph_index];
                        glyphWidth = 8;
                    }
                    else
                    {
                        glyph      = _glyph4_cb[glyph_index];
                        glyphWidth = 4;
                    }

                    byte bgLow  = (byte)bg_color;
                    byte bgHigh = (byte)(bg_color >> 8);

                    byte fgLow  = (byte)fg_color;
                    byte fgHigh = (byte)(fg_color >> 8);

                    for (int i = 0; i < param; i++)
                    {
                        for (int j = 0; j < param; j++)
                        {
                            if (glyph[i * glyphWidth + j] == 0)
                            {
                                context.Buffer0[pos + j * 2]     = bgLow;
                                context.Buffer0[pos + j * 2 + 1] = bgHigh;
                            }
                            else
                            {
                                context.Buffer0[pos + j * 2]     = fgLow;
                                context.Buffer0[pos + j * 2 + 1] = fgHigh;
                            }
                        }

                        pos += stride;
                    }
                }
                else
                {
                    for (int i = 0; i < 2; i++)
                    {
                        for (int j = 0; j < 2 * 2; j += 2)
                        {
                            context.Buffer0[pos + j]     = input[inputPos++];
                            context.Buffer0[pos + j + 1] = input[inputPos++];
                        }

                        pos += stride;
                    }
                }
            }
            else if (opcode >= 0xF9 && opcode <= 0xFC)
            {
                ushort color = video.SmallCodebook[opcode - 0xF9];

                byte lowColor  = (byte)color;
                byte highColor = (byte)(color >> 8);

                for (int i = 0; i < param; i++)
                {
                    for (int j = 0; j < param * 2; j += 2)
                    {
                        context.Buffer0[pos + j]     = lowColor;
                        context.Buffer0[pos + j + 1] = highColor;
                    }

                    pos += stride;
                }
            }
            else if (opcode == 0xFD)
            {
                byte   index = input[inputPos++];
                ushort color = video.Codebook[index];

                byte lowColor  = (byte)color;
                byte highColor = (byte)(color >> 8);

                for (int i = 0; i < param; i++)
                {
                    for (int j = 0; j < param * 2; j += 2)
                    {
                        context.Buffer0[pos + j]     = lowColor;
                        context.Buffer0[pos + j + 1] = highColor;
                    }

                    pos += stride;
                }
            }
            else if (opcode == 0xFE)
            {
                ushort color = BitConverter.ToUInt16(input, inputPos);
                inputPos += 2;

                byte lowColor  = (byte)color;
                byte highColor = (byte)(color >> 8);

                for (int i = 0; i < param; i++)
                {
                    for (int j = 0; j < param * 2; j += 2)
                    {
                        context.Buffer0[pos + j]     = lowColor;
                        context.Buffer0[pos + j + 1] = highColor;
                    }

                    pos += stride;
                }
            }
            else if (opcode == 0xFF)
            {
                if (param > 2)
                {
                    int nextLevel = param / 2;
                    Level(nextLevel, input, ref inputPos, video, context, cx, cy);
                    Level(nextLevel, input, ref inputPos, video, context, cx + nextLevel, cy);
                    Level(nextLevel, input, ref inputPos, video, context, cx, cy + nextLevel);
                    Level(nextLevel, input, ref inputPos, video, context, cx + nextLevel, cy + nextLevel);
                }
                else
                {
                    for (int i = 0; i < 2; i++)
                    {
                        for (int j = 0; j < 2 * 2; j += 2)
                        {
                            context.Buffer0[pos + j]     = input[inputPos++];
                            context.Buffer0[pos + j + 1] = input[inputPos++];
                        }

                        pos += stride;
                    }
                }
            }
        }