alder_lake_bios/Insyde/InsydeModulePkg/Library/H2OImageDecoderLib/H2OJpegDecoder/McuDecode.c

686 lines
18 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2020, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
/*++
Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
McuDecode.c
Abstract:
This code decode the JFIF image.
--*/
#include "McuDecode.h"
#define GetByteBits(CurByte, BitPos, Bits)\
(((CurByte) >> ((BitPos)- (Bits) + 1)) & (0xFF >> (8 - (Bits))))
#define GetWordBits(CurByte, BitPos, Bits)\
(((CurByte) >> ((BitPos)- (Bits) + 1)) & (0xFFFF >> (16 - (Bits))))
#define GetRGB(x) ((x)<0?0:((x)>255?255:x))
#define GetMax(x,y) ((x)>(y)?(x):(y))
#define GetRate(x,y) ((y)==1?(x):((y)==2?((x)>>1):((y)==4?((x)>>2):0)))
extern EFI_JPEG_DECODER_DATA mDecoderData;
UINT8 ZigZag[8][8]={
{ 0, 1, 5, 6,14,15,27,28},
{ 2, 4, 7,13,16,26,29,42},
{ 3, 8,12,17,25,30,41,43},
{ 9,11,18,24,37,40,44,53},
{10,19,23,32,39,45,52,54},
{20,22,33,38,46,51,55,60},
{21,34,37,47,50,56,59,61},
{35,36,48,49,57,58,62,63}};
/**
Get the bit of mDecoderData.BitPos in the mDecoderData.CurByte,
mDecoderData.BitPos is between 0 and 7.
@param [out] IsEnd When reading a new byte from the image, the image is end or not
@return 0 or 1 The bit value of the mDecoderData.BitPos in the mDecoderData.CurByte.
**/
UINT8
GetNextBit (
OUT BOOLEAN *IsEnd
)
{
UINT8 value;
value = (mDecoderData.CurByte >> mDecoderData.BitPos) & 0x01;
*IsEnd = FALSE;
if (mDecoderData.BitPos > 0) {
mDecoderData.BitPos--;
} else {
*IsEnd = ReadByte ();
mDecoderData.BitPos = 7;
}
return value;
}
/**
Read a byte from the mDecoderData.ImagePtr to the mDecoderData.CurByte,
@retval TRUE The mDecoderData.CurByte is image end.
@retval FALSE The mDecoderData.CurByte is not image end.
**/
BOOLEAN
ReadByte (
)
{
BOOLEAN IsEnd;
IsEnd = FALSE;
mDecoderData.CurByte = *(mDecoderData.ImagePtr);
if (*(mDecoderData.ImagePtr) == 0xFF) {
if (*(mDecoderData.ImagePtr + 1) == 0x00) {
mDecoderData.ImagePtr += 2;
} else if (*(mDecoderData.ImagePtr + 1) == 0xD9) {
//
//arrived the End of JFIF image 0xFFD9
//
IsEnd = TRUE;
}
} else {
mDecoderData.ImagePtr++;
}
return IsEnd;
}
/**
Decode the block element from the image(Base on the mDecoderData.ImagePtr).
@retval EFI_SUCCESS The element decoded successfully
@retval EFI_UNSUPPORTED The element decoding is failed, detail status refers "DecoderStatus"
**/
EFI_STATUS
ElementDecode (
IN UINT8 HTIndex,
OUT UINT8 *ZeroCount,
OUT INT16 *DecodedVal,
OUT BOOLEAN *IsEnd,
OUT EFI_JPEG_DECODER_STATUS *DecoderStatus
)
{
INT16 Code;
UINT8 CurBit;
UINT16 CurWord;
UINT8 LayerIndex;
UINT8 ValIndex;
UINT8 HuffVal;
UINT8 ValBits;
UINT16 DecodingVal;
UINT16 ReferVal;
//
//Decode the Huffman code
//
*IsEnd = FALSE;
Code = 0;
LayerIndex = 0;
do {
if (*IsEnd) {
*DecoderStatus = EFI_JPEG_DECODEDATA_ERROR;
return EFI_UNSUPPORTED;
}
LayerIndex++;
CurBit = GetNextBit(IsEnd);
Code = (Code << 1) + CurBit;
if (LayerIndex > 16) {
*DecoderStatus = EFI_JPEG_DECODEHT_ERROR;
return EFI_UNSUPPORTED;
}
}while (Code > mJfifData.HuffTable[HTIndex].MaxCode[LayerIndex]
|| mJfifData.HuffTable[HTIndex].Codes[LayerIndex] == 0
);
ValIndex = mJfifData.HuffTable[HTIndex].FirstCode[LayerIndex];
ValIndex = ValIndex + (UINT8)(Code - mJfifData.HuffTable[HTIndex].MinCode[LayerIndex]);
HuffVal = mJfifData.HuffTable[HTIndex].HuffmanVal[ValIndex];
//
//get the HuffVal's bits and get the value
//
*ZeroCount = HuffVal >> 4;
ValBits = HuffVal & 0x0F;
ReferVal = 1 << (ValBits - 1);
if (ValBits == 0) {
*DecodedVal = 0;
*DecoderStatus = EFI_JPEG_DECODE_SUCCESS;
return EFI_SUCCESS;
}
if (mDecoderData.BitPos >= (ValBits - 1)) {
DecodingVal = GetByteBits(mDecoderData.CurByte, mDecoderData.BitPos, ValBits);
if (mDecoderData.BitPos > (ValBits - 1)) {
mDecoderData.BitPos = mDecoderData.BitPos - ValBits;
} else {
mDecoderData.BitPos = 7;
if (ReadByte ()) {
*DecoderStatus = EFI_JPEG_DECODEDATA_ERROR;
return EFI_UNSUPPORTED;
}
}
} else {
DecodingVal = GetByteBits(
mDecoderData.CurByte,
mDecoderData.BitPos,
(mDecoderData.BitPos + 1)
);
ValBits = ValBits - (mDecoderData.BitPos + 1);
if (ValBits >= 8) {
if (ReadByte ()) {
*DecoderStatus = EFI_JPEG_DECODEDATA_ERROR;
return EFI_UNSUPPORTED;
}
CurWord = mDecoderData.CurByte;
if (ReadByte ()) {
*DecoderStatus = EFI_JPEG_DECODEDATA_ERROR;
return EFI_UNSUPPORTED;
}
CurWord = (CurWord << 8) + mDecoderData.CurByte;
DecodingVal = (DecodingVal << ValBits) + GetWordBits(CurWord, 15, ValBits);
mDecoderData.BitPos = 15 - ValBits;
} else {
if (ReadByte ()) {
*DecoderStatus = EFI_JPEG_DECODEDATA_ERROR;
return EFI_UNSUPPORTED;
}
DecodingVal = (DecodingVal << ValBits) + GetByteBits(mDecoderData.CurByte, 7, ValBits);
mDecoderData.BitPos = 7 - ValBits;
}
}
//
//the decode value is negative.
//
if ( DecodingVal < ReferVal) {
ReferVal = (0xFFFF << (HuffVal & 0x0F)) + 1;
DecodingVal = DecodingVal + ReferVal;
}
*DecodedVal = DecodingVal;
return EFI_SUCCESS;
}
/**
Decode the block data from the image.
@param [out] BlockBuff The pointer of the block's decoded data
@param [in] DcAcHTIndex The indexes of this block's AC, DC Huffman table
@param [out] IsEnd The image is end or not
@param [out] DecoderStatus The detail status of the block decoding
@retval EFI_SUCCESS The block decoded successfully
@retval EFI_UNSUPPORTED The block decoding is failed, detail status refers "DecoderStatus"
**/
EFI_STATUS
BlockDecode (
OUT INT16 *BlockBuff,
IN UINT8 DcAcHTIndex,
OUT BOOLEAN *IsEnd,
OUT EFI_JPEG_DECODER_STATUS *DecoderStatus
)
{
EFI_STATUS Status;
UINT8 Count;
UINT8 HTIndex;
UINT8 ZeroCount;
INT16 DecodedVal;
Count = 0;
//
//DC decode
//
HTIndex = DcAcHTIndex >> 4;
Status=ElementDecode (HTIndex, &ZeroCount, &DecodedVal, IsEnd, DecoderStatus);
if (EFI_ERROR (Status)) {
return Status;
}
BlockBuff[Count++] = DecodedVal;
//
//AC decode
//
while (Count<64)
{
HTIndex = (DcAcHTIndex & 0x0F) + 2;
Status = ElementDecode (HTIndex, &ZeroCount, &DecodedVal, IsEnd, DecoderStatus);
if (EFI_ERROR (Status)) {
return Status;
}
if (DecodedVal == 0) {
if (ZeroCount == 15) {
Count += 16;
} else {
Count = 64;
}
} else {
Count = Count + ZeroCount;
if (Count > 63) {
*DecoderStatus = EFI_JPEG_DECODEAC_ERROR;
return EFI_UNSUPPORTED;
}
BlockBuff[Count++] = DecodedVal;
}
}
return EFI_SUCCESS;
}
/**
Decode the MCU data from the image, get the MCU's blocks data.
@param [out] McuDstBuff The pointer of the MCU's decoded data
@param [in] IntervalFlag When image has RST marker, the flag of the interval restart
@param [out] IsEnd The image is end or not
@param [out] DecoderStatus The detail status of the MCU decoding
@retval EFI_SUCCESS The MCU decoded successfully
@retval EFI_UNSUPPORTED The MCU decoding is failed, detail status refers "DecoderStatus"
**/
EFI_STATUS
McuRetrieve (
OUT INT16 *McuDstBuff,
IN BOOLEAN IntervalFlag,
OUT BOOLEAN *IsEnd,
OUT EFI_JPEG_DECODER_STATUS *DecoderStatus
)
{
EFI_STATUS Status;
INT16 BlockBuff[64];
INT16 *McuBuffPtr;
UINT8 i;
McuBuffPtr = McuDstBuff;
if (IntervalFlag) {
if (*mDecoderData.ImagePtr != 0xFF
|| *(mDecoderData.ImagePtr + 1) > 0xD7
|| *(mDecoderData.ImagePtr + 1) < 0xD0 ) {
*DecoderStatus = EFI_JPEG_DECODERST_ERROR;
return EFI_UNSUPPORTED;
}
mDecoderData.ImagePtr += 2;
mDecoderData.DcVal[0] = 0;
mDecoderData.DcVal[1] = 0;
mDecoderData.DcVal[2] = 0;
mDecoderData.BitPos = 7;
if (ReadByte()) {
*IsEnd = TRUE;
*DecoderStatus = EFI_JPEG_DECODEDATA_ERROR;
return EFI_UNSUPPORTED;
};
}
for (i = 0; i < mDecoderData.Blocks; i++) {
SetMem (&BlockBuff, sizeof(BlockBuff), 0);
Status = BlockDecode (
BlockBuff,
mDecoderData.BlocksInMcu[i].DcAcHTIndex,
IsEnd,
DecoderStatus
);
if (EFI_ERROR (Status)) {
return Status;
}
BlockBuff[0] = BlockBuff[0] + *(mDecoderData.BlocksInMcu[i].DcValPtr);
*(mDecoderData.BlocksInMcu[i].DcValPtr) = BlockBuff[0];
CopyMem(McuBuffPtr, BlockBuff, 128);
McuBuffPtr += 64;
}
return EFI_SUCCESS;
}
/**
Dequantize and De-Zigzag the block data.
@param [in] BlockSrcBuff The pointer of the source data
@param [out] BlockDstBuff The pointer of the destination data
@param [in] BlockIndex The index of the block in the MCU
**/
VOID
BlockDequantDezigzag (
IN INT16 *BlockSrcBuff,
OUT INT16 *BlockDstBuff,
IN UINT8 BlockIndex
)
{
UINT8 i,j;
UINT8 QtIndex;
UINT8 ZigZagTag;
INT16 QtValue;
UINT8 *BlockQtBuffPtr;
QtValue = 0;
QtIndex = mDecoderData.BlocksInMcu[BlockIndex].QTIndex;
BlockQtBuffPtr = mJfifData.DqtPtr[QtIndex];
for (i = 0; i < 8; i++) {
for ( j = 0; j < 8; j++) {
ZigZagTag = ZigZag[i][j];
BlockDstBuff[i * 8 + j] = BlockSrcBuff[ZigZagTag] * BlockQtBuffPtr[ZigZagTag];
}
}
}
/**
Do the IDCT with the block data, and add the offset(128) to Y component.
**/
VOID
BlockIDctAddoffset (
IN OUT INT16 *BlockSrcDstBuff,
IN UINT8 BlockIndex
)
{
UINT8 Index1;
UINT8 Index2;
UINT8 col;
UINT8 Offset;
INT16 BlockTemp[64];
INT16 *Src;
INT16 *Dst;
INT32 c0;
INT32 c1;
INT32 c2;
INT32 c3;
INT32 c4;
INT32 c5;
INT32 c6;
INT32 c7;
INT32 x0;
INT32 x1;
INT32 x2;
INT32 x3;
INT32 x4;
INT32 x5;
INT32 x6;
INT32 x7;
Offset = 0;
c0 = Cos0;
//
// Index1 == 0: T=A*[Y], (row of A)*(col of Y)
// calculate the values of T row by row, but store the values
// col by col, so get the matrix of T' (T' is the inverse matrix of T)
// Index1 == 1: [X]=T*A'=(A*T')', (row of A)*(col of T')
// calculate the values of [X] row by row, but stored col by col
//
for (Index1 = 0; Index1 < 2; Index1++) {
if ( Index1 == 0) {
Src = (INT16 *)BlockSrcDstBuff;
Dst = (INT16 *)BlockTemp;
} else {
Src = (INT16 *)BlockTemp;
Dst = (INT16 *)BlockSrcDstBuff;
if (BlockIndex < mJfifData.Sof0Data.Samples[0].Blocks) {
//
//this compenent is Y, and need to add 128 offset
//
Offset = 128;
}
}
for (Index2 = 0; Index2 < 4; Index2++) {
switch (Index2) {
case 0:
c1 = Cos1;
c2 = Cos2;
c3 = Cos3;
c4 = Cos4;
c5 = Cos5;
c6 = Cos6;
c7 = Cos7;
break;
case 1:
c1 = Cos3;
c2 = Cos6;
c3 = -Cos7;
c4 = -Cos4;
c5 = -Cos1;
c6 = -Cos2;
c7 = -Cos5;
break;
case 2:
c1 = Cos5;
c2 = -Cos6;
c3 = -Cos1;
c4 = -Cos4;
c5 = Cos7;
c6 = Cos2;
c7 = Cos3;
break;
default:
c1 = Cos7;
c2 = -Cos2;
c3 = -Cos5;
c4 = Cos4;
c5 = Cos3;
c6 = -Cos6;
c7 = -Cos1;
}
//
//get the values of Dst's col(j) and col(7-j)
//
for (col = 0; col <8; col++) {
x0 = c0 * Src[col];
x1 = c1 * Src[8 + col];
x2 = c2 * Src[16 + col];
x3 = c3 * Src[24 + col];
x4 = c4 * Src[32 + col];
x5 = c5 * Src[40 + col];
x6 = c6 * Src[48 + col];
x7 = c7 * Src[56 + col];
Dst[col*8 + Index2] = (UINT16)(((x0 + x2 + x4 + x6) + (x1 + x3 + x5 + x7)) >> 12) + Offset;
Dst[col*8 + (7 - Index2)] = (UINT16)(((x0 + x2 + x4 + x6) - (x1 + x3 + x5 + x7)) >> 12) + Offset;
}
}
}
}
/**
Decode the MCU data.
@param [in] McuSrcBuff The pointer of the source data
@param [out] McuDstBuff The pointer of the destination data
**/
VOID
McuDecode (
IN INT16 *McuSrcBuff,
OUT INT16 *McuDstBuff
)
{
UINT8 Index1;
UINT8 Index2;
UINT8 Index3;
UINT8 ComponentId;
UINT8 HIndex;
UINT8 VIndex;
UINT16 TempValue;
INT16 *BlockPtr;
INT16 McuTempBuff[10*64];
INT16 *McuTempBuffPtr;
INT16 *McuDstBuffPtr;
McuDstBuffPtr = NULL;
McuTempBuffPtr = (INT16 *)&McuTempBuff;
for (Index1 = 0; Index1 < mDecoderData.Blocks; Index1++) {
BlockDequantDezigzag (McuSrcBuff + Index1 * 64, McuTempBuffPtr + Index1 * 64, Index1);
BlockIDctAddoffset (McuTempBuffPtr + Index1 * 64, Index1);
if ( Index1 < mJfifData.Sof0Data.Samples[0].Blocks ) {
McuDstBuffPtr = McuDstBuff;
ComponentId = 0;
} else if (Index1 < (mJfifData.Sof0Data.Samples[0].Blocks + mJfifData.Sof0Data.Samples[1].Blocks)) {
McuDstBuffPtr = McuDstBuff + 4*64;
ComponentId = 1;
} else {
McuDstBuffPtr = McuDstBuff + 8*64;
ComponentId = 2;
}
HIndex = mDecoderData.BlocksInMcu[Index1].HiViIndex >> 4;
VIndex = mDecoderData.BlocksInMcu[Index1].HiViIndex & 0x0F;
BlockPtr = McuTempBuffPtr + Index1 * 64;
for (Index2 = 0; Index2 < 8; Index2++) {
for(Index3 = 0; Index3 < 8; Index3++) {
TempValue = (VIndex * 8 + Index2) * mJfifData.Sof0Data.Samples[ComponentId].Hi * 8 \
+ HIndex * 8 \
+ Index3;
McuDstBuffPtr[TempValue] = *BlockPtr;
BlockPtr++;
}
}
}
}
/**
Store the MCU data into the UGA buffer.
@param [in] McuSrcBuff The pointer of the source data
@param [in, out] DstBuff The pointer of the destination data
@param [in, out] CurHPixel The current horizontal pixel index of the MCU
@param [in, out] CurVLine The current vertical line index of the MCU
**/
VOID
StoreMcuToUgaBlt (
IN INT16 *McuSrcBuff,
IN OUT UINT8 **DstBuff,
IN OUT UINT16 *CurHPixel,
IN OUT UINT16 *CurVLine
)
{
INT16 Y;
INT16 Cb;
INT16 Cr;
INT16 R;
INT16 G;
INT16 B;
UINT16 TempIndex;
UINT8 HiMax;
UINT8 Index1;
UINT8 Index2;
UINT8 ViMax;
UINT8 YHiRate;
UINT8 CbHiRate;
UINT8 CrHiRate;
UINT8 YViRate;
UINT8 CbViRate;
UINT8 CrViRate;
EFI_UGA_PIXEL *BltBuffer;
EFI_UGA_PIXEL *Blt;
HiMax = GetMax(
GetMax(mJfifData.Sof0Data.Samples[0].Hi, mJfifData.Sof0Data.Samples[1].Hi),
mJfifData.Sof0Data.Samples[2].Hi
);
ViMax = GetMax(
GetMax(mJfifData.Sof0Data.Samples[0].Vi, mJfifData.Sof0Data.Samples[1].Vi),
mJfifData.Sof0Data.Samples[2].Vi
);
YHiRate = GetRate(HiMax, mJfifData.Sof0Data.Samples[0].Hi);
CbHiRate = GetRate(HiMax, mJfifData.Sof0Data.Samples[1].Hi);
CrHiRate = GetRate(HiMax, mJfifData.Sof0Data.Samples[2].Hi);
YViRate = GetRate(ViMax, mJfifData.Sof0Data.Samples[0].Vi);
CbViRate = GetRate(ViMax, mJfifData.Sof0Data.Samples[1].Vi);
CrViRate = GetRate(ViMax, mJfifData.Sof0Data.Samples[2].Vi);
BltBuffer = (EFI_UGA_PIXEL *)*DstBuff;
for (Index1 = 0; Index1 < ViMax * 8; Index1++) {
if ((*CurVLine + Index1) < mJfifData.Sof0Data.Height) {
Blt = &BltBuffer[(*CurVLine + Index1)*mJfifData.Sof0Data.Width + *CurHPixel];
for (Index2 = 0; Index2 < HiMax * 8; Index2++) {
if ((*CurHPixel + Index2) < mJfifData.Sof0Data.Width) {
TempIndex = GetRate(Index1, YViRate) * 8 * mJfifData.Sof0Data.Samples[0].Hi \
+ GetRate(Index2, YHiRate);
Y = McuSrcBuff[TempIndex];
TempIndex = 4 * 64 \
+ GetRate (Index1, CbViRate) * 8 * mJfifData.Sof0Data.Samples[1].Hi \
+ GetRate (Index2, CbHiRate);
Cb = McuSrcBuff[TempIndex];
TempIndex = 8 * 64 \
+ GetRate (Index1, CrViRate) * 8 * mJfifData.Sof0Data.Samples[2].Hi \
+ GetRate (Index2, CrHiRate);
Cr = McuSrcBuff[TempIndex];
R = (Y + ((1436 * Cr)>> 10));
G = (Y - ((352 * Cb + 731 * Cr) >> 10));
B = (Y + ((1815 * Cb)>> 10));
Blt->Red = (UINT8)GetRGB(R);
Blt->Green = (UINT8)GetRGB(G);
Blt->Blue = (UINT8)GetRGB(B);
Blt++;
} else {
break;
}
}
} else {
break;
}
}
//
// Modify the current Horizontal Pixel and Vertical Pixel
//
*CurHPixel += HiMax * 8;
if (*CurHPixel >= mJfifData.Sof0Data.Width) {
*CurHPixel = 0;
*CurVLine += ViMax * 8;
}
}