Files
MAX_CARLINK_A270S/MXC_A27-PCB4.5-270T/lib/hx170dec/src/jpegdechdrs.c
2025-01-21 16:49:37 +08:00

710 lines
23 KiB
C

/*------------------------------------------------------------------------------
-- --
-- This software is confidential and proprietary and may be used --
-- only as expressly authorized by a licensing agreement from --
-- --
-- Hantro Products Oy. --
-- --
-- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
-- ALL RIGHTS RESERVED --
-- --
-- The entire notice above must be reproduced --
-- on all copies and should not be removed. --
-- --
--------------------------------------------------------------------------------
--
-- Description : Jpeg decoder header decoding source code
--
------------------------------------------------------------------------------
--
-- Version control information, please leave untouched.
--
-- $RCSfile: jpegdechdrs.c,v $
-- $Revision: 1.9 $
-- $Date: 2008/11/25 12:41:31 $
--
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
Table of contents
1. Include headers
2. External compiler flags
3. Module defines
4. Local function prototypes
5. Functions
- JpegDecDecodeFrame
- JpegDecDecodeQuantTables
- JpegDecDecodeHuffmanTables
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
1. Include headers
------------------------------------------------------------------------------*/
#include "jpegdechdrs.h"
#include "jpegdecutils.h"
#include "jpegdecmarkers.h"
#include "jpegdecinternal.h"
#include "jpegdecscan.h"
#include "jpegdecapi.h"
#include "dwl.h"
/*------------------------------------------------------------------------------
2. External compiler flags
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
3. Module defines
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
4. Local function prototypes
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
5. Functions
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
Function name: JpegDecDecodeFrame
Functional description:
Decodes frame headers
Inputs:
JpegDecContainer *pDecData Pointer to JpegDecContainer structure
Outputs:
OK/NOK
------------------------------------------------------------------------------*/
JpegDecRet JpegDecDecodeFrameHdr(JpegDecContainer * pDecData)
{
u32 i;
u32 width, height;
u32 tmp1, tmp2;
u32 Hmax = 0;
u32 Vmax = 0;
u32 size = 0;
JpegDecRet retCode;
retCode = JPEGDEC_OK;
/* frame header length */
pDecData->frame.Lf = JpegDecGet2Bytes(&(pDecData->stream));
/* check if there is enough data */
if(((pDecData->stream.readBits / 8) + pDecData->frame.Lf) >
pDecData->stream.streamLength)
return (JPEGDEC_STRM_ERROR);
/* Sample precision */
pDecData->frame.P = JpegDecGetByte(&(pDecData->stream));
if(pDecData->frame.P != 8)
{
JPEGDEC_TRACE_INTERNAL(("if ( pDecData->frame.P != 8)\n"));
return (JPEGDEC_UNSUPPORTED);
}
/* Number of Lines */
pDecData->frame.Y = JpegDecGet2Bytes(&(pDecData->stream));
if(pDecData->frame.Y < 1)
{
return (JPEGDEC_UNSUPPORTED);
}
pDecData->frame.hwY = pDecData->frame.Y;
/* round up to next multiple-of-16 */
pDecData->frame.hwY += 0xf;
pDecData->frame.hwY &= ~(0xf);
/* Number of samples per line */
pDecData->frame.X = JpegDecGet2Bytes(&(pDecData->stream));
if(pDecData->frame.X < 1)
{
return (JPEGDEC_UNSUPPORTED);
}
pDecData->frame.hwX = pDecData->frame.X;
/* round up to next multiple-of-16 */
pDecData->frame.hwX += 0xf;
pDecData->frame.hwX &= ~(0xf);
/* for internal() */
pDecData->info.X = pDecData->frame.hwX;
pDecData->info.Y = pDecData->frame.hwY;
/* check for minimum and maximum dimensions */
if(pDecData->frame.hwX < pDecData->minSupportedWidth ||
pDecData->frame.hwY < pDecData->minSupportedHeight ||
pDecData->frame.hwX > pDecData->maxSupportedWidth ||
pDecData->frame.hwY > pDecData->maxSupportedHeight ||
(pDecData->frame.hwX * pDecData->frame.hwY) >
pDecData->maxSupportedPixelAmount)
{
JPEGDEC_TRACE_INTERNAL(("FRAME: Unsupported size\n"));
return (JPEGDEC_UNSUPPORTED);
}
/* Number of components */
pDecData->frame.Nf = JpegDecGetByte(&(pDecData->stream));
if((pDecData->frame.Nf != 3) && (pDecData->frame.Nf != 1))
{
JPEGDEC_TRACE_INTERNAL(("pDecData->frame.Nf != 3 && pDecData->frame.Nf != 1\n"));
return (JPEGDEC_UNSUPPORTED);
}
/* save component specific data */
/* Nf == number of components */
for(i = 0; i < pDecData->frame.Nf; i++)
{
pDecData->frame.component[i].C = JpegDecGetByte(&(pDecData->stream));
if(i == 0) /* for the first component */
{
/* if first component id is something else than 1 (jfif) */
pDecData->scan.index = pDecData->frame.component[i].C;
}
else
{
/* if component ids 'jumps' */
if((pDecData->frame.component[i - 1].C + 1) !=
pDecData->frame.component[i].C)
{
JPEGDEC_TRACE_INTERNAL(("component ids 'jumps'\n"));
return (JPEGDEC_UNSUPPORTED);
}
}
tmp1 = JpegDecGetByte(&(pDecData->stream));
pDecData->frame.component[i].H = tmp1 >> 4;
if(pDecData->frame.component[i].H > Hmax)
{
Hmax = pDecData->frame.component[i].H;
}
pDecData->frame.component[i].V = tmp1 & 0xF;
if(pDecData->frame.component[i].V > Vmax)
{
Vmax = pDecData->frame.component[i].V;
}
pDecData->frame.component[i].Tq = JpegDecGetByte(&(pDecData->stream));
}
if(pDecData->frame.Nf == 1)
{
Hmax = Vmax = 1;
pDecData->frame.component[0].H = 1;
pDecData->frame.component[0].V = 1;
}
else if(Hmax == 0 || Vmax == 0)
{
JPEGDEC_TRACE_INTERNAL(("Hmax == 0 || Vmax == 0 \n"));
return (JPEGDEC_UNSUPPORTED);
}
/* JPEG_YCBCR411 horizontal size has to be multiple of 32 pels */
if(Hmax == 4 && (pDecData->frame.hwX & 0x1F))
{
/* round up to next multiple-of-32 */
pDecData->frame.hwX += 16;
pDecData->info.X = pDecData->frame.hwX;
/* check for minimum and maximum dimensions */
if(pDecData->frame.hwX > pDecData->maxSupportedWidth ||
(pDecData->frame.hwX * pDecData->frame.hwY) >
pDecData->maxSupportedPixelAmount)
{
JPEGDEC_TRACE_INTERNAL(("FRAME: Unsupported size\n"));
return (JPEGDEC_UNSUPPORTED);
}
}
/* set image pointers, calculate pixelPerRow for each component */
width = ((pDecData->frame.hwX + Hmax * 8 - 1) / (Hmax * 8)) * Hmax * 8;
height = ((pDecData->frame.hwY + Vmax * 8 - 1) / (Vmax * 8)) * Vmax * 8;
/* calculate numMcuInRow and numMcuInFrame */
ASSERT(Hmax != 0);
ASSERT(Vmax != 0);
pDecData->frame.numMcuInRow = width / (8 * Hmax);
pDecData->frame.numMcuInFrame = pDecData->frame.numMcuInRow *
(height / (8 * Vmax));
/* reset mcuNumbers */
pDecData->frame.mcuNumber = 0;
pDecData->frame.row = pDecData->frame.col = 0;
for(i = 0; i < pDecData->frame.Nf; i++)
{
ASSERT(i <= 2);
tmp1 = (width * pDecData->frame.component[i].H + Hmax - 1) / Hmax;
tmp2 = (height * pDecData->frame.component[i].V + Vmax - 1) / Vmax;
size += tmp1 * tmp2;
/* pixels per row */
pDecData->image.pixelsPerRow[i] = tmp1;
pDecData->image.columns[i] = tmp2;
pDecData->frame.numBlocks[i] =
(((pDecData->frame.hwX * pDecData->frame.component[i].H) / Hmax +
7) >> 3) * (((pDecData->frame.hwY *
pDecData->frame.component[i].V) / Vmax + 7) >> 3);
if(i == 0)
{
pDecData->image.sizeLuma = size;
}
}
pDecData->image.size = size;
pDecData->image.sizeChroma = size - pDecData->image.sizeLuma;
/* set mode & calculate rlc tmp size */
retCode = JpegDecMode(pDecData);
if(retCode != JPEGDEC_OK)
{
return (retCode);
}
return (JPEGDEC_OK);
}
/*------------------------------------------------------------------------------
Function name: JpegDecDecodeQuantTables
Functional description:
Decodes quantisation tables from the stream
Inputs:
JpegDecContainer *pDecData Pointer to JpegDecContainer structure
Outputs:
OK (0)
NOK (-1)
------------------------------------------------------------------------------*/
JpegDecRet JpegDecDecodeQuantTables(JpegDecContainer * pDecData)
{
u32 t, tmp, i;
StreamStorage *pStream = &(pDecData->stream);
pDecData->quant.Lq = JpegDecGet2Bytes(pStream);
/* check if there is enough data for tables */
if(((pStream->readBits / 8) + pDecData->quant.Lq) > pStream->streamLength)
return (JPEGDEC_STRM_ERROR);
t = 4;
while(t < pDecData->quant.Lq)
{
/* Tq value selects what table the components use */
/* read tables and write to decData->quant */
tmp = JpegDecGetByte(pStream);
t++;
/* supporting only 8 bits / sample */
if((tmp >> 4) != 0)
{
return (JPEGDEC_UNSUPPORTED);
}
tmp &= 0xF;
/* set the quantisation table pointer */
if(tmp == 0)
{
JPEGDEC_TRACE_INTERNAL(("qtable0\n"));
pDecData->quant.table = pDecData->quant.table0;
}
else if(tmp == 1)
{
JPEGDEC_TRACE_INTERNAL(("qtable1\n"));
pDecData->quant.table = pDecData->quant.table1;
}
else if(tmp == 2)
{
JPEGDEC_TRACE_INTERNAL(("qtable2\n"));
pDecData->quant.table = pDecData->quant.table2;
}
else if(tmp == 3)
{
JPEGDEC_TRACE_INTERNAL(("qtable3\n"));
pDecData->quant.table = pDecData->quant.table3;
}
else
{
return (JPEGDEC_UNSUPPORTED);
}
for(i = 0; i < 64; i++)
{
pDecData->quant.table[i] = JpegDecGetByte(pStream);
t++;
}
}
return (JPEGDEC_OK);
}
/*------------------------------------------------------------------------------
Function name: JpegDecDecodeHuffmanTables
Functional description:
Decodes huffman tables from the stream
Inputs:
DecData *JpegDecContainer Pointer to JpegDecContainer structure
Outputs:
OK (0)
NOK (-1)
------------------------------------------------------------------------------*/
JpegDecRet JpegDecDecodeHuffmanTables(JpegDecContainer * pDecData)
{
u32 i, len, Tc, Th, tmp;
i32 j;
StreamStorage *pStream = &(pDecData->stream);
pDecData->vlc.Lh = JpegDecGet2Bytes(pStream);
/* check if there is enough data for tables */
if(((pStream->readBits / 8) + pDecData->vlc.Lh) > pStream->streamLength)
return (JPEGDEC_STRM_ERROR);
/* four bytes already read in */
len = 4;
while(len < pDecData->vlc.Lh)
{
tmp = JpegDecGetByte(pStream);
len++;
Tc = tmp >> 4; /* Table class */
if(Tc != 0 && Tc != 1)
{
return (JPEGDEC_UNSUPPORTED);
}
Th = tmp & 0xF; /* Huffman table identifier */
/* only two tables in baseline allowed */
if((pDecData->frame.codingType == SOF0) && (Th > 1))
{
return (JPEGDEC_UNSUPPORTED);
}
/* four tables in progressive allowed */
if((pDecData->frame.codingType == SOF2) && (Th > 3))
{
return (JPEGDEC_UNSUPPORTED);
}
/* set the table pointer */
if(Tc)
{
/* Ac table */
switch (Th)
{
case 0:
JPEGDEC_TRACE_INTERNAL(("ac0\n"));
pDecData->vlc.table = &(pDecData->vlc.acTable0);
break;
case 1:
JPEGDEC_TRACE_INTERNAL(("ac1\n"));
pDecData->vlc.table = &(pDecData->vlc.acTable1);
break;
case 2:
JPEGDEC_TRACE_INTERNAL(("ac2\n"));
pDecData->vlc.table = &(pDecData->vlc.acTable2);
break;
case 3:
JPEGDEC_TRACE_INTERNAL(("ac3\n"));
pDecData->vlc.table = &(pDecData->vlc.acTable3);
break;
default:
return (JPEGDEC_UNSUPPORTED);
}
}
else
{
/* Dc table */
switch (Th)
{
case 0:
JPEGDEC_TRACE_INTERNAL(("dc0\n"));
pDecData->vlc.table = &(pDecData->vlc.dcTable0);
break;
case 1:
JPEGDEC_TRACE_INTERNAL(("dc1\n"));
pDecData->vlc.table = &(pDecData->vlc.dcTable1);
break;
case 2:
JPEGDEC_TRACE_INTERNAL(("dc2\n"));
pDecData->vlc.table = &(pDecData->vlc.dcTable2);
break;
case 3:
JPEGDEC_TRACE_INTERNAL(("dc3\n"));
pDecData->vlc.table = &(pDecData->vlc.dcTable3);
break;
default:
return (JPEGDEC_UNSUPPORTED);
}
}
tmp = 0;
/* read in the values of list BITS */
for(i = 0; i < 16; i++)
{
tmp += pDecData->vlc.table->bits[i] = JpegDecGetByte(pStream);
len++;
}
/* allocate memory for HUFFVALs */
if(pDecData->vlc.table->vals != NULL)
{
/* free previously reserved table */
DWLfree(pDecData->vlc.table->vals);
}
pDecData->vlc.table->vals = (u32 *) DWLmalloc(sizeof(u32) * tmp);
/* set the table length */
pDecData->vlc.table->tableLength = tmp;
/* read in the HUFFVALs */
for(i = 0; i < tmp; i++)
{
pDecData->vlc.table->vals[i] = JpegDecGetByte(pStream);
len++;
}
/* first and last lengths */
for(i = 0; i < 16; i++)
{
if(pDecData->vlc.table->bits[i] != 0)
{
pDecData->vlc.table->start = i;
break;
}
}
for(j = 15; j >= 0; j--)
{
if(pDecData->vlc.table->bits[j] != 0)
{
pDecData->vlc.table->last = ((u32) j + 1);
break;
}
}
}
return (JPEGDEC_OK);
}
/*------------------------------------------------------------------------------
Function name: JpegDecMode
Functional description:
check YCBCR mode
Inputs:
JpegDecContainer *pDecData Pointer to JpegDecContainer structure
Outputs:
OK/NOK
------------------------------------------------------------------------------*/
JpegDecRet JpegDecMode(JpegDecContainer * pDecData)
{
/* check input format */
if(pDecData->frame.Nf == 3)
{
/* JPEG_YCBCR420 */
if(pDecData->frame.component[0].H == 2 &&
pDecData->frame.component[0].V == 2 &&
pDecData->frame.component[1].H == 1 &&
pDecData->frame.component[1].V == 1 &&
pDecData->frame.component[2].H == 1 &&
pDecData->frame.component[2].V == 1)
{
pDecData->info.yCbCrMode = JPEGDEC_YUV420;
pDecData->info.X = pDecData->frame.hwX;
pDecData->info.Y = pDecData->frame.hwY;
/* calculate new output size if slice mode used */
if(pDecData->info.sliceMbSetValue)
{
/* Y */
pDecData->image.sizeLuma = (pDecData->info.X *
(pDecData->info.sliceMbSetValue *
16));
/* CbCr */
pDecData->image.sizeChroma = pDecData->image.sizeLuma / 2;
}
}
/* JPEG_YCBCR422 */
else if(pDecData->frame.component[0].H == 2 &&
pDecData->frame.component[0].V == 1 &&
pDecData->frame.component[1].H == 1 &&
pDecData->frame.component[1].V == 1 &&
pDecData->frame.component[2].H == 1 &&
pDecData->frame.component[2].V == 1)
{
pDecData->info.yCbCrMode = JPEGDEC_YUV422;
pDecData->info.X = (pDecData->frame.hwX);
pDecData->info.Y = (pDecData->frame.hwY);
/* check if fill needed */
if((pDecData->frame.Y & 0xF) && (pDecData->frame.Y & 0xF) <= 8)
pDecData->info.fillBottom = 1;
/* calculate new output size if slice mode used */
if(pDecData->info.sliceMbSetValue)
{
/* Y */
pDecData->image.sizeLuma = (pDecData->info.X *
(pDecData->info.sliceMbSetValue *
16));
/* CbCr */
pDecData->image.sizeChroma = pDecData->image.sizeLuma;
}
}
/* JPEG_YCBCR440 */
else if(pDecData->frame.component[0].H == 1 &&
pDecData->frame.component[0].V == 2 &&
pDecData->frame.component[1].H == 1 &&
pDecData->frame.component[1].V == 1 &&
pDecData->frame.component[2].H == 1 &&
pDecData->frame.component[2].V == 1)
{
pDecData->info.yCbCrMode = JPEGDEC_YUV440;
pDecData->info.X = (pDecData->frame.hwX);
pDecData->info.Y = (pDecData->frame.hwY);
/* check if fill needed */
if((pDecData->frame.X & 0xF) && (pDecData->frame.X & 0xF) <= 8)
pDecData->info.fillRight = 1;
/* calculate new output size if slice mode used */
if(pDecData->info.sliceMbSetValue)
{
/* Y */
pDecData->image.sizeLuma = (pDecData->info.X *
(pDecData->info.sliceMbSetValue *
16));
/* CbCr */
pDecData->image.sizeChroma = pDecData->image.sizeLuma;
}
}
/* JPEG_YCBCR444 : NOT SUPPORTED */
else if(pDecData->frame.component[0].H == 1 &&
pDecData->frame.component[0].V == 1 &&
pDecData->frame.component[1].H == 1 &&
pDecData->frame.component[1].V == 1 &&
pDecData->frame.component[2].H == 1 &&
pDecData->frame.component[2].V == 1)
{
pDecData->info.yCbCrMode = JPEGDEC_YUV444;
pDecData->info.X = pDecData->frame.hwX;
pDecData->info.Y = pDecData->frame.hwY;
/* check if fill needed */
if((pDecData->frame.X & 0xF) && (pDecData->frame.X & 0xF) <= 8)
pDecData->info.fillRight = 1;
if((pDecData->frame.Y & 0xF) && (pDecData->frame.Y & 0xF) <= 8)
pDecData->info.fillBottom = 1;
/* calculate new output size if slice mode used */
if(pDecData->info.sliceMbSetValue)
{
/* Y */
pDecData->image.sizeLuma = (pDecData->info.X *
(pDecData->info.sliceMbSetValue *
16));
/* CbCr */
pDecData->image.sizeChroma = pDecData->image.sizeLuma * 2;
}
}
/* JPEG_YCBCR411 */
else if(pDecData->frame.component[0].H == 4 &&
pDecData->frame.component[0].V == 1 &&
pDecData->frame.component[1].H == 1 &&
pDecData->frame.component[1].V == 1 &&
pDecData->frame.component[2].H == 1 &&
pDecData->frame.component[2].V == 1)
{
pDecData->info.yCbCrMode = JPEGDEC_YUV411;
pDecData->info.X = (pDecData->frame.hwX);
pDecData->info.Y = (pDecData->frame.hwY);
/* check if fill needed */
if((pDecData->frame.Y & 0xF) && (pDecData->frame.Y & 0xF) <= 8)
pDecData->info.fillBottom = 1;
/* calculate new output size if slice mode used */
if(pDecData->info.sliceMbSetValue)
{
/* Y */
pDecData->image.sizeLuma = (pDecData->info.X *
(pDecData->info.sliceMbSetValue *
16));
/* CbCr */
pDecData->image.sizeChroma = pDecData->image.sizeLuma / 2;
}
}
else
{
return (JPEGDEC_UNSUPPORTED);
}
}
else if(pDecData->frame.Nf == 1)
{
/* 4:0:0 */
if((pDecData->frame.component[0].V == 1) ||
(pDecData->frame.component[0].H == 1))
{
pDecData->info.yCbCrMode = JPEGDEC_YUV400;
pDecData->info.X = (pDecData->frame.hwX);
pDecData->info.Y = (pDecData->frame.hwY);
/* check if fill needed */
if((pDecData->frame.X & 0xF) && (pDecData->frame.X & 0xF) <= 8)
pDecData->info.fillRight = 1;
if((pDecData->frame.Y & 0xF) && (pDecData->frame.Y & 0xF) <= 8)
pDecData->info.fillBottom = 1;
/* calculate new output size if slice mode used */
if(pDecData->info.sliceMbSetValue)
{
/* Y */
pDecData->image.sizeLuma =
((((pDecData->info.X +
15) / 16) * 16) * (pDecData->info.sliceMbSetValue *
16));
/* CbCr */
pDecData->image.sizeChroma = 0;
}
}
else
{
return (JPEGDEC_UNSUPPORTED);
}
}
else
{
return (JPEGDEC_UNSUPPORTED);
}
/* save the original sampling format for progressive use */
pDecData->info.yCbCrModeOrig = pDecData->info.yCbCrMode;
return (JPEGDEC_OK);
}