All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codeminders.ardrone.video.BufferedVideoImage Maven / Gradle / Ivy

The newest version!
package com.codeminders.ardrone.video;

import java.nio.ByteBuffer;

// Copyright (C) 2007-2011, PARROT SA, all rights reserved.

// DISCLAIMER
// The APIs is provided by PARROT and contributors "AS IS" and any express or
// implied warranties, including, but not limited to, the implied warranties of
// merchantability
// and fitness for a particular purpose are disclaimed. In no event shall PARROT
// and contributors be liable for any direct, indirect, incidental, special,
// exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or business
// interruption) however
// caused and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of the use
// of this software, even if advised of the possibility of such damage.

// Author : Daniel Schmidt
// Publishing date : 2011-07-15
// based on work by : Wilke Jansoone

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions, the disclaimer and the original author of the source
// code.
// - Neither the name of the PixVillage Team, nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.

public class BufferedVideoImage
{
    private static final int BLOCK_WIDTH = 8;
    private static final int CIF_WIDTH = 88;
    private static final int CIG_HEIGHT = 72;

    private static final int VGA_WIDTH = 160;
    private static final int VGA_HEIGHT = 120;

    private static final int TABLE_QUANTIZATION_MODE = 31;

    private static final int FIX_0_298631336 = 2446;
    private static final int FIX_0_390180644 = 3196;
    private static final int FIX_0_541196100 = 4433;
    private static final int FIX_0_765366865 = 6270;
    private static final int FIX_0_899976223 = 7373;
    private static final int FIX_1_175875602 = 9633;
    private static final int FIX_1_501321110 = 12299;
    private static final int FIX_1_847759065 = 15137;
    private static final int FIX_1_961570560 = 16069;
    private static final int FIX_2_053119869 = 16819;
    private static final int FIX_2_562915447 = 20995;
    private static final int FIX_3_072711026 = 25172;

    private static final int BITS = 13;
    private static final int PASS1_BITS = 1;
    private static final int F1 = BITS - PASS1_BITS - 1;
    private static final int F2 = BITS - PASS1_BITS;
    private static final int F3 = BITS + PASS1_BITS + 3;

    /**
     * 176px x 144px
     */
    private static final int CIF = 1;

    /**
     * 320px x 240px
     */
    private static final int QVGA = 2;

    private static final short[] ZIGZAG_POSITIONS = 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, };

    // Cfr. Handbook of Data Compression - Page 529
    // David Salomon
    // Giovanni Motta

    private static final short[] QUANTIZER_VALUES = new short[] { 3, 5, 7, 9, 11, 13, 15, 17, 5, 7, 9, 11, 13, 15, 17, 19, 7, 9, 11, 13, 15, 17, 19, 21, 9, 11, 13, 15, 17, 19, 21, 23, 11, 13, 15, 17, 19, 21, 23, 25, 13, 15, 17, 19, 21, 23, 25, 27, 15, 17, 19, 21, 23, 25, 27, 29, 17, 19, 21, 23, 25, 27, 29, 31 };

    static byte[] CLZLUT = new byte[] { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    private static final int[] CROMA_QUADRANT_OFFSETS = new int[] { 0, 4, 32, 36 };

    private short[] dataBlockBuffer = new short[64];

    private int streamField;
    private int streamFieldBitIndex;
    private int streamIndex;
    private int sliceCount;
    private boolean pictureComplete;
    private int pictureFormat;
    private int resolution;
    private int pictureType;
    private int quantizerMode;
    private int frameIndex;
    private int sliceIndex;
    private int blockCount;
    private int width;
    private int height;

    /**
     * Length of one row of pixels in the destination image in bytes.
     */
    private int pixelRowSize;
    private ByteBuffer imageStream;
    private byte[] imageStreamByteArray;
    private int imageStreamCapacity;
    private ImageSlice imageSlice;
    private int[] javaPixelData;

    /* Data used by inverseTransform */
    private int[] workSpace = new int[64];
    
    /* Data used by decodeFieldBytes */
    private int run;
    private int level;
    private boolean last;
    
    /*
     * Convert a stream to an image
     * 
     * Takes in bytes representing an image and renders the image after decoding the bytes.
     * 
     * @param ByteBuffer stream
     *      A ByteBuffer full of the bytes that represent the image to be decoded.
     */
    public void addImageStream(ByteBuffer stream)
    {
        imageStream = stream;
        imageStreamByteArray = imageStream.array();
        imageStreamCapacity = imageStream.capacity();
        processStream();
    }
    
    /*
     * Adjusts the stream to fix the start of the actual data
     * 
     * Prepares the stream data for reading the header, by adjusting byte values
     */
    private void alignStreamData()
    {
        int alignedLength;
        int actualLength;

        actualLength = streamFieldBitIndex;

        if (actualLength > 0)
        {
            alignedLength = (actualLength & ~7);
            if (alignedLength != actualLength)
            {
                alignedLength += 0x08;
                streamField <<= (alignedLength - actualLength);
                streamFieldBitIndex = alignedLength;
            }
        }
    }
    
    /*
     * Constructs the image from byte values
     * 
     * From the blocks in the image, uses the byte data which is converted to rgb
     * and applies various transformations, like saturation, to adjust for the
     * image creation. See comments above peekStreamData for more information on
     * how the image bytes are laid out and decoded then put together to form the 
     * image slice.
     */
    private void composeImageSlice()
    {
        int u, ug, ub;
        int v, vg, vr;
        int r, g, b;

        int lumaElementIndex1 = 0;
        int lumaElementIndex2 = 0;
        int chromaOffset = 0;

        int dataIndex1 = 0;
        int dataIndex2 = 0;

        int lumaElementValue1 = 0;
        int lumaElementValue2 = 0;
        int chromaBlueValue = 0;
        int chromaRedValue = 0;

        int x = 0;

        int[] pixelDataQuadrantOffsets = new int[] { 0, BLOCK_WIDTH, width * BLOCK_WIDTH, (width * BLOCK_WIDTH) + BLOCK_WIDTH };
        short[] mbDBArr;
        short[][] dbArr;
        int imageDataOffset = (sliceIndex - 1) * width * 16;

        for (MacroBlock macroBlock : imageSlice.MacroBlocks)
        {
            dbArr = macroBlock.DataBlocks;
            for (int verticalStep = 0; verticalStep < BLOCK_WIDTH / 2; verticalStep++)
            {
                chromaOffset = verticalStep * BLOCK_WIDTH;
                lumaElementIndex1 = verticalStep * BLOCK_WIDTH * 2;
                lumaElementIndex2 = lumaElementIndex1 + BLOCK_WIDTH;

                dataIndex1 = imageDataOffset + (2 * verticalStep * width);
                dataIndex2 = dataIndex1 + width;

                for (int horizontalStep = 0; horizontalStep < BLOCK_WIDTH / 2; horizontalStep++)
                {
                    for (int quadrant = 0; quadrant < 4; quadrant++)
                    {
                        int uvg;
                        int chromaIndex = chromaOffset + CROMA_QUADRANT_OFFSETS[quadrant] + horizontalStep;
                        chromaBlueValue = dbArr[4][chromaIndex];
                        chromaRedValue = dbArr[5][chromaIndex];
                        mbDBArr = dbArr[quadrant];

                        u = chromaBlueValue - 128;
                        ug = 88 * u;
                        ub = 454 * u;

                        v = chromaRedValue - 128;
                        vg = 183 * v;
                        vr = 359 * v;

                        uvg = ug + vg;
                        
                        for (int pixel = 0; pixel < 2; pixel++)
                        {
                            int deltaIndex = 2 * horizontalStep + pixel;
                            lumaElementValue1 = mbDBArr[lumaElementIndex1 + deltaIndex] << 8;
                            lumaElementValue2 = mbDBArr[lumaElementIndex2 + deltaIndex] << 8;
                            x = lumaElementValue1 + vr;
                            if (x < 0)
                            {
                                r = 0;
                            } else
                            {
                                x >>= 8;
                                r = (x > 0xFF) ? 0xFF : x;
                            }
                            x = lumaElementValue1 - uvg;
                            if (x < 0)
                            {
                                g = 0;
                            } else
                            {
                                x >>= 8;
                                g = (x > 0xFF) ? 0xFF : x;
                            }
                            x = lumaElementValue1 + ub;
                            if (x < 0)
                            {
                                b = 0;
                            } else
                            {
                                x >>= 8;
                                b = (x > 0xFF) ? 0xFF : x;
                            }
                            javaPixelData[dataIndex1 + pixelDataQuadrantOffsets[quadrant] + deltaIndex] = ((r << 16) | (g << 8) | b);
                            
                            x = lumaElementValue2 + vr;
                            if (x < 0)
                            {
                                r = 0;
                            } else
                            {
                                x >>= 8;
                                r = (x > 0xFF) ? 0xFF : x;
                            }
                            x = lumaElementValue2 - uvg;
                            if (x < 0)
                            {
                                g = 0;
                            } else
                            {
                                x >>= 8;
                                g = (x > 0xFF) ? 0xFF : x;
                            }
                            x = lumaElementValue2 + ub;
                            if (x < 0)
                            {
                                b = 0;
                            } else
                            {
                                x >>= 8;
                                b = (x > 0xFF) ? 0xFF : x;
                            }
                            javaPixelData[dataIndex2 + pixelDataQuadrantOffsets[quadrant] + deltaIndex] = ((r << 16) | (g << 8) | b);
                        }
                    }
                }
            }

            imageDataOffset += 16;
        }
    }

    /*
     * Decompresses the byte data into a uncompressed format which can be parsed easier
     * 
     * Decodes the byte stream data by combining the two fields, run fields and level fields
     * which are used to compress data.
     * 
     * @param int[] run
     *      Wrapper for an int. Used to calculate run value
     * 
     * @param int[] level
     *      Wrapper for an int. Used to calculate run value with a sign
     * 
     * @param boolean[]last
     *      Wrapper for a boolean. Used to determine if this is the end of the stream or not.
     */
    private void decodeFieldBytes()
    {
        int streamCode;
        int streamLength;
        int zeroCount;
        int temp;
        int sign;

        // Use the RLE and Huffman dictionaries to understand this code
        // fragment. You can find
        // them in the developers guide on page 34.
        // The bits in the data are actually composed of two kinds of fields:
        // - run fields - this field contains information on the number of
        // consecutive zeros.
        // - level fields - this field contains the actual non zero value which
        // can be negative or positive.
        // First we extract the run field info and then the level field info.

        // NOTE: explicit inline expansion done here; simplified quite a bit
        //streamCode = peekStreamData(imageStream, 32);
        
        if ((streamFieldBitIndex > 0) && streamIndex < (imageStreamCapacity >> 2))
        {
            temp =  ((imageStreamByteArray[streamIndex * 4 + 0] & 0xFF) | 
                    ((imageStreamByteArray[streamIndex * 4 + 1] & 0xFF) << 8) | 
                    ((imageStreamByteArray[streamIndex * 4 + 2] & 0xFF) << 16) | 
                    ((imageStreamByteArray[streamIndex * 4 + 3] & 0xFF) << 24));

            streamCode =    ((streamField >>> streamFieldBitIndex) << streamFieldBitIndex) | 
                            (temp >>> (32 - streamFieldBitIndex));          
        }
        else
        {
            streamCode = streamField;
        }
        
        // Determine number of consecutive zeros in zig zag. (a.k.a
        // 'run' field info)

        // Suppose we have following bit sequence:
        // 00001111.....
        // 1 - Count the number of leading zeros -> 4
        // Coarse value lookup is thus 00001
        // 2 - Lookup the additional value, for coarse value 00001 this is 3
        // addtional bits
        // 3 - Calculate value of run, for coarse value 00001 this is (111) + 8

        zeroCount = CLZLUT[streamCode >>> 24];
        if (zeroCount == 8)
        {
            zeroCount += CLZLUT[(streamCode >>> 16) & 0xFF];
            if (zeroCount == 16)
            {
                zeroCount += CLZLUT[(streamCode >>> 8) & 0xFF];
                if (zeroCount == 24)
                {
                    zeroCount += CLZLUT[streamCode & 0xFF];
                }
            }
        }

        if (zeroCount > 1)
        {
            temp = (streamCode << (zeroCount + 1)) >>> (32 - (zeroCount - 1));
            // (2)
            // ->
            // shift right to determine the additional bits (number of
            // additional bits is zerocount -1)
            
            // NOTE: earlier operations on streamCode and streamLength have been
            // included in operations below, comments may be inaccurate
            
            streamCode <<= 2*zeroCount; // - shift all of the run bits out
                                            // of the way so the first bit
                                            // points to the first bit of the
                                            // level field
            streamLength = 2*zeroCount; // - position bit pointer to keep tack
                                            // off how many bits to consume
                                            // later on the stream
            run = temp + (1 << (zeroCount - 1)); // - (3) -> calculate run
                                                    // value
        } else
        {
            streamCode <<= (zeroCount + 1); // - (2) -> shift left to get
            // rid of the coarse value
            streamLength = zeroCount + 1; // - position bit pointer to keep track
            // off how many bits to consume later on
            // the stream.

            run = zeroCount;
        }

        // Determine non zero value. (a.k.a 'level' field info)

        // Suppose we have following bit sequence:
        // 000011111.....
        // 1 - Count the number of leading zeros -> 4
        // Coarse value lookup is thus 00001
        // 2 - Lookup the additional value, for coarse value 00001 this is 4
        // addtional bits (last bit is sign bit)
        // 3 - Calculate value of run, for coarse value 00001 this is (xxx) + 8,
        // multiply by sign

        zeroCount = CLZLUT[streamCode >>> 24];
        if (zeroCount == 8)
        {
            zeroCount += CLZLUT[(streamCode >>> 16) & 0xFF];
            if (zeroCount == 16)
            {
                zeroCount += CLZLUT[(streamCode >>> 8) & 0xFF];
                if (zeroCount == 24)
                {
                    zeroCount += CLZLUT[streamCode & 0xFF];
                }
            }
        }

        if (zeroCount == 1)
        {
            // NOTE: earlier operations on streamCode and streamLength have been
            // included in operations below, comments may be inaccurate
            
            streamCode <<= 2;   // - (1)
            streamLength += 2;  // - position bit pointer to keep track
                                // off how many bits to consume later on the stream

            // If coarse value is 01 according to the Huffman dictionary this
            // means EOB, so there is no run and level and we indicate this 
            // by setting last to true (run and level do not need any clearing 
            // here because they are ignored)
            last = true;
        } else
        {
            if (zeroCount == 0)
            {
                // NOTE: earlier operations on streamCode and streamLength have been
                // included in operations below, comments may be inaccurate
                
                streamLength += 2;                      // - position bit pointer to keep track
                                                        // off how many bits to consume later on the stream
                streamCode = (streamCode << 1) >>> 31;  // - (2) -> shift right
                
                temp = (streamCode >>> 1) + 1;          // take into account that last bit is sign, 
                                                        // so shift it out of the way
            }
            else
            {
                // NOTE: earlier operations on streamCode and streamLength have been
                // included in operations below, comments may be inaccurate
                
                streamLength += 2*zeroCount + 1;    // - position bit pointer to keep track
                                                    // off how many bits to consume later on the stream
                streamCode = (streamCode << (zeroCount + 1)) >>> (32 - zeroCount); // - (2) -> shift right

                temp = streamCode >>> 1;                // take into account that last bit is sign,
                                                        // so shift it out of the way
                temp += (int) (1 << (zeroCount - 1));   // - (3) -> calculate run value without sign
            }

            // sign = (sbyte)(streamCode & 1); // determine sign, last bit is sign
            sign = streamCode & 1; // determine sign, last bit is sign

            level = (sign == 1) ? -temp : temp; // - (3) -> calculate run
            // value with sign
            last = false;
        }

        readStreamDataInt(streamLength);
    }

    /*
     * Decodes the field bytes within this block.
     * 
     * Reads the stream 
     */
    private void getBlockBytes(boolean acCoefficientsAvailable)
    {
        int zigZagPosition = 0;
        int matrixPosition = 0;

        for (int i = 0; i < dataBlockBuffer.length; i++)
            dataBlockBuffer[i] = 0;

        int dcCoefficientTemp = readStreamDataInt(10);

        if (quantizerMode == TABLE_QUANTIZATION_MODE)
        {
            dataBlockBuffer[0] = (short) (dcCoefficientTemp * QUANTIZER_VALUES[0]);

            if (acCoefficientsAvailable)
            {
                decodeFieldBytes();

                while (!last)
                {
                    zigZagPosition += run + 1;
                    matrixPosition = ZIGZAG_POSITIONS[zigZagPosition];
                    level *= QUANTIZER_VALUES[matrixPosition];
                    dataBlockBuffer[matrixPosition] = (short) level;
                    decodeFieldBytes();
                }
            }
        } else
        {
            // Currently not implemented.
            throw new RuntimeException("ant quantizer mode is not yet implemented.");
        }
    }

    public int getFrameIndex() 
    {
        return frameIndex;
    }

    public int getHeight()
    {
        return height;
    }

    public int[] getJavaPixelData()
    {
        return javaPixelData;
    }

    public int getPictureType()
    {
        return pictureType;
    }

    public int getPixelRowSize()
    {
        return pixelRowSize;
    }

    public int getSliceCount()
    {
        return sliceCount;
    }

    public int getWidth()
    {
        return width;
    }

    void inverseTransform(int macroBlockIndex, int dataBlockIndex)
    {
        int z1, z2, z3, z4, z5;
        int tmp0, tmp1, tmp2, tmp3;
        int tmp10, tmp11, tmp12, tmp13;

        int pointer;
        
        short[] blockArray = imageSlice.MacroBlocks[macroBlockIndex].DataBlocks[dataBlockIndex];

        for (pointer = 0; pointer < 8; pointer++)
        {
            if (dataBlockBuffer[pointer + 8] == 0 && dataBlockBuffer[pointer + 16] == 0 && dataBlockBuffer[pointer + 24] == 0 && dataBlockBuffer[pointer + 32] == 0 && dataBlockBuffer[pointer + 40] == 0 && dataBlockBuffer[pointer + 48] == 0 && dataBlockBuffer[pointer + 56] == 0)
            {
                int dcValue = dataBlockBuffer[pointer] << PASS1_BITS;

                workSpace[pointer + 0] = dcValue;
                workSpace[pointer + 8] = dcValue;
                workSpace[pointer + 16] = dcValue;
                workSpace[pointer + 24] = dcValue;
                workSpace[pointer + 32] = dcValue;
                workSpace[pointer + 40] = dcValue;
                workSpace[pointer + 48] = dcValue;
                workSpace[pointer + 56] = dcValue;
            } else
            {
                z2 = dataBlockBuffer[pointer + 16];
                z3 = dataBlockBuffer[pointer + 48];

                z1 = (z2 + z3) * FIX_0_541196100;
                tmp2 = z1 + z3 * -FIX_1_847759065;
                tmp3 = z1 + z2 * FIX_0_765366865;

                z2 = dataBlockBuffer[pointer];
                z3 = dataBlockBuffer[pointer + 32];

                tmp0 = (z2 + z3) << BITS;
                tmp1 = (z2 - z3) << BITS;

                tmp10 = tmp0 + tmp3;
                tmp13 = tmp0 - tmp3;
                tmp11 = tmp1 + tmp2;
                tmp12 = tmp1 - tmp2;

                tmp0 = dataBlockBuffer[pointer + 56];
                tmp1 = dataBlockBuffer[pointer + 40];
                tmp2 = dataBlockBuffer[pointer + 24];
                tmp3 = dataBlockBuffer[pointer + 8];

                z1 = tmp0 + tmp3;
                z2 = tmp1 + tmp2;
                z3 = tmp0 + tmp2;
                z4 = tmp1 + tmp3;
                z5 = (z3 + z4) * FIX_1_175875602;

                tmp0 = tmp0 * FIX_0_298631336;
                tmp1 = tmp1 * FIX_2_053119869;
                tmp2 = tmp2 * FIX_3_072711026;
                tmp3 = tmp3 * FIX_1_501321110;
                z1 = z1 * -FIX_0_899976223;
                z2 = z2 * -FIX_2_562915447;
                z3 = z3 * -FIX_1_961570560;
                z4 = z4 * -FIX_0_390180644;

                z3 += z5;
                z4 += z5;

                tmp0 += z1 + z3;
                tmp1 += z2 + z4;
                tmp2 += z2 + z3;
                tmp3 += z1 + z4;

                workSpace[pointer + 0] = ((tmp10 + tmp3 + (1 << F1)) >> F2);
                workSpace[pointer + 56] = ((tmp10 - tmp3 + (1 << F1)) >> F2);
                workSpace[pointer + 8] = ((tmp11 + tmp2 + (1 << F1)) >> F2);
                workSpace[pointer + 48] = ((tmp11 - tmp2 + (1 << F1)) >> F2);
                workSpace[pointer + 16] = ((tmp12 + tmp1 + (1 << F1)) >> F2);
                workSpace[pointer + 40] = ((tmp12 - tmp1 + (1 << F1)) >> F2);
                workSpace[pointer + 24] = ((tmp13 + tmp0 + (1 << F1)) >> F2);
                workSpace[pointer + 32] = ((tmp13 - tmp0 + (1 << F1)) >> F2);

            }
        }

        for (pointer = 0; pointer < 64; pointer += 8)
        {
            z2 = workSpace[pointer + 2];
            z3 = workSpace[pointer + 6];

            z1 = (z2 + z3) * FIX_0_541196100;
            tmp2 = z1 + z3 * -FIX_1_847759065;
            tmp3 = z1 + z2 * FIX_0_765366865;

            z1 = workSpace[pointer];
            z2 = workSpace[pointer + 4];

            tmp0 = (z1 + z2) << BITS;
            tmp1 = (z1 - z2) << BITS;

            tmp10 = tmp0 + tmp3;
            tmp13 = tmp0 - tmp3;
            tmp11 = tmp1 + tmp2;
            tmp12 = tmp1 - tmp2;

            tmp3 = workSpace[pointer + 1];
            tmp2 = workSpace[pointer + 3];
            tmp1 = workSpace[pointer + 5];
            tmp0 = workSpace[pointer + 7];

            z1 = (tmp0 + tmp3) * -FIX_0_899976223;
            z2 = (tmp1 + tmp2) * -FIX_2_562915447;
            z3 = tmp0 + tmp2;
            z4 = tmp1 + tmp3;

            z5 = (z3 + z4) * FIX_1_175875602;

            z3 = (z3 * -FIX_1_961570560) + z5;
            z4 = (z4 * -FIX_0_390180644) + z5;

            tmp0 = (tmp0 * FIX_0_298631336) + z1 + z3;
            tmp1 = (tmp1 * FIX_2_053119869) + z2 + z4;
            tmp2 = (tmp2 * FIX_3_072711026) + z2 + z3;
            tmp3 = (tmp3 * FIX_1_501321110) + z1 + z4;
            
            blockArray[pointer] = (short) ((tmp10 + tmp3) >> F3);
            blockArray[pointer + 1] = (short) ((tmp11 + tmp2) >> F3);
            blockArray[pointer + 2] = (short) ((tmp12 + tmp1) >> F3);
            blockArray[pointer + 3] = (short) ((tmp13 + tmp0) >> F3);
            blockArray[pointer + 4] = (short) ((tmp13 - tmp0) >> F3);
            blockArray[pointer + 5] = (short) ((tmp12 - tmp1) >> F3);
            blockArray[pointer + 6] = (short) ((tmp11 - tmp2) >> F3);
            blockArray[pointer + 7] = (short) ((tmp10 - tmp3) >> F3);
        }
    }

    // Blockline:
    // _______
    // | 1 | 2 |
    // |___|___| Y
    // | 3 | 4 |
    // |___|___|
    // ___
    // | 5 |
    // |___| Cb
    // ___
    // | 6 |
    // |___| Cr
    //
    // Layout in memory
    // _______________________
    // | 1 | 2 | 3 | 4 | 5 | 6 | ...
    // |___|___|___|___|___|___|
    //

    // Example, suppose the six data sub blocks are as follows:

    // ==============Y0============== ==============Y1==============
    // ==============Y2============== ==============Y3==============

    // 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
    // 0, 1, 2, 3, 4, 5, 6, 7,
    // 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11,
    // 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15,
    // 16, 17, 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23, 16, 17,
    // 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23,
    // 24, 25, 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31, 24, 25,
    // 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31,
    // 32, 33, 34, 35, 36, 37, 38, 39, 32, 33, 34, 35, 36, 37, 38, 39, 32, 33,
    // 34, 35, 36, 37, 38, 39, 32, 33, 34, 35, 36, 37, 38, 39,
    // 40, 41, 42, 43, 44, 45, 46, 47, 40, 41, 42, 43, 44, 45, 46, 47, 40, 41,
    // 42, 43, 44, 45, 46, 47, 40, 41, 42, 43, 44, 45, 46, 47,
    // 48, 49, 50, 51, 52, 53, 54, 55, 48, 49, 50, 51, 52, 53, 54, 55, 48, 49,
    // 50, 51, 52, 53, 54, 55, 48, 49, 50, 51, 52, 53, 54, 55,
    // 56, 57, 58, 59, 60, 61, 62, 63, 56, 57, 58, 59, 60, 61, 62, 63, 56, 57,
    // 58, 59, 60, 61, 62, 63, 56, 57, 58, 59, 60, 61, 62, 63

    // ==============Cb============== ==============Cr==============

    // 0, 1, 2, 3, | 4, 5, 6, 7, 0, 1, 2, 3, | 4, 5, 6, 7,
    // 8, 9, 10, 11, | 12, 13, 14, 15, 8, 9, 10, 11, | 12, 13, 14, 15,
    // 16, 17, 18, 19, | 20, 21, 22, 23, 16, 17, 18, 19, | 20, 21, 22, 23,
    // 24, 25, 26, 27, | 28, 29, 30, 31, 24, 25, 26, 27, | 28, 29, 30, 31,
    // ----------------| --------------- --------------- | ---------------
    // 32, 33, 34, 35, | 36, 37, 38, 39, 32, 33, 34, 35, | 36, 37, 38, 39,
    // 40, 41, 42, 43, | 44, 45, 46, 47, 40, 41, 42, 43, | 44, 45, 46, 47,
    // 48, 49, 50, 51, | 52, 53, 54, 55, 48, 49, 50, 51, | 52, 53, 54, 55,
    // 56, 57, 58, 59, | 60, 61, 62, 63, 56, 57, 58, 59, | 60, 61, 62, 63,

    // Pixel Matrix

    // 0, 1, 2, 3, 4, 5, 6, 7, | 8, 9, 10, 11, 12, 13, 14, 15,
    // 16, 17, 18, 19, 20, 21, 22, 23, | 24, 25, 26, 27, 28, 29, 30, 31,
    // 32, 33, 34, 35, 36, 37, 38, 39, | 40, 41, 42, 43, 44, 45, 46, 47,
    // 48, 49, 50, 51, 52, 53, 54, 55, | 56, 57, 58, 59, 60, 61, 62, 63,
    // 64, 65, 66, 67, 68, 69, 70, 71, | 72, 73, 74, 75, 76, 77, 78, 79,
    // 80, 81, 82, 83, 84, 85, 86, 87, | 88, 89, 90, 91, 92, 93, 94, 95,
    // 96, 97, 98, 99, 100, 101, 102, 103, | 104, 105, 106, 107, 108, 109, 110,
    // 111,
    // 112, 113, 114, 115, 116, 117, 118, 119, | 120, 121, 122, 123, 124, 125,
    // 126, 127,
    // ----------------------------------------|---------------------------------------
    // 128, 129, 130, 131, 132, 133, 134, 135, | 136, 137, 138, 139, 140, 141,
    // 142, 143,
    // 144, 145, 146, 147, 148, 149, 150, 151, | 152, 153, 154, 155, 156, 157,
    // 158, 159,
    // 160, 161, 162, 163, 164, 165, 166, 167, | 168, 169, 170, 171, 172, 173,
    // 174, 175,
    // 176, 177, 178, 179, 180, 181, 182, 183, | 184, 185, 186, 187, 188, 189,
    // 190, 191,
    // 192, 193, 194, 195, 196, 197, 198, 199, | 200, 201, 202, 203, 204, 205,
    // 206, 207,
    // 208, 209, 210, 211, 212, 213, 214, 215, | 216, 217, 218, 219, 220, 221,
    // 222, 223,
    // 224, 225, 226, 227, 228, 229, 230, 231, | 232, 233, 234, 235, 236, 237,
    // 238, 239,
    // 240, 241, 242, 243, 244, 245, 246, 247, | 248, 249, 250, 251, 252, 253,
    // 254, 255,

    // The four Luma 8x8 matrices (quadrants Y0, Y1, Y2, Y3) form the basis of
    // the final 16x16 pixel matrix.
    // The two Croma 8x8 matrices are used to calculate the actual RGB value of
    // the pixel (RGB565, each pixel is represented by two bytes)

    // Each processing loop processes from each Luma matrix two rows. In each
    // 'two row' loop the rows are processed
    // by two columns.

    // First Loop will take (assume there is only one pixel matrix to fill):

    // Quadrant 1
    // From Cb -> 0
    // From Cr -> 0
    // From Y0 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 0, 16 and 1 and 17

    // Quadrant 2
    // From Cb -> 4
    // From Cr -> 4
    // From Y1 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 8, 24 and 9 and 25

    // Quadrant 3
    // From Cb -> 32
    // From Cr -> 32
    // From Y2 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 128, 144 and 129 and 145

    // Quadrant 4
    // From Cb -> 36
    // From Cr -> 36
    // From Y3 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 136, 152 and 137 and 153

    // Second Loop will take (assume there is only one pixel matrix to fill):

    // Quadrant 1
    // From Cb -> 1
    // From Cr -> 1
    // From Y0 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 2, 18 and 3 and 19

    // Quadrant 2
    // From Cb -> 5
    // From Cr -> 5
    // From Y1 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 10, 26 and 11 and 27

    // Quadrant 3
    // From Cb -> 33
    // From Cr -> 33
    // From Y2 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 130, 146 and 131 and 147
    // Quadrant 4
    // From Cb -> 37
    // From Cr -> 37
    // From Y3 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
    // pixel matrix in 138, 154 and 139 and 155

    // We need third and fourth loop to complete first two lines of the luma
    // blocks. At this time we
    // have written 64 pixels to the pixel matrix.

    // These four loops have to be repeated 4 more times (4 * 64 = 256) to fill
    // complete pixel matrix.

    // Remark the offsets to use in the pixel matrix have to take into account
    // that an GroupOfBlocks contains multiple pixel matrices.
    // So to calculate the real index we have to take that also into account
    // (blockCount)

    // contains common code for optimization purposes
    /*
    private int peekStreamData(ByteBuffer stream, int count)
    {
        int data = 0;
        int stream_field = streamField;
        int stream_field_bit_index = streamFieldBitIndex;
        while (count > (32 - stream_field_bit_index) && streamIndex < (imageStreamCapacity >> 2))
        {
            data = (data << (32 - stream_field_bit_index)) | (stream_field >>> stream_field_bit_index);
            count -= 32 - stream_field_bit_index;
            stream_field = ((imageStreamByteArray[streamIndex * 4 + 0] & 0xFF) | ((imageStreamByteArray[streamIndex * 4 + 1] & 0xFF) << 8) | ((imageStreamByteArray[streamIndex * 4 + 2] & 0xFF) << 16) | ((imageStreamByteArray[streamIndex * 4 + 3] & 0xFF) << 24));
            stream_field_bit_index = 0;
        }
        if (count > 0)
            data = (data << count) | (stream_field >>> (32 - count));
        return data;
    }
     */
    private void processStream()
    {
        boolean blockY0HasAcComponents = false;
        boolean blockY1HasAcComponents = false;
        boolean blockY2HasAcComponents = false;
        boolean blockY3HasAcComponents = false;
        boolean blockCbHasAcComponents = false;
        boolean blockCrHasAcComponents = false;

        // Set streamFieldBitIndex to 32 to make sure that the first call to
        // ReadStreamData
        // actually consumes data from the stream
        streamFieldBitIndex = 32;
        streamField = 0;
        streamIndex = 0;
        sliceIndex = 0;
        pictureComplete = false;

        while (!pictureComplete && streamIndex < (imageStreamCapacity >> 2))
        {
            readHeader();

            if (!pictureComplete)
            {
                for (int count = 0; count < blockCount; count++)
                {
                    int macroBlockEmpty = readStreamDataInt(1);
                    if (macroBlockEmpty == 0)
                    {
                        int acCoefficientsTemp = readStreamDataInt(8);
                        blockY0HasAcComponents = (acCoefficientsTemp >>> 0 & 1) == 1;
                        blockY1HasAcComponents = (acCoefficientsTemp >>> 1 & 1) == 1;
                        blockY2HasAcComponents = (acCoefficientsTemp >>> 2 & 1) == 1;
                        blockY3HasAcComponents = (acCoefficientsTemp >>> 3 & 1) == 1;
                        blockCbHasAcComponents = (acCoefficientsTemp >>> 4 & 1) == 1;
                        blockCrHasAcComponents = (acCoefficientsTemp >>> 5 & 1) == 1;

                        if ((acCoefficientsTemp >>> 6 & 1) == 1)
                        {
                            int quantizer_modeTemp = readStreamDataInt(2);
                            quantizerMode = (int) ((quantizer_modeTemp < 2) ? ~quantizer_modeTemp : quantizer_modeTemp);
                        }

                        getBlockBytes(blockY0HasAcComponents);
                        inverseTransform(count, 0);

                        getBlockBytes(blockY1HasAcComponents);
                        inverseTransform(count, 1);

                        getBlockBytes(blockY2HasAcComponents);
                        inverseTransform(count, 2);

                        getBlockBytes(blockY3HasAcComponents);
                        inverseTransform(count, 3);

                        getBlockBytes(blockCbHasAcComponents);
                        inverseTransform(count, 4);

                        getBlockBytes(blockCrHasAcComponents);
                        inverseTransform(count, 5);
                    }
                }
                composeImageSlice();
            }
        }
    }

    private void readHeader()
    {
        alignStreamData();

        int code = readStreamDataInt(22);
        int startCode = code & (~0x1F);

        if (startCode == 32)
        {
            if ((code & 0x1F) == 0x1F)
            {
                pictureComplete = true;
            } else
            {
                if (sliceIndex++ == 0)
                {
                    pictureFormat = readStreamDataInt(2);
                    resolution = readStreamDataInt(3);
                    pictureType = readStreamDataInt(3);
                    quantizerMode = readStreamDataInt(5);
                    frameIndex = readStreamDataInt(32);

                    switch (pictureFormat)
                    {
                    case CIF:
                        width = CIF_WIDTH << resolution - 1;
                        height = CIG_HEIGHT << resolution - 1;
                        break;
                    case QVGA:
                        width = VGA_WIDTH << resolution - 1;
                        height = VGA_HEIGHT << resolution - 1;
                        break;
                    }

                    // We assume two bytes per pixel (RGB 565)
                    pixelRowSize = width << 1;

                    sliceCount = height >> 4;
                    blockCount = width >> 4;

                    if (imageSlice == null || imageSlice.MacroBlocks.length != blockCount)
                    {
                        imageSlice = new ImageSlice(blockCount);
                        javaPixelData = new int[width * height];
                    }
                } else
                {
                    quantizerMode = readStreamDataInt(5);
                }
            }
        }
    }

    private int readStreamDataInt(int count)
    {
        int data = 0;
        while (count > (32 - streamFieldBitIndex))
        {
            data = data << (32 - streamFieldBitIndex) | (streamField >>> streamFieldBitIndex);
            count -= 32 - streamFieldBitIndex;
            streamField = ((imageStreamByteArray[streamIndex * 4 + 0] & 0xFF) | ((imageStreamByteArray[streamIndex * 4 + 1] & 0xFF) << 8) | ((imageStreamByteArray[streamIndex * 4 + 2] & 0xFF) << 16) | ((imageStreamByteArray[streamIndex * 4 + 3] & 0xFF) << 24));
            streamFieldBitIndex = 0;
            streamIndex++;
        }
        if (count > 0)
        {
            data = (data << count) | (streamField >>> (32 - count));
            streamField <<= count;
            streamFieldBitIndex += count;
        }
        return data;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy