mirror of
https://github.com/nyanmisaka/mpp.git
synced 2025-10-04 16:52:40 +08:00

git-svn-id: https://10.10.10.66:8443/svn/MediaProcessPlatform/trunk/mpp@1180 6e48237b-75ef-9749-8fc9-41990f28c85a
2955 lines
118 KiB
C
2955 lines
118 KiB
C
/*
|
|
*
|
|
* Copyright 2015 Rockchip Electronics Co. LTD
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define MODULE_TAG "jpegd_parser"
|
|
|
|
#include "mpp_bitread.h"
|
|
#include "mpp_mem.h"
|
|
#include "mpp_env.h"
|
|
#include "mpp_packet_impl.h"
|
|
|
|
#include "jpegd_api.h"
|
|
#include "jpegd_parser.h"
|
|
|
|
|
|
#define STRM_ERROR 0xFFFFFFFFU
|
|
RK_U32 jpegd_log = 0;
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name: jpegd_get_byte
|
|
|
|
Functional description:
|
|
Reads one byte (8 bits) from stream and returns the bits
|
|
|
|
Note! This function does not skip the 0x00 byte if the previous
|
|
byte value was 0xFF!!!
|
|
|
|
Inputs:
|
|
StreamStorage *pStream Pointer to structure
|
|
|
|
Outputs:
|
|
Returns 8 bit value if ok
|
|
else returns STRM_ERROR (0xFFFFFFFF)
|
|
------------------------------------------------------------------------------*/
|
|
RK_U32 jpegd_get_byte(StreamStorage * pStream)
|
|
{
|
|
RK_U32 tmp;
|
|
|
|
if ((pStream->readBits + 8) > (8 * pStream->streamLength))
|
|
return (STRM_ERROR);
|
|
|
|
tmp = *(pStream->pCurrPos)++;
|
|
tmp = (tmp << 8) | *(pStream->pCurrPos);
|
|
tmp = (tmp >> (8 - pStream->bitPosInByte)) & 0xFF;
|
|
pStream->readBits += 8;
|
|
return (tmp);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name: jpegd_get_two_bytes
|
|
|
|
Functional description:
|
|
Reads two bytes (16 bits) from stream and returns the bits
|
|
|
|
Note! This function does not skip the 0x00 byte if the previous
|
|
byte value was 0xFF!!!
|
|
|
|
Inputs:
|
|
StreamStorage *pStream Pointer to structure
|
|
|
|
Outputs:
|
|
Returns 16 bit value
|
|
------------------------------------------------------------------------------*/
|
|
RK_U32 jpegd_get_two_bytes(StreamStorage * pStream)
|
|
{
|
|
RK_U32 tmp;
|
|
|
|
if ((pStream->readBits + 16) > (8 * pStream->streamLength))
|
|
return (STRM_ERROR);
|
|
|
|
tmp = *(pStream->pCurrPos)++;
|
|
tmp = (tmp << 8) | *(pStream->pCurrPos)++;
|
|
tmp = (tmp << 8) | *(pStream->pCurrPos);
|
|
tmp = (tmp >> (8 - pStream->bitPosInByte)) & 0xFFFF;
|
|
pStream->readBits += 16;
|
|
return (tmp);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name: jpegd_show_bits
|
|
|
|
Functional description:
|
|
Reads 32 bits from stream and returns the bits, does not update
|
|
stream pointers. If there are not enough bits in data buffer it
|
|
reads the rest of the data buffer bits and fills the lsb of return
|
|
value with zero bits.
|
|
|
|
Note! This function will skip the byte valued 0x00 if the previous
|
|
byte value was 0xFF!!!
|
|
|
|
Inputs:
|
|
StreamStorage *pStream Pointer to structure
|
|
|
|
Outputs:
|
|
Returns 32 bit value
|
|
------------------------------------------------------------------------------*/
|
|
RK_U32 jpegd_show_bits(StreamStorage * pStream)
|
|
{
|
|
RK_S32 bits;
|
|
RK_U32 readBits;
|
|
RK_U32 out = 0;
|
|
RK_U8 *pData = pStream->pCurrPos;
|
|
|
|
/* bits left in buffer */
|
|
bits = (RK_S32) (8 * pStream->streamLength - pStream->readBits);
|
|
if (!bits)
|
|
return (0);
|
|
|
|
readBits = 0;
|
|
do {
|
|
if (pData > pStream->pStartOfStream) {
|
|
/* FF 00 bytes in stream -> jump over 00 byte */
|
|
if ((pData[-1] == 0xFF) && (pData[0] == 0x00)) {
|
|
pData++;
|
|
bits -= 8;
|
|
}
|
|
}
|
|
if (readBits == 32 && pStream->bitPosInByte) {
|
|
out <<= pStream->bitPosInByte;
|
|
out |= *pData >> (8 - pStream->bitPosInByte);
|
|
readBits = 0;
|
|
break;
|
|
}
|
|
out = (out << 8) | *pData++;
|
|
readBits += 8;
|
|
bits -= 8;
|
|
} while (readBits < (32 + pStream->bitPosInByte) && bits > 0);
|
|
|
|
if (bits <= 0 &&
|
|
((readBits + pStream->readBits) >= (pStream->streamLength * 8))) {
|
|
/* not enough bits in stream, fill with zeros */
|
|
out = (out << (32 - (readBits - pStream->bitPosInByte)));
|
|
}
|
|
|
|
return (out);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name: jpegd_flush_bits
|
|
|
|
Functional description:
|
|
Updates stream pointers, flushes bits from stream
|
|
|
|
Note! This function will skip the byte valued 0x00 if the previous
|
|
byte value was 0xFF!!!
|
|
|
|
Inputs:
|
|
StreamStorage *pStream Pointer to structure
|
|
RK_U32 bits Number of bits to be flushed
|
|
|
|
Outputs:
|
|
OK
|
|
STRM_ERROR
|
|
------------------------------------------------------------------------------*/
|
|
RK_U32 jpegd_flush_bits(StreamStorage * pStream, RK_U32 bits)
|
|
{
|
|
RK_U32 tmp;
|
|
RK_U32 extraBits = 0;
|
|
|
|
if ((pStream->readBits + bits) > (8 * pStream->streamLength)) {
|
|
/* there are not so many bits left in buffer */
|
|
/* stream pointers to the end of the stream */
|
|
/* and return value STRM_ERROR */
|
|
pStream->readBits = 8 * pStream->streamLength;
|
|
pStream->bitPosInByte = 0;
|
|
pStream->pCurrPos = pStream->pStartOfStream + pStream->streamLength;
|
|
return (STRM_ERROR);
|
|
} else {
|
|
tmp = 0;
|
|
while (tmp < bits) {
|
|
if (bits - tmp < 8) {
|
|
if ((8 - pStream->bitPosInByte) > (bits - tmp)) {
|
|
/* inside one byte */
|
|
pStream->bitPosInByte += bits - tmp;
|
|
tmp = bits;
|
|
} else {
|
|
if (pStream->pCurrPos[0] == 0xFF &&
|
|
pStream->pCurrPos[1] == 0x00) {
|
|
extraBits += 8;
|
|
pStream->pCurrPos += 2;
|
|
} else {
|
|
pStream->pCurrPos++;
|
|
}
|
|
tmp += 8 - pStream->bitPosInByte;
|
|
pStream->bitPosInByte = 0;
|
|
pStream->bitPosInByte = bits - tmp;
|
|
tmp = bits;
|
|
}
|
|
} else {
|
|
tmp += 8;
|
|
if (pStream->appnFlag) {
|
|
pStream->pCurrPos++;
|
|
} else {
|
|
if (pStream->pCurrPos[0] == 0xFF &&
|
|
pStream->pCurrPos[1] == 0x00) {
|
|
extraBits += 8;
|
|
pStream->pCurrPos += 2;
|
|
} else {
|
|
pStream->pCurrPos++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* update stream pointers */
|
|
pStream->readBits += bits + extraBits;
|
|
return (MPP_OK);
|
|
}
|
|
}
|
|
|
|
JpegDecRet jpegd_set_yuv_mode(JpegSyntaxParam *pSyntax)
|
|
{
|
|
/* check input format */
|
|
if (pSyntax->frame.Nf == 3) {
|
|
/* JPEG_YCBCR420 */
|
|
if (pSyntax->frame.component[0].H == 2 &&
|
|
pSyntax->frame.component[0].V == 2 &&
|
|
pSyntax->frame.component[1].H == 1 &&
|
|
pSyntax->frame.component[1].V == 1 &&
|
|
pSyntax->frame.component[2].H == 1 &&
|
|
pSyntax->frame.component[2].V == 1) {
|
|
JPEGD_INFO_LOG("YCbCr Format: YUV420(2*2:1*1:1*1)");
|
|
pSyntax->info.yCbCrMode = JPEGDEC_YUV420;
|
|
pSyntax->info.X = pSyntax->frame.hwX;
|
|
pSyntax->info.Y = pSyntax->frame.hwY;
|
|
|
|
/* calculate new output size if slice mode used */
|
|
if (pSyntax->info.sliceMbSetValue) {
|
|
/* Y */
|
|
pSyntax->image.sizeLuma = (pSyntax->info.X * (pSyntax->info.sliceMbSetValue * 16));
|
|
|
|
/* CbCr */
|
|
pSyntax->image.sizeChroma = pSyntax->image.sizeLuma / 2;
|
|
}
|
|
}
|
|
/* JPEG_YCBCR422 */
|
|
else if (pSyntax->frame.component[0].H == 2 && pSyntax->frame.component[0].V == 1 &&
|
|
pSyntax->frame.component[1].H == 1 && pSyntax->frame.component[1].V == 1 &&
|
|
pSyntax->frame.component[2].H == 1 && pSyntax->frame.component[2].V == 1) {
|
|
JPEGD_INFO_LOG("YCbCr Format: YUV422(%d*%d:%d*%d:%d*%d)",
|
|
pSyntax->frame.component[0].H, pSyntax->frame.component[0].V,
|
|
pSyntax->frame.component[1].H, pSyntax->frame.component[1].V,
|
|
pSyntax->frame.component[2].H, pSyntax->frame.component[2].V);
|
|
pSyntax->info.yCbCrMode = JPEGDEC_YUV422;
|
|
pSyntax->info.X = (pSyntax->frame.hwX);
|
|
pSyntax->info.Y = (pSyntax->frame.hwY);
|
|
|
|
/* check if fill needed */
|
|
if ((pSyntax->frame.Y & 0xF) && (pSyntax->frame.Y & 0xF) <= 8)
|
|
pSyntax->info.fillBottom = 1;
|
|
|
|
/* calculate new output size if slice mode used */
|
|
if (pSyntax->info.sliceMbSetValue) {
|
|
/* Y */
|
|
pSyntax->image.sizeLuma = (pSyntax->info.X * (pSyntax->info.sliceMbSetValue * 16));
|
|
|
|
/* CbCr */
|
|
pSyntax->image.sizeChroma = pSyntax->image.sizeLuma;
|
|
}
|
|
}
|
|
/* JPEG_YCBCR440 */
|
|
else if (pSyntax->frame.component[0].H == 1 &&
|
|
pSyntax->frame.component[0].V == 2 &&
|
|
pSyntax->frame.component[1].H == 1 &&
|
|
pSyntax->frame.component[1].V == 1 &&
|
|
pSyntax->frame.component[2].H == 1 &&
|
|
pSyntax->frame.component[2].V == 1) {
|
|
JPEGD_INFO_LOG("YCbCr Format: YUV440(1*2:1*1:1*1)");
|
|
pSyntax->info.yCbCrMode = JPEGDEC_YUV440;
|
|
pSyntax->info.X = (pSyntax->frame.hwX);
|
|
pSyntax->info.Y = (pSyntax->frame.hwY);
|
|
|
|
/* check if fill needed */
|
|
if ((pSyntax->frame.X & 0xF) && (pSyntax->frame.X & 0xF) <= 8)
|
|
pSyntax->info.fillRight = 1;
|
|
|
|
/* calculate new output size if slice mode used */
|
|
if (pSyntax->info.sliceMbSetValue) {
|
|
/* Y */
|
|
pSyntax->image.sizeLuma = (pSyntax->info.X * (pSyntax->info.sliceMbSetValue * 16));
|
|
|
|
/* CbCr */
|
|
pSyntax->image.sizeChroma = pSyntax->image.sizeLuma;
|
|
}
|
|
}
|
|
/* JPEG_YCBCR444 : NOT SUPPORTED */
|
|
else if (pSyntax->frame.component[0].H == 1 &&
|
|
pSyntax->frame.component[0].V == 1 &&
|
|
pSyntax->frame.component[1].H == 1 &&
|
|
pSyntax->frame.component[1].V == 1 &&
|
|
pSyntax->frame.component[2].H == 1 &&
|
|
pSyntax->frame.component[2].V == 1) {
|
|
JPEGD_INFO_LOG("YCbCr Format: YUV444(1*1:1*1:1*1)");
|
|
pSyntax->info.yCbCrMode = JPEGDEC_YUV444;
|
|
pSyntax->info.X = pSyntax->frame.hwX;
|
|
pSyntax->info.Y = pSyntax->frame.hwY;
|
|
|
|
/* check if fill needed */
|
|
if ((pSyntax->frame.X & 0xF) && (pSyntax->frame.X & 0xF) <= 8)
|
|
pSyntax->info.fillRight = 1;
|
|
|
|
if ((pSyntax->frame.Y & 0xF) && (pSyntax->frame.Y & 0xF) <= 8)
|
|
pSyntax->info.fillBottom = 1;
|
|
|
|
/* calculate new output size if slice mode used */
|
|
if (pSyntax->info.sliceMbSetValue) {
|
|
/* Y */
|
|
pSyntax->image.sizeLuma = (pSyntax->info.X * (pSyntax->info.sliceMbSetValue * 16));
|
|
|
|
/* CbCr */
|
|
pSyntax->image.sizeChroma = pSyntax->image.sizeLuma * 2;
|
|
}
|
|
}
|
|
/* JPEG_YCBCR411 */
|
|
else if (pSyntax->frame.component[0].H == 4 &&
|
|
pSyntax->frame.component[0].V == 1 &&
|
|
pSyntax->frame.component[1].H == 1 &&
|
|
pSyntax->frame.component[1].V == 1 &&
|
|
pSyntax->frame.component[2].H == 1 &&
|
|
pSyntax->frame.component[2].V == 1) {
|
|
JPEGD_INFO_LOG("YCbCr Format: YUV411(4*1:1*1:1*1)");
|
|
pSyntax->info.yCbCrMode = JPEGDEC_YUV411;
|
|
pSyntax->info.X = (pSyntax->frame.hwX);
|
|
pSyntax->info.Y = (pSyntax->frame.hwY);
|
|
|
|
/* check if fill needed */
|
|
if ((pSyntax->frame.Y & 0xF) && (pSyntax->frame.Y & 0xF) <= 8)
|
|
pSyntax->info.fillBottom = 1;
|
|
|
|
/* calculate new output size if slice mode used */
|
|
if (pSyntax->info.sliceMbSetValue) {
|
|
/* Y */
|
|
pSyntax->image.sizeLuma = (pSyntax->info.X * (pSyntax->info.sliceMbSetValue * 16));
|
|
|
|
/* CbCr */
|
|
pSyntax->image.sizeChroma = pSyntax->image.sizeLuma / 2;
|
|
}
|
|
} else {
|
|
JPEGD_ERROR_LOG("Unsupported YCbCr Format: (%d*%d:%d*%d:%d*%d)", pSyntax->frame.component[0].H, pSyntax->frame.component[0].V,
|
|
pSyntax->frame.component[1].H, pSyntax->frame.component[1].V,
|
|
pSyntax->frame.component[2].H, pSyntax->frame.component[2].V);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
} else if (pSyntax->frame.Nf == 1) {
|
|
/* 4:0:0 */
|
|
if ((pSyntax->frame.component[0].V == 1) ||
|
|
(pSyntax->frame.component[0].H == 1)) {
|
|
pSyntax->info.yCbCrMode = JPEGDEC_YUV400;
|
|
pSyntax->info.X = (pSyntax->frame.hwX);
|
|
pSyntax->info.Y = (pSyntax->frame.hwY);
|
|
|
|
/* check if fill needed */
|
|
if ((pSyntax->frame.X & 0xF) && (pSyntax->frame.X & 0xF) <= 8)
|
|
pSyntax->info.fillRight = 1;
|
|
|
|
if ((pSyntax->frame.Y & 0xF) && (pSyntax->frame.Y & 0xF) <= 8)
|
|
pSyntax->info.fillBottom = 1;
|
|
|
|
/* calculate new output size if slice mode used */
|
|
if (pSyntax->info.sliceMbSetValue) {
|
|
/* Y */
|
|
pSyntax->image.sizeLuma =
|
|
((((pSyntax->info.X + 15) / 16) * 16) * (pSyntax->info.sliceMbSetValue * 16));
|
|
|
|
/* CbCr */
|
|
pSyntax->image.sizeChroma = 0;
|
|
}
|
|
} else {
|
|
JPEGD_ERROR_LOG("unsupported format");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
} else {
|
|
JPEGD_ERROR_LOG("unsupported format");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* save the original sampling format for progressive use */
|
|
pSyntax->info.yCbCrModeOrig = pSyntax->info.yCbCrMode;
|
|
|
|
return (JPEGDEC_OK);
|
|
}
|
|
|
|
JpegDecRet jpegd_decode_frame_header(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_U32 i;
|
|
RK_U32 width, height;
|
|
RK_U32 tmp1, tmp2;
|
|
RK_U32 Hmax = 0;
|
|
RK_U32 Vmax = 0;
|
|
RK_U32 size = 0;
|
|
JpegDecRet retCode;
|
|
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
StreamStorage *pStream = &(pSyntax->stream);
|
|
|
|
retCode = JPEGDEC_OK;
|
|
|
|
/* frame header length */
|
|
pSyntax->frame.Lf = jpegd_get_two_bytes(pStream);
|
|
|
|
/* check if there is enough data */
|
|
if (((pSyntax->stream.readBits / 8) + pSyntax->frame.Lf) >
|
|
pSyntax->stream.streamLength)
|
|
return (JPEGDEC_STRM_ERROR);
|
|
|
|
/* Sample precision */
|
|
pSyntax->frame.P = jpegd_get_byte(pStream);
|
|
if (pSyntax->frame.P != 8) {
|
|
JPEGD_ERROR_LOG("frame.P(%d) is not supported", pSyntax->frame.P);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
/* Number of Lines */
|
|
pSyntax->frame.Y = jpegd_get_two_bytes(pStream);
|
|
if (pSyntax->frame.Y < 1) {
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
pSyntax->frame.hwY = pSyntax->frame.Y;
|
|
|
|
/* round up to next multiple-of-16 */
|
|
pSyntax->frame.hwY += 0xf;
|
|
pSyntax->frame.hwY &= ~(0xf);
|
|
JPEGD_INFO_LOG("Height, frame.Y:%d, frame.hwY:%d", pSyntax->frame.Y, pSyntax->frame.hwY);
|
|
|
|
/* Number of samples per line */
|
|
pSyntax->frame.X = jpegd_get_two_bytes(pStream);
|
|
if (pSyntax->frame.X < 1) {
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
pSyntax->frame.hwX = pSyntax->frame.X;
|
|
|
|
/* round up to next multiple-of-16 */
|
|
pSyntax->frame.hwX += 0xf;
|
|
pSyntax->frame.hwX &= ~(0xf);
|
|
JPEGD_INFO_LOG("Width, frame.X:%d, frame.hwX:%d", pSyntax->frame.X, pSyntax->frame.hwX);
|
|
|
|
/* for internal() */
|
|
pSyntax->info.X = pSyntax->frame.hwX;
|
|
pSyntax->info.Y = pSyntax->frame.hwY;
|
|
|
|
/* check for minimum and maximum dimensions */
|
|
if (pSyntax->frame.hwX < pCtx->minSupportedWidth ||
|
|
pSyntax->frame.hwY < pCtx->minSupportedHeight ||
|
|
pSyntax->frame.hwX > pCtx->maxSupportedWidth ||
|
|
pSyntax->frame.hwY > pCtx->maxSupportedHeight ||
|
|
(pSyntax->frame.hwX * pSyntax->frame.hwY) > pCtx->maxSupportedPixelAmount) {
|
|
JPEGD_ERROR_LOG("FRAME(%d*%d): Unsupported size\n", pSyntax->frame.hwX, pSyntax->frame.hwY);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* Number of components */
|
|
pSyntax->frame.Nf = jpegd_get_byte(pStream);
|
|
if ((pSyntax->frame.Nf != 3) && (pSyntax->frame.Nf != 1)) {
|
|
JPEGD_ERROR_LOG("frame.Nf(%d) is unsupported", pSyntax->frame.Nf);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* save component specific data */
|
|
/* Nf == number of components */
|
|
for (i = 0; i < pSyntax->frame.Nf; i++) {
|
|
pSyntax->frame.component[i].C = jpegd_get_byte(pStream);
|
|
if (i == 0) { /* for the first component */
|
|
/* if first component id is something else than 1 (jfif) */
|
|
pSyntax->scan.index = pSyntax->frame.component[i].C;
|
|
} else {
|
|
/* if component ids 'jumps' */
|
|
if ((pSyntax->frame.component[i - 1].C + 1) != pSyntax->frame.component[i].C) {
|
|
JPEGD_ERROR_LOG("component ids 'jumps'\n");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
}
|
|
tmp1 = jpegd_get_byte(pStream);
|
|
pSyntax->frame.component[i].H = tmp1 >> 4;
|
|
if (pSyntax->frame.component[i].H > Hmax) {
|
|
Hmax = pSyntax->frame.component[i].H;
|
|
}
|
|
pSyntax->frame.component[i].V = tmp1 & 0xF;
|
|
if (pSyntax->frame.component[i].V > Vmax) {
|
|
Vmax = pSyntax->frame.component[i].V;
|
|
}
|
|
|
|
pSyntax->frame.component[i].Tq = jpegd_get_byte(pStream);
|
|
}
|
|
|
|
if (pSyntax->frame.Nf == 1) {
|
|
Hmax = Vmax = 1;
|
|
pSyntax->frame.component[0].H = 1;
|
|
pSyntax->frame.component[0].V = 1;
|
|
} else if (Hmax == 0 || Vmax == 0) {
|
|
JPEGD_ERROR_LOG("Hmax(%d),Vmax(%d) is unsupported", Hmax, Vmax);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* JPEG_YCBCR411 horizontal size has to be multiple of 32 pels */
|
|
if (Hmax == 4 && (pSyntax->frame.hwX & 0x1F)) {
|
|
/* round up to next multiple-of-32 */
|
|
pSyntax->frame.hwX += 16;
|
|
pSyntax->info.X = pSyntax->frame.hwX;
|
|
|
|
/* check for minimum and maximum dimensions */
|
|
if (pSyntax->frame.hwX > pCtx->maxSupportedWidth ||
|
|
(pSyntax->frame.hwX * pSyntax->frame.hwY) > pCtx->maxSupportedPixelAmount) {
|
|
JPEGD_ERROR_LOG("FRAME(%d*%d): Unsupported size\n", pSyntax->frame.hwX, pSyntax->frame.hwY);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
}
|
|
|
|
/* set image pointers, calculate pixelPerRow for each component */
|
|
width = ((pSyntax->frame.hwX + Hmax * 8 - 1) / (Hmax * 8)) * Hmax * 8;
|
|
height = ((pSyntax->frame.hwY + Vmax * 8 - 1) / (Vmax * 8)) * Vmax * 8;
|
|
JPEGD_VERBOSE_LOG("width:%d, height:%d", width, height);
|
|
|
|
/* calculate numMcuInRow and numMcuInFrame */
|
|
JPEGD_ASSERT(Hmax != 0);
|
|
JPEGD_ASSERT(Vmax != 0);
|
|
pSyntax->frame.numMcuInRow = width / (8 * Hmax);
|
|
pSyntax->frame.numMcuInFrame = pSyntax->frame.numMcuInRow * (height / (8 * Vmax));
|
|
JPEGD_VERBOSE_LOG("numMcuInRow:%d, numMcuInFrame:%d", pSyntax->frame.numMcuInRow, pSyntax->frame.numMcuInFrame);
|
|
|
|
/* reset mcuNumbers */
|
|
pSyntax->frame.mcuNumber = 0;
|
|
pSyntax->frame.row = pSyntax->frame.col = 0;
|
|
|
|
for (i = 0; i < pSyntax->frame.Nf; i++) {
|
|
JPEGD_ASSERT(i <= 2);
|
|
tmp1 = (width * pSyntax->frame.component[i].H + Hmax - 1) / Hmax;
|
|
tmp2 = (height * pSyntax->frame.component[i].V + Vmax - 1) / Vmax;
|
|
size += tmp1 * tmp2;
|
|
|
|
/* pixels per row */
|
|
pSyntax->image.pixelsPerRow[i] = tmp1;
|
|
pSyntax->image.columns[i] = tmp2;
|
|
pSyntax->frame.numBlocks[i] =
|
|
(((pSyntax->frame.hwX * pSyntax->frame.component[i].H) / Hmax + 7) >> 3) *
|
|
(((pSyntax->frame.hwY * pSyntax->frame.component[i].V) / Vmax + 7) >> 3);
|
|
|
|
if (i == 0) {
|
|
pSyntax->image.sizeLuma = size;
|
|
}
|
|
}
|
|
|
|
pSyntax->image.size = size;
|
|
pSyntax->image.sizeChroma = size - pSyntax->image.sizeLuma;
|
|
JPEGD_VERBOSE_LOG("sizeLuma:%d", pSyntax->image.sizeLuma);
|
|
JPEGD_VERBOSE_LOG("image.size:%d, sizeChroma:%d", pSyntax->image.size, pSyntax->image.sizeChroma);
|
|
|
|
/* set YUV mode & calculate rlc tmp size */
|
|
retCode = jpegd_set_yuv_mode(pSyntax);
|
|
if (retCode != JPEGDEC_OK) {
|
|
JPEGD_ERROR_LOG("set YUV mode failed");
|
|
return (retCode);
|
|
}
|
|
|
|
return (JPEGDEC_OK);
|
|
FUN_TEST("Exit");
|
|
}
|
|
|
|
JpegDecRet jpegd_decode_scan_header(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_U32 i;
|
|
RK_U32 tmp;
|
|
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
StreamStorage *pStream = &(pSyntax->stream);
|
|
|
|
pSyntax->scan.Ls = jpegd_get_two_bytes(pStream);
|
|
|
|
/* check if there is enough data */
|
|
if (((pStream->readBits / 8) + pSyntax->scan.Ls) > pStream->streamLength) {
|
|
JPEGD_ERROR_LOG("no enough data");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
|
|
pSyntax->scan.Ns = jpegd_get_byte(pStream);
|
|
|
|
pSyntax->info.fillX = pSyntax->info.fillY = 0;
|
|
if (pSyntax->scan.Ns == 1) {
|
|
JPEGD_INFO_LOG("scan.Ns == 1");
|
|
/* Reset to non-interleaved baseline operation type */
|
|
if (pSyntax->info.operationType == JPEGDEC_BASELINE &&
|
|
pSyntax->info.yCbCrMode != JPEGDEC_YUV400)
|
|
pSyntax->info.operationType = JPEGDEC_NONINTERLEAVED;
|
|
|
|
tmp = jpegd_get_byte(pStream);
|
|
pSyntax->frame.cIndex = tmp - 1;
|
|
pSyntax->info.componentId = pSyntax->frame.cIndex;
|
|
pSyntax->scan.Cs[pSyntax->frame.cIndex] = tmp;
|
|
tmp = jpegd_get_byte(pStream);
|
|
pSyntax->scan.Td[pSyntax->frame.cIndex] = tmp >> 4;
|
|
pSyntax->scan.Ta[pSyntax->frame.cIndex] = tmp & 0x0F;
|
|
|
|
/* check/update component info */
|
|
if (pSyntax->frame.Nf == 3) {
|
|
pSyntax->info.fillRight = 0;
|
|
pSyntax->info.fillBottom = 0;
|
|
pSyntax->info.pfNeeded[pSyntax->scan.Cs[pSyntax->frame.cIndex] - 1] = 0;
|
|
if (pSyntax->scan.Cs[pSyntax->frame.cIndex] == 2 ||
|
|
pSyntax->scan.Cs[pSyntax->frame.cIndex] == 3) {
|
|
if (pSyntax->info.operationType == JPEGDEC_PROGRESSIVE ||
|
|
pSyntax->info.operationType == JPEGDEC_NONINTERLEAVED ||
|
|
pSyntax->info.nonInterleavedScanReady) {
|
|
if (pSyntax->info.yCbCrModeOrig == JPEGDEC_YUV420) {
|
|
pSyntax->info.X = pSyntax->frame.hwX >> 1;
|
|
pSyntax->info.Y = pSyntax->frame.hwY >> 1;
|
|
} else if (pSyntax->info.yCbCrModeOrig == JPEGDEC_YUV422) {
|
|
pSyntax->info.X = pSyntax->frame.hwX >> 1;
|
|
} else if (pSyntax->info.yCbCrModeOrig == JPEGDEC_YUV440) {
|
|
pSyntax->info.Y = pSyntax->frame.hwY >> 1;
|
|
} else {
|
|
pSyntax->info.yCbCrMode = 0;
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
}
|
|
|
|
pSyntax->info.yCbCrMode = 0;
|
|
} else if (pSyntax->scan.Cs[pSyntax->frame.cIndex] == 1) { /* YCbCr 4:2:0 */
|
|
pSyntax->info.X = pSyntax->frame.hwX;
|
|
pSyntax->info.Y = pSyntax->frame.hwY;
|
|
if (pSyntax->info.yCbCrMode == JPEGDEC_YUV420) {
|
|
pSyntax->info.yCbCrMode = 1;
|
|
} else if (pSyntax->info.yCbCrMode == JPEGDEC_YUV422) {
|
|
pSyntax->info.yCbCrMode = 0;
|
|
if (pSyntax->frame.cIndex == 0) {
|
|
JPEGD_INFO_LOG("SCAN: #YUV422 FLAG\n");
|
|
pSyntax->info.yCbCr422 = 1;
|
|
}
|
|
} else if (pSyntax->info.yCbCrMode == JPEGDEC_YUV444) {
|
|
pSyntax->info.yCbCrMode = 0;
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
} else {
|
|
pSyntax->info.yCbCrMode = 0;
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
if (pSyntax->info.X & 0xF) {
|
|
pSyntax->info.X += 8;
|
|
pSyntax->info.fillX = 1;
|
|
} else if ((pSyntax->scan.Cs[pSyntax->frame.cIndex] == 1 ||
|
|
pSyntax->info.yCbCrModeOrig == JPEGDEC_YUV440) &&
|
|
(pSyntax->frame.X & 0xF) && (pSyntax->frame.X & 0xF) <= 8) {
|
|
pSyntax->info.fillRight = 1;
|
|
}
|
|
|
|
if (pSyntax->info.Y & 0xF) {
|
|
pSyntax->info.Y += 8;
|
|
pSyntax->info.fillY = 1;
|
|
} else if ((pSyntax->scan.Cs[pSyntax->frame.cIndex] == 1 ||
|
|
pSyntax->info.yCbCrModeOrig == JPEGDEC_YUV422) &&
|
|
(pSyntax->frame.Y & 0xF) && (pSyntax->frame.Y & 0xF) <= 8) {
|
|
pSyntax->info.fillBottom = 1;
|
|
}
|
|
} else if (pSyntax->frame.Nf == 1) {
|
|
JPEGD_INFO_LOG("SCAN: #YUV422 FLAG\n");
|
|
pSyntax->info.yCbCr422 = 0;
|
|
}
|
|
|
|
/* decoding info */
|
|
if (pSyntax->info.operationType == JPEGDEC_PROGRESSIVE ||
|
|
pSyntax->info.operationType == JPEGDEC_NONINTERLEAVED) {
|
|
pSyntax->info.yCbCrMode = 0;
|
|
}
|
|
} else {
|
|
for (i = 0; i < pSyntax->scan.Ns; i++) {
|
|
pSyntax->scan.Cs[i] = jpegd_get_byte(pStream);
|
|
tmp = jpegd_get_byte(pStream);
|
|
pSyntax->scan.Td[i] = tmp >> 4; /* which DC table */
|
|
pSyntax->scan.Ta[i] = tmp & 0x0F; /* which AC table */
|
|
pSyntax->info.pfNeeded[i] = 1;
|
|
}
|
|
pSyntax->info.X = pSyntax->frame.hwX;
|
|
pSyntax->info.Y = pSyntax->frame.hwY;
|
|
pSyntax->frame.cIndex = 0;
|
|
pSyntax->info.yCbCrMode = pSyntax->info.yCbCrModeOrig;
|
|
}
|
|
|
|
pSyntax->scan.Ss = jpegd_get_byte(pStream);
|
|
pSyntax->scan.Se = jpegd_get_byte(pStream);
|
|
tmp = jpegd_get_byte(pStream);
|
|
pSyntax->scan.Ah = tmp >> 4;
|
|
pSyntax->scan.Al = tmp & 0x0F;
|
|
|
|
if (pSyntax->frame.codingType == SOF0) {
|
|
/* baseline */
|
|
if (pSyntax->scan.Ss != 0)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
if (pSyntax->scan.Se != 63)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
if (pSyntax->scan.Ah != 0)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
if (pSyntax->scan.Al != 0)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
|
|
/* update scan decoding parameters */
|
|
/* interleaved/non-interleaved */
|
|
if (pSyntax->info.operationType == JPEGDEC_BASELINE)
|
|
pSyntax->info.nonInterleaved = 0;
|
|
else
|
|
pSyntax->info.nonInterleaved = 1;
|
|
/* decoding info */
|
|
if ((pSyntax->frame.Nf == 3 && pSyntax->scan.Ns == 1) ||
|
|
(pSyntax->frame.Nf == 1 && pSyntax->scan.Ns == 1))
|
|
pSyntax->info.amountOfQTables = 1;
|
|
else
|
|
pSyntax->info.amountOfQTables = 3;
|
|
}
|
|
|
|
if (pSyntax->frame.codingType == SOF2) {
|
|
/* progressive */
|
|
if (pSyntax->scan.Ss == 0 && pSyntax->scan.Se != 0)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
if (/*pSyntax->scan.Ah < 0 ||*/ pSyntax->scan.Ah > 13)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
if (/*pSyntax->scan.Al < 0 ||*/ pSyntax->scan.Al > 13)
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
|
|
/* update scan decoding parameters */
|
|
/* TODO! What if 2 components, possible??? */
|
|
/* interleaved/non-interleaved */
|
|
if (pSyntax->scan.Ns == 1) {
|
|
pSyntax->info.nonInterleaved = 1;
|
|
/* component ID */
|
|
pSyntax->info.componentId = pSyntax->frame.cIndex;
|
|
pSyntax->info.amountOfQTables = 1;
|
|
} else {
|
|
pSyntax->info.nonInterleaved = 0;
|
|
/* component ID ==> set to luma ==> interleaved */
|
|
pSyntax->info.componentId = 0;
|
|
pSyntax->info.amountOfQTables = 3;
|
|
}
|
|
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
return (JPEGDEC_OK);
|
|
}
|
|
|
|
JpegDecRet jpegd_decode_scan(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
JpegDecRet retCode;
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
retCode = JPEGDEC_ERROR;
|
|
|
|
retCode = jpegd_decode_scan_header(pCtx);
|
|
if (retCode != JPEGDEC_OK) {
|
|
JPEGD_ERROR_LOG("Decode Scan Header Failed");
|
|
return (retCode);
|
|
}
|
|
|
|
JPEGD_VERBOSE_LOG("SCAN: MODE: %d\n", pSyntax->frame.codingType);
|
|
FUN_TEST("Exit");
|
|
return (JPEGDEC_OK);
|
|
}
|
|
|
|
JpegDecRet jpegd_decode_huffman_tables(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_U32 i, len, Tc, Th, tmp;
|
|
RK_S32 j;
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
StreamStorage *pStream = &(pSyntax->stream);
|
|
|
|
pSyntax->vlc.Lh = jpegd_get_two_bytes(pStream);
|
|
|
|
/* check if there is enough data for tables */
|
|
if (((pStream->readBits / 8) + pSyntax->vlc.Lh) > pStream->streamLength) {
|
|
JPEGD_ERROR_LOG("no enough data for tables");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
|
|
/* four bytes already read in */
|
|
len = 4;
|
|
|
|
while (len < pSyntax->vlc.Lh) {
|
|
tmp = jpegd_get_byte(pStream);
|
|
len++;
|
|
Tc = tmp >> 4; /* Table class */
|
|
if (Tc != 0 && Tc != 1) {
|
|
JPEGD_ERROR_LOG("Tc(%d) is unsupported", Tc);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
Th = tmp & 0xF; /* Huffman table identifier */
|
|
/* only two tables in baseline allowed */
|
|
if ((pSyntax->frame.codingType == SOF0) && (Th > 1)) {
|
|
JPEGD_ERROR_LOG("Th(%d) is unsupported", Th);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
/* four tables in progressive allowed */
|
|
if ((pSyntax->frame.codingType == SOF2) && (Th > 3)) {
|
|
JPEGD_ERROR_LOG("Th(%d) is unsupported", Th);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* set the table pointer */
|
|
if (Tc) {
|
|
/* Ac table */
|
|
switch (Th) {
|
|
case 0:
|
|
JPEGD_VERBOSE_LOG("ac0\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.acTable0);
|
|
break;
|
|
case 1:
|
|
JPEGD_VERBOSE_LOG("ac1\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.acTable1);
|
|
break;
|
|
case 2:
|
|
JPEGD_VERBOSE_LOG("ac2\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.acTable2);
|
|
break;
|
|
case 3:
|
|
JPEGD_VERBOSE_LOG("ac3\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.acTable3);
|
|
break;
|
|
default:
|
|
JPEGD_ERROR_LOG("Th(%d) is unsupported", Th);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
} else {
|
|
/* Dc table */
|
|
switch (Th) {
|
|
case 0:
|
|
JPEGD_VERBOSE_LOG("dc0\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.dcTable0);
|
|
break;
|
|
case 1:
|
|
JPEGD_VERBOSE_LOG("dc1\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.dcTable1);
|
|
break;
|
|
case 2:
|
|
JPEGD_VERBOSE_LOG("dc2\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.dcTable2);
|
|
break;
|
|
case 3:
|
|
JPEGD_VERBOSE_LOG("dc3\n");
|
|
pSyntax->vlc.table = &(pSyntax->vlc.dcTable3);
|
|
break;
|
|
default:
|
|
JPEGD_ERROR_LOG("Th(%d) is unsupported", Th);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
}
|
|
|
|
tmp = 0;
|
|
/* read in the values of list BITS */
|
|
for (i = 0; i < 16; i++) {
|
|
tmp += pSyntax->vlc.table->bits[i] = jpegd_get_byte(pStream);
|
|
len++;
|
|
}
|
|
/* allocate memory for HUFFVALs */
|
|
if (pSyntax->vlc.table->vals != NULL) {
|
|
/* free previously reserved table */
|
|
mpp_free(pSyntax->vlc.table->vals);
|
|
}
|
|
|
|
pSyntax->vlc.table->vals = (RK_U32 *) mpp_calloc(RK_U32, tmp);
|
|
|
|
/* set the table length */
|
|
pSyntax->vlc.table->tableLength = tmp;
|
|
/* read in the HUFFVALs */
|
|
for (i = 0; i < tmp; i++) {
|
|
pSyntax->vlc.table->vals[i] = jpegd_get_byte(pStream);
|
|
len++;
|
|
}
|
|
/* first and last lengths */
|
|
for (i = 0; i < 16; i++) {
|
|
if (pSyntax->vlc.table->bits[i] != 0) {
|
|
pSyntax->vlc.table->start = i;
|
|
break;
|
|
}
|
|
}
|
|
for (j = 15; j >= 0; j--) {
|
|
if (pSyntax->vlc.table->bits[j] != 0) {
|
|
pSyntax->vlc.table->last = ((RK_U32) j + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (JPEGDEC_OK);
|
|
FUN_TEST("Exit");
|
|
}
|
|
|
|
JpegDecRet jpegd_decode_quant_tables(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_U32 t, tmp, i;
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
StreamStorage *pStream = &(pSyntax->stream);
|
|
|
|
pSyntax->quant.Lq = jpegd_get_two_bytes(pStream);
|
|
|
|
/* check if there is enough data for tables */
|
|
if (((pStream->readBits / 8) + pSyntax->quant.Lq) > pStream->streamLength) {
|
|
JPEGD_ERROR_LOG("no enough data for tables");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
|
|
t = 4;
|
|
|
|
while (t < pSyntax->quant.Lq) {
|
|
/* Tq value selects what table the components use */
|
|
|
|
/* read tables and write to decData->quant */
|
|
tmp = jpegd_get_byte(pStream);
|
|
t++;
|
|
/* supporting only 8 bits / sample */
|
|
if ((tmp >> 4) != 0) {
|
|
JPEGD_ERROR_LOG("Pq(%d) is not supported!", (tmp >> 4));
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
tmp &= 0xF; /* Tq */
|
|
/* set the quantisation table pointer */
|
|
|
|
if (tmp == 0) {
|
|
JPEGD_VERBOSE_LOG("qtable0\n");
|
|
pSyntax->quant.table = pSyntax->quant.table0;
|
|
} else if (tmp == 1) {
|
|
JPEGD_VERBOSE_LOG("qtable1\n");
|
|
pSyntax->quant.table = pSyntax->quant.table1;
|
|
} else if (tmp == 2) {
|
|
JPEGD_VERBOSE_LOG("qtable2\n");
|
|
pSyntax->quant.table = pSyntax->quant.table2;
|
|
} else if (tmp == 3) {
|
|
JPEGD_VERBOSE_LOG("qtable3\n");
|
|
pSyntax->quant.table = pSyntax->quant.table3;
|
|
} else {
|
|
JPEGD_ERROR_LOG("Tq(%d) is not supported!", tmp);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
for (i = 0; i < 64; i++) {
|
|
pSyntax->quant.table[i] = jpegd_get_byte(pStream);
|
|
t++;
|
|
}
|
|
}
|
|
|
|
return (MPP_OK);
|
|
FUN_TEST("Exit");
|
|
}
|
|
|
|
JpegDecRet jpegd_default_huffman_tables(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
|
|
/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
|
|
/* IMPORTANT: these are only valid for 8-bit data precision! */
|
|
uint8_t ff_mjpeg_bits_dc_luminance[17] =
|
|
{ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
|
|
uint8_t ff_mjpeg_val_dc[12] = //luminance and chrominance all use it
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
|
|
|
|
uint8_t ff_mjpeg_bits_dc_chrominance[17] =
|
|
{ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
|
|
|
|
uint8_t ff_mjpeg_bits_ac_luminance[17] =
|
|
{ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
|
|
uint8_t ff_mjpeg_val_ac_luminance[] = {
|
|
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
|
|
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
|
|
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
|
|
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
|
|
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
|
|
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
|
|
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
|
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
|
|
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
|
|
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
|
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
|
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
|
|
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
|
|
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
|
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
|
|
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
|
|
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
|
|
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
|
|
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
|
|
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
|
0xf9, 0xfa
|
|
};
|
|
|
|
uint8_t ff_mjpeg_bits_ac_chrominance[17] =
|
|
{ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
|
|
|
|
uint8_t ff_mjpeg_val_ac_chrominance[] = {
|
|
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
|
|
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
|
|
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
|
|
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
|
|
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
|
|
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
|
|
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
|
|
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
|
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
|
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
|
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
|
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
|
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
|
|
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
|
|
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
|
|
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
|
|
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
|
|
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
|
|
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
|
|
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
|
0xf9, 0xfa
|
|
};
|
|
|
|
RK_U32 i, len, tmp, k;
|
|
RK_S32 j;
|
|
uint8_t *bitstable[4] = {ff_mjpeg_bits_dc_luminance, ff_mjpeg_bits_ac_luminance, ff_mjpeg_bits_dc_chrominance, ff_mjpeg_bits_ac_chrominance};
|
|
uint8_t *valtable[4] = {ff_mjpeg_val_dc, ff_mjpeg_val_ac_luminance, ff_mjpeg_val_dc, ff_mjpeg_val_ac_chrominance};
|
|
uint8_t *bitstmp;
|
|
uint8_t *valtmp;
|
|
|
|
for (k = 0; k < 4; k++) {
|
|
bitstmp = bitstable[k];
|
|
valtmp = valtable[k];
|
|
|
|
if (k == 0)
|
|
pSyntax->vlc.table = &(pSyntax->vlc.dcTable0);
|
|
else if (k == 1)
|
|
pSyntax->vlc.table = &(pSyntax->vlc.acTable0);
|
|
else if (k == 2)
|
|
pSyntax->vlc.table = &(pSyntax->vlc.dcTable1);
|
|
else
|
|
pSyntax->vlc.table = &(pSyntax->vlc.acTable1);
|
|
|
|
tmp = 0;
|
|
/* read in the values of list BITS */
|
|
for (i = 0; i < 16; i++) {
|
|
tmp += pSyntax->vlc.table->bits[i] = bitstmp[i + 1];
|
|
len++;
|
|
}
|
|
/* allocate memory for HUFFVALs */
|
|
if (pSyntax->vlc.table->vals != NULL) {
|
|
/* free previously reserved table */
|
|
mpp_free(pSyntax->vlc.table->vals);
|
|
}
|
|
|
|
pSyntax->vlc.table->vals = (RK_U32 *) mpp_calloc(RK_U32, tmp);
|
|
|
|
/* set the table length */
|
|
pSyntax->vlc.table->tableLength = tmp;
|
|
/* read in the HUFFVALs */
|
|
for (i = 0; i < tmp; i++) {
|
|
pSyntax->vlc.table->vals[i] = valtmp[i];
|
|
len++;
|
|
}
|
|
/* first and last lengths */
|
|
for (i = 0; i < 16; i++) {
|
|
if (pSyntax->vlc.table->bits[i] != 0) {
|
|
pSyntax->vlc.table->start = i;
|
|
break;
|
|
}
|
|
}
|
|
for (j = 15; j >= 0; j--) {
|
|
if (pSyntax->vlc.table->bits[j] != 0) {
|
|
pSyntax->vlc.table->last = ((RK_U32) j + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_parser_split_frame(RK_U8 *src, RK_U32 src_size, RK_U8 *dst, RK_U32 *dst_size)
|
|
{
|
|
FUN_TEST("Enter");
|
|
MPP_RET ret = MPP_OK;
|
|
if (NULL == src || NULL == dst || src_size <= 0) {
|
|
JPEGD_ERROR_LOG("NULL pointer or wrong src_size(%d)", src_size);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
RK_U8 *end;
|
|
RK_U8 *tmp;
|
|
RK_U32 str_size = (src_size + 255) & (~255);
|
|
end = dst + src_size;
|
|
|
|
if (src[6] == 0x41 && src[7] == 0x56 && src[8] == 0x49 && src[9] == 0x31) {
|
|
//distinguish 310 from 210 camera
|
|
RK_U32 i;
|
|
RK_U32 copy_len = 0;
|
|
tmp = src;
|
|
JPEGD_INFO_LOG("distinguish 310 from 210 camera");
|
|
|
|
for (i = 0; i < src_size - 4; i++) {
|
|
if (tmp[i] == 0xff) {
|
|
if (tmp[i + 1] == 0x00 && tmp[i + 2] == 0xff && ((tmp[i + 3] & 0xf0) == 0xd0))
|
|
i += 2;
|
|
}
|
|
*dst++ = tmp[i];
|
|
copy_len++;
|
|
}
|
|
for (; i < src_size; i++) {
|
|
*dst++ = tmp[i];
|
|
copy_len++;
|
|
}
|
|
if (copy_len < src_size)
|
|
memset(dst, 0, src_size - copy_len);
|
|
*dst_size = copy_len;
|
|
} else {
|
|
memcpy(dst, src, src_size);
|
|
memset(dst + src_size, 0, str_size - src_size);
|
|
*dst_size = src_size;
|
|
}
|
|
|
|
/* NOTE: hardware bug, need to remove tailing FF 00 before FF D9 end flag */
|
|
if (end[-1] == 0xD9 && end[-2] == 0xFF) {
|
|
end -= 2;
|
|
|
|
do {
|
|
if (end[-1] == 0xFF) {
|
|
end--;
|
|
continue;
|
|
}
|
|
if (end[-1] == 0x00 && end [-2] == 0xFF) {
|
|
end -= 2;
|
|
continue;
|
|
}
|
|
break;
|
|
} while (1);
|
|
|
|
JPEGD_INFO_LOG("remove tailing FF 00 before FF D9 end flag.");
|
|
end[0] = 0xff;
|
|
end[1] = 0xD9;
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET jpegd_prepare(void *ctx, MppPacket pkt, HalDecTask *task)
|
|
{
|
|
FUN_TEST("Enter");
|
|
MPP_RET ret = MPP_OK;
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
MppPacket input_packet = JpegParserCtx->input_packet;
|
|
RK_U32 pkt_length = 0;
|
|
RK_U32 copy_length = 0;
|
|
void *pPacket = NULL;
|
|
void *pPos = NULL;
|
|
|
|
task->valid = 0;
|
|
|
|
JpegParserCtx->pts = mpp_packet_get_pts(pkt);
|
|
JpegParserCtx->eos = mpp_packet_get_eos(pkt);
|
|
pkt_length = mpp_packet_get_length(pkt);
|
|
pPacket = pPos = mpp_packet_get_pos(pkt);
|
|
|
|
if (JpegParserCtx->eos) {
|
|
|
|
JPEGD_INFO_LOG("it is end of stream.");
|
|
task->flags.eos = 1;
|
|
return ret;
|
|
}
|
|
|
|
if (pkt_length > JpegParserCtx->bufferSize) {
|
|
JPEGD_INFO_LOG("Huge Frame(%d Bytes)!", pkt_length);
|
|
mpp_free(JpegParserCtx->recv_buffer);
|
|
JpegParserCtx->recv_buffer = NULL;
|
|
|
|
JpegParserCtx->recv_buffer = mpp_calloc(RK_U8, pkt_length + 1024);
|
|
if (NULL == JpegParserCtx->recv_buffer) {
|
|
JPEGD_ERROR_LOG("no memory!");
|
|
return MPP_ERR_NOMEM;
|
|
}
|
|
|
|
JpegParserCtx->bufferSize = pkt_length + 1024;
|
|
}
|
|
|
|
jpegd_parser_split_frame(pPacket, pkt_length, JpegParserCtx->recv_buffer, ©_length);
|
|
|
|
pPos += pkt_length;
|
|
mpp_packet_set_pos(pkt, pPos);
|
|
if (copy_length != pkt_length) {
|
|
JPEGD_INFO_LOG("there seems to be something wrong with split_frame. pkt_length:%d, copy_length:%d", pkt_length, copy_length);
|
|
}
|
|
|
|
/* debug information */
|
|
if (JpegParserCtx->parser_debug_enable && JpegParserCtx->input_jpeg_count < 3) {
|
|
static FILE *jpg_file;
|
|
static char name[32];
|
|
|
|
snprintf(name, sizeof(name), "/data/input%02d.jpg", JpegParserCtx->input_jpeg_count);
|
|
jpg_file = fopen(name, "wb+");
|
|
if (jpg_file) {
|
|
JPEGD_INFO_LOG("input jpeg(%d Bytes) saving to %s\n", pkt_length, name);
|
|
fwrite(pPacket, pkt_length, 1, jpg_file);
|
|
fclose(jpg_file);
|
|
JpegParserCtx->input_jpeg_count++;
|
|
}
|
|
}
|
|
|
|
mpp_packet_set_data(input_packet, JpegParserCtx->recv_buffer);
|
|
mpp_packet_set_size(input_packet, pkt_length);
|
|
mpp_packet_set_length(input_packet, pkt_length);
|
|
|
|
JpegParserCtx->streamLength = pkt_length;
|
|
JpegParserCtx->bufferSize = pkt_length;
|
|
task->input_packet = input_packet;
|
|
task->valid = 1;
|
|
JPEGD_VERBOSE_LOG("input_packet:%p, recv_buffer:%p, pkt_length:%d", input_packet,
|
|
JpegParserCtx->recv_buffer, pkt_length);
|
|
|
|
FUN_TEST("Exit");
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET jpegd_read_decode_parameters(JpegParserContext *ctx, StreamStorage *pStream)
|
|
{
|
|
FUN_TEST("Enter");
|
|
if (NULL == ctx || NULL == pStream) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
JpegParserContext *pCtx = ctx;
|
|
JpegDecImageInfo *pImageInfo = (JpegDecImageInfo *) & (pCtx->imageInfo);
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
RK_U32 Nf = 0, Ns = 0, NsThumb = 0;
|
|
RK_U32 i, j = 0, init = 0, initThumb = 0;
|
|
RK_U32 H[MAX_NUMBER_OF_COMPONENTS];
|
|
RK_U32 V[MAX_NUMBER_OF_COMPONENTS];
|
|
RK_U32 Htn[MAX_NUMBER_OF_COMPONENTS];
|
|
RK_U32 Vtn[MAX_NUMBER_OF_COMPONENTS];
|
|
RK_U32 Hmax = 0, Vmax = 0, headerLength = 0;
|
|
RK_U32 currentByte = 0, currentBytes = 0;
|
|
RK_U32 appLength = 0, appBits = 0;
|
|
RK_U32 thumbnail = 0, errorCode = 0;
|
|
|
|
/* reset sampling factors */
|
|
for (i = 0; i < MAX_NUMBER_OF_COMPONENTS; i++) {
|
|
H[i] = 0;
|
|
V[i] = 0;
|
|
Htn[i] = 0;
|
|
Vtn[i] = 0;
|
|
}
|
|
|
|
/* Read decoding parameters */
|
|
for (pStream->readBits = 0; (pStream->readBits / 8) < pStream->streamLength; pStream->readBits++) {
|
|
/* Look for marker prefix byte from stream */
|
|
if ((currentByte == 0xFF) || jpegd_get_byte(pStream) == 0xFF) {
|
|
currentByte = jpegd_get_byte(pStream);
|
|
|
|
switch (currentByte) { /* switch to certain header decoding */
|
|
case SOF0: /* baseline marker */
|
|
case SOF2: { /* progresive marker */
|
|
JPEGD_VERBOSE_LOG("SOF, currentByte:0x%x", currentByte);
|
|
if (currentByte == SOF0) {
|
|
pImageInfo->codingMode = pSyntax->info.operationType = JPEGDEC_BASELINE;
|
|
} else {
|
|
pImageInfo->codingMode = pSyntax->info.operationType = JPEGDEC_PROGRESSIVE;
|
|
}
|
|
|
|
/* Frame header */
|
|
i++;
|
|
Hmax = 0;
|
|
Vmax = 0;
|
|
|
|
/* SOF0/SOF2 length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
/* Sample precision (only 8 bits/sample supported) */
|
|
currentByte = jpegd_get_byte(pStream);
|
|
if (currentByte != 8) {
|
|
JPEGD_ERROR_LOG("Sample precision");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* Number of Lines */
|
|
pImageInfo->outputHeight = jpegd_get_two_bytes(pStream);
|
|
pImageInfo->displayHeight = pImageInfo->outputHeight;
|
|
if (pImageInfo->outputHeight < 1) {
|
|
JPEGD_ERROR_LOG("pImageInfo->outputHeight(%d) Unsupported", pImageInfo->outputHeight);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* round up to next multiple-of-16 */
|
|
pImageInfo->outputHeight += 0xf;
|
|
pImageInfo->outputHeight &= ~(0xf);
|
|
pSyntax->frame.hwY = pImageInfo->outputHeight;
|
|
|
|
/* Number of Samples per Line */
|
|
pImageInfo->outputWidth = jpegd_get_two_bytes(pStream);
|
|
pImageInfo->displayWidth = pImageInfo->outputWidth;
|
|
if (pImageInfo->outputWidth < 1) {
|
|
JPEGD_ERROR_LOG("pImageInfo->outputWidth(%d) Unsupported", pImageInfo->outputWidth);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
pImageInfo->outputWidth += 0xf;
|
|
pImageInfo->outputWidth &= ~(0xf);
|
|
pSyntax->frame.hwX = pImageInfo->outputWidth;
|
|
|
|
/* check for minimum and maximum dimensions */
|
|
if (pImageInfo->outputWidth < pCtx->minSupportedWidth ||
|
|
pImageInfo->outputHeight < pCtx->minSupportedHeight ||
|
|
pImageInfo->outputWidth > pCtx->maxSupportedWidth ||
|
|
pImageInfo->outputHeight > pCtx->maxSupportedHeight ||
|
|
(pImageInfo->outputWidth * pImageInfo->outputHeight) > pCtx->maxSupportedPixelAmount) {
|
|
JPEGD_ERROR_LOG("Unsupported size(%d*%d)", pImageInfo->outputWidth, pImageInfo->outputHeight);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* Number of Image Components per Frame */
|
|
Nf = jpegd_get_byte(pStream);
|
|
if (Nf != 3 && Nf != 1) {
|
|
JPEGD_ERROR_LOG("Number of Image Components per Frame: %d", Nf);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
for (j = 0; j < Nf; j++) {
|
|
if (jpegd_flush_bits(pStream, 8) == STRM_ERROR) { /* jump over component identifier */
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
currentByte = jpegd_get_byte(pStream);
|
|
H[j] = (currentByte >> 4); /* Horizontal sampling factor */
|
|
V[j] = (currentByte & 0xF); /* Vertical sampling factor */
|
|
|
|
if (jpegd_flush_bits(pStream, 8) == STRM_ERROR) { /* jump over Tq */
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
if (H[j] > Hmax)
|
|
Hmax = H[j];
|
|
if (V[j] > Vmax)
|
|
Vmax = V[j];
|
|
}
|
|
if (Hmax == 0 || Vmax == 0) {
|
|
JPEGD_ERROR_LOG("Hmax(%d), Vmax(%d)", Hmax, Vmax);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* check format */
|
|
if (H[0] == 2 && V[0] == 2 &&
|
|
H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) {
|
|
pImageInfo->outputFormat = JPEGDEC_YCbCr420_SEMIPLANAR;
|
|
pSyntax->frame.numMcuInRow = (pSyntax->frame.hwX / 16);
|
|
pSyntax->frame.numMcuInFrame = ((pSyntax->frame.hwX * pSyntax->frame.hwY) / 256);
|
|
} else if (H[0] == 2 && V[0] == 1 && H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) {
|
|
pImageInfo->outputFormat = JPEGDEC_YCbCr422_SEMIPLANAR;
|
|
pSyntax->frame.numMcuInRow = (pSyntax->frame.hwX / 16);
|
|
pSyntax->frame.numMcuInFrame = ((pSyntax->frame.hwX * pSyntax->frame.hwY) / 128);
|
|
} else if (H[0] == 1 && V[0] == 2 &&
|
|
H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) {
|
|
pImageInfo->outputFormat = JPEGDEC_YCbCr440;
|
|
pSyntax->frame.numMcuInRow = (pSyntax->frame.hwX / 8);
|
|
pSyntax->frame.numMcuInFrame = ((pSyntax->frame.hwX * pSyntax->frame.hwY) / 128);
|
|
} else if (H[0] == 1 && V[0] == 1 &&
|
|
H[1] == 0 && V[1] == 0 && H[2] == 0 && V[2] == 0) {
|
|
pImageInfo->outputFormat = JPEGDEC_YCbCr400;
|
|
pSyntax->frame.numMcuInRow = (pSyntax->frame.hwX / 8);
|
|
pSyntax->frame.numMcuInFrame = ((pSyntax->frame.hwX * pSyntax->frame.hwY) / 64);
|
|
} else if (pCtx->extensionsSupported &&
|
|
H[0] == 4 && V[0] == 1 &&
|
|
H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) {
|
|
/* YUV411 output has to be 32 pixel multiple */
|
|
if (pImageInfo->outputWidth & 0x1F) {
|
|
pImageInfo->outputWidth += 16;
|
|
pSyntax->frame.hwX = pImageInfo->outputWidth;
|
|
}
|
|
|
|
/* check for maximum dimensions */
|
|
if (pImageInfo->outputWidth > pCtx->maxSupportedWidth ||
|
|
(pImageInfo->outputWidth * pImageInfo->outputHeight) > pCtx->maxSupportedPixelAmount) {
|
|
JPEGD_ERROR_LOG("Unsupported size(%d*%d)", pImageInfo->outputWidth, pImageInfo->outputHeight);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
pImageInfo->outputFormat = JPEGDEC_YCbCr411_SEMIPLANAR;
|
|
pSyntax->frame.numMcuInRow = (pSyntax->frame.hwX / 32);
|
|
pSyntax->frame.numMcuInFrame = ((pSyntax->frame.hwX * pSyntax->frame.hwY) / 256);
|
|
} else if (pCtx->extensionsSupported &&
|
|
H[0] == 1 && V[0] == 1 &&
|
|
H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) {
|
|
pImageInfo->outputFormat = JPEGDEC_YCbCr444_SEMIPLANAR;
|
|
pSyntax->frame.numMcuInRow = (pSyntax->frame.hwX / 8);
|
|
pSyntax->frame.numMcuInFrame = ((pSyntax->frame.hwX * pSyntax->frame.hwY) / 64);
|
|
} else {
|
|
JPEGD_ERROR_LOG("Unsupported YCbCr format");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* restore output format */
|
|
pSyntax->info.yCbCrMode = pSyntax->info.getInfoYCbCrMode = pImageInfo->outputFormat;
|
|
break;
|
|
}
|
|
case SOS: {
|
|
JPEGD_VERBOSE_LOG("SOS, currentByte:0x%x", currentByte);
|
|
/* SOS length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("SOS, headerLength:%d", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
/* check if interleaved or non-ibnterleaved */
|
|
Ns = jpegd_get_byte(pStream);
|
|
if (Ns == MIN_NUMBER_OF_COMPONENTS &&
|
|
pImageInfo->outputFormat != JPEGDEC_YCbCr400 && pImageInfo->codingMode == JPEGDEC_BASELINE) {
|
|
pImageInfo->codingMode = pSyntax->info.operationType = JPEGDEC_NONINTERLEAVED;
|
|
}
|
|
|
|
/* jump over SOS header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
|
|
if ((pStream->readBits + 8) < (8 * pStream->streamLength)) {
|
|
pSyntax->info.init = 1;
|
|
init = 1;
|
|
} else {
|
|
JPEGD_ERROR_LOG("Needs to increase input buffer");
|
|
return (JPEGDEC_INCREASE_INPUT_BUFFER);
|
|
}
|
|
break;
|
|
}
|
|
case DQT: {
|
|
JPEGD_VERBOSE_LOG("DQT, currentByte:0x%x", currentByte);
|
|
/* DQT length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("headerLength:%d", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
/* jump over DQT header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
break;
|
|
}
|
|
case DHT: {
|
|
JPEGD_VERBOSE_LOG("DHT, currentByte:0x%x", currentByte);
|
|
/* DHT length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("headerLength:%d", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over DHT header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
break;
|
|
}
|
|
case DRI: {
|
|
JPEGD_VERBOSE_LOG("DRI, currentByte:0x%x", currentByte);
|
|
/* DRI length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("headerLength:%d", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
#if 0
|
|
/* jump over DRI header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
#endif
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("headerLength:%d", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
pSyntax->frame.Ri = headerLength;
|
|
break;
|
|
}
|
|
case APP0: { /* application segments */
|
|
JPEGD_VERBOSE_LOG("APP0, currentByte:0x%x", currentByte);
|
|
/* reset */
|
|
appBits = 0;
|
|
appLength = 0;
|
|
pStream->appnFlag = 0;
|
|
|
|
/* APP0 length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("headerLength:%d", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
appLength = headerLength;
|
|
if (appLength < 16) {
|
|
pStream->appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - 16)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("flush bits failed");
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
appBits += 16;
|
|
|
|
/* check identifier: 0x4A 0x46 0x49 0x46 0x00 */
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("currentBytes:%x", currentBytes);
|
|
appBits += 16;
|
|
if (currentBytes != 0x4A46) {
|
|
pStream->appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("flush bits failed");
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("currentBytes:%x", currentBytes);
|
|
appBits += 16;
|
|
if (currentBytes != 0x4946 && currentBytes != 0x5858) {
|
|
pStream->appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("flush bits failed");
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* APP0 Extended */
|
|
if (currentBytes == 0x5858) {
|
|
JPEGD_VERBOSE_LOG("APP0 Extended");
|
|
thumbnail = 1;
|
|
}
|
|
currentByte = jpegd_get_byte(pStream);
|
|
JPEGD_VERBOSE_LOG("currentBytes:%x", currentBytes);
|
|
appBits += 8;
|
|
if (currentByte != 0x00) {
|
|
pStream->appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("flush bits failed");
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
pStream->appnFlag = 0;
|
|
break;
|
|
}
|
|
|
|
/* APP0 Extended thumb type */
|
|
if (thumbnail) {
|
|
/* extension code */
|
|
currentByte = jpegd_get_byte(pStream);
|
|
JPEGD_VERBOSE_LOG("APP0 Extended thumb type, currentBytes:%x", currentBytes);
|
|
if (currentByte == JPEGDEC_THUMBNAIL_JPEG) {
|
|
pImageInfo->thumbnailType = JPEGDEC_THUMBNAIL_JPEG;
|
|
appBits += 8;
|
|
pStream->appnFlag = 1;
|
|
|
|
/* check thumbnail data */
|
|
Hmax = 0;
|
|
Vmax = 0;
|
|
|
|
/* Read decoding parameters */
|
|
for (; (pStream->readBits / 8) < pStream->streamLength; pStream->readBits++) {
|
|
appBits += 8; /* Look for marker prefix byte from stream */
|
|
if (jpegd_get_byte(pStream) == 0xFF) {
|
|
appBits += 8;
|
|
|
|
currentByte = jpegd_get_byte(pStream);
|
|
switch (currentByte) { /* switch to certain header decoding */
|
|
case SOF0: /* baseline marker */
|
|
case SOF2: { /* progresive marker */
|
|
if (currentByte == SOF0)
|
|
pImageInfo->codingModeThumb = pSyntax->info.operationTypeThumb = JPEGDEC_BASELINE;
|
|
else
|
|
pImageInfo->codingModeThumb = pSyntax->info.operationTypeThumb = JPEGDEC_PROGRESSIVE;
|
|
|
|
/* Frame header */
|
|
i++;
|
|
|
|
/* jump over Lf field */
|
|
if (jpegd_flush_bits(pStream, 16) == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
appBits += 16;
|
|
|
|
/* Sample precision (only 8 bits/sample supported) */
|
|
currentByte = jpegd_get_byte(pStream);
|
|
appBits += 8;
|
|
if (currentByte != 8) {
|
|
JPEGD_ERROR_LOG("Thumbnail Sample precision");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* Number of Lines */
|
|
pImageInfo->outputHeightThumb = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
pImageInfo->displayHeightThumb = pImageInfo->outputHeightThumb;
|
|
if (pImageInfo->outputHeightThumb < 1) {
|
|
JPEGD_ERROR_LOG("pImageInfo->outputHeightThumb unsupported");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* round up to next multiple-of-16 */
|
|
pImageInfo->outputHeightThumb += 0xf;
|
|
pImageInfo->outputHeightThumb &= ~(0xf);
|
|
|
|
/* Number of Samples per Line */
|
|
pImageInfo->outputWidthThumb = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
pImageInfo->displayWidthThumb = pImageInfo->outputWidthThumb;
|
|
if (pImageInfo->outputWidthThumb < 1) {
|
|
JPEGD_ERROR_LOG("pImageInfo->outputWidthThumb unsupported");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
pImageInfo->outputWidthThumb += 0xf;
|
|
pImageInfo->outputWidthThumb &= ~(0xf);
|
|
if (pImageInfo->outputWidthThumb < pCtx->minSupportedWidth ||
|
|
pImageInfo->outputHeightThumb < pCtx->minSupportedHeight ||
|
|
pImageInfo->outputWidthThumb > JPEGDEC_MAX_WIDTH_TN ||
|
|
pImageInfo->outputHeightThumb > JPEGDEC_MAX_HEIGHT_TN) {
|
|
JPEGD_ERROR_LOG("Thumbnail Unsupported size");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* Number of Image Components per Frame */
|
|
Nf = jpegd_get_byte(pStream);
|
|
appBits += 8;
|
|
if (Nf != 3 && Nf != 1) {
|
|
JPEGD_ERROR_LOG("Thumbnail Number of Image Components per Frame");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
for (j = 0; j < Nf; j++) {
|
|
/* jump over component identifier */
|
|
if (jpegd_flush_bits(pStream, 8) == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
appBits += 8;
|
|
|
|
currentByte = jpegd_get_byte(pStream);
|
|
appBits += 8;
|
|
Htn[j] = (currentByte >> 4); /* Horizontal sampling factor */
|
|
Vtn[j] = (currentByte & 0xF); /* Vertical sampling factor */
|
|
|
|
if (jpegd_flush_bits(pStream, 8) == STRM_ERROR) { /* jump over Tq */
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
appBits += 8;
|
|
|
|
if (Htn[j] > Hmax)
|
|
Hmax = Htn[j];
|
|
if (Vtn[j] > Vmax)
|
|
Vmax = Vtn[j];
|
|
}
|
|
if (Hmax == 0 || Vmax == 0) {
|
|
JPEGD_ERROR_LOG("Thumbnail Hmax == 0 || Vmax == 0");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* check format */
|
|
if (Htn[0] == 2 && Vtn[0] == 2 &&
|
|
Htn[1] == 1 && Vtn[1] == 1 && Htn[2] == 1 && Vtn[2] == 1) {
|
|
pImageInfo->outputFormatThumb = JPEGDEC_YCbCr420_SEMIPLANAR;
|
|
} else if (Htn[0] == 2 && Vtn[0] == 1 &&
|
|
Htn[1] == 1 && Vtn[1] == 1 && Htn[2] == 1 && Vtn[2] == 1) {
|
|
pImageInfo->outputFormatThumb = JPEGDEC_YCbCr422_SEMIPLANAR;
|
|
} else if (Htn[0] == 1 && Vtn[0] == 2 &&
|
|
Htn[1] == 1 && Vtn[1] == 1 && Htn[2] == 1 && Vtn[2] == 1) {
|
|
pImageInfo->outputFormatThumb = JPEGDEC_YCbCr440;
|
|
} else if (Htn[0] == 1 && Vtn[0] == 1 &&
|
|
Htn[1] == 0 && Vtn[1] == 0 && Htn[2] == 0 && Vtn[2] == 0) {
|
|
pImageInfo->outputFormatThumb = JPEGDEC_YCbCr400;
|
|
} else if (pCtx->is8190 && Htn[0] == 4 && Vtn[0] == 1 &&
|
|
Htn[1] == 1 && Vtn[1] == 1 && Htn[2] == 1 && Vtn[2] == 1) {
|
|
pImageInfo->outputFormatThumb = JPEGDEC_YCbCr411_SEMIPLANAR;
|
|
} else if (pCtx->is8190 && Htn[0] == 1 && Vtn[0] == 1 &&
|
|
Htn[1] == 1 && Vtn[1] == 1 && Htn[2] == 1 && Vtn[2] == 1) {
|
|
pImageInfo->outputFormatThumb = JPEGDEC_YCbCr444_SEMIPLANAR;
|
|
} else {
|
|
JPEGD_ERROR_LOG("Thumbnail Unsupported YCbCr format");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
pSyntax->info.initThumb = 1;
|
|
initThumb = 1;
|
|
break;
|
|
}
|
|
case SOS: {
|
|
/* SOS length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
|
|
/* check if interleaved or non-ibnterleaved */
|
|
NsThumb = jpegd_get_byte(pStream);
|
|
if (NsThumb == MIN_NUMBER_OF_COMPONENTS &&
|
|
pImageInfo->outputFormatThumb != JPEGDEC_YCbCr400 &&
|
|
pImageInfo->codingModeThumb == JPEGDEC_BASELINE) {
|
|
pImageInfo->codingModeThumb = pSyntax->info.operationTypeThumb = JPEGDEC_NONINTERLEAVED;
|
|
}
|
|
|
|
/* jump over SOS header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
|
|
if ((pStream->readBits + 8) < (8 * pStream->streamLength)) {
|
|
pSyntax->info.init = 1;
|
|
init = 1;
|
|
} else {
|
|
JPEGD_ERROR_LOG("Needs to increase input buffer");
|
|
return (JPEGDEC_INCREASE_INPUT_BUFFER);
|
|
}
|
|
break;
|
|
}
|
|
case DQT: {
|
|
/* DQT length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over DQT header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
appBits += (headerLength * 8);
|
|
break;
|
|
}
|
|
case DHT: {
|
|
/* DHT length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over DHT header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
appBits += (headerLength * 8);
|
|
break;
|
|
}
|
|
case DRI: {
|
|
/* DRI length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over DRI header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
appBits += (headerLength * 8);
|
|
break;
|
|
}
|
|
case APP0:
|
|
case APP1:
|
|
case APP2:
|
|
case APP3:
|
|
case APP4:
|
|
case APP5:
|
|
case APP6:
|
|
case APP7:
|
|
case APP8:
|
|
case APP9:
|
|
case APP10:
|
|
case APP11:
|
|
case APP12:
|
|
case APP13:
|
|
case APP14:
|
|
case APP15: {
|
|
/* APPn length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over APPn header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
appBits += (headerLength * 8);
|
|
break;
|
|
}
|
|
case DNL: {
|
|
/* DNL length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over DNL header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
appBits += (headerLength * 8);
|
|
break;
|
|
}
|
|
case COM: {
|
|
/* COM length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
if (headerLength == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over COM header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
appBits += (headerLength * 8);
|
|
break;
|
|
}
|
|
case SOF1: /* unsupported coding styles */
|
|
case SOF3:
|
|
case SOF5:
|
|
case SOF6:
|
|
case SOF7:
|
|
case SOF9:
|
|
case SOF10:
|
|
case SOF11:
|
|
case SOF13:
|
|
case SOF14:
|
|
case SOF15:
|
|
case DAC:
|
|
case DHP: {
|
|
JPEGD_ERROR_LOG("Unsupported coding styles");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pSyntax->info.initThumb && initThumb) {
|
|
/* flush the rest of thumbnail data */
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
pStream->appnFlag = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
if (!pSyntax->info.initThumb && pCtx->bufferSize)
|
|
return (JPEGDEC_INCREASE_INPUT_BUFFER);
|
|
else
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
}
|
|
break;
|
|
} else {
|
|
appBits += 8;
|
|
pImageInfo->thumbnailType = JPEGDEC_THUMBNAIL_NOT_SUPPORTED_FORMAT;
|
|
pStream->appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
pStream->appnFlag = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
/* version */
|
|
pImageInfo->version = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("APP0, version:%x", pImageInfo->version);
|
|
appBits += 16;
|
|
|
|
/* units */
|
|
currentByte = jpegd_get_byte(pStream);
|
|
if (currentByte == 0) {
|
|
pImageInfo->units = JPEGDEC_NO_UNITS;
|
|
} else if (currentByte == 1) {
|
|
pImageInfo->units = JPEGDEC_DOTS_PER_INCH;
|
|
} else if (currentByte == 2) {
|
|
pImageInfo->units = JPEGDEC_DOTS_PER_CM;
|
|
}
|
|
appBits += 8;
|
|
|
|
/* Xdensity */
|
|
pImageInfo->xDensity = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
|
|
/* Ydensity */
|
|
pImageInfo->yDensity = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
|
|
/* jump over rest of header data */
|
|
pStream->appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
pStream->appnFlag = 0;
|
|
break;
|
|
}
|
|
}
|
|
case APP1:
|
|
case APP2:
|
|
case APP3:
|
|
case APP4:
|
|
case APP5:
|
|
case APP6:
|
|
case APP7:
|
|
case APP8:
|
|
case APP9:
|
|
case APP10:
|
|
case APP11:
|
|
case APP12:
|
|
case APP13:
|
|
case APP14:
|
|
case APP15: {
|
|
JPEGD_VERBOSE_LOG("APPn, currentByte:0x%x", currentByte);
|
|
/* APPn length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("APPn length, headerLength:%x", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over APPn header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
break;
|
|
}
|
|
case DNL: {
|
|
JPEGD_VERBOSE_LOG("DNL, currentByte:0x%x", currentByte);
|
|
/* DNL length */
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("DNL, headerLength:%x", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over DNL header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
break;
|
|
}
|
|
case COM: {
|
|
JPEGD_VERBOSE_LOG("COM, currentByte:0x%x", currentByte);
|
|
headerLength = jpegd_get_two_bytes(pStream);
|
|
JPEGD_VERBOSE_LOG("COM, headerLength:%x", headerLength);
|
|
if (headerLength == STRM_ERROR ||
|
|
((pStream->readBits + ((headerLength * 8) - 16)) > (8 * pStream->streamLength))) {
|
|
JPEGD_ERROR_LOG("readBits:%d, headerLength:%d, streamLength:%d", pStream->readBits, headerLength, pStream->streamLength);
|
|
errorCode = 1;
|
|
break;
|
|
}
|
|
/* jump over COM header */
|
|
if (headerLength != 0) {
|
|
pStream->readBits += ((headerLength * 8) - 16);
|
|
pStream->pCurrPos += (((headerLength * 8) - 16) / 8);
|
|
}
|
|
break;
|
|
}
|
|
case SOF1: /* unsupported coding styles */
|
|
case SOF3:
|
|
case SOF5:
|
|
case SOF6:
|
|
case SOF7:
|
|
case SOF9:
|
|
case SOF10:
|
|
case SOF11:
|
|
case SOF13:
|
|
case SOF14:
|
|
case SOF15:
|
|
case DAC:
|
|
case DHP: {
|
|
JPEGD_ERROR_LOG("SOF, currentByte:0x%x", currentByte);
|
|
JPEGD_ERROR_LOG("Unsupported coding styles");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (pSyntax->info.init && init)
|
|
break;
|
|
|
|
if (errorCode) {
|
|
if (pCtx->bufferSize) {
|
|
JPEGD_ERROR_LOG("get image info failed!");
|
|
return (JPEGDEC_INCREASE_INPUT_BUFFER);
|
|
} else {
|
|
JPEGD_ERROR_LOG("Stream error");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
}
|
|
} else {
|
|
JPEGD_ERROR_LOG("Could not get marker");
|
|
if (!pSyntax->info.init)
|
|
return (JPEGDEC_INCREASE_INPUT_BUFFER);
|
|
else
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_get_image_info(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
MPP_RET ret = MPP_OK;
|
|
PostProcessInfo ppInfo;
|
|
RK_U32 ppInputFomart = 0;
|
|
RK_U32 ppScaleW = 640, ppScaleH = 480;
|
|
RK_U32 pic_size = 0;
|
|
StreamStorage stream;
|
|
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
|
|
if (pCtx->streamLength < 1) {
|
|
JPEGD_ERROR_LOG("streamLength:%d", pCtx->streamLength);
|
|
return MPP_ERR_VALUE;
|
|
}
|
|
|
|
if ((pCtx->streamLength > DEC_MAX_STREAM) &&
|
|
(pCtx->bufferSize < JPEGDEC_MIN_BUFFER || pCtx->bufferSize > JPEGDEC_MAX_BUFFER)) {
|
|
JPEGD_ERROR_LOG("bufferSize = %d,streamLength = %d\n", pCtx->bufferSize, pCtx->streamLength);
|
|
return MPP_ERR_VALUE;
|
|
}
|
|
|
|
if (pCtx->bufferSize && (pCtx->bufferSize < JPEGDEC_MIN_BUFFER ||
|
|
pCtx->bufferSize > JPEGDEC_MAX_BUFFER)) {
|
|
JPEGD_ERROR_LOG("bufferSize = %d\n", pCtx->bufferSize);
|
|
return MPP_ERR_VALUE;
|
|
}
|
|
|
|
memset(&(pCtx->imageInfo), 0, sizeof(JpegDecImageInfo));
|
|
pCtx->imageInfo.thumbnailType = JPEGDEC_NO_THUMBNAIL;
|
|
|
|
/* utils initialization */
|
|
stream.bitPosInByte = 0;
|
|
stream.pCurrPos = (RK_U8 *)mpp_packet_get_data(pCtx->input_packet);
|
|
stream.pStartOfStream = (RK_U8 *)mpp_packet_get_data(pCtx->input_packet);
|
|
stream.streamLength = (RK_U32)mpp_packet_get_size(pCtx->input_packet);
|
|
stream.readBits = 0;
|
|
stream.appnFlag = 0;
|
|
|
|
ret = jpegd_read_decode_parameters(pCtx, &stream);
|
|
if (ret != MPP_OK) {
|
|
JPEGD_ERROR_LOG("read decode parameters failed, ret:%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
if (pCtx->color_conv) {
|
|
/* Using pp to convert all format to yuv420sp */
|
|
switch (pCtx->imageInfo.outputFormat) {
|
|
case JPEGDEC_YCbCr400:
|
|
ppInputFomart = PP_IN_FORMAT_YUV400;
|
|
break;
|
|
case JPEGDEC_YCbCr420_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV420SEMI;
|
|
break;
|
|
case JPEGDEC_YCbCr422_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV422SEMI;
|
|
break;
|
|
case JPEGDEC_YCbCr440:
|
|
ppInputFomart = PP_IN_FORMAT_YUV440SEMI;
|
|
break;
|
|
case JPEGDEC_YCbCr411_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV411_SEMI;
|
|
break;
|
|
case JPEGDEC_YCbCr444_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV444_SEMI;
|
|
break;
|
|
}
|
|
|
|
// set pp info
|
|
memset(&ppInfo, 0, sizeof(ppInfo));
|
|
ppInfo.enable = 1;
|
|
ppInfo.outFomart = 5; //PP_OUT_FORMAT_YUV420INTERLAVE
|
|
ppScaleW = pCtx->imageInfo.outputWidth;
|
|
ppScaleH = pCtx->imageInfo.outputHeight;
|
|
if (ppScaleW > 1920) { // || ppScaleH > 1920) {
|
|
ppScaleW = (ppScaleW + 15) & (~15); //(ppScaleW + 15)/16*16;
|
|
ppScaleH = (ppScaleH + 15) & (~15);
|
|
} else {
|
|
ppScaleW = (ppScaleW + 7) & (~7); // pp dest width must be dividable by 8
|
|
ppScaleH = (ppScaleH + 1) & (~1); // must be dividable by 2.in pp downscaling ,the output lines always equal (desire lines - 1);
|
|
}
|
|
|
|
JPEGD_INFO_LOG("Post Process! ppScaleW:%d, ppScaleH:%d", ppScaleW, ppScaleH);
|
|
|
|
pic_size = ppScaleW * ppScaleH * 2;
|
|
pSyntax->ppInstance = (void *)1;
|
|
} else {
|
|
/* keep original output format */
|
|
memset(&ppInfo, 0, sizeof(ppInfo));
|
|
ppInfo.outFomart = 5; //PP_OUT_FORMAT_YUV420INTERLAVE
|
|
ppScaleW = pCtx->imageInfo.outputWidth;
|
|
ppScaleH = pCtx->imageInfo.outputHeight;
|
|
|
|
ppScaleW = (ppScaleW + 15) & (~15);
|
|
ppScaleH = (ppScaleH + 15) & (~15);
|
|
|
|
switch (pCtx->imageInfo.outputFormat) {
|
|
case JPEGDEC_YCbCr400:
|
|
ppInputFomart = PP_IN_FORMAT_YUV400;
|
|
pic_size = ppScaleW * ppScaleH;
|
|
break;
|
|
case JPEGDEC_YCbCr420_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV420SEMI;
|
|
pic_size = ppScaleW * ppScaleH * 3 / 2;
|
|
break;
|
|
case JPEGDEC_YCbCr422_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV422SEMI;
|
|
pic_size = ppScaleW * ppScaleH * 2;
|
|
break;
|
|
case JPEGDEC_YCbCr440:
|
|
ppInputFomart = PP_IN_FORMAT_YUV440SEMI;
|
|
pic_size = ppScaleW * ppScaleH * 2;
|
|
break;
|
|
case JPEGDEC_YCbCr411_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV411_SEMI;
|
|
pic_size = ppScaleW * ppScaleH * 2;
|
|
break;
|
|
case JPEGDEC_YCbCr444_SEMIPLANAR:
|
|
ppInputFomart = PP_IN_FORMAT_YUV444_SEMI;
|
|
pic_size = ppScaleW * ppScaleH * 3;
|
|
break;
|
|
}
|
|
|
|
pSyntax->ppInstance = (void *)0;
|
|
}
|
|
|
|
(void)pic_size;
|
|
memcpy(&(pSyntax->imageInfo), &(pCtx->imageInfo), sizeof(JpegDecImageInfo));
|
|
memcpy(&(pSyntax->ppInfo), &(ppInfo), sizeof(PostProcessInfo));
|
|
pSyntax->ppScaleW = ppScaleW;
|
|
pSyntax->ppScaleH = ppScaleH;
|
|
pSyntax->ppInputFomart = ppInputFomart;
|
|
|
|
FUN_TEST("Exit");
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET jpegd_decode_frame_impl(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_U32 i = 0;
|
|
RK_U32 currentByte = 0;
|
|
RK_U32 currentBytes = 0;
|
|
RK_U32 appLength = 0;
|
|
RK_U32 appBits = 0;
|
|
JpegDecRet retCode; /* Returned code container */
|
|
RK_U32 findhufftable = 0;
|
|
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
StreamStorage *pStream = (StreamStorage *) & (pSyntax->stream);
|
|
|
|
do {
|
|
/* if slice mode/slice done return to hw handling */
|
|
if (pSyntax->image.headerReady && pSyntax->info.SliceReadyForPause)
|
|
break;
|
|
|
|
/* Look for marker prefix byte from stream */
|
|
if ((currentByte == 0xFF) || (jpegd_get_byte(pStream) == 0xFF)) {
|
|
currentByte = jpegd_get_byte(pStream);
|
|
|
|
/* switch to certain header decoding */
|
|
switch (currentByte) {
|
|
case 0x00: {
|
|
JPEGD_VERBOSE_LOG("currentByte:0x00");
|
|
break;
|
|
}
|
|
case SOF0:
|
|
case SOF2: {
|
|
JPEGD_VERBOSE_LOG("SOF, currentByte:0x%x", currentByte);
|
|
/* Baseline/Progressive */
|
|
pSyntax->frame.codingType = currentByte;
|
|
/* Set operation type */
|
|
if (pSyntax->frame.codingType == SOF0)
|
|
pSyntax->info.operationType = JPEGDEC_BASELINE;
|
|
else
|
|
pSyntax->info.operationType = JPEGDEC_PROGRESSIVE;
|
|
|
|
retCode = jpegd_decode_frame_header(pCtx);
|
|
if (retCode != JPEGDEC_OK) {
|
|
if (retCode == JPEGDEC_STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (retCode);
|
|
} else {
|
|
JPEGD_ERROR_LOG("Decode Frame Header Error");
|
|
return (retCode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SOS: { /* Start of Scan */
|
|
JPEGD_VERBOSE_LOG("SOS, currentByte:0x%x", currentByte);
|
|
/* reset image ready */
|
|
pSyntax->image.imageReady = 0;
|
|
retCode = jpegd_decode_scan(pCtx);
|
|
pSyntax->image.headerReady = 1;
|
|
if (retCode != JPEGDEC_OK) {
|
|
if (retCode == JPEGDEC_STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (retCode);
|
|
} else {
|
|
JPEGD_ERROR_LOG("Decode Scan Error\n");
|
|
return (retCode);
|
|
}
|
|
}
|
|
|
|
if (pSyntax->stream.bitPosInByte) {
|
|
/* delete stuffing bits */
|
|
currentByte = (8 - pSyntax->stream.bitPosInByte);
|
|
if (jpegd_flush_bits(pStream, 8 - pSyntax->stream.bitPosInByte) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
}
|
|
JPEGD_VERBOSE_LOG("Stuffing bits deleted\n");
|
|
break;
|
|
}
|
|
case DHT: { /* Start of Huffman tables */
|
|
JPEGD_VERBOSE_LOG("DHT, currentByte:0x%x", currentByte);
|
|
retCode = jpegd_decode_huffman_tables(pCtx);
|
|
if (retCode != JPEGDEC_OK) {
|
|
if (retCode == JPEGDEC_STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (retCode);
|
|
} else {
|
|
JPEGD_ERROR_LOG("Decode Huffman Tables Error");
|
|
return (retCode);
|
|
}
|
|
}
|
|
findhufftable = 1;
|
|
break;
|
|
}
|
|
case DQT: { /* start of Quantisation Tables */
|
|
JPEGD_VERBOSE_LOG("DQT, currentByte:0x%x", currentByte);
|
|
retCode = jpegd_decode_quant_tables(pCtx);
|
|
if (retCode != JPEGDEC_OK) {
|
|
if (retCode == JPEGDEC_STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (retCode);
|
|
} else {
|
|
JPEGD_ERROR_LOG("Decode Quant Tables Error");
|
|
return (retCode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SOI: { /* Start of Image */
|
|
/* no actions needed, continue */
|
|
break;
|
|
}
|
|
case EOI: { /* End of Image */
|
|
JPEGD_VERBOSE_LOG("EOI, currentByte:0x%x", currentByte);
|
|
if (pSyntax->image.imageReady) {
|
|
JPEGD_ERROR_LOG("EOI: OK\n");
|
|
return (JPEGDEC_FRAME_READY);
|
|
} else {
|
|
JPEGD_ERROR_LOG("EOI: NOK\n");
|
|
return (JPEGDEC_ERROR);
|
|
}
|
|
}
|
|
case DRI: { /* Define Restart Interval */
|
|
JPEGD_VERBOSE_LOG("DRI, currentByte:0x%x", currentByte);
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
if (currentBytes == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Read bits ");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
pSyntax->frame.Ri = jpegd_get_two_bytes(pStream);
|
|
pCtx->dri_en = 0xffd0; //find dri
|
|
break;
|
|
}
|
|
case RST0: /* Restart with modulo 8 count m */
|
|
case RST1:
|
|
case RST2:
|
|
case RST3:
|
|
case RST4:
|
|
case RST5:
|
|
case RST6:
|
|
case RST7: {
|
|
JPEGD_VERBOSE_LOG("RST, currentByte:0x%x", currentByte);
|
|
/* initialisation of DC predictors to zero value !!! */
|
|
for (i = 0; i < MAX_NUMBER_OF_COMPONENTS; i++) {
|
|
pSyntax->scan.pred[i] = 0;
|
|
}
|
|
break;
|
|
}
|
|
case DNL: /* unsupported features */
|
|
case SOF1:
|
|
case SOF3:
|
|
case SOF5:
|
|
case SOF6:
|
|
case SOF7:
|
|
case SOF9:
|
|
case SOF10:
|
|
case SOF11:
|
|
case SOF13:
|
|
case SOF14:
|
|
case SOF15:
|
|
case DAC:
|
|
case DHP:
|
|
case TEM: {
|
|
JPEGD_ERROR_LOG("Unsupported Features, currentByte:0x%x", currentByte);
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
case APP0: { /* application data & comments */
|
|
JPEGD_VERBOSE_LOG("APP0, currentByte:0x%x", currentByte);
|
|
/* APP0 Extended Thumbnail */
|
|
if (pCtx->decImageType == JPEGDEC_THUMBNAIL) {
|
|
/* reset */
|
|
appBits = 0;
|
|
appLength = 0;
|
|
|
|
/* length */
|
|
appLength = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
|
|
/* check identifier */
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
if (currentBytes != 0x4A46) {
|
|
pSyntax->stream.appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
pSyntax->stream.appnFlag = 0;
|
|
break;
|
|
}
|
|
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
appBits += 16;
|
|
if (currentBytes != 0x5858) {
|
|
pSyntax->stream.appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
pSyntax->stream.appnFlag = 0;
|
|
break;
|
|
}
|
|
|
|
currentByte = jpegd_get_byte(pStream);
|
|
appBits += 8;
|
|
if (currentByte != 0x00) {
|
|
pSyntax->stream.appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((appLength * 8) - appBits)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
pSyntax->stream.appnFlag = 0;
|
|
break;
|
|
}
|
|
|
|
/* extension code */
|
|
currentByte = jpegd_get_byte(pStream);
|
|
pSyntax->stream.appnFlag = 0;
|
|
if (currentByte != JPEGDEC_THUMBNAIL_JPEG) {
|
|
JPEGD_ERROR_LOG("thumbnail unsupported");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
|
|
/* thumbnail mode */
|
|
JPEGD_VERBOSE_LOG("Thumbnail data ok!");
|
|
pSyntax->stream.thumbnail = 1;
|
|
break;
|
|
} else {
|
|
/* Flush unsupported thumbnail */
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
pSyntax->stream.appnFlag = 1;
|
|
if (jpegd_flush_bits(pStream, ((currentBytes - 2) * 8)) == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Stream Error");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
pSyntax->stream.appnFlag = 0;
|
|
break;
|
|
}
|
|
}
|
|
case APP1:
|
|
case APP2:
|
|
case APP3:
|
|
case APP4:
|
|
case APP5:
|
|
case APP6:
|
|
case APP7:
|
|
case APP8:
|
|
case APP9:
|
|
case APP10:
|
|
case APP11:
|
|
case APP12:
|
|
case APP13:
|
|
case APP14:
|
|
case APP15:
|
|
case COM: {
|
|
JPEGD_VERBOSE_LOG("APPn, currentByte:0x%x", currentByte);
|
|
currentBytes = jpegd_get_two_bytes(pStream);
|
|
if (currentBytes == STRM_ERROR) {
|
|
JPEGD_ERROR_LOG("Read bits ");
|
|
return (JPEGDEC_STRM_ERROR);
|
|
}
|
|
/* jump over not supported header */
|
|
if (currentBytes != 0) {
|
|
pSyntax->stream.readBits += ((currentBytes * 8) - 16);
|
|
pSyntax->stream.pCurrPos += (((currentBytes * 8) - 16) / 8);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
if (currentByte == 0xFFFFFFFF) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pSyntax->image.headerReady)
|
|
break;
|
|
} while ((pSyntax->stream.readBits >> 3) <= pSyntax->stream.streamLength);
|
|
|
|
if (!findhufftable) {
|
|
JPEGD_INFO_LOG("do not find Huffman Tables");
|
|
jpegd_default_huffman_tables(pCtx);
|
|
}
|
|
|
|
return MPP_OK;
|
|
FUN_TEST("Exit");
|
|
}
|
|
|
|
MPP_RET jpegd_allocate_frame(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
if (pCtx->frame_slot_index == -1) {
|
|
mpp_frame_set_width(pCtx->output_frame, pCtx->pSyntax->frame.X);
|
|
mpp_frame_set_height(pCtx->output_frame, pCtx->pSyntax->frame.Y);
|
|
mpp_frame_set_hor_stride(pCtx->output_frame, pCtx->pSyntax->frame.X);
|
|
mpp_frame_set_ver_stride(pCtx->output_frame, pCtx->pSyntax->frame.Y);
|
|
mpp_frame_set_pts(pCtx->output_frame, pCtx->pts);
|
|
|
|
mpp_buf_slot_get_unused(pCtx->frame_slots, &pCtx->frame_slot_index);
|
|
JPEGD_INFO_LOG("frame_slot_index:%d, X:%d, Y:%d", pCtx->frame_slot_index, pCtx->pSyntax->frame.X, pCtx->pSyntax->frame.Y);
|
|
|
|
mpp_buf_slot_set_prop(pCtx->frame_slots, pCtx->frame_slot_index, SLOT_FRAME, pCtx->output_frame);
|
|
mpp_buf_slot_set_flag(pCtx->frame_slots, pCtx->frame_slot_index, SLOT_CODEC_USE);
|
|
mpp_buf_slot_set_flag(pCtx->frame_slots, pCtx->frame_slot_index, SLOT_HAL_OUTPUT);
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_update_frame(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
mpp_buf_slot_set_flag(pCtx->frame_slots, pCtx->frame_slot_index, SLOT_QUEUE_USE);
|
|
mpp_buf_slot_enqueue(pCtx->frame_slots, pCtx->frame_slot_index, QUEUE_DISPLAY);
|
|
mpp_buf_slot_clr_flag(pCtx->frame_slots, pCtx->frame_slot_index, SLOT_CODEC_USE);
|
|
pCtx->frame_slot_index = -1;
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_decode_frame(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
MPP_RET ret = MPP_OK;
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
JpegSyntaxParam *pSyntax = pCtx->pSyntax;
|
|
RK_U32 mcuSizeDivider = 0;
|
|
|
|
/* Store the stream parameters */
|
|
if (pSyntax->info.progressiveScanReady == 0 &&
|
|
pSyntax->info.nonInterleavedScanReady == 0) {
|
|
pSyntax->stream.bitPosInByte = 0;
|
|
pSyntax->stream.pCurrPos = (RK_U8 *) mpp_packet_get_data(pCtx->input_packet);
|
|
pSyntax->stream.pStartOfStream = (RK_U8 *)mpp_packet_get_data(pCtx->input_packet);
|
|
pSyntax->stream.readBits = 0;
|
|
pSyntax->stream.streamLength = (RK_U32)mpp_packet_get_size(pCtx->input_packet);
|
|
pSyntax->stream.appnFlag = 0;
|
|
} else {
|
|
pSyntax->image.headerReady = 0;
|
|
}
|
|
|
|
/* set mcu/slice value */
|
|
pSyntax->info.sliceMbSetValue = pCtx->sliceMbSet;
|
|
|
|
/* check HW supported features */
|
|
if (!pCtx->is8190) {
|
|
// TODO:
|
|
} else {
|
|
/* check if fuse was burned */
|
|
if (pCtx->fuseBurned) {
|
|
/* return if not valid HW and unsupported operation type */
|
|
if (pSyntax->info.operationType == JPEGDEC_PROGRESSIVE) {
|
|
JPEGD_ERROR_LOG ("Operation type not supported");
|
|
return (JPEGDEC_UNSUPPORTED);
|
|
}
|
|
}
|
|
|
|
/* check slice config */
|
|
if ((pCtx->sliceMbSet && pCtx->decImageType == JPEGDEC_IMAGE &&
|
|
pSyntax->info.operationType != JPEGDEC_BASELINE) ||
|
|
(pCtx->sliceMbSet && pCtx->decImageType == JPEGDEC_THUMBNAIL &&
|
|
pSyntax->info.operationTypeThumb != JPEGDEC_BASELINE)) {
|
|
JPEGD_ERROR_LOG("Slice mode not supported for this operation type");
|
|
return (JPEGDEC_SLICE_MODE_UNSUPPORTED);
|
|
}
|
|
|
|
/* check if frame size over 16M */
|
|
if ((!pCtx->sliceMbSet) &&
|
|
((pSyntax->frame.hwX * pSyntax->frame.hwY) > JPEGDEC_MAX_PIXEL_AMOUNT)) {
|
|
JPEGD_ERROR_LOG ("Resolution > 16M ==> use slice mode!");
|
|
return (JPEGDEC_PARAM_ERROR);
|
|
}
|
|
|
|
if (pSyntax->info.getInfoYCbCrMode == JPEGDEC_YCbCr400 ||
|
|
pSyntax->info.getInfoYCbCrMode == JPEGDEC_YCbCr440 ||
|
|
pSyntax->info.getInfoYCbCrMode == JPEGDEC_YCbCr444_SEMIPLANAR)
|
|
mcuSizeDivider = 2;
|
|
else
|
|
mcuSizeDivider = 1;
|
|
|
|
/* check slice config */
|
|
if ((pCtx->sliceMbSet * (pSyntax->frame.numMcuInRow / mcuSizeDivider)) > pCtx->maxSupportedSliceSize) {
|
|
JPEGD_ERROR_LOG("sliceMbSet > JPEGDEC_MAX_SLICE_SIZE");
|
|
return (JPEGDEC_PARAM_ERROR);
|
|
}
|
|
}
|
|
|
|
/* check slice size */
|
|
if (pCtx->sliceMbSet && !pSyntax->info.SliceReadyForPause && !pSyntax->info.inputBufferEmpty) {
|
|
if (pSyntax->info.getInfoYCbCrMode == JPEGDEC_YCbCr400 ||
|
|
pSyntax->info.getInfoYCbCrMode == JPEGDEC_YCbCr440 ||
|
|
pSyntax->info.getInfoYCbCrMode == JPEGDEC_YCbCr444_SEMIPLANAR)
|
|
mcuSizeDivider = 2;
|
|
else
|
|
mcuSizeDivider = 1;
|
|
|
|
if ((pCtx->sliceMbSet * (pSyntax->frame.numMcuInRow / mcuSizeDivider)) > pSyntax->frame.numMcuInFrame) {
|
|
JPEGD_ERROR_LOG("(sliceMbSet * Number of MCU's in row) > Number of MCU's in frame");
|
|
return (JPEGDEC_PARAM_ERROR);
|
|
}
|
|
}
|
|
|
|
/* check if input streaming used */
|
|
if (!pSyntax->info.SliceReadyForPause &&
|
|
!pSyntax->info.inputBufferEmpty && pCtx->bufferSize) {
|
|
pSyntax->info.inputStreaming = 1;
|
|
pSyntax->info.inputBufferLen = pCtx->bufferSize;
|
|
pSyntax->info.decodedStreamLen += pSyntax->info.inputBufferLen;
|
|
}
|
|
|
|
ret = jpegd_decode_frame_impl(pCtx);
|
|
|
|
FUN_TEST("Exit");
|
|
return ret;
|
|
}
|
|
|
|
void jpegd_free_huffman_tables(void *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.acTable0.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.acTable0.vals);
|
|
JpegParserCtx->pSyntax->vlc.acTable0.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.acTable1.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.acTable1.vals);
|
|
JpegParserCtx->pSyntax->vlc.acTable1.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.acTable2.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.acTable2.vals);
|
|
JpegParserCtx->pSyntax->vlc.acTable2.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.acTable3.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.acTable3.vals);
|
|
JpegParserCtx->pSyntax->vlc.acTable3.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.dcTable0.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.dcTable0.vals);
|
|
JpegParserCtx->pSyntax->vlc.dcTable0.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.dcTable1.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.dcTable1.vals);
|
|
JpegParserCtx->pSyntax->vlc.dcTable1.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.dcTable2.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.dcTable2.vals);
|
|
JpegParserCtx->pSyntax->vlc.dcTable2.vals = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->pSyntax->vlc.dcTable3.vals) {
|
|
mpp_free(JpegParserCtx->pSyntax->vlc.dcTable3.vals);
|
|
JpegParserCtx->pSyntax->vlc.dcTable3.vals = NULL;
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
}
|
|
|
|
|
|
MPP_RET jpegd_parse(void *ctx, HalDecTask *task)
|
|
{
|
|
FUN_TEST("Enter");
|
|
MPP_RET ret = MPP_OK;
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
task->valid = 0;
|
|
|
|
jpegd_free_huffman_tables(JpegParserCtx);
|
|
memset(JpegParserCtx->pSyntax, 0, sizeof(JpegSyntaxParam));
|
|
jpegd_get_image_info(JpegParserCtx);
|
|
ret = jpegd_decode_frame(JpegParserCtx);
|
|
|
|
if (MPP_OK == ret) {
|
|
jpegd_allocate_frame(JpegParserCtx);
|
|
task->syntax.data = (void *)JpegParserCtx->pSyntax;
|
|
task->syntax.number = sizeof(JpegSyntaxParam);
|
|
task->output = JpegParserCtx->frame_slot_index;
|
|
task->valid = 1;
|
|
jpegd_update_frame(JpegParserCtx);
|
|
}
|
|
|
|
//mpp_show_mem_status();
|
|
|
|
FUN_TEST("Exit");
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET jpegd_deinit(void *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
|
|
if (JpegParserCtx->recv_buffer) {
|
|
mpp_free(JpegParserCtx->recv_buffer);
|
|
JpegParserCtx->recv_buffer = NULL;
|
|
}
|
|
|
|
jpegd_free_huffman_tables(JpegParserCtx);
|
|
|
|
if (JpegParserCtx->pSyntax) {
|
|
mpp_free(JpegParserCtx->pSyntax);
|
|
JpegParserCtx->pSyntax = NULL;
|
|
}
|
|
|
|
if (JpegParserCtx->output_frame) {
|
|
mpp_free(JpegParserCtx->output_frame);
|
|
}
|
|
|
|
if (JpegParserCtx->input_packet) {
|
|
mpp_packet_deinit(&JpegParserCtx->input_packet);
|
|
}
|
|
|
|
JpegParserCtx->pts = 0;
|
|
JpegParserCtx->eos = 0;
|
|
JpegParserCtx->parser_debug_enable = 0;
|
|
JpegParserCtx->input_jpeg_count = 0;
|
|
|
|
FUN_TEST("Exit");
|
|
return 0;
|
|
}
|
|
|
|
MPP_RET reset_jpeg_parser_context(JpegParserContext *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *pCtx = ctx;
|
|
if (NULL == pCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
pCtx->packet_slots = NULL;
|
|
pCtx->frame_slots = NULL;
|
|
pCtx->recv_buffer = NULL;
|
|
|
|
/* resolution */
|
|
pCtx->minSupportedWidth = 0;
|
|
pCtx->minSupportedHeight = 0;
|
|
pCtx->maxSupportedWidth = 0;
|
|
pCtx->maxSupportedHeight = 0;
|
|
pCtx->maxSupportedPixelAmount = 0;
|
|
pCtx->maxSupportedSliceSize = 0;
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_init(void *ctx, ParserCfg *parser_cfg)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
if (NULL == JpegParserCtx) {
|
|
JpegParserCtx = (JpegParserContext *)mpp_calloc(JpegParserContext, 1);
|
|
if (NULL == JpegParserCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
}
|
|
mpp_env_get_u32("jpegd_log", &jpegd_log, JPEGD_ERR_LOG);
|
|
|
|
reset_jpeg_parser_context(JpegParserCtx);
|
|
JpegParserCtx->frame_slots = parser_cfg->frame_slots;
|
|
JpegParserCtx->packet_slots = parser_cfg->packet_slots;
|
|
JpegParserCtx->frame_slot_index = -1;
|
|
mpp_buf_slot_setup(JpegParserCtx->frame_slots, 16);
|
|
|
|
JpegParserCtx->recv_buffer = mpp_calloc(RK_U8, JPEGD_STREAM_BUFF_SIZE);
|
|
if (NULL == JpegParserCtx->recv_buffer) {
|
|
JPEGD_ERROR_LOG("no memory!");
|
|
return MPP_ERR_NOMEM;
|
|
}
|
|
JpegParserCtx->bufferSize = JPEGD_STREAM_BUFF_SIZE;
|
|
mpp_packet_init(&JpegParserCtx->input_packet, JpegParserCtx->recv_buffer, JPEGD_STREAM_BUFF_SIZE);
|
|
|
|
mpp_frame_init(&JpegParserCtx->output_frame);
|
|
if (!JpegParserCtx->output_frame) {
|
|
JPEGD_ERROR_LOG("Failed to allocate output frame buffer");
|
|
return MPP_ERR_NOMEM;
|
|
}
|
|
JpegParserCtx->fuseBurned = 1; /* changed by application*/
|
|
|
|
JpegParserCtx->pSyntax = mpp_calloc(JpegSyntaxParam, 1);
|
|
if (NULL == JpegParserCtx->pSyntax) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
memset(JpegParserCtx->pSyntax, 0, sizeof(JpegSyntaxParam));
|
|
JpegParserCtx->pSyntax->ppInstance = (void *)0; /* will be changed when need pp */
|
|
|
|
memset(&(JpegParserCtx->imageInfo), 0, sizeof(JpegDecImageInfo));
|
|
JpegParserCtx->decImageType = JPEGDEC_IMAGE; /* FULL MODEs */
|
|
JpegParserCtx->sliceMbSet = 0; /* will be changed when over 16MB*/
|
|
JpegParserCtx->color_conv = 0;
|
|
|
|
/* max */
|
|
JpegParserCtx->maxSupportedWidth = JPEGDEC_MAX_WIDTH_8190;
|
|
JpegParserCtx->maxSupportedHeight = JPEGDEC_MAX_HEIGHT_8190;
|
|
JpegParserCtx->maxSupportedPixelAmount = JPEGDEC_MAX_PIXEL_AMOUNT_8190;
|
|
JpegParserCtx->maxSupportedSliceSize = JPEGDEC_MAX_SLICE_SIZE_8190;
|
|
|
|
/* min */
|
|
JpegParserCtx->minSupportedWidth = JPEGDEC_MIN_WIDTH;
|
|
JpegParserCtx->minSupportedHeight = JPEGDEC_MIN_HEIGHT;
|
|
|
|
JpegParserCtx->is8190 = 1;
|
|
JpegParserCtx->extensionsSupported = 1;
|
|
|
|
JpegParserCtx->pts = 0;
|
|
JpegParserCtx->eos = 0;
|
|
JpegParserCtx->parser_debug_enable = 0;
|
|
JpegParserCtx->input_jpeg_count = 0;
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_flush(void *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
(void)JpegParserCtx;
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_reset(void *ctx)
|
|
{
|
|
FUN_TEST("Enter");
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
|
|
(void)JpegParserCtx;
|
|
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET jpegd_control(void *ctx, RK_S32 cmd, void *param)
|
|
{
|
|
FUN_TEST("Enter");
|
|
|
|
MPP_RET ret = MPP_OK;
|
|
JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx;
|
|
if (NULL == JpegParserCtx) {
|
|
JPEGD_ERROR_LOG("NULL pointer");
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case MPP_DEC_SET_OUTPUT_FORMAT: {
|
|
JpegParserCtx->color_conv = *((RK_U32 *)param);
|
|
JPEGD_INFO_LOG("output_format:%d\n", JpegParserCtx->color_conv);
|
|
} break;
|
|
default :
|
|
ret = MPP_NOK;
|
|
}
|
|
|
|
FUN_TEST("Exit");
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET jpegd_callback(void *ctx, void *err_info)
|
|
{
|
|
FUN_TEST("Enter");
|
|
(void) ctx;
|
|
(void) err_info;
|
|
FUN_TEST("Exit");
|
|
return MPP_OK;
|
|
}
|
|
|
|
const ParserApi api_jpegd_parser = {
|
|
"jpegd_parse",
|
|
MPP_VIDEO_CodingMJPEG,
|
|
sizeof(JpegParserContext),
|
|
0,
|
|
jpegd_init,
|
|
jpegd_deinit,
|
|
jpegd_prepare,
|
|
jpegd_parse,
|
|
jpegd_reset,
|
|
jpegd_flush,
|
|
jpegd_control,
|
|
jpegd_callback,
|
|
};
|
|
|
|
|