
com.codeminders.ardrone.video.BufferedVideoImage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javadrone-api Show documentation
Show all versions of javadrone-api Show documentation
Java API (without using native code) to control AR.Drone
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