diff --git a/mpp/codec/CMakeLists.txt b/mpp/codec/CMakeLists.txt index 178866c9..75b572fc 100644 --- a/mpp/codec/CMakeLists.txt +++ b/mpp/codec/CMakeLists.txt @@ -24,7 +24,8 @@ target_link_libraries(mpp_codec codec_mpg4d codec_vp8d codec_vp9d - codec_h264e + codec_jpegd + codec_h264e codec_dummy_enc codec_dummy_dec mpp_base) diff --git a/mpp/codec/dec/CMakeLists.txt b/mpp/codec/dec/CMakeLists.txt index 48a03f7f..8cd42d5b 100644 --- a/mpp/codec/dec/CMakeLists.txt +++ b/mpp/codec/dec/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(vp8) add_subdirectory(vp9) +add_subdirectory(jpeg) diff --git a/mpp/codec/dec/jpeg/CMakeLists.txt b/mpp/codec/dec/jpeg/CMakeLists.txt new file mode 100644 index 00000000..7c6a4521 --- /dev/null +++ b/mpp/codec/dec/jpeg/CMakeLists.txt @@ -0,0 +1,17 @@ +# vim: syntax=cmake +set(JPEGD_PARSER_HDR + jpegd_parser.h + ) + +set(JPEGD_PARSER_SRC + jpegd_parser.c + ) +add_library(codec_jpegd STATIC + ${JPEGD_PARSER_SRC} ${JPEGD_PARSER_HDR} + ) + +set_target_properties(codec_jpegd PROPERTIES FOLDER "mpp/codec") + +target_link_libraries(codec_jpegd mpp_base) + +#add_subdirectory(test) diff --git a/mpp/codec/dec/jpeg/jpegd_parser.c b/mpp/codec/dec/jpeg/jpegd_parser.c new file mode 100644 index 00000000..177a6cd5 --- /dev/null +++ b/mpp/codec/dec/jpeg/jpegd_parser.c @@ -0,0 +1,2770 @@ +/* + * + * 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"); + (void) ctx; + // TODO: + FUN_TEST("Exit"); + return MPP_OK; +} + +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; + void *pPacket = NULL; + void *pPos = NULL; + + task->valid = 0; + + JpegParserCtx->pts = mpp_packet_get_pts(pkt); + pkt_length = mpp_packet_get_length(pkt); + pPacket = pPos = mpp_packet_get_pos(pkt); + memcpy(JpegParserCtx->recv_buffer, pPacket, pkt_length); + pPos += pkt_length; + mpp_packet_set_pos(pkt, pPos); + + /* 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_RK70_MAX_STREAM) && + (pCtx->bufferSize < JPEGDEC_RK70_MIN_BUFFER || pCtx->bufferSize > JPEGDEC_RK70_MAX_BUFFER)) { + JPEGD_ERROR_LOG("bufferSize = %d,streamLength = %d\n",pCtx->bufferSize, pCtx->streamLength); + return MPP_ERR_VALUE; + } + + if (pCtx->bufferSize && (pCtx->bufferSize < JPEGDEC_RK70_MIN_BUFFER || + pCtx->bufferSize > JPEGDEC_RK70_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"); + if (pCtx->dri_en == 0xffd0) { + /*ALOGI("STREAM HAS dri marker!"); + RK_U8 *dst, *tmp; + tmp = PTR_JPGC->stream.pCurrPos; + dst = PTR_JPGC->stream.pCurrPos; + for(i=0;istream.streamLength;i++) + { + if(tmp[i]==0xff && tmp[i+1]==0x00 && tmp[i+2]==0xff) + i += 2; + *dst++ = tmp[i]; + } + VPUMemClean(pDecIn->pstreamMem); + VPUMemInvalidate(pDecIn->pstreamMem);*/ + } + 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_ERROR_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; + /*pDecOut->outputPictureY.pVirtualAddress = NULL; + pDecOut->outputPictureY.busAddress = 0; + pDecOut->outputPictureCbCr.pVirtualAddress = NULL; + pDecOut->outputPictureCbCr.busAddress = 0; + pDecOut->outputPictureCr.pVirtualAddress = NULL; + pDecOut->outputPictureCr.busAddress = 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); + } + } + + /* Handle stream/hw parameters after buffer empty */ + if (pSyntax->info.inputBufferEmpty) { + // TODO: + } + + /* update user allocated output */ + // TODO: + + if (pSyntax->info.progressiveFinish) { + // TODO: + } + + /* 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; +} + +MPP_RET jpegd_parse(void *ctx, HalDecTask *task) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + JpegParserContext *JpegParserCtx = (JpegParserContext *)ctx; + task->valid = 0; + + 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); + } + + 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; + } + + 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; + } + + 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->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("NULL pointer"); + return MPP_ERR_NULL_PTR; + } + 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->bufferSize = JPEGD_STREAM_BUFF_SIZE; + JpegParserCtx->decImageType = JPEGDEC_IMAGE; /* FULL MODEs */ + JpegParserCtx->sliceMbSet = 0; /* will be changed when over 16MB*/ + JpegParserCtx->color_conv = 1; + + /* 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->parser_debug_enable = 1; + 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"); + (void)ctx; + (void)cmd; + (void)param; + return MPP_OK; +} + +MPP_RET jpegd_callback(void *ctx, void *err_info) +{ + FUN_TEST("Enter"); + (void) ctx; + (void) err_info; + 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, +}; + + diff --git a/mpp/codec/dec/jpeg/jpegd_parser.h b/mpp/codec/dec/jpeg/jpegd_parser.h new file mode 100644 index 00000000..ac2461ee --- /dev/null +++ b/mpp/codec/dec/jpeg/jpegd_parser.h @@ -0,0 +1,203 @@ +/* + * + * 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. + */ + +#ifndef __JPEGD_PARSER_H__ +#define __JPEGD_PARSER_H__ + +#include "mpp_bitread.h" +#include "mpp_common.h" +#include "mpp_frame.h" +#include "limits.h" +#include +#include +#include "mpp_dec.h" +#include "mpp_buf_slot.h" +#include "mpp_packet.h" + +#include "jpegd_syntax.h" + +/* Max amount of stream */ +#define DEC_RK70_MAX_STREAM ((1<<24)-1) + +#define JPEGDEC_RK70_MIN_BUFFER 256//5120 +#define JPEGDEC_RK70_MAX_BUFFER 16776960 +#define JPEGDEC_MAX_SLICE_SIZE 4096 +#define JPEGDEC_TABLE_SIZE 544 +#define JPEGDEC_MIN_WIDTH 48 +#define JPEGDEC_MIN_HEIGHT 48 +#define JPEGDEC_MAX_WIDTH 4672 +#define JPEGDEC_MAX_HEIGHT 4672 +#define JPEGDEC_MAX_PIXEL_AMOUNT 16370688 +#define JPEGDEC_MAX_WIDTH_8190 8176 +#define JPEGDEC_MAX_HEIGHT_8190 8176 +#define JPEGDEC_MAX_PIXEL_AMOUNT_8190 66846976 +#define JPEGDEC_MAX_SLICE_SIZE_8190 8100 +#define JPEGDEC_MAX_WIDTH_TN 256 +#define JPEGDEC_MAX_HEIGHT_TN 256 + +//#define JPEGDEC_BASELINE_TABLE_SIZE 544 +#define JPEGDEC_PROGRESSIVE_TABLE_SIZE 576 +#define JPEGDEC_QP_BASE 32 +#define JPEGDEC_AC1_BASE 48 +#define JPEGDEC_AC2_BASE 88 +#define JPEGDEC_DC1_BASE 129 +#define JPEGDEC_DC2_BASE 132 +#define JPEGDEC_DC3_BASE 135 + +#define PP_IN_FORMAT_YUV422INTERLAVE 0 +#define PP_IN_FORMAT_YUV420SEMI 1 +#define PP_IN_FORMAT_YUV420PLANAR 2 +#define PP_IN_FORMAT_YUV400 3 +#define PP_IN_FORMAT_YUV422SEMI 4 +#define PP_IN_FORMAT_YUV420SEMITIELED 5 +#define PP_IN_FORMAT_YUV440SEMI 6 +#define PP_IN_FORMAT_YUV444_SEMI 7 +#define PP_IN_FORMAT_YUV411_SEMI 8 + +#define PP_OUT_FORMAT_RGB565 0 +#define PP_OUT_FORMAT_ARGB 1 +#define PP_OUT_FORMAT_YUV422INTERLAVE 3 +#define PP_OUT_FORMAT_YUV420INTERLAVE 5 + +/* progressive */ +#define JPEGDEC_COEFF_SIZE 96 + +/* Timeout value for the VPUWaitHwReady() call. */ +/* Set to -1 for an unspecified value */ +#ifndef DEC_RK70_TIMEOUT_LENGTH +#define DEC_RK70_TIMEOUT_LENGTH (-1) +#endif + +enum { + JPEGDEC_NO_UNITS = 0, /* No units, X and Y specify + * the pixel aspect ratio */ + JPEGDEC_DOTS_PER_INCH = 1, /* X and Y are dots per inch */ + JPEGDEC_DOTS_PER_CM = 2 /* X and Y are dots per cm */ +}; + +enum { + JPEGDEC_THUMBNAIL_JPEG = 0x10, + JPEGDEC_THUMBNAIL_NOT_SUPPORTED_FORMAT = 0x11, + JPEGDEC_NO_THUMBNAIL = 0x12 +}; + +enum { + JPEGDEC_IMAGE = 0, + JPEGDEC_THUMBNAIL = 1 +}; + +enum{ + SOF0 = 0xC0, + SOF1 = 0xC1, + SOF2 = 0xC2, + SOF3 = 0xC3, + SOF5 = 0xC5, + SOF6 = 0xC6, + SOF7 = 0xC7, + SOF9 = 0xC8, + SOF10 = 0xCA, + SOF11 = 0xCB, + SOF13 = 0xCD, + SOF14 = 0xCE, + SOF15 = 0xCF, + JPG = 0xC8, + DHT = 0xC4, + DAC = 0xCC, + SOI = 0xD8, + EOI = 0xD9, + SOS = 0xDA, + DQT = 0xDB, + DNL = 0xDC, + DRI = 0xDD, + DHP = 0xDE, + EXP = 0xDF, + APP0 = 0xE0, + APP1 = 0xE1, + APP2 = 0xE2, + APP3 = 0xE3, + APP4 = 0xE4, + APP5 = 0xE5, + APP6 = 0xE6, + APP7 = 0xE7, + APP8 = 0xE8, + APP9 = 0xE9, + APP10 = 0xEA, + APP11 = 0xEB, + APP12 = 0xEC, + APP13 = 0xED, + APP14 = 0xEE, + APP15 = 0xEF, + JPG0 = 0xF0, + JPG1 = 0xF1, + JPG2 = 0xF2, + JPG3 = 0xF3, + JPG4 = 0xF4, + JPG5 = 0xF5, + JPG6 = 0xF6, + JPG7 = 0xF7, + JPG8 = 0xF8, + JPG9 = 0xF9, + JPG10 = 0xFA, + JPG11 = 0xFB, + JPG12 = 0xFC, + JPG13 = 0xFD, + COM = 0xFE, + TEM = 0x01, + RST0 = 0xD0, + RST1 = 0xD1, + RST2 = 0xD2, + RST3 = 0xD3, + RST4 = 0xD4, + RST5 = 0xD5, + RST6 = 0xD6, + RST7 = 0xD7 +}; + +typedef struct JpegParserContext { + MppBufSlots packet_slots; + MppBufSlots frame_slots; + RK_S32 frame_slot_index; /* slot index for output */ + RK_U8 *recv_buffer; + JpegSyntaxParam *pSyntax; + JpegDecImageInfo imageInfo; + + RK_U32 streamLength; /* input stream length or buffer size */ + RK_U32 bufferSize; /* input stream buffer size */ + RK_U32 decImageType; /* Full image or Thumbnail to be decoded */ + RK_U32 sliceMbSet; /* slice mode: mcu rows to decode */ + RK_U32 color_conv; + RK_U32 dri_en; + + MppPacket input_packet; + MppFrame output_frame; + RK_U32 is8190; + RK_U32 fuseBurned; + RK_U32 minSupportedWidth; + RK_U32 minSupportedHeight; + RK_U32 maxSupportedWidth; + RK_U32 maxSupportedHeight; + RK_U32 maxSupportedPixelAmount; + RK_U32 maxSupportedSliceSize; + RK_U32 extensionsSupported; + + RK_S64 pts; + + RK_U32 parser_debug_enable; + RK_U32 input_jpeg_count; +}JpegParserContext; + +#endif /* __JPEGD_PARSER_H__ */ diff --git a/mpp/codec/inc/jpegd_api.h b/mpp/codec/inc/jpegd_api.h new file mode 100644 index 00000000..fb28710e --- /dev/null +++ b/mpp/codec/inc/jpegd_api.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#ifndef __JPEGD_API_H__ +#define __JPEGD_API_H__ +#include "parser_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const ParserApi api_jpegd_parser; + +extern RK_U32 jpegd_log; +#define JPEGD_VBE_LOG (0x01) +#define JPEGD_DBG_LOG (0x02) +#define JPEGD_INF_LOG (0x04) +#define JPEGD_ERR_LOG (0x08) +#define JPEGD_DBG_ASSERT (1) + +#define FUN_TEST(tag) \ + do {\ + if (JPEGD_VBE_LOG & jpegd_log)\ + { mpp_log("[Verbose] %s: line(%d), func(%s)", tag, __LINE__, __FUNCTION__); }\ + } while (0) + + +#define JPEGD_ASSERT(val)\ + do {\ + if (JPEGD_DBG_ASSERT)\ + { mpp_assert(val); }\ + } while (0) + + +//check function return +#define CHECK_FUN(val) \ + do{ \ + if((val) < 0) { \ + ret = (val); \ + mpp_log("func return error(Line %d), ret:%d\n", __LINE__, ret); \ + goto __FAILED; \ + } \ + } while (0) + +//memory malloc check +#define CHECK_MEM(val, ...)\ + do{ if(!(val)) {\ + ret = MPP_ERR_MALLOC;\ + mpp_log("malloc buffer error(Line %d), pointer:%p\n", __LINE__, val);\ + goto __FAILED;\ + } } while (0) + +#define JPEGD_VERBOSE_LOG(fmt, ...) \ + do {\ + if (JPEGD_VBE_LOG & jpegd_log)\ + { mpp_log("[Verbose] func(%s), line(%d), "fmt"", __FUNCTION__, __LINE__, ##__VA_ARGS__); }\ + } while (0) + +#define JPEGD_DEBUG_LOG(fmt, ...) \ + do {\ + if (JPEGD_DBG_LOG & jpegd_log)\ + { mpp_log("[Debug] func(%s), line(%d), "fmt"", __FUNCTION__, __LINE__, ##__VA_ARGS__); }\ + } while (0) + +#define JPEGD_INFO_LOG(fmt, ...) \ + do {\ + if (JPEGD_INF_LOG & jpegd_log)\ + { mpp_log("[Info] func(%s), line(%d), "fmt"", __FUNCTION__, __LINE__, ##__VA_ARGS__); }\ + } while (0) + +#define JPEGD_ERROR_LOG(fmt, ...) \ + do {\ + if (JPEGD_ERR_LOG & jpegd_log)\ + { mpp_log("[Error] func(%s), line(%d), "fmt"", __FUNCTION__, __LINE__, ##__VA_ARGS__); }\ + } while (0) + + +MPP_RET jpegd_prepare(void *ctx, MppPacket pkt, HalDecTask *task); +MPP_RET jpegd_init(void *ctx, ParserCfg *parser_cfg); +MPP_RET jpegd_parse(void *ctx, HalDecTask *task); +MPP_RET jpegd_deinit(void *ctx); +MPP_RET jpegd_flush(void *ctx); +MPP_RET jpegd_reset(void *ctx); +MPP_RET jpegd_control(void *ctx, RK_S32 cmd, void *param); +MPP_RET jpegd_callback(void *ctx, void *err_info); + +#ifdef __cplusplus +} +#endif + +#endif /*__JPEGD_API_H__*/ diff --git a/mpp/codec/mpp_parser.cpp b/mpp/codec/mpp_parser.cpp index 8d1ca6c8..81326458 100644 --- a/mpp/codec/mpp_parser.cpp +++ b/mpp/codec/mpp_parser.cpp @@ -32,6 +32,7 @@ #include "m2vd_api.h" #include "mpg4d_api.h" #include "vp8d_api.h" +#include "jpegd_api.h" // for test and demo #include "dummy_dec_api.h" @@ -49,6 +50,7 @@ static const ParserApi *parsers[] = { &api_mpg4d_parser, &api_vp8d_parser, &api_vp9d_parser, + &api_jpegd_parser, &dummy_dec_parser, }; diff --git a/mpp/common/jpegd_syntax.h b/mpp/common/jpegd_syntax.h new file mode 100644 index 00000000..9d8b8650 --- /dev/null +++ b/mpp/common/jpegd_syntax.h @@ -0,0 +1,376 @@ +/* + * + * 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. + */ + +#ifndef __JPEGD_SYNTAX__ +#define __JPEGD_SYNTAX__ + +#include "vpu_api.h" + +#define MIN_NUMBER_OF_COMPONENTS 1 +#define MAX_NUMBER_OF_COMPONENTS 3 + +#define JPEGDEC_YCbCr400 0x080000U +#define JPEGDEC_YCbCr420_SEMIPLANAR 0x020001U +#define JPEGDEC_YCbCr422_SEMIPLANAR 0x010001U +#define JPEGDEC_YCbCr440 0x010004U +#define JPEGDEC_YCbCr411_SEMIPLANAR 0x100000U +#define JPEGDEC_YCbCr444_SEMIPLANAR 0x200000U + +#define JPEGDEC_BASELINE 0x0 +#define JPEGDEC_PROGRESSIVE 0x1 +#define JPEGDEC_NONINTERLEAVED 0x2 + +#define JPEGDEC_YUV400 0 +#define JPEGDEC_YUV420 2 +#define JPEGDEC_YUV422 3 +#define JPEGDEC_YUV444 4 +#define JPEGDEC_YUV440 5 +#define JPEGDEC_YUV411 6 + +#define JPEGD_STREAM_BUFF_SIZE (10*1024*1024) +#define JPEGDEC_BASELINE_TABLE_SIZE (544) + +typedef enum { + JPEGDEC_SLICE_READY = 2, + JPEGDEC_FRAME_READY = 1, + JPEGDEC_STRM_PROCESSED = 3, + JPEGDEC_SCAN_PROCESSED = 4, + JPEGDEC_OK = 0, + JPEGDEC_ERROR = -1, + JPEGDEC_UNSUPPORTED = -2, + JPEGDEC_PARAM_ERROR = -3, + JPEGDEC_MEMFAIL = -4, + JPEGDEC_INITFAIL = -5, + JPEGDEC_INVALID_STREAM_LENGTH = -6, + JPEGDEC_STRM_ERROR = -7, + JPEGDEC_INVALID_INPUT_BUFFER_SIZE = -8, + JPEGDEC_HW_RESERVED = -9, + JPEGDEC_INCREASE_INPUT_BUFFER = -10, + JPEGDEC_SLICE_MODE_UNSUPPORTED = -11, + JPEGDEC_DWL_HW_TIMEOUT = -253, + JPEGDEC_DWL_ERROR = -254, + JPEGDEC_HW_BUS_ERROR = -255, + JPEGDEC_SYSTEM_ERROR = -256, + JPEGDEC_FORMAT_NOT_SUPPORTED = -1000 +} JpegDecRet; + +typedef struct { + RK_U32 C; /* Component id */ + RK_U32 H; /* Horizontal sampling factor */ + RK_U32 V; /* Vertical sampling factor */ + RK_U32 Tq; /* Quantization table destination selector */ +} Components; + +typedef struct { + RK_U8 *pStartOfStream; + RK_U8 *pCurrPos; + RK_U32 streamBus; /* physical address */ + RK_U32 bitPosInByte; + RK_U32 streamLength; + RK_U32 readBits; + RK_U32 appnFlag; + RK_U32 thumbnail; + RK_U32 returnSosMarker; +} StreamStorage; + +typedef struct { + RK_U8 *pStartOfImage; + RK_U8 *pLum; + RK_U8 *pCr; + RK_U8 *pCb; + RK_U32 imageReady; + RK_U32 headerReady; + RK_U32 size; + RK_U32 sizeLuma; + RK_U32 sizeChroma; + RK_U32 ready; + RK_U32 columns[MAX_NUMBER_OF_COMPONENTS]; + RK_U32 pixelsPerRow[MAX_NUMBER_OF_COMPONENTS]; +} ImageData; + +typedef struct { + RK_U32 Lf; + RK_U32 P; + RK_U32 Y; + RK_U32 hwY; + RK_U32 X; + RK_U32 hwX; + RK_U32 Nf; /* Number of components in frame */ + RK_U32 codingType; + RK_U32 numMcuInFrame; + RK_U32 numMcuInRow; + RK_U32 mcuNumber; + RK_U32 nextRstNumber; + RK_U32 Ri; + RK_U32 driPeriod; + RK_U32 block; + RK_U32 row; + RK_U32 col; + RK_U32 cIndex; + RK_U32 *pBuffer; + RK_U32 bufferBus; + RK_S32 *pBufferCb; + RK_S32 *pBufferCr; + VPUMemLinear_t pTableBase; + RK_U32 numBlocks[MAX_NUMBER_OF_COMPONENTS]; + RK_U32 blocksPerRow[MAX_NUMBER_OF_COMPONENTS]; + RK_U32 useAcOffset[MAX_NUMBER_OF_COMPONENTS]; + Components component[MAX_NUMBER_OF_COMPONENTS]; +} FrameInfo; + +typedef struct { + RK_U32 Ls; + RK_U32 Ns; + RK_U32 Cs[MAX_NUMBER_OF_COMPONENTS]; /* Scan component selector */ + RK_U32 Td[MAX_NUMBER_OF_COMPONENTS]; /* Selects table for DC */ + RK_U32 Ta[MAX_NUMBER_OF_COMPONENTS]; /* Selects table for AC */ + RK_U32 Ss; + RK_U32 Se; + RK_U32 Ah; + RK_U32 Al; + RK_U32 index; + RK_S32 numIdctRows; + RK_S32 pred[MAX_NUMBER_OF_COMPONENTS]; +} ScanInfo; + +typedef struct { + RK_U32 sliceHeight; + RK_U32 amountOfQTables; + RK_U32 yCbCrMode; + RK_U32 yCbCr422; + RK_U32 column; + RK_U32 X; /* width */ + RK_U32 Y; /* height */ + RK_U32 memSize; + RK_U32 SliceCount; + RK_U32 SliceReadyForPause; + RK_U32 SliceMBCutValue; + RK_U32 pipeline; + RK_U32 userAllocMem; + RK_U32 sliceMbSetValue; + RK_U32 timeout; + RK_U32 rlcMode; + RK_U32 lumaPos; + RK_U32 chromaPos; + RK_U32 sliceStartCount; + RK_U32 amountOfSlices; + RK_U32 noSliceIrqForUser; + RK_U32 sliceLimitReached; + RK_U32 inputBufferEmpty; + RK_U32 fillRight; + RK_U32 fillBottom; + RK_U32 streamEnd; + RK_U32 streamEndFlag; + RK_U32 inputBufferLen; + RK_U32 inputStreaming; + RK_U32 decodedStreamLen; + RK_U32 init; + RK_U32 initThumb; + RK_U32 initBufferSize; + RK_S32 dcRes[MAX_NUMBER_OF_COMPONENTS]; + VPUMemLinear_t outLuma; + VPUMemLinear_t outChroma; + VPUMemLinear_t outChroma2; + VPUMemLinear_t givenOutLuma; + VPUMemLinear_t givenOutChroma; + VPUMemLinear_t givenOutChroma2; + RK_S32 pred[MAX_NUMBER_OF_COMPONENTS]; + /* progressive parameters */ + RK_U32 nonInterleaved; + RK_U32 componentId; + RK_U32 operationType; + RK_U32 operationTypeThumb; + RK_U32 progressiveScanReady; + RK_U32 nonInterleavedScanReady; + RK_U32 allocated; + RK_U32 yCbCrModeOrig; + RK_U32 getInfoYCbCrMode; + RK_U32 components[MAX_NUMBER_OF_COMPONENTS]; + VPUMemLinear_t pCoeffBase; + + RK_U32 fillX; + RK_U32 fillY; + + RK_U32 progressiveFinish; + RK_U32 pfCompId; + RK_U32 pfNeeded[MAX_NUMBER_OF_COMPONENTS]; + VPUMemLinear_t tmpStrm; + +} DecInfo; + +// TODO: The way to malloc buffer has been changed in MPP +typedef struct { + VPUMemLinear_t outLumaBuffer; + VPUMemLinear_t outChromaBuffer; + VPUMemLinear_t outChromaBuffer2; + +} JpegAsicBuffers; + +typedef struct { + RK_U32 bits[16]; + RK_U32 *vals; + RK_U32 tableLength; + RK_U32 start; + RK_U32 last; +} VlcTable; + +typedef struct { + RK_U32 Lh; + VlcTable acTable0; + VlcTable acTable1; + VlcTable acTable2; + VlcTable acTable3; + VlcTable dcTable0; + VlcTable dcTable1; + VlcTable dcTable2; + VlcTable dcTable3; + VlcTable *table; +} HuffmanTables; + +typedef struct { + RK_U32 Lq; /* Quantization table definition length */ + RK_U32 table0[64]; + RK_U32 table1[64]; + RK_U32 table2[64]; + RK_U32 table3[64]; + RK_U32 *table; +} QuantTables; + +/* Control interface between decoder and pp */ +/* decoder writes, pp read-only */ +typedef struct DecPpInterface_ { + enum { + DECPP_IDLE = 0, + DECPP_RUNNING, /* PP was started */ + DECPP_PIC_READY, /* PP has finished a picture */ + DECPP_PIC_NOT_FINISHED /* PP still processing a picture */ + } ppStatus; /* Decoder keeps track of what it asked the pp to do */ + + enum { + MULTIBUFFER_UNINIT = 0, /* buffering mode not yet decided */ + MULTIBUFFER_DISABLED, /* Single buffer legacy mode */ + MULTIBUFFER_SEMIMODE, /* enabled but full pipel cannot be used */ + MULTIBUFFER_FULLMODE /* enabled and full pipeline successful */ + } multiBufStat; + + RK_U32 inputBusLuma; + RK_U32 inputBusChroma; + RK_U32 bottomBusLuma; + RK_U32 bottomBusChroma; + RK_U32 picStruct; /* structure of input picture */ + RK_U32 topField; + RK_U32 inwidth; + RK_U32 inheight; + RK_U32 usePipeline; + RK_U32 littleEndian; + RK_U32 wordSwap; + RK_U32 croppedW; + RK_U32 croppedH; + + RK_U32 bufferIndex; /* multibuffer, where to put PP output */ + RK_U32 displayIndex; /* multibuffer, next picture in display order */ + RK_U32 prevAnchorDisplayIndex; + + /* VC-1 */ + RK_U32 rangeRed; + RK_U32 rangeMapYEnable; + RK_U32 rangeMapYCoeff; + RK_U32 rangeMapCEnable; + RK_U32 rangeMapCCoeff; +} DecPpInterface; + +typedef struct { + int enable; + int outFomart; /* =0,RGB565;=1,ARGB 8888 */ + //int destWidth; + //int destHeight; + int scale_denom; + int shouldDither; + int cropX; + int cropY; + int cropW; + int cropH; +} PostProcessInfo; + +/* Image information */ +typedef struct { + RK_U32 displayWidth; + RK_U32 displayHeight; + RK_U32 outputWidth; /* Number of pixels/line in the image */ + RK_U32 outputHeight; /* Number of lines in in the image */ + RK_U32 version; + RK_U32 units; + RK_U32 xDensity; + RK_U32 yDensity; + RK_U32 outputFormat; /* JPEGDEC_YCbCr400 + * JPEGDEC_YCbCr420 + * JPEGDEC_YCbCr422 + */ + RK_U32 codingMode; /* JPEGDEC_BASELINE + * JPEGDEC_PROGRESSIVE + * JPEGDEC_NONINTERLEAVED + */ + + RK_U32 thumbnailType; /* Thumbnail exist or not or not supported */ + RK_U32 displayWidthThumb; + RK_U32 displayHeightThumb; + RK_U32 outputWidthThumb; /* Number of pixels/line in the image */ + RK_U32 outputHeightThumb; /* Number of lines in in the image */ + RK_U32 outputFormatThumb; /* JPEGDEC_YCbCr400 + * JPEGDEC_YCbCr420 + * JPEGDEC_YCbCr422 + */ + RK_U32 codingModeThumb; /* JPEGDEC_BASELINE + * JPEGDEC_PROGRESSIVE + * JPEGDEC_NONINTERLEAVED + */ +} JpegDecImageInfo; + +typedef struct JpegSyntaxParam{ + StreamStorage stream; + FrameInfo frame; + ImageData image; + ScanInfo scan; + DecInfo info; + HuffmanTables vlc; + QuantTables quant; + JpegDecImageInfo imageInfo; + RK_U32 ppInputFomart; + PostProcessInfo ppInfo; + RK_U32 is8190; + RK_U32 fuseBurned; + RK_U32 ppScaleW; + RK_U32 ppScaleH; + RK_U32 minSupportedWidth; + RK_U32 minSupportedHeight; + RK_U32 maxSupportedWidth; + RK_U32 maxSupportedHeight; + RK_U32 maxSupportedPixelAmount; + RK_U32 maxSupportedSliceSize; + RK_U32 extensionsSupported; + JpegAsicBuffers asicBuff; + DecPpInterface ppControl; + RK_U32 ppStatus; + int socket; /* socket instance */ + void* vpumem_ctx; + + const void *ppInstance; + VPUMemLinear_t *pictureMem; +}JpegSyntaxParam; + + +#endif /*__JPEGD_SYNTAX__*/ diff --git a/mpp/hal/CMakeLists.txt b/mpp/hal/CMakeLists.txt index b08ae48c..50e5b73d 100644 --- a/mpp/hal/CMakeLists.txt +++ b/mpp/hal/CMakeLists.txt @@ -30,6 +30,8 @@ add_subdirectory(vpu/mpg4d) add_subdirectory(vpu/vp8d) +add_subdirectory(vpu/jpegd) + add_subdirectory(rkenc/h264e) # ---------------------------------------------------------------------------- @@ -52,7 +54,8 @@ target_link_libraries(mpp_hal hal_mpg4d hal_vp8d hal_vp9d - hal_h264e + hal_jpegd + hal_h264e hal_dummy ${RKPLAT_VPU} ) diff --git a/mpp/hal/inc/hal_jpegd_api.h b/mpp/hal/inc/hal_jpegd_api.h new file mode 100644 index 00000000..93bf2657 --- /dev/null +++ b/mpp/hal/inc/hal_jpegd_api.h @@ -0,0 +1,47 @@ +/* +* +* 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. +*/ + + +#ifndef __HAL_JPEGD_API_H__ +#define __HAL_JPEGD_API_H__ + +#include "rk_type.h" +#include "mpp_err.h" +#include "mpp_hal.h" + + + +#ifdef __cplusplus +extern "C" { +#endif + +extern const MppHalApi hal_api_jpegd; + +RK_S32 hal_jpegd_init(void *hal, MppHalCfg *cfg); +RK_S32 hal_jpegd_gen_regs(void *hal, HalTaskInfo *syn); +RK_S32 hal_jpegd_deinit(void *hal); +MPP_RET hal_jpegd_start(void *hal, HalTaskInfo *task); +MPP_RET hal_jpegd_wait(void *hal, HalTaskInfo *task); +MPP_RET hal_jpegd_reset(void *hal); +MPP_RET hal_jpegd_flush(void *hal); +MPP_RET hal_jpegd_control(void *hal, RK_S32 cmd_type, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /*__HAL_JPEGD_API_H__*/ diff --git a/mpp/hal/mpp_hal.cpp b/mpp/hal/mpp_hal.cpp index b0a546e0..8d0064da 100644 --- a/mpp/hal/mpp_hal.cpp +++ b/mpp/hal/mpp_hal.cpp @@ -34,6 +34,7 @@ #include "hal_mpg4d_api.h" #include "hal_vp8d_api.h" #include "hal_h264e_api.h" +#include "hal_jpegd_api.h" // for test and demo #include "hal_dummy_dec_api.h" @@ -51,7 +52,8 @@ static const MppHalApi *hw_apis[] = { &hal_api_mpg4d, &hal_api_vp8d, &hal_api_vp9d, - &hal_api_h264e, + &hal_api_jpegd, + &hal_api_h264e, &hal_api_dummy_dec, &hal_api_dummy_enc, }; diff --git a/mpp/hal/vpu/jpegd/CMakeLists.txt b/mpp/hal/vpu/jpegd/CMakeLists.txt new file mode 100644 index 00000000..0f91067d --- /dev/null +++ b/mpp/hal/vpu/jpegd/CMakeLists.txt @@ -0,0 +1,20 @@ +# vim: syntax=cmake +# hal jpeg reg + +set(HAL_JPEGD_HDR + hal_jpegd_reg.h + ) + +set(HAL_JPEGD_SRC + hal_jpegd_reg.c + ) + +add_library(hal_jpegd STATIC + ${HAL_JPEGD_SRC} ${HAL_JPEGD_HDR} + ) + +set_target_properties(hal_jpegd PROPERTIES FOLDER "mpp/hal") + + target_link_libraries(hal_jpegd mpp_base) + +#add_subdirectory(test) diff --git a/mpp/hal/vpu/jpegd/hal_jpegd_reg.c b/mpp/hal/vpu/jpegd/hal_jpegd_reg.c new file mode 100644 index 00000000..d63fcc83 --- /dev/null +++ b/mpp/hal/vpu/jpegd/hal_jpegd_reg.c @@ -0,0 +1,2102 @@ +/* + * + * 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 "JPEGHAL" + +#include +#include + +#include "mpp_buffer.h" +#include "mpp_log.h" +#include "mpp_err.h" +#include "mpp_mem.h" +#include "mpp_bitread.h" +#include "mpp_dec.h" +#include "vpu.h" +#include "mpp_buffer.h" +#include "mpp_env.h" +#include "mpp_bitput.h" + +#include "jpegd_api.h" +#include "hal_jpegd_reg.h" + +static const RK_U8 zzOrder[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +void jpegd_calculate_slice_size(JpegSyntaxParam *pSyntax) +{ + FUN_TEST("Enter"); + (void)pSyntax; + FUN_TEST("Exit"); +} + +void jpegd_input_buff_load_init(JpegSyntaxParam *pSyntax) +{ + FUN_TEST("Enter"); + // TODO: no need so far + (void)pSyntax; + FUN_TEST("Exit"); +} + +static void jpegd_write_len_bits(JpegSyntaxParam *pSyntax, JpegHalContext *pCtx) +{ + FUN_TEST("Enter"); + ScanInfo *JPG_SCN = &pSyntax->scan; + HuffmanTables *JPG_VLC = &pSyntax->vlc; + JpegRegSet *reg = &(pCtx->regs); + + VlcTable *pTable1 = NULL; + VlcTable *pTable2 = NULL; + + /* first select the table we'll use */ + + /* this trick is done because hw always wants luma table as ac hw table 1 */ + if (JPG_SCN->Ta[0] == 0) { + pTable1 = &(JPG_VLC->acTable0); + pTable2 = &(JPG_VLC->acTable1); + } else { + pTable1 = &(JPG_VLC->acTable1); + pTable2 = &(JPG_VLC->acTable0); + } + + JPEGD_ASSERT(pTable1); + JPEGD_ASSERT(pTable2); + + /* write AC table 1 (luma) */ + reg->reg134.sw_ac1_code1_cnt = pTable1->bits[0]; + reg->reg134.sw_ac1_code2_cnt = pTable1->bits[1]; + reg->reg134.sw_ac1_code3_cnt = pTable1->bits[2]; + reg->reg134.sw_ac1_code4_cnt = pTable1->bits[3]; + reg->reg134.sw_ac1_code5_cnt = pTable1->bits[4]; + reg->reg134.sw_ac1_code6_cnt = pTable1->bits[5]; + + reg->reg135.sw_ac1_code7_cnt = pTable1->bits[6]; + reg->reg135.sw_ac1_code8_cnt = pTable1->bits[7]; + reg->reg135.sw_ac1_code9_cnt = pTable1->bits[8]; + reg->reg135.sw_ac1_code10_cnt = pTable1->bits[9]; + + reg->reg136.sw_ac1_code11_cnt = pTable1->bits[10]; + reg->reg136.sw_ac1_code12_cnt = pTable1->bits[11]; + reg->reg136.sw_ac1_code13_cnt = pTable1->bits[12]; + reg->reg136.sw_ac1_code14_cnt = pTable1->bits[13]; + + reg->reg137.sw_ac1_code15_cnt = pTable1->bits[14]; + reg->reg137.sw_ac1_code16_cnt = pTable1->bits[15]; + + /* table AC2 (the not-luma table) */ + reg->reg137.sw_ac2_code1_cnt = pTable2->bits[0]; + reg->reg137.sw_ac2_code2_cnt = pTable2->bits[1]; + reg->reg137.sw_ac2_code3_cnt = pTable2->bits[2]; + reg->reg137.sw_ac2_code4_cnt = pTable2->bits[3]; + + reg->reg138.sw_ac2_code5_cnt = pTable2->bits[4]; + reg->reg138.sw_ac2_code6_cnt = pTable2->bits[5]; + reg->reg138.sw_ac2_code7_cnt = pTable2->bits[6]; + reg->reg138.sw_ac2_code8_cnt = pTable2->bits[7]; + + reg->reg139.sw_ac2_code9_cnt = pTable2->bits[8]; + reg->reg139.sw_ac2_code10_cnt = pTable2->bits[9]; + reg->reg139.sw_ac2_code11_cnt = pTable2->bits[10]; + reg->reg139.sw_ac2_code12_cnt = pTable2->bits[11]; + + reg->reg140.sw_ac2_code13_cnt = pTable2->bits[12]; + reg->reg140.sw_ac2_code14_cnt = pTable2->bits[13]; + reg->reg140.sw_ac2_code15_cnt = pTable2->bits[14]; + reg->reg140.sw_ac2_code16_cnt = pTable2->bits[15]; + + if (JPG_SCN->Td[0] == 0) { + pTable1 = &(JPG_VLC->dcTable0); + pTable2 = &(JPG_VLC->dcTable1); + } else { + pTable1 = &(JPG_VLC->dcTable1); + pTable2 = &(JPG_VLC->dcTable0); + } + + JPEGD_ASSERT(pTable1); + JPEGD_ASSERT(pTable2); + + /* write DC table 1 (luma) */ + reg->reg141.sw_dc1_code1_cnt = pTable1->bits[0]; + reg->reg141.sw_dc1_code2_cnt = pTable1->bits[1]; + reg->reg141.sw_dc1_code3_cnt = pTable1->bits[2]; + reg->reg141.sw_dc1_code4_cnt = pTable1->bits[3]; + reg->reg141.sw_dc1_code5_cnt = pTable1->bits[4]; + reg->reg141.sw_dc1_code6_cnt = pTable1->bits[5]; + reg->reg141.sw_dc1_code7_cnt = pTable1->bits[6]; + reg->reg141.sw_dc1_code8_cnt = pTable1->bits[7]; + + reg->reg142.sw_dc1_code9_cnt = pTable1->bits[8]; + reg->reg142.sw_dc1_code10_cnt = pTable1->bits[9]; + reg->reg142.sw_dc1_code11_cnt = pTable1->bits[10]; + reg->reg142.sw_dc1_code12_cnt = pTable1->bits[11]; + reg->reg142.sw_dc1_code13_cnt = pTable1->bits[12]; + reg->reg142.sw_dc1_code14_cnt = pTable1->bits[13]; + reg->reg142.sw_dc1_code15_cnt = pTable1->bits[14]; + reg->reg142.sw_dc1_code16_cnt = pTable1->bits[15]; + + /* table DC2 (the not-luma table) */ + reg->reg143.sw_dc2_code1_cnt = pTable2->bits[0]; + reg->reg143.sw_dc2_code2_cnt = pTable2->bits[1]; + reg->reg143.sw_dc2_code3_cnt = pTable2->bits[2]; + reg->reg143.sw_dc2_code4_cnt = pTable2->bits[3]; + reg->reg143.sw_dc2_code5_cnt = pTable2->bits[4]; + reg->reg143.sw_dc2_code6_cnt = pTable2->bits[5]; + reg->reg143.sw_dc2_code7_cnt = pTable2->bits[6]; + reg->reg143.sw_dc2_code8_cnt = pTable2->bits[7]; + + reg->reg144.sw_dc2_code9_cnt = pTable2->bits[8]; + reg->reg144.sw_dc2_code10_cnt = pTable2->bits[9]; + reg->reg144.sw_dc2_code11_cnt = pTable2->bits[10]; + reg->reg144.sw_dc2_code12_cnt = pTable2->bits[11]; + reg->reg144.sw_dc2_code13_cnt = pTable2->bits[12]; + reg->reg144.sw_dc2_code14_cnt = pTable2->bits[13]; + reg->reg144.sw_dc2_code15_cnt = pTable2->bits[14]; + reg->reg144.sw_dc2_code16_cnt = pTable2->bits[15]; + + FUN_TEST("Exit"); + return; +} + +static void jpegd_set_stream_params(JpegSyntaxParam *pSyntax, JpegHalContext *pCtx) +{ + FUN_TEST("Enter"); + StreamStorage *JPG_STR = &pSyntax->stream; + JpegRegSet *reg = &(pCtx->regs); + + RK_U32 addrTmp = 0; + RK_U32 amountOfStream = 0; + + JPEGD_INFO_LOG("read %d bits\n", JPG_STR->readBits); + JPEGD_INFO_LOG("read %d bytes\n", JPG_STR->readBits / 8); + JPEGD_INFO_LOG("Stream physical address start: 0x%08x\n", JPG_STR->streamBus); + JPEGD_INFO_LOG("Stream virtual address start: %p\n", JPG_STR->pStartOfStream); + + /* calculate and set stream start address to hw */ + addrTmp = (((RK_U32) JPG_STR->pStartOfStream & 0x3) + + (RK_U32) (JPG_STR->pCurrPos - JPG_STR->pStartOfStream)) & (~7); + + JPEGD_INFO_LOG("pStartOfStream data: 0x%x, 0x%x, 0x%x, 0x%x", JPG_STR->pStartOfStream[JPG_STR->streamLength - 4], + JPG_STR->pStartOfStream[JPG_STR->streamLength - 3], + JPG_STR->pStartOfStream[JPG_STR->streamLength - 2], + JPG_STR->pStartOfStream[JPG_STR->streamLength - 1]); + + if (VPUClientGetIOMMUStatus() <= 0) { + reg->reg64_rlc_vlc_base = JPG_STR->streamBus + addrTmp; + } else { + reg->reg64_rlc_vlc_base = JPG_STR->streamBus | (addrTmp << 10); + } + JPEGD_INFO_LOG("reg64_rlc_vlc_base: 0x%08x\n", reg->reg64_rlc_vlc_base); + + /* calculate and set stream start bit to hw */ + + /* change current pos to bus address style */ + /* remove three lowest bits and add the difference to bitPosInWord */ + /* used as bit pos in word not as bit pos in byte actually... */ + switch ((RK_U32) JPG_STR->pCurrPos & (7)) { + case 0: + break; + case 1: + JPG_STR->bitPosInByte += 8; + break; + case 2: + JPG_STR->bitPosInByte += 16; + break; + case 3: + JPG_STR->bitPosInByte += 24; + break; + case 4: + JPG_STR->bitPosInByte += 32; + break; + case 5: + JPG_STR->bitPosInByte += 40; + break; + case 6: + JPG_STR->bitPosInByte += 48; + break; + case 7: + JPG_STR->bitPosInByte += 56; + break; + default: + JPEGD_ASSERT(0); + break; + } + + reg->reg122.sw_strm_start_bit = JPG_STR->bitPosInByte; + + /* set up stream length for HW. + * length = size of original buffer - stream we already decoded in SW */ + JPG_STR->pCurrPos = (RK_U8 *) ((RK_U32) JPG_STR->pCurrPos & (~7)); + + if (pSyntax->info.inputStreaming) { + JPEGD_VERBOSE_LOG("inputStreaming-1, inputBufferLen:%d", pSyntax->info.inputBufferLen); + amountOfStream = (pSyntax->info.inputBufferLen - + (RK_U32) (JPG_STR->pCurrPos - JPG_STR->pStartOfStream)); + + reg->reg51_stream_info.sw_stream_len = amountOfStream; + pSyntax->info.streamEnd = 1; + } else { + JPEGD_VERBOSE_LOG("inputStreaming-2"); + amountOfStream = (JPG_STR->streamLength - + (RK_U32) (JPG_STR->pCurrPos - JPG_STR->pStartOfStream)); + + reg->reg51_stream_info.sw_stream_len = amountOfStream; + + /* because no input streaming, frame should be ready during decoding this buffer */ + pSyntax->info.streamEnd = 1; + } + + reg->reg122.sw_jpeg_stream_all = pSyntax->info.streamEnd; + + JPEGD_INFO_LOG("streamLength: %d\n", JPG_STR->streamLength); + JPEGD_INFO_LOG("pCurrPos: %p\n", JPG_STR->pCurrPos); + JPEGD_INFO_LOG("pStartOfStream: %p\n", JPG_STR->pStartOfStream); + JPEGD_INFO_LOG("bitPosInByte: 0x%08x\n", JPG_STR->bitPosInByte); + + FUN_TEST("Exit"); + return; +} + +static void jpegd_select_chroma_table(JpegSyntaxParam *pSyntax, JpegHalContext *pCtx) +{ + FUN_TEST("Enter"); + ScanInfo *JPG_SCN = &pSyntax->scan; + JpegRegSet *reg = &(pCtx->regs); + + /* this trick is done because hw always wants luma table as ac hw table 1 */ + if (JPG_SCN->Ta[0] == 0) { + reg->reg122.sw_cr_ac_vlctable = JPG_SCN->Ta[2]; + reg->reg122.sw_cb_ac_vlctable = JPG_SCN->Ta[1]; + } else { + if (JPG_SCN->Ta[0] == JPG_SCN->Ta[1]) + reg->reg122.sw_cb_ac_vlctable = 0; + else + reg->reg122.sw_cb_ac_vlctable = 1; + + if (JPG_SCN->Ta[0] == JPG_SCN->Ta[2]) + reg->reg122.sw_cr_ac_vlctable = 0; + else + reg->reg122.sw_cr_ac_vlctable = 1; + } + + /* Third DC table selectors */ + if (pSyntax->info.operationType != JPEGDEC_PROGRESSIVE) { + JPEGD_INFO_LOG("NON_PROGRESSIVE"); + if (JPG_SCN->Td[0] == 0) { + reg->reg122.sw_cr_dc_vlctable = JPG_SCN->Td[2]; + reg->reg122.sw_cb_dc_vlctable = JPG_SCN->Td[1]; + } else { + if (JPG_SCN->Td[0] == JPG_SCN->Td[1]) + reg->reg122.sw_cb_dc_vlctable = 0; + else + reg->reg122.sw_cb_dc_vlctable = 1; + + if (JPG_SCN->Td[0] == JPG_SCN->Td[2]) + reg->reg122.sw_cr_dc_vlctable = 0; + else + reg->reg122.sw_cr_dc_vlctable = 1; + } + + reg->reg122.sw_cr_dc_vlctable3 = 0; + reg->reg122.sw_cb_dc_vlctable3 = 0; + } else { + JPEGD_INFO_LOG("JPEGDEC_PROGRESSIVE"); +#if 0 + /* if non-interleaved ==> decoding mode YUV400, uses table zero (0) */ + if (PTR_JPGC->info.nonInterleaved) { + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CR_DC_VLCTABLE, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CB_DC_VLCTABLE, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CR_DC_VLCTABLE3, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CB_DC_VLCTABLE3, 0); + } else { + /* if later stage DC ==> no need for table */ + if (PTR_JPGC->scan.Ah != 0 && PTR_JPGC->scan.Ss == 0) { + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CR_DC_VLCTABLE, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CR_DC_VLCTABLE3, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CB_DC_VLCTABLE, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CB_DC_VLCTABLE3, 0); + } else { + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CR_DC_VLCTABLE, 0); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CR_DC_VLCTABLE3, 1); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CB_DC_VLCTABLE, 1); + rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_CB_DC_VLCTABLE3, 0); + } + } +#endif + } + + FUN_TEST("Exit"); + return; +} + + +static void jpegd_write_tables(JpegSyntaxParam *pSyntax, JpegHalContext *pCtx) +{ + FUN_TEST("Enter"); + ScanInfo *JPG_SCN = &pSyntax->scan; + HuffmanTables *JPG_VLC = &pSyntax->vlc; + QuantTables *JPG_QTB = &pSyntax->quant; + FrameInfo *JPG_FRM = &pSyntax->frame; + + RK_U32 i, j = 0; + RK_U32 shifter = 32; + RK_U32 tableWord = 0; + RK_U32 tableValue = 0; + RK_U8 tableTmp[64] = { 0 }; + RK_U32 *pTableBase = NULL; + + pTableBase = (RK_U32 *)mpp_buffer_get_ptr(pCtx->pTableBase); + + /* QP tables for all components */ + for (j = 0; j < pSyntax->info.amountOfQTables; j++) { + if ((JPG_FRM->component[j].Tq) == 0) { + for (i = 0; i < 64; i++) { + tableTmp[zzOrder[i]] = (RK_U8) JPG_QTB->table0[i]; + } + + /* update shifter */ + shifter = 32; + + for (i = 0; i < 64; i++) { + shifter -= 8; + + if (shifter == 24) + tableWord = (tableTmp[i] << shifter); + else + tableWord |= (tableTmp[i] << shifter); + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 64; i++) { + tableTmp[zzOrder[i]] = (RK_U8) JPG_QTB->table1[i]; + } + + /* update shifter */ + shifter = 32; + + for (i = 0; i < 64; i++) { + shifter -= 8; + + if (shifter == 24) + tableWord = (tableTmp[i] << shifter); + else + tableWord |= (tableTmp[i] << shifter); + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + } + + /* update shifter */ + shifter = 32; + + if (pSyntax->info.yCbCrMode != JPEGDEC_YUV400) { + /* this trick is done because hw always wants luma table as ac hw table 1 */ + if (JPG_SCN->Ta[0] == 0) { + /* Write AC Table 1 (as specified in HW regs) + * NOTE: Not the same as actable[1] (as specified in JPEG Spec) */ + JPEGD_VERBOSE_LOG("INTERNAL: Write tables: AC1 (luma)\n"); + if (JPG_VLC->acTable0.vals) { + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* Write AC Table 2 */ + JPEGD_VERBOSE_LOG("INTERNAL: Write tables: AC2 (not-luma)\n"); + if (JPG_VLC->acTable1.vals) { + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + } else { + /* Write AC Table 1 (as specified in HW regs) + * NOTE: Not the same as actable[1] (as specified in JPEG Spec) */ + if (JPG_VLC->acTable1.vals) { + JPEGD_INFO_LOG("INTERNAL: Write tables: AC1 (luma)\n"); + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* Write AC Table 2 */ + if (JPG_VLC->acTable0.vals) { + JPEGD_INFO_LOG("INTERNAL: writeTables: AC2 (not-luma)\n"); + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + } + + /* this trick is done because hw always wants luma table as dc hw table 1 */ + if (JPG_SCN->Td[0] == 0) { + if (JPG_VLC->dcTable0.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + if (JPG_VLC->dcTable1.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + } else { + if (JPG_VLC->dcTable1.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + if (JPG_VLC->dcTable0.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + } + } else { /* YUV400 */ + if (!pSyntax->info.nonInterleavedScanReady) { + /* this trick is done because hw always wants luma table as ac hw table 1 */ + if (JPG_SCN->Ta[0] == 0) { + /* Write AC Table 1 (as specified in HW regs) + * NOTE: Not the same as actable[1] (as specified in JPEG Spec) */ + JPEGD_INFO_LOG("INTERNAL: Write tables: AC1 (luma)\n"); + if (JPG_VLC->acTable0.vals) { + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* Write AC Table 2 */ + JPEGD_INFO_LOG("INTERNAL: Write zero table (YUV400): \n"); + for (i = 0; i < 162; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + /* Write AC Table 1 (as specified in HW regs) + * NOTE: Not the same as actable[1] (as specified in JPEG Spec) */ + if (JPG_VLC->acTable1.vals) { + JPEGD_INFO_LOG("INTERNAL: Write tables: AC1 (luma)\n"); + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* Write AC Table 2 */ + JPEGD_INFO_LOG("INTERNAL: writeTables: padding zero (YUV400)\n"); + for (i = 0; i < 162; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* this trick is done because hw always wants luma table as dc hw table 1 */ + if (JPG_SCN->Td[0] == 0) { + if (JPG_VLC->dcTable0.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + for (i = 0; i < 12; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + if (JPG_VLC->dcTable1.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + for (i = 0; i < 12; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + } else { + /* this trick is done because hw always wants luma table as ac hw table 1 */ + if (JPG_SCN->Ta[pSyntax->info.componentId] == 0) { + /* Write AC Table 1 (as specified in HW regs) + * NOTE: Not the same as actable[1] (as specified in JPEG Spec) */ + JPEGD_INFO_LOG("INTERNAL: Write tables: AC1 (luma)\n"); + if (JPG_VLC->acTable0.vals) { + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* Write AC Table 2 */ + JPEGD_INFO_LOG("INTERNAL: Write zero table (YUV400): \n"); + for (i = 0; i < 162; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + /* Write AC Table 1 (as specified in HW regs) + * NOTE: Not the same as actable[1] (as specified in JPEG Spec) */ + if (JPG_VLC->acTable1.vals) { + JPEGD_INFO_LOG("INTERNAL: Write tables: AC1 (luma)\n"); + for (i = 0; i < 162; i++) { + if (i < JPG_VLC->acTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->acTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 162; i++) { + tableWord = 0; + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* Write AC Table 2 */ + JPEGD_INFO_LOG("INTERNAL: writeTables: padding zero (YUV400)\n"); + for (i = 0; i < 162; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + /* this trick is done because hw always wants luma table as dc hw table 1 */ + if (JPG_SCN->Td[pSyntax->info.componentId] == 0) { + if (JPG_VLC->dcTable0.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable0.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable0.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + for (i = 0; i < 12; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + if (JPG_VLC->dcTable1.vals) { + for (i = 0; i < 12; i++) { + if (i < JPG_VLC->dcTable1.tableLength) { + tableValue = (RK_U8) JPG_VLC->dcTable1.vals[i]; + } else { + tableValue = 0; + } + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } else { + for (i = 0; i < 12; i++) { + tableWord = 0; + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + + for (i = 0; i < 12; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + } + } + + } + + for (i = 0; i < 4; i++) { + tableValue = 0; + + if (shifter == 32) + tableWord = (tableValue << (shifter - 8)); + else + tableWord |= (tableValue << (shifter - 8)); + + shifter -= 8; + + if (shifter == 0) { + *(pTableBase) = tableWord; + pTableBase++; + shifter = 32; + } + } + FUN_TEST("Exit"); +} + +MPP_RET jpegd_allocate_chroma_out_buffer(JpegSyntaxParam *pSyntax) +{ + FUN_TEST("Enter"); + if(NULL == pSyntax){ + JPEGD_ERROR_LOG("NULL pointer"); + return MPP_ERR_NULL_PTR; + } + + if (pSyntax->ppInstance == NULL || (pSyntax->ppInstance != NULL && !pSyntax->ppControl.usePipeline)){ + if (pSyntax->info.givenOutLuma.vir_addr == NULL) { + JPEGD_INFO_LOG("givenOutLuma is NULL"); + + /* luma bus address to output */ + pSyntax->info.outLuma = pSyntax->asicBuff.outLumaBuffer; + + if (pSyntax->image.sizeChroma) { + JPEGD_INFO_LOG("sizeChroma:%d", pSyntax->image.sizeChroma); + JPEGD_INFO_LOG("sizeLuma:%d, outLumaBuffer.phy_addr:%x", pSyntax->image.sizeLuma, pSyntax->asicBuff.outLumaBuffer.phy_addr); + + pSyntax->asicBuff.outChromaBuffer.phy_addr = pSyntax->asicBuff.outLumaBuffer.phy_addr + (pSyntax->image.sizeLuma << 10); + + if (pSyntax->info.operationType != JPEGDEC_BASELINE) { + pSyntax->asicBuff.outChromaBuffer2.phy_addr = pSyntax->asicBuff.outChromaBuffer.phy_addr + ((pSyntax->image.sizeChroma / 2) << 10); + } else { + pSyntax->asicBuff.outChromaBuffer2.phy_addr = 0; + } + + // chroma bus address to output + pSyntax->info.outChroma = pSyntax->asicBuff.outChromaBuffer; + pSyntax->info.outChroma2 = pSyntax->asicBuff.outChromaBuffer2; + } + } else { + JPEGD_INFO_LOG("givenOutLuma is not NULL"); + pSyntax->asicBuff.outLumaBuffer.vir_addr = pSyntax->info.givenOutLuma.vir_addr; + pSyntax->asicBuff.outLumaBuffer.phy_addr = pSyntax->info.givenOutLuma.phy_addr; + + pSyntax->asicBuff.outChromaBuffer.vir_addr = pSyntax->info.givenOutChroma.vir_addr; + pSyntax->asicBuff.outChromaBuffer.phy_addr = pSyntax->info.givenOutChroma.phy_addr; + pSyntax->asicBuff.outChromaBuffer2.vir_addr = pSyntax->info.givenOutChroma2.vir_addr; + pSyntax->asicBuff.outChromaBuffer2.phy_addr = pSyntax->info.givenOutChroma2.phy_addr; + + /* luma bus address to output */ + pSyntax->info.outLuma = pSyntax->asicBuff.outLumaBuffer; + + if (pSyntax->image.sizeChroma) { + // chroma bus address to output + pSyntax->info.outChroma = pSyntax->asicBuff.outChromaBuffer; + pSyntax->info.outChroma2 = pSyntax->asicBuff.outChromaBuffer2; + } + + /* flag to release */ + pSyntax->info.userAllocMem = 1; + } + + JPEGD_INFO_LOG("Luma virtual: %p, phy_addr: %x\n", pSyntax->asicBuff.outLumaBuffer.vir_addr, + pSyntax->asicBuff.outLumaBuffer.phy_addr); + JPEGD_INFO_LOG("Chroma virtual: %p, phy_addr: %x\n", pSyntax->asicBuff.outChromaBuffer.vir_addr, + pSyntax->asicBuff.outChromaBuffer.phy_addr); + } + FUN_TEST("Exit"); + return MPP_OK; +} + +MPP_RET jpegd_set_post_processor(JpegHalContext *pCtx, JpegSyntaxParam *pSyntax) +{ + FUN_TEST("Enter"); + if(NULL == pCtx || NULL == pSyntax){ + JPEGD_ERROR_LOG("NULL pointer"); + return MPP_ERR_NULL_PTR; + } + + PostProcessInfo *ppInfo = &(pSyntax->ppInfo); + JpegRegSet *reg = &(pCtx->regs); + int inColor = pSyntax->ppInputFomart; + int outColor = ppInfo->outFomart; + int dither = ppInfo->shouldDither; + int inWidth = pSyntax->imageInfo.outputWidth; + int inHeigth = pSyntax->imageInfo.outputHeight; + int outWidth = pSyntax->ppScaleW; + int outHeight = pSyntax->ppScaleH; + + reg->reg0.sw_pp_axi_rd_id = 0; + reg->reg0.sw_pp_axi_wr_id = 0; + reg->reg0.sw_pp_scmd_dis = 1; + reg->reg0.sw_pp_max_burst = 16; + + reg->reg18_pp_in_lu_base = 0; + + reg->reg34.sw_ext_orig_width = inWidth >> 4; + + reg->reg37.sw_pp_in_a2_endsel = 1; + reg->reg37.sw_pp_in_a1_swap32 = 1; + reg->reg37.sw_pp_in_a1_endian = 1; + reg->reg37.sw_pp_in_swap32_e = 1; + reg->reg37.sw_pp_in_endian = 1; + reg->reg37.sw_pp_out_endian = 1; + reg->reg37.sw_pp_out_swap32_e = 1; + + reg->reg41.sw_pp_clk_gate_e = 1; + reg->reg41.sw_pp_ahb_hlock_e = 1; + reg->reg41.sw_pp_data_disc_e = 1; + + if (ppInfo->cropW <= 0) { + reg->reg34.sw_pp_in_w_ext = (((inWidth / 16) & 0xE00) >> 9); + reg->reg34.sw_pp_in_width = ((inWidth / 16) & 0x1FF); + reg->reg34.sw_pp_in_h_ext = (((inHeigth / 16) & 0x700) >> 8); + reg->reg34.sw_pp_in_height = ((inHeigth / 16) & 0x0FF); + } else { + reg->reg34.sw_pp_in_w_ext = (((ppInfo->cropW / 16) & 0xE00) >> 9); + reg->reg34.sw_pp_in_width = ((ppInfo->cropW / 16) & 0x1FF); + reg->reg34.sw_pp_in_h_ext = (((ppInfo->cropH / 16) & 0x700) >> 8); + reg->reg34.sw_pp_in_height = ((ppInfo->cropH / 16) & 0x0FF); + + reg->reg14.sw_crop_startx_ext = (((ppInfo->cropX / 16) & 0xE00) >> 9); + reg->reg14.sw_crop_startx = ((ppInfo->cropX / 16) & 0x1FF); + reg->reg14.sw_crop_starty_ext = (((ppInfo->cropY / 16) & 0x700) >> 8); + reg->reg14.sw_crop_starty = ((ppInfo->cropY / 16) & 0x0FF); + + if (ppInfo->cropW & 0x0F) { + reg->reg14.sw_pp_crop8_r_e = 1; + } else { + reg->reg14.sw_pp_crop8_r_e = 0; + } + if (ppInfo->cropH & 0x0F) { + reg->reg14.sw_pp_crop8_d_e = 1; + } else { + reg->reg14.sw_pp_crop8_d_e = 0; + } + inWidth = ppInfo->cropW; + inHeigth = ppInfo->cropH; + } + + reg->reg39.sw_display_width = outWidth; + reg->reg35.sw_pp_out_width = outWidth; + reg->reg35.sw_pp_out_height = outHeight; + reg->reg21_pp_out_lu_base = pSyntax->asicBuff.outLumaBuffer.phy_addr; + + switch (inColor) { + case PP_IN_FORMAT_YUV422INTERLAVE: + reg->reg38.sw_pp_in_format = 0; + break; + case PP_IN_FORMAT_YUV420SEMI: + reg->reg38.sw_pp_in_format = 1; + break; + case PP_IN_FORMAT_YUV420PLANAR: + reg->reg38.sw_pp_in_format = 2; + break; + case PP_IN_FORMAT_YUV400: + reg->reg38.sw_pp_in_format = 3; + break; + case PP_IN_FORMAT_YUV422SEMI: + reg->reg38.sw_pp_in_format = 4; + break; + case PP_IN_FORMAT_YUV420SEMITIELED: + reg->reg38.sw_pp_in_format = 5; + break; + case PP_IN_FORMAT_YUV440SEMI: + reg->reg38.sw_pp_in_format = 6; + break; + case PP_IN_FORMAT_YUV444_SEMI: + reg->reg38.sw_pp_in_format = 7; + reg->reg38.sw_pp_in_format_es = 0; + break; + case PP_IN_FORMAT_YUV411_SEMI: + reg->reg38.sw_pp_in_format = 0; + reg->reg38.sw_pp_in_format_es = 1; + break; + default: + JPEGD_ERROR_LOG("unsupported format:%d", inColor); + return -1; + } + +#define VIDEORANGE 1 //0 or 1 + int videoRange = VIDEORANGE; + + reg->reg15.sw_rangemap_coef_y = 9; + reg->reg15.sw_rangemap_coef_c = 9; + /* brightness */ + reg->reg3.sw_pp_color_coefff = BRIGHTNESS; + + if (outColor <= PP_OUT_FORMAT_ARGB) { + /*Bt.601*/ + unsigned int a = 298; + unsigned int b = 409; + unsigned int c = 208; + unsigned int d = 100; + unsigned int e = 516; + + /*Bt.709 + unsigned int a = 298; + unsigned int b = 459; + unsigned int c = 137; + unsigned int d = 55; + unsigned int e = 544;*/ + + int satur = 0, tmp; + if (videoRange != 0) { + /*Bt.601*/ + a = 256; + b = 350; + c = 179; + d = 86; + e = 443; + /*Bt.709 + a = 256; + b = 403; + c = 120; + d = 48; + e = 475;*/ + + reg->reg15.sw_ycbcr_range = videoRange; + } + int contrast = CONTRAST; + if (contrast != 0) { + int thr1y, thr2y, off1, off2, thr1, thr2, a1, a2; + if (videoRange == 0) { + int tmp1, tmp2; + /* Contrast */ + thr1 = (219 * (contrast + 128)) / 512; + thr1y = (219 - 2 * thr1) / 2; + thr2 = 219 - thr1; + thr2y = 219 - thr1y; + + tmp1 = (thr1y * 256) / thr1; + tmp2 = ((thr2y - thr1y) * 256) / (thr2 - thr1); + off1 = ((thr1y - ((tmp2 * thr1) / 256)) * a) / 256; + off2 = ((thr2y - ((tmp1 * thr2) / 256)) * a) / 256; + + tmp1 = (64 * (contrast + 128)) / 128; + tmp2 = 256 * (128 - tmp1); + a1 = (tmp2 + off2) / thr1; + a2 = a1 + (256 * (off2 - 1)) / (thr2 - thr1); + } else { + /* Contrast */ + thr1 = (64 * (contrast + 128)) / 128; + thr1y = 128 - thr1; + thr2 = 256 - thr1; + thr2y = 256 - thr1y; + a1 = (thr1y * 256) / thr1; + a2 = ((thr2y - thr1y) * 256) / (thr2 - thr1); + off1 = thr1y - (a2 * thr1) / 256; + off2 = thr2y - (a1 * thr2) / 256; + } + + if (a1 > 1023) + a1 = 1023; + else if (a1 < 0) + a1 = 0; + + if (a2 > 1023) + a2 = 1023; + else if (a2 < 0) + a2 = 0; + + if (thr1 > 255) + thr1 = 255; + else if (thr1 < 0) + thr1 = 0; + + if (thr2 > 255) + thr2 = 255; + else if (thr2 < 0) + thr2 = 0; + + if (off1 > 511) + off1 = 511; + else if (off1 < -512) + off1 = -512; + + if (off2 > 511) + off2 = 511; + else if (off2 < -512) + off2 = -512; + + reg->reg31.sw_contrast_thr1 = thr1; + reg->reg31.sw_contrast_thr2 = thr2; + reg->reg32.sw_contrast_off1 = off1; + reg->reg32.sw_contrast_off2 = off2; + + reg->reg1.sw_color_coeffa1 = a1; + reg->reg1.sw_color_coeffa2 = a2; + } else { + reg->reg31.sw_contrast_thr1 = 55; + reg->reg31.sw_contrast_thr2 = 165; + reg->reg32.sw_contrast_off1 = 0; + reg->reg32.sw_contrast_off2 = 0; + + tmp = a; + if (tmp > 1023) + tmp = 1023; + else if (tmp < 0) + tmp = 0; + + reg->reg1.sw_color_coeffa1 = tmp; + reg->reg1.sw_color_coeffa2 = tmp; + } + + reg->reg37.sw_pp_out_endian = 0; + + /* saturation */ + satur = 64 + SATURATION; + + tmp = (satur * (int) b) / 64; + if (tmp > 1023) + tmp = 1023; + else if (tmp < 0) + tmp = 0; + reg->reg1.sw_color_coeffb = (unsigned int) tmp; + + tmp = (satur * (int) c) / 64; + if (tmp > 1023) + tmp = 1023; + else if (tmp < 0) + tmp = 0; + reg->reg2.sw_color_coeffc = (unsigned int) tmp; + + tmp = (satur * (int) d) / 64; + if (tmp > 1023) + tmp = 1023; + else if (tmp < 0) + tmp = 0; + reg->reg2.sw_color_coeffd = (unsigned int) tmp; + + tmp = (satur * (int) e) / 64; + if (tmp > 1023) + tmp = 1023; + else if (tmp < 0) + tmp = 0; + reg->reg2.sw_color_coeffe = (unsigned int) tmp; + } + + switch (outColor) { + case PP_OUT_FORMAT_RGB565: + reg->reg9_r_mask = 0xF800F800; + reg->reg10_g_mask = 0x07E007E0; + reg->reg11_b_mask = 0x001F001F; + reg->reg16.sw_rgb_r_padd = 0; + reg->reg16.sw_rgb_g_padd = 5; + reg->reg16.sw_rgb_b_padd = 11; + if (dither) { //always do dither + JPEGD_VERBOSE_LOG("we do dither."); + reg->reg36.sw_dither_select_r = 2; + reg->reg36.sw_dither_select_g = 3; + reg->reg36.sw_dither_select_b = 2; + } else { + JPEGD_VERBOSE_LOG("we do not dither."); + } + reg->reg37.sw_rgb_pix_in32 = 1; + reg->reg37.sw_pp_out_swap16_e = 1; + reg->reg38.sw_pp_out_format = 0; + break; + case PP_OUT_FORMAT_ARGB: + reg->reg9_r_mask = 0x000000FF | (0xff << 24); + reg->reg10_g_mask = 0x0000FF00 | (0xff << 24); + reg->reg11_b_mask = 0x00FF0000 | (0xff << 24); + + reg->reg16.sw_rgb_r_padd = 24; + reg->reg16.sw_rgb_g_padd = 16; + reg->reg16.sw_rgb_b_padd = 8; + + reg->reg37.sw_rgb_pix_in32 = 0; + reg->reg38.sw_pp_out_format = 0; + break; + case PP_OUT_FORMAT_YUV422INTERLAVE: + reg->reg38.sw_pp_out_format = 3; + break; + case PP_OUT_FORMAT_YUV420INTERLAVE: { + RK_U32 phy_addr = pSyntax->asicBuff.outLumaBuffer.phy_addr; + if(VPUClientGetIOMMUStatus() <= 0) { + reg->reg22_pp_out_ch_base = (phy_addr + outWidth * outHeight); + } else { + if (outWidth * outHeight > 0x400000) { + JPEGD_ERROR_LOG("out offset big than 22bit iommu map may be error"); + } else { + reg->reg22_pp_out_ch_base = (phy_addr | ((outWidth * outHeight) << 10)); + } + } + reg->reg38.sw_pp_out_format = 5; + JPEGD_INFO_LOG("outWidth:%d, outHeight:%d", outWidth, outHeight); + JPEGD_INFO_LOG("outLumaBuffer:%x, reg22:%x", phy_addr, reg->reg22_pp_out_ch_base); + } + break; + default: + JPEGD_ERROR_LOG("unsuppotred format:%d", outColor); + return -1; + } + + reg->reg38.sw_rotation_mode = 0; + + unsigned int inw, inh; + unsigned int outw, outh; + + inw = inWidth - 1; + inh = inHeigth - 1; + outw = outWidth - 1; + outh = outHeight - 1; + + if (inw < outw) { + reg->reg4.sw_hor_scale_mode = 1; + reg->reg4.sw_scale_wratio = (outw << 16) / inw; + reg->reg6.sw_wscale_invra = (inw << 16) / outw; + } else if (inw > outw) { + reg->reg4.sw_hor_scale_mode = 2; + reg->reg6.sw_wscale_invra = ((outw + 1) << 16) / (inw + 1); + } else + reg->reg4.sw_hor_scale_mode = 0; + + if (inh < outh) { + reg->reg4.sw_ver_scale_mode = 1; + reg->reg5.sw_scale_hratio = (outh << 16) / inh; + reg->reg6.sw_hscale_invra = (inh << 16) / outh; + } else if (inh > outh) { + reg->reg4.sw_ver_scale_mode = 2; + reg->reg6.sw_hscale_invra = ((outh + 1) << 16) / (inh + 1) + 1; + } else + reg->reg4.sw_ver_scale_mode = 0; + + reg->reg41.sw_pp_pipeline_e = ppInfo->enable; + FUN_TEST("Exit"); + return 0; +} + +JpegDecRet jpegd_configure_regs(JpegSyntaxParam *pSyntax, JpegHalContext *pCtx) +{ + FUN_TEST("Enter"); + JpegRegSet *reg = &(pCtx->regs); + + reg->reg50_dec_ctrl.sw_filtering_dis = 1; + + reg->reg53_dec_mode = JPEG_RK70_MODE_JPEG; + + reg->reg57_enable_ctrl.sw_dec_out_dis = 0; + reg->reg57_enable_ctrl.sw_rlc_mode_e = pSyntax->info.rlcMode; + + /* frame size, round up the number of mbs */ + reg->reg120.sw_pic_mb_h_ext = ((((pSyntax->info.Y) >> (4)) & 0x700) >> 8); + reg->reg120.sw_pic_mb_w_ext = ((((pSyntax->info.X) >> (4)) & 0xE00) >> 9); + reg->reg120.sw_pic_mb_width = ((pSyntax->info.X) >> (4)) & 0x1FF; + reg->reg120.sw_pic_mb_hight_p = ((pSyntax->info.Y) >> (4)) & 0x0FF; + + reg->reg121.sw_pjpeg_fildown_e = pSyntax->info.fillBottom; + reg->reg121.sw_pjpeg_ss = pSyntax->scan.Ss; /* Set spectral selection start coefficient */ + reg->reg121.sw_pjpeg_se = pSyntax->scan.Se; /* Set spectral selection end coefficient */ + reg->reg121.sw_pjpeg_ah = pSyntax->scan.Ah; /* Set the point transform used in the preceding scan */ + reg->reg121.sw_pjpeg_al = pSyntax->scan.Al; /* Set the point transform value */ + + reg->reg122.sw_jpeg_qtables = pSyntax->info.amountOfQTables; + reg->reg122.sw_jpeg_mode = pSyntax->info.yCbCrMode; + reg->reg122.sw_jpeg_filright_e = pSyntax->info.fillRight; + + reg->reg148.sw_slice_h = pSyntax->info.sliceHeight; + + /* Set JPEG operation mode */ + if (pSyntax->info.operationType != JPEGDEC_PROGRESSIVE) { + reg->reg57_enable_ctrl.sw_pjpeg_e = 0; + } else { + reg->reg57_enable_ctrl.sw_pjpeg_e = 1; + } + + /* Set needed progressive parameters */ + if (pSyntax->info.operationType == JPEGDEC_PROGRESSIVE) { // TODO: unsupported so far + JPEGD_INFO_LOG("JPEGDEC_PROGRESSIVE"); + } + + if (pSyntax->info.operationType == JPEGDEC_BASELINE) { + /* write "length amounts" */ + JPEGD_VERBOSE_LOG("Write VLC length amounts to register\n"); + jpegd_write_len_bits(pSyntax, pCtx); + + /* Create AC/DC/QP tables for HW */ + JPEGD_VERBOSE_LOG("Write AC,DC,QP tables to base\n"); + jpegd_write_tables(pSyntax, pCtx); + } else if (pSyntax->info.operationType == JPEGDEC_NONINTERLEAVED) { + JPEGD_INFO_LOG("JPEGDEC_NONINTERLEAVED"); + } else { + JPEGD_INFO_LOG("other operation type"); + } + + /* Select which tables the chromas use */ + jpegd_select_chroma_table(pSyntax, pCtx); + + /* write table base */ + reg->reg61_qtable_base = mpp_buffer_get_fd(pCtx->pTableBase); + + /* set up stream position for HW decode */ + jpegd_set_stream_params(pSyntax, pCtx); + + /* set restart interval */ + if (pSyntax->frame.Ri) { + reg->reg122.sw_sync_marker_e = 1; + reg->reg123.sw_pjpeg_rest_freq = pSyntax->frame.Ri; + } else{ + reg->reg122.sw_sync_marker_e = 0; + } + + /* PP depending register writes */ + if (pSyntax->ppInstance != NULL && pSyntax->ppControl.usePipeline) { + JPEGD_INFO_LOG("ppInstance is not NULL!"); + reg->reg57_enable_ctrl.sw_dec_out_dis = 1; + + /* set output to zero, because of pp */ + /* Luminance output */ + reg->reg63_dec_out_base = 0; + + /* Chrominance output */ + if (pSyntax->image.sizeChroma) { + reg->reg131_jpg_ch_out_base = 0; + } + + if (pSyntax->info.sliceStartCount == JPEGDEC_SLICE_START_VALUE) { + /* Enable pp */ + } + + pSyntax->info.pipeline = 1; + } else { + JPEGD_INFO_LOG("ppInstance is NULL!"); + + if (pSyntax->info.operationType == JPEGDEC_BASELINE) { + /* Luminance output */ + JPEGD_INFO_LOG("INTERNAL: Set LUMA OUTPUT data base address\n"); + JPEGD_INFO_LOG("Luma virtual: %p, phy_addr: %x\n", pSyntax->asicBuff.outLumaBuffer.vir_addr, + pSyntax->asicBuff.outLumaBuffer.phy_addr); + reg->reg63_dec_out_base = pSyntax->asicBuff.outLumaBuffer.phy_addr; + + /* Chrominance output */ + if (pSyntax->image.sizeChroma) { + JPEGD_INFO_LOG("INTERNAL: Set CHROMA OUTPUT data base address\n"); + JPEGD_INFO_LOG("Chroma virtual: %p, phy_addr: %x\n", pSyntax->asicBuff.outChromaBuffer.vir_addr, + pSyntax->asicBuff.outChromaBuffer.phy_addr); + reg->reg131_jpg_ch_out_base = pSyntax->asicBuff.outChromaBuffer.phy_addr; + } + } else { + JPEGD_INFO_LOG("NON_JPEGDEC_BASELINE"); + } + + pSyntax->info.pipeline = 0; + } + + pSyntax->info.sliceStartCount = 1; + //pSyntax->asicRunning = 1; + + /* Enable jpeg mode and set slice mode */ + JPEGD_VERBOSE_LOG("Enable jpeg\n"); + reg->reg57_enable_ctrl.sw_dec_e = 1; + + FUN_TEST("Exit"); + return MPP_OK; +} + +static MPP_RET jpegd_regs_init(JpegRegSet *reg) +{ + FUN_TEST("Enter"); + reg->reg50_dec_ctrl.sw_dec_out_tiled_e = 0; + reg->reg50_dec_ctrl.sw_dec_scmd_dis = DEC_RK70_SCMD_DISABLE; + reg->reg50_dec_ctrl.sw_dec_latency = DEC_RK70_LATENCY_COMPENSATION; + + reg->reg54_endian.sw_dec_in_endian = DEC_RK70_BIG_ENDIAN; + reg->reg54_endian.sw_dec_out_endian = DEC_RK70_LITTLE_ENDIAN; + reg->reg54_endian.sw_dec_strendian_e = DEC_RK70_LITTLE_ENDIAN; + reg->reg54_endian.sw_dec_outswap32_e = DEC_RK70_LITTLE_ENDIAN; + reg->reg54_endian.sw_dec_inswap32_e = 1; + reg->reg54_endian.sw_dec_strswap32_e = 1; + + reg->reg55_Interrupt.sw_dec_irq_dis = 0; + + reg->reg56_axi_ctrl.sw_dec_axi_rn_id = 0xff; + reg->reg56_axi_ctrl.sw_dec_axi_wr_id = 0; + reg->reg56_axi_ctrl.sw_dec_max_burst = DEC_RK70_BUS_BURST_LENGTH_16; + reg->reg56_axi_ctrl.sw_dec_data_disc_e = DEC_RK70_DATA_DISCARD_ENABLE; + + reg->reg57_enable_ctrl.sw_dec_timeout_e = 1; + reg->reg57_enable_ctrl.sw_dec_clk_gate_e = 1; + + FUN_TEST("Exit"); + return MPP_OK; +} + +MPP_RET jpegd_gen_regs(JpegHalContext *ctx, JpegSyntaxParam *syntax) +{ + FUN_TEST("Enter"); + if(NULL == ctx || NULL == syntax){ + JPEGD_ERROR_LOG("NULL pointer"); + return MPP_ERR_NULL_PTR; + } + JpegDecRet retCode; + JpegHalContext *pCtx = ctx; + JpegSyntaxParam *pSyntax = syntax; + + retCode = JPEGDEC_OK; + if (pSyntax->image.headerReady) { + JPEGD_INFO_LOG("image header is ready"); + do { /* loop until decoding control should return for user */ + if (pSyntax->ppInstance != NULL) { /* if pp enabled ==> set pp control */ + pSyntax->ppControl.usePipeline = 1; + } + + /* check if we had to load input buffer or not */ + if (!pSyntax->info.inputBufferEmpty) { + /* if slice mode ==> set slice height */ + if (pSyntax->info.sliceMbSetValue && pSyntax->ppControl.usePipeline == 0) { + jpegd_calculate_slice_size(pSyntax); + JPEGD_INFO_LOG("sliceHeight is %d, sliceMbSetValue is %d",pSyntax->info.sliceHeight,pSyntax->info.sliceMbSetValue); + } + + /* Start HW or continue after pause */ + if (!pSyntax->info.SliceReadyForPause) { + if (!pSyntax->info.progressiveScanReady || pSyntax->info.nonInterleavedScanReady) { + JPEGD_INFO_LOG("Start to configure registers\n"); + retCode = jpegd_configure_regs(pSyntax, pCtx); + + pSyntax->info.nonInterleavedScanReady = 0; + if (retCode != JPEGDEC_OK) { + return retCode; + } + } else { + JPEGD_INFO_LOG("Continue HW decoding after progressive scan ready"); + // TODO: configure registers for progressive continue image + pSyntax->info.progressiveScanReady = 0; + } + } else { + JPEGD_INFO_LOG("Continue HW decoding after slice ready"); + // TODO: configure registers for continue image + } + + pSyntax->info.SliceCount++; + } else { + JPEGD_INFO_LOG("Continue HW decoding after input buffer has been loaded"); + jpegd_input_buff_load_init(pSyntax); + + /* buffer loaded ==> reset flag */ + pSyntax->info.inputBufferEmpty = 0; + } + } while (0 /*!pSyntax->image.imageReady*/); // TODO: when to end this loop?? + } + + FUN_TEST("Exit"); + return MPP_OK; +} + +MPP_RET hal_jpegd_init(void *hal, MppHalCfg *cfg) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + JpegHalContext *JpegHalCtx = (JpegHalContext *)hal; + if (NULL == JpegHalCtx) { + JpegHalCtx = (JpegHalContext *)mpp_calloc(JpegHalContext, 1); + if(NULL == JpegHalCtx){ + JPEGD_ERROR_LOG("NULL pointer"); + return MPP_ERR_NULL_PTR; + } + } + + //configure + JpegHalCtx->packet_slots = cfg->packet_slots; + JpegHalCtx->frame_slots = cfg->frame_slots; + + //get vpu socket +#ifdef RKPLATFORM + if(JpegHalCtx->vpu_socket <= 0) { + JpegHalCtx->vpu_socket = VPUClientInit(VPU_DEC_PP/*VPU_DEC*/); + if (JpegHalCtx->vpu_socket <= 0) { + JPEGD_ERROR_LOG("get vpu_socket(%d) <= 0, failed. \n", JpegHalCtx->vpu_socket); + return MPP_ERR_UNKNOW; + } else { + JPEGD_VERBOSE_LOG("get vpu_socket(%d), success. \n", JpegHalCtx->vpu_socket); + } + } +#endif + + //init regs + JpegRegSet *reg = &(JpegHalCtx->regs); + memset(reg, 0, sizeof(JpegRegSet)); + jpegd_regs_init(reg); + + //malloc hw buf + if (JpegHalCtx->group == NULL) { +#ifdef RKPLATFORM + JPEGD_VERBOSE_LOG("mpp_buffer_group_get_internal used ion in"); + ret = mpp_buffer_group_get_internal(&JpegHalCtx->group, MPP_BUFFER_TYPE_ION); +#else + ret = mpp_buffer_group_get_internal(&JpegHalCtx->group, MPP_BUFFER_TYPE_NORMAL); +#endif + if (MPP_OK != ret) { + JPEGD_ERROR_LOG("mpp_buffer_group_get failed\n"); + return ret; + } + } + + ret = mpp_buffer_get(JpegHalCtx->group, &JpegHalCtx->frame_buf, JPEGD_STREAM_BUFF_SIZE); + if (MPP_OK != ret) { + JPEGD_ERROR_LOG("get buffer failed\n"); + return ret; + } + + ret = mpp_buffer_get(JpegHalCtx->group, &JpegHalCtx->pTableBase, JPEGDEC_BASELINE_TABLE_SIZE); + if (MPP_OK != ret) { + JPEGD_ERROR_LOG("get buffer failed\n"); + return ret; + } + + //init dbg stuff + JpegHalCtx->hal_debug_enable = 1; + JpegHalCtx->frame_count = 0; + JpegHalCtx->output_yuv_count = 0; + + FUN_TEST("Exit"); + return MPP_OK; +} + +MPP_RET hal_jpegd_deinit(void *hal) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + JpegHalContext *JpegHalCtx = (JpegHalContext *)hal; + +#ifdef RKPLATFORM + if (JpegHalCtx->vpu_socket >= 0) { + VPUClientRelease(JpegHalCtx->vpu_socket); + } +#endif + + if (JpegHalCtx->frame_buf) { + ret = mpp_buffer_put(JpegHalCtx->frame_buf); + if (MPP_OK != ret) { + JPEGD_ERROR_LOG("put buffer failed\n"); + return ret; + } + } + + if (JpegHalCtx->pTableBase) { + ret = mpp_buffer_put(JpegHalCtx->pTableBase); + if (MPP_OK != ret) { + JPEGD_ERROR_LOG("put buffer failed\n"); + return ret; + } + } + + if (JpegHalCtx->group) { + ret = mpp_buffer_group_put(JpegHalCtx->group); + if (MPP_OK != ret) { + JPEGD_ERROR_LOG("group free buffer failed\n"); + return ret; + } + } + + JpegHalCtx->hal_debug_enable = 0; + JpegHalCtx->frame_count = 0; + JpegHalCtx->output_yuv_count = 0; + + return MPP_OK; + FUN_TEST("Exit"); +} + +MPP_RET hal_jpegd_gen_regs(void *hal, HalTaskInfo *syn) +{ + FUN_TEST("Enter"); + if(NULL == hal || NULL == syn){ + JPEGD_ERROR_LOG("NULL pointer"); + return MPP_ERR_NULL_PTR; + } + + MPP_RET ret = MPP_OK; + JpegHalContext *JpegHalCtx = (JpegHalContext *)hal; + JpegSyntaxParam *pSyntax = (JpegSyntaxParam *)syn->dec.syntax.data; +#ifdef RKPLATFORM + MppBuffer streambuf = NULL; + MppBuffer outputBuf = NULL; +#endif + + if(syn->dec.valid){ + syn->dec.valid = 0; + +#ifdef RKPLATFORM + mpp_buf_slot_get_prop(JpegHalCtx->packet_slots, syn->dec.input, SLOT_BUFFER, &streambuf); + pSyntax->stream.streamBus = mpp_buffer_get_fd(streambuf); + + mpp_buf_slot_get_prop(JpegHalCtx->frame_slots, syn->dec.output, SLOT_BUFFER, &outputBuf); + pSyntax->asicBuff.outLumaBuffer.phy_addr = mpp_buffer_get_fd(outputBuf); + + jpegd_allocate_chroma_out_buffer(pSyntax); +#endif + + ret = jpegd_set_post_processor(JpegHalCtx, pSyntax); + + ret = jpegd_gen_regs(JpegHalCtx, pSyntax); + + if(JpegHalCtx->hal_debug_enable && JpegHalCtx->frame_count < 3){ + RK_U32 idx = 0; + RK_U32 *pRegs = (RK_U32 *) &(JpegHalCtx->regs); + JPEGD_INFO_LOG("sizeof(JpegRegSet)=%d, sizeof(pRegs[0])=%d", sizeof(JpegRegSet), sizeof(pRegs[0])); + + JpegHalCtx->frame_count++; + for(idx = 0; idx < sizeof(JpegRegSet)/sizeof(pRegs[0]); idx++){ + JPEGD_INFO_LOG("frame_%d_reg[%d]=0x%08x", JpegHalCtx->frame_count, idx, pRegs[idx]); + } + } + + syn->dec.valid = 1; + } + + return ret; + FUN_TEST("Exit"); +} + +MPP_RET hal_jpegd_start(void *hal, HalTaskInfo *task) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + JpegHalContext *JpegHalCtx = (JpegHalContext *)hal; + +#ifdef RKPLATFORM + RK_U32 *p_regs = (RK_U32 *)&JpegHalCtx->regs; + ret = VPUClientSendReg(JpegHalCtx->vpu_socket, p_regs, JPEGD_REG_NUM); + if (ret != 0) { + JPEGD_ERROR_LOG("VPUClientSendReg Failed!!!\n"); + return MPP_ERR_VPUHW; + } +#endif + (void)JpegHalCtx; + (void)task; + FUN_TEST("Exit"); + return ret; +} + +MPP_RET hal_jpegd_wait(void *hal, HalTaskInfo *task) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + JpegHalContext *JpegHalCtx = (JpegHalContext *)hal; + (void)JpegHalCtx; + (void)task; + +#ifdef RKPLATFORM + JpegRegSet reg_out; + VPU_CMD_TYPE cmd = 0; + RK_S32 length = 0; + memset(®_out, 0, sizeof(JpegRegSet)); + + ret = VPUClientWaitResult(JpegHalCtx->vpu_socket, (RK_U32 *)®_out, JPEGD_REG_NUM, &cmd, &length); + if(reg_out.reg55_Interrupt.sw_dec_bus_int){ + JPEGD_ERROR_LOG("IRQ BUS ERROR!"); + }else if(reg_out.reg55_Interrupt.sw_dec_error_int){ + JPEGD_ERROR_LOG("IRQ STREAM ERROR!"); + }else if(reg_out.reg55_Interrupt.sw_dec_timeout){ + JPEGD_ERROR_LOG("IRQ TIMEOUT!"); + }else if(reg_out.reg55_Interrupt.sw_dec_buffer_int){ + JPEGD_ERROR_LOG("IRQ BUFFER EMPTY!"); + }else if(reg_out.reg55_Interrupt.sw_dec_irq){ + JPEGD_INFO_LOG("DECODE SUCCESS!"); + } + + /* debug information */ + if(JpegHalCtx->hal_debug_enable && JpegHalCtx->output_yuv_count < 3) + { + static FILE *jpg_file; + static char name[32]; + MppBuffer outputBuf = NULL; + void *pOutYUV = NULL; + mpp_buf_slot_get_prop(JpegHalCtx->frame_slots, task->dec.output, SLOT_BUFFER, &outputBuf); + pOutYUV = mpp_buffer_get_ptr(outputBuf); + + snprintf(name, sizeof(name), "/data/output%02d.yuv", JpegHalCtx->output_yuv_count); + jpg_file = fopen(name, "wb+"); + if (jpg_file) { + JpegSyntaxParam *pTmpSyn = (JpegSyntaxParam *)task->dec.syntax.data; + RK_U32 width = pTmpSyn->frame.hwX; + RK_U32 height = pTmpSyn->frame.hwY; + + JPEGD_INFO_LOG("output YUV(%d*%d) saving to %s\n", width, height, name); + JPEGD_INFO_LOG("pOutYUV:%p", pOutYUV); + fwrite(pOutYUV, width*height*3/2, 1, jpg_file); + fclose(jpg_file); + JpegHalCtx->output_yuv_count++; + } + } +#endif + + FUN_TEST("Exit"); + return ret; +} + +MPP_RET hal_jpegd_reset(void *hal) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + JpegHalContext *JpegHalCtx = (JpegHalContext *)hal; + (void)JpegHalCtx; + + return ret; +} + +MPP_RET hal_jpegd_flush(void *hal) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + + (void)hal; + return ret; +} + +MPP_RET hal_jpegd_control(void *hal, RK_S32 cmd_type, void *param) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + + (void)hal; + (void)cmd_type; + (void)param; + return ret; +} + +const MppHalApi hal_api_jpegd = { + "jpegd_rkdec", + MPP_CTX_DEC, + MPP_VIDEO_CodingMJPEG, + sizeof(JpegHalContext), + 0, + hal_jpegd_init, + hal_jpegd_deinit, + hal_jpegd_gen_regs, + hal_jpegd_start, + hal_jpegd_wait, + hal_jpegd_reset, + hal_jpegd_flush, + hal_jpegd_control, +}; + + diff --git a/mpp/hal/vpu/jpegd/hal_jpegd_reg.h b/mpp/hal/vpu/jpegd/hal_jpegd_reg.h new file mode 100644 index 00000000..9ff9e700 --- /dev/null +++ b/mpp/hal/vpu/jpegd/hal_jpegd_reg.h @@ -0,0 +1,723 @@ +/* + * + * 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. + */ + + +#ifndef __HAL_JPEGD_REG_H__ +#define __HAL_JPEGD_REG_H__ +#include "rk_type.h" +#include "mpp_log.h" +#include "mpp_buf_slot.h" + +#include "jpegd_syntax.h" + +#define JPEGD_REG_NUM 159 +#define JPEG_RK70_MODE_JPEG (3) + +#define DEC_RK70_LITTLE_ENDIAN 1 +#define DEC_RK70_BIG_ENDIAN 0 + +#define DEC_RK70_BUS_BURST_LENGTH_UNDEFINED 0 +#define DEC_RK70_BUS_BURST_LENGTH_4 4 +#define DEC_RK70_BUS_BURST_LENGTH_8 8 +#define DEC_RK70_BUS_BURST_LENGTH_16 16 + +#define DEC_RK70_ASIC_SERVICE_PRIORITY_DEFAULT 0 +#define DEC_RK70_ASIC_SERVICE_PRIORITY_WR_1 1 +#define DEC_RK70_ASIC_SERVICE_PRIORITY_WR_2 2 +#define DEC_RK70_ASIC_SERVICE_PRIORITY_RD_1 3 +#define DEC_RK70_ASIC_SERVICE_PRIORITY_RD_2 4 + +#define DEC_RK70_OUTPUT_FORMAT_RASTER_SCAN 0 +#define DEC_RK70_OUTPUT_FORMAT_TILED 1 + +#define DEC_RK70_SCMD_DISABLE (0) +#define DEC_RK70_LATENCY_COMPENSATION 0 +#define DEC_RK70_DATA_DISCARD_ENABLE 0 + +#define JPEGDEC_SLICE_START_VALUE 0 + +//modify following values in special product +#define BRIGHTNESS 4 // -128 ~ 127 +#define CONTRAST 0 // -64 ~ 64 +#define SATURATION 0 // -64 ~ 128 +#define PP_IN_FORMAT_YUV422INTERLAVE 0 +#define PP_IN_FORMAT_YUV420SEMI 1 +#define PP_IN_FORMAT_YUV420PLANAR 2 +#define PP_IN_FORMAT_YUV400 3 +#define PP_IN_FORMAT_YUV422SEMI 4 +#define PP_IN_FORMAT_YUV420SEMITIELED 5 +#define PP_IN_FORMAT_YUV440SEMI 6 +#define PP_IN_FORMAT_YUV444_SEMI 7 +#define PP_IN_FORMAT_YUV411_SEMI 8 + +#define PP_OUT_FORMAT_RGB565 0 +#define PP_OUT_FORMAT_ARGB 1 +#define PP_OUT_FORMAT_YUV422INTERLAVE 3 +#define PP_OUT_FORMAT_YUV420INTERLAVE 5 + + +typedef struct JpegRegSet{ + struct { + RK_U32 sw_pp_max_burst : 5; + RK_U32 sw_pp_scmd_dis : 1; + RK_U32 sw_reserved_1 : 2; + RK_U32 sw_pp_axi_rd_id : 8; + RK_U32 sw_pp_axi_wr_id : 8; + } reg0; + + struct { + RK_U32 sw_color_coeffa1 : 10; + RK_U32 sw_color_coeffa2 : 10; + RK_U32 sw_color_coeffb : 10; + } reg1; + + struct { + RK_U32 sw_color_coeffc : 10; + RK_U32 sw_color_coeffd : 10; + RK_U32 sw_color_coeffe : 10; + } reg2; + + struct { + RK_U32 sw_pp_color_coefff : 8; + } reg3; + + struct { + RK_U32 sw_scale_wratio : 18; + RK_U32 sw_hor_scale_mode : 2; + RK_U32 sw_ver_scale_mode : 2; + } reg4; + + struct { + RK_U32 sw_scale_hratio : 18; + } reg5; + + struct { + RK_U32 sw_wscale_invra : 16; + RK_U32 sw_hscale_invra : 16; + } reg6; + + RK_U32 reg7; + RK_U32 reg8; + RK_U32 reg9_r_mask; + RK_U32 reg10_g_mask; + RK_U32 reg11_b_mask; + RK_U32 reg12_pp_bot_yin_base; + RK_U32 reg13_pp_bot_cin_base; + + struct { + RK_U32 sw_crop_startx : 9; + RK_U32 sw_crop_starty_ext : 3; + RK_U32 sw_reserved_1 : 4; + RK_U32 sw_crop_starty : 8; + RK_U32 sw_crop_startx_ext : 3; + RK_U32 sw_reserved_2 : 1; + RK_U32 sw_pp_crop8_d_e : 1; + RK_U32 sw_pp_crop8_r_e : 1; + } reg14; + + struct { + RK_U32 sw_rangemap_coef_y : 5; + RK_U32 sw_ycbcr_range : 1; + RK_U32 sw_reserved_1 : 2; + RK_U32 sw_rangemap_coef_c : 5; + } reg15; + + struct { + RK_U32 sw_rgb_r_padd : 5; + RK_U32 sw_reserved_1 : 3; + RK_U32 sw_rgb_g_padd : 5; + RK_U32 sw_reserved_2 : 3; + RK_U32 sw_rgb_b_padd : 5; + } reg16; + + RK_U32 reg17; + RK_U32 reg18_pp_in_lu_base; + RK_U32 reg19; + RK_U32 reg20; + RK_U32 reg21_pp_out_lu_base; + RK_U32 reg22_pp_out_ch_base; + RK_U32 reg23; + RK_U32 reg24; + RK_U32 reg25; + RK_U32 reg26; + RK_U32 reg27; + RK_U32 reg28; + RK_U32 reg29; + RK_U32 reg30; + + struct { + RK_U32 sw_contrast_thr1 : 8; + RK_U32 sw_contrast_thr2 : 8; + } reg31; + + struct { + RK_U32 sw_contrast_off1 : 10; + RK_U32 sw_reserved_1 : 6; + RK_U32 sw_contrast_off2 : 10; + } reg32; + + RK_U32 reg33; + + struct { + RK_U32 sw_pp_in_width : 9; + RK_U32 sw_pp_in_w_ext : 3; + RK_U32 sw_ext_orig_width : 9; + RK_U32 sw_pp_in_height : 8; + RK_U32 sw_pp_in_h_ext : 3; + } reg34; + + struct { + RK_U32 sw_pp_out_width : 11; + RK_U32 sw_reserved_1 : 5; + RK_U32 sw_pp_out_height : 11; + } reg35; + + struct { + RK_U32 sw_dither_select_r : 2; + RK_U32 sw_dither_select_g : 2; + RK_U32 sw_dither_select_b : 2; + } reg36; + + struct { + RK_U32 sw_pp_in_endian : 1; + RK_U32 sw_pp_in_a1_endian : 1; + RK_U32 sw_pp_in_a2_endsel : 1; + RK_U32 sw_pp_out_endian : 1; + RK_U32 sw_rgb_pix_in32 : 1; + RK_U32 sw_reserved_1 : 3; + RK_U32 sw_pp_in_swap32_e : 1; + RK_U32 sw_pp_in_a1_swap32 : 1; + RK_U32 sw_pp_out_swap16_e : 1; + RK_U32 sw_pp_out_swap32_e : 1; + RK_U32 sw_reserved_2 : 4; + RK_U32 sw_pp_in_start_ch : 1; + RK_U32 sw_pp_out_start_ch : 1; + RK_U32 sw_pp_in_cr_first : 1; + RK_U32 sw_pp_out_cr_first : 1; + RK_U32 sw_reserved_3 : 4; + RK_U32 sw_pp_in_struct : 3; + } reg37; + + struct { + RK_U32 sw_rotation_mode : 3; + RK_U32 sw_reserved_1 : 5; + RK_U32 sw_pp_in_format : 3; + RK_U32 sw_pp_out_format : 3; + RK_U32 sw_reserved_2 : 2; + RK_U32 sw_pp_in_format_es : 3; + } reg38; + + struct { + RK_U32 sw_display_width : 12; + } reg39; + + RK_U32 reg40; + + struct { + RK_U32 sw_pp_e : 1; + RK_U32 sw_deint_blend_e : 1; + RK_U32 sw_deint_e : 1; + RK_U32 sw_pp_clk_gate_e : 1; + RK_U32 sw_pp_pipeline_e : 1; + RK_U32 sw_reserved_1 : 3; + RK_U32 sw_rangemap_y_e : 1; + RK_U32 sw_rangemap_c_e : 1; + RK_U32 sw_reserved_2 : 6; + RK_U32 sw_pp_data_disc_e : 1; + RK_U32 sw_reserved_3 : 3; + RK_U32 sw_mask1_e : 1; + RK_U32 sw_mask2_e : 1; + RK_U32 sw_mask1_ablend_e : 1; + RK_U32 sw_mask2_ablend_e : 1; + RK_U32 sw_up_cross_e : 1; + RK_U32 sw_down_cross_e : 1; + RK_U32 sw_left_cross_e : 1; + RK_U32 sw_right_cross_e : 1; + RK_U32 sw_pp_ahb_hlock_e : 1; + } reg41; + + RK_U32 ppReg2[8]; + struct { + RK_U32 sw_dec_out_tiled_e : 1; + RK_U32 sw_dec_latency : 6; + RK_U32 sw_pic_fixed_quant : 1; + RK_U32 sw_filtering_dis : 1; + RK_U32 sw_skip_mode : 1; + RK_U32 sw_dec_scmd_dis : 1; + RK_U32 sw_dec_adv_pre_dis : 1; + RK_U32 sw_priority_mode : 1; + RK_U32 sw_refbu2_thr : 12; + RK_U32 sw_refbu2_picid : 5; + RK_U32 reserve1 : 2; + } reg50_dec_ctrl; + + struct { + RK_U32 sw_stream_len : 24; + RK_U32 reserve1 : 1; + RK_U32 sw_init_qp : 6; + RK_U32 reserve2 : 1; + } reg51_stream_info; + + struct { + RK_U32 sw_startmb_y : 8; + RK_U32 sw_startmb_x : 9; + RK_U32 sw_apf_threshold : 14; + RK_U32 sw_reserve : 1; + } reg52_error_concealment; + + RK_U32 reg53_dec_mode; + + struct { + RK_U32 sw_dec_in_endian : 1; + RK_U32 sw_dec_out_endian : 1; + RK_U32 sw_dec_inswap32_e : 1; + RK_U32 sw_dec_outswap32_e : 1; + RK_U32 sw_dec_strswap32_e : 1; + RK_U32 sw_dec_strendian_e : 1; + RK_U32 reserve3 : 26; + } reg54_endian; + + struct { + RK_U32 sw_dec_irq : 1; + RK_U32 sw_dec_irq_dis : 1; + RK_U32 reserve0 : 2; + RK_U32 sw_dec_rdy_int : 1; + RK_U32 sw_dec_bus_int : 1; + RK_U32 sw_dec_buffer_int : 1; + RK_U32 reserve1 : 1; + RK_U32 sw_dec_aso_int : 1; + RK_U32 sw_dec_slice_int : 1; + RK_U32 sw_dec_pic_inf : 1; + RK_U32 reserve2 : 1; + RK_U32 sw_dec_error_int: 1; + RK_U32 sw_dec_timeout : 1; + RK_U32 reserve3 : 18; + } reg55_Interrupt; + + struct { + RK_U32 sw_dec_axi_rn_id : 8; + RK_U32 sw_dec_axi_wr_id : 8; + RK_U32 sw_dec_max_burst : 5; + RK_U32 resever : 1; + RK_U32 sw_dec_data_disc_e : 1; + RK_U32 resever1 : 9; + } reg56_axi_ctrl; + + struct { + RK_U32 sw_dec_e : 1; + RK_U32 sw_refbu2_buf_e : 1; + RK_U32 sw_dec_out_dis : 1; + RK_U32 resever : 1; + RK_U32 sw_dec_clk_gate_e : 1; + RK_U32 sw_dec_timeout_e : 1; + RK_U32 sw_picord_count_e : 1; + RK_U32 sw_seq_mbaff_e : 1; + RK_U32 sw_reftopfirst_e : 1; + RK_U32 sw_ref_topfield_e : 1; + RK_U32 sw_write_mvs_e : 1; + RK_U32 sw_sorenson_e : 1; + RK_U32 sw_fwd_interlace_e : 1; + RK_U32 sw_pic_topfield_e : 1 ; + RK_U32 sw_pic_inter_e : 1; + RK_U32 sw_pic_b_e : 1; + RK_U32 sw_pic_fieldmode_e : 1; + RK_U32 sw_pic_interlace_e : 1; + RK_U32 sw_pjpeg_e : 1; + RK_U32 sw_divx3_e : 1; + RK_U32 sw_rlc_mode_e : 1; + RK_U32 sw_ch_8pix_ileav_e : 1; + RK_U32 sw_start_code_e : 1; + RK_U32 resever1 : 8; + RK_U32 sw_dec_ahb_hlock_e : 1; + } reg57_enable_ctrl; + + RK_U32 reg58_soft_rest; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_0_2 : 10; + RK_U32 sw_pred_bc_tap_0_1 : 10; + RK_U32 sw_pred_bc_tap_0_0 : 10; + } reg59; + + RK_U32 reg60_addit_ch_st_base; + RK_U32 reg61_qtable_base; + RK_U32 reg62_directmv_base; + RK_U32 reg63_dec_out_base; + RK_U32 reg64_rlc_vlc_base; + + struct { + RK_U32 sw_refbu_y_offset : 9; + RK_U32 sw_reserve : 3; + RK_U32 sw_refbu_fparmod_e : 1; + RK_U32 sw_refbu_eval_e : 1; + RK_U32 sw_refbu_picid : 5; + RK_U32 sw_refbu_thr : 12; + RK_U32 sw_refbu_e : 1; + } reg65_refpicbuf_ctrl; + + struct { + RK_U32 build_version : 3; + RK_U32 product_IDen : 1; + RK_U32 minor_version : 8; + RK_U32 major_version : 4; + RK_U32 product_numer : 16; + } reg66_id; + + struct { + RK_U32 sw_reserve : 25; + RK_U32 sw_dec_rtl_rom : 1; + RK_U32 sw_dec_rv_prof : 2; + RK_U32 sw_ref_buff2_exist : 1; + RK_U32 sw_dec_divx_prof : 1; + RK_U32 sw_dec_refbu_ilace : 1; + RK_U32 sw_dec_jpeg_exten : 1; + } reg67_synthesis_cfg; + + struct { + RK_U32 sw_refbu_top_sum : 16; + RK_U32 sw_refbu_bot_sum : 16; + } reg68_sum_of_partitions; + + struct { + RK_U32 sw_refbu_intra_sum : 16; + RK_U32 sw_refbu_hit_sum : 16; + } reg69_sum_inf; + + struct { + RK_U32 sw_refbu_mv_sum : 22; + RK_U32 sw_reserve : 10; + } reg70_sum_mv; + + RK_U32 reg71_119_reserve[49]; + + struct { + RK_U32 sw_pic_mb_h_ext : 3; + RK_U32 sw_pic_mb_w_ext : 3; + RK_U32 sw_alt_scan_e : 1; + RK_U32 sw_mb_height_off : 4; + RK_U32 sw_pic_mb_hight_p : 8; + RK_U32 sw_mb_width_off : 4; + RK_U32 sw_pic_mb_width : 9; + } reg120; + + struct { + RK_U32 sw_pjpeg_se : 8; + RK_U32 sw_pjpeg_ss : 8; + RK_U32 sw_pjpeg_al : 4; + RK_U32 sw_pjpeg_ah : 4; + RK_U32 sw_pjpeg_hdiv8 : 1; + RK_U32 sw_pjpeg_wdiv8 : 1; + RK_U32 sw_pjpeg_fildown_e : 1; + } reg121; + + struct { + RK_U32 sw_cb_dc_vlctable3 : 1; + RK_U32 sw_cr_dc_vlctable3 : 1; + RK_U32 sw_cb_dc_vlctable : 1; + RK_U32 sw_cr_dc_vlctable : 1; + RK_U32 sw_cb_ac_vlctable : 1; + RK_U32 sw_cr_ac_vlctable : 1; + RK_U32 sw_jpeg_stream_all : 1; + RK_U32 sw_jpeg_filright_e : 1; + RK_U32 sw_jpeg_mode : 3; + RK_U32 sw_jpeg_qtables : 2; + RK_U32 sw_reserved_1 : 12; + RK_U32 sw_sync_marker_e : 1; + RK_U32 sw_strm_start_bit : 6; + } reg122; + + struct { + RK_U32 sw_pjpeg_rest_freq : 16; + } reg123; + + struct { + RK_U32 sw_stream1_len : 24; + RK_U32 sw_coeffs_part_am : 4; + RK_U32 sw_resever : 4; + } reg124; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_5_3 : 10; + RK_U32 sw_pred_bc_tap_5_2 : 10; + RK_U32 sw_pred_bc_tap_5_1 : 10; + } reg125; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_6_2 : 10; + RK_U32 sw_pred_bc_tap_6_1 : 10; + RK_U32 sw_pred_bc_tap_6_0 : 10; + } reg126; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_7_1 : 10; + RK_U32 sw_pred_bc_tap_7_0 : 10; + RK_U32 sw_pred_bc_tap_6_3 : 10; + } reg127; + + struct { + RK_U32 sw_pred_tap_6_4 : 2; + RK_U32 sw_pred_tap_6_M1 : 2; + RK_U32 sw_pred_tap_4_4 : 2; + RK_U32 sw_pred_tap_4_M1 : 2; + RK_U32 sw_pred_tap_2_4 : 2; + RK_U32 sw_pred_tap_2_M1 : 2; + RK_U32 sw_pred_bc_tap_7_3 : 10; + RK_U32 sw_pred_bc_tap_7_2 : 10; + } reg128; + + struct { + RK_U32 sw_filt_level_3 : 6; + RK_U32 sw_filt_level_2 : 6; + RK_U32 sw_filt_level_1 : 6; + RK_U32 sw_filt_level_0 : 6; + RK_U32 resever : 8; + } reg129; + + struct { + RK_U32 sw_quant_1 : 11; + RK_U32 sw_quant_0 : 11; + RK_U32 sw_quant_delta_1 : 5; + RK_U32 sw_quant_delta_0 : 5; + } reg130; + + + RK_U32 reg131_jpg_ch_out_base; + + struct { + RK_U32 sw_filt_mb_adj_3 : 7; + RK_U32 sw_filt_mb_adj_2 : 7; + RK_U32 sw_filt_mb_adj_1 : 7; + RK_U32 sw_filt_mb_adj_0 : 7; + RK_U32 sw_filt_sharpness : 3; + RK_U32 sw_filt_type : 1; + } reg132; + + + struct { + RK_U32 sw_filt_ref_adj_3 : 7; + RK_U32 sw_filt_ref_adj_2 : 7; + RK_U32 sw_filt_ref_adj_1 : 7; + RK_U32 sw_filt_ref_adj_0 : 7; + RK_U32 sw_resver : 4; + } reg133; + + struct { + RK_U32 sw_ac1_code1_cnt : 2; + RK_U32 sw_reserved_1 : 1; + RK_U32 sw_ac1_code2_cnt : 3; + RK_U32 sw_reserved_2 : 1; + RK_U32 sw_ac1_code3_cnt : 4; + RK_U32 sw_ac1_code4_cnt : 5; + RK_U32 sw_ac1_code5_cnt : 6; + RK_U32 sw_reserved_3 : 2; + RK_U32 sw_ac1_code6_cnt : 7; + }reg134; + + struct { + RK_U32 sw_ac1_code7_cnt : 8; + RK_U32 sw_ac1_code8_cnt : 8; + RK_U32 sw_ac1_code9_cnt : 8; + RK_U32 sw_ac1_code10_cnt : 8; + }reg135; + + struct { + RK_U32 sw_ac1_code11_cnt : 8; + RK_U32 sw_ac1_code12_cnt : 8; + RK_U32 sw_ac1_code13_cnt : 8; + RK_U32 sw_ac1_code14_cnt : 8; + }reg136; + + struct { + RK_U32 sw_ac1_code15_cnt : 8; + RK_U32 sw_ac1_code16_cnt : 8; + RK_U32 sw_ac2_code1_cnt : 2; + RK_U32 sw_reserved_1 : 1; + RK_U32 sw_ac2_code2_cnt : 3; + RK_U32 sw_reserved_2 : 1; + RK_U32 sw_ac2_code3_cnt : 4; + RK_U32 sw_ac2_code4_cnt : 5; + } reg137; + + struct { + RK_U32 sw_ac2_code5_cnt : 6; + RK_U32 sw_reserved_1 : 2; + RK_U32 sw_ac2_code6_cnt : 7; + RK_U32 sw_reserved_2 : 1; + RK_U32 sw_ac2_code7_cnt : 8; + RK_U32 sw_ac2_code8_cnt : 8; + } reg138; + + struct { + RK_U32 sw_ac2_code9_cnt : 8; + RK_U32 sw_ac2_code10_cnt : 8; + RK_U32 sw_ac2_code11_cnt : 8; + RK_U32 sw_ac2_code12_cnt : 8; + }reg139; + + struct { + RK_U32 sw_ac2_code13_cnt : 8; + RK_U32 sw_ac2_code14_cnt : 8; + RK_U32 sw_ac2_code15_cnt : 8; + RK_U32 sw_ac2_code16_cnt : 8; + }reg140; + + struct { + RK_U32 sw_dc1_code1_cnt : 2; + RK_U32 sw_reserved_1 : 2; + RK_U32 sw_dc1_code2_cnt : 3; + RK_U32 sw_reserved_2 : 1; + RK_U32 sw_dc1_code3_cnt : 4; + RK_U32 sw_dc1_code4_cnt : 4; + RK_U32 sw_dc1_code5_cnt : 4; + RK_U32 sw_dc1_code6_cnt : 4; + RK_U32 sw_dc1_code7_cnt : 4; + RK_U32 sw_dc1_code8_cnt : 4; + }reg141; + + struct { + RK_U32 sw_dc1_code9_cnt : 4; + RK_U32 sw_dc1_code10_cnt : 4; + RK_U32 sw_dc1_code11_cnt : 4; + RK_U32 sw_dc1_code12_cnt : 4; + RK_U32 sw_dc1_code13_cnt : 4; + RK_U32 sw_dc1_code14_cnt : 4; + RK_U32 sw_dc1_code15_cnt : 4; + RK_U32 sw_dc1_code16_cnt : 4; + }reg142; + + struct { + RK_U32 sw_dc2_code1_cnt : 2; + RK_U32 sw_reserved_1 : 2; + RK_U32 sw_dc2_code2_cnt : 3; + RK_U32 sw_reserved_2 : 1; + RK_U32 sw_dc2_code3_cnt : 4; + RK_U32 sw_dc2_code4_cnt : 4; + RK_U32 sw_dc2_code5_cnt : 4; + RK_U32 sw_dc2_code6_cnt : 4; + RK_U32 sw_dc2_code7_cnt : 4; + RK_U32 sw_dc2_code8_cnt : 4; + }reg143; + + struct { + RK_U32 sw_dc2_code9_cnt : 4; + RK_U32 sw_dc2_code10_cnt : 4; + RK_U32 sw_dc2_code11_cnt : 4; + RK_U32 sw_dc2_code12_cnt : 4; + RK_U32 sw_dc2_code13_cnt : 4; + RK_U32 sw_dc2_code14_cnt : 4; + RK_U32 sw_dc2_code15_cnt : 4; + RK_U32 sw_dc2_code16_cnt : 4; + }reg144; + + RK_U32 reg145_bitpl_ctrl_base; + RK_U32 reg_dct_strm1_base[2]; + + struct { + RK_U32 sw_slice_h : 8; + RK_U32 sw_resver : 24; + } reg148; + + RK_U32 reg149_segment_map_base; + + struct { + RK_U32 sw_dct_start_bit_7 : 6; + RK_U32 sw_dct_start_bit_6 : 6; + RK_U32 sw_dct_start_bit_5 : 6; + RK_U32 sw_dct_start_bit_4 : 6; + RK_U32 sw_dct_start_bit_3 : 6; + RK_U32 sw_resver : 2; + } reg150; + + struct { + RK_U32 sw_quant_3 : 11; + RK_U32 sw_quant_2 : 11; + RK_U32 sw_quant_delta_3 : 5; + RK_U32 sw_quant_delta_2 : 5; + } reg151; + + struct { + RK_U32 sw_quant_5 : 11; + RK_U32 sw_quant_4 : 11; + RK_U32 sw_quant_delta_4 : 5; + RK_U32 sw_resver : 5; + } reg152; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_1_1 : 10; + RK_U32 sw_pred_bc_tap_1_0 : 10; + RK_U32 sw_pred_bc_tap_0_3 : 10; + } reg153; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_2_0 : 10; + RK_U32 sw_pred_bc_tap_1_3 : 10; + RK_U32 sw_pred_bc_tap_1_2 : 10; + } reg154; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_2_3 : 10; + RK_U32 sw_pred_bc_tap_2_2 : 10; + RK_U32 sw_pred_bc_tap_2_1 : 10; + } reg155; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_3_2 : 10; + RK_U32 sw_pred_bc_tap_3_1 : 10; + RK_U32 sw_pred_bc_tap_3_0 : 10; + } reg156; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_4_1 : 10; + RK_U32 sw_pred_bc_tap_4_0 : 10; + RK_U32 sw_pred_bc_tap_3_3 : 10; + } reg157; + + struct { + RK_U32 resever : 2; + RK_U32 sw_pred_bc_tap_5_0 : 10; + RK_U32 sw_pred_bc_tap_4_3 : 10; + RK_U32 sw_pred_bc_tap_4_2 : 10; + } reg158; +} JpegRegSet; + +typedef struct JpegHalContext { + MppBufSlots packet_slots; + MppBufSlots frame_slots; + RK_S32 vpu_socket; + JpegRegSet regs; + MppBufferGroup group; + MppBuffer frame_buf; + MppBuffer pTableBase; + + RK_U32 hal_debug_enable; + RK_U32 frame_count; + RK_U32 output_yuv_count; + + FILE *fp_reg_in; + FILE *fp_reg_out; +}JpegHalContext; + +#endif /* __HAL_JPEGD_REG_H__ */ diff --git a/mpp/mpi.cpp b/mpp/mpi.cpp index d80a787d..44d011db 100644 --- a/mpp/mpi.cpp +++ b/mpp/mpi.cpp @@ -43,7 +43,8 @@ static MppCodingTypeInfo support_list[] = { { MPP_CTX_DEC, MPP_VIDEO_CodingVP8, "dec", "vp8", }, { MPP_CTX_DEC, MPP_VIDEO_CodingVP9, "dec", "VP9", }, { MPP_CTX_DEC, MPP_VIDEO_CodingAVS, "dec", "avs+", }, - { MPP_CTX_ENC, MPP_VIDEO_CodingAVC, "enc", "h.264/AVC", }, +// { MPP_CTX_DEC, MPP_VIDEO_CodingMJPEG, "dec", "jpeg", }, + { MPP_CTX_ENC, MPP_VIDEO_CodingAVC, "enc", "h.264/AVC", }, }; #define check_mpp_ctx(ctx) _check_mpp_ctx(ctx, __FUNCTION__) diff --git a/mpp/test/CMakeLists.txt b/mpp/test/CMakeLists.txt index 73a92800..1e71c2a6 100644 --- a/mpp/test/CMakeLists.txt +++ b/mpp/test/CMakeLists.txt @@ -36,3 +36,7 @@ if (${HAVE_AVSD}) include_directories(../codec/dec/avs) add_mpp_test(avsd) endif() + +# jpeg decoder test +include_directories(../codec/dec/jpeg) +add_mpp_test(jpegd) diff --git a/mpp/test/jpegd_test.c b/mpp/test/jpegd_test.c new file mode 100644 index 00000000..2e30ebbe --- /dev/null +++ b/mpp/test/jpegd_test.c @@ -0,0 +1,570 @@ +/* + * 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_TEST" + +#include + +#include "mpp_env.h" +#include "mpp_err.h" +#include "mpp_log.h" +#include "mpp_mem.h" +#include "mpp_common.h" + +#include "mpp_dec.h" +#include "mpp_frame.h" + +#include "jpegd_api.h" +#include "jpegd_syntax.h" +#include "hal_jpegd_api.h" + +#include "utils.h" + + +#define JPEGD_STREAM_BUFF_SIZE (10*1024*1024) + +typedef enum VPU_API_DEMO_RET { + PARSER_DEMO_OK = 0, + PARSER_DEMO_PARSE_HELP_OK = 1, + + PARSER_DEMO_ERROR_BASE = -100, + ERROR_INVALID_PARAM = PARSER_DEMO_ERROR_BASE - 1, + ERROR_INVALID_STREAM = PARSER_DEMO_ERROR_BASE - 2, + ERROR_IO = PARSER_DEMO_ERROR_BASE - 3, + ERROR_MEMORY = PARSER_DEMO_ERROR_BASE - 4, + ERROR_INIT_VPU = PARSER_DEMO_ERROR_BASE - 5, + + ERROR_VPU_DECODE = PARSER_DEMO_ERROR_BASE - 90, +} PARSER_API_DEMO_RET; + +typedef struct parserDemoCmdCtx { + char input_file[200]; + char output_file[200]; + RK_U32 width; + RK_U32 height; + RK_U8 have_input; + RK_U8 have_output; + RK_U8 disable_debug; + RK_U32 record_frames; + RK_S64 record_start_ms; +} parserDemoCmdCtx; + +typedef struct jpegdDemoCtx { + parserDemoCmdCtx *cfg; + MppDec api; + HalDecTask task; + MppBuffer pkt_buf; + MppBuffer pic_buf; + MppBufferGroup frmbuf_grp; + MppBufferGroup strmbuf_grp; + MppPacket pkt; + + FILE* pOutFile; + + RK_U8 *strmbuf; + RK_U32 strmbytes; + RK_U32 dec_frm_num; +}jpegdDemoCtx; + +static OptionInfo jpeg_parserCmd[] = { + {"i", "input_file", "input bitstream file"}, + {"o", "output_file", "output bitstream file, "}, + {"w", "width", "the width of input bitstream"}, + {"h", "height", "the height of input bitstream"}, + {"vframes", "number", "set the number of video frames to record"}, + {"ss", "time_off", "set the start time offset, use Ms as the unit."}, + {"d", "disable", "disable the debug output info."}, +}; + +MPP_RET jpegd_readbytes_from_file(RK_U8* buf, RK_S32 aBytes, FILE* fp) +{ + MPP_RET ret = MPP_OK; + if ((NULL == buf) || (NULL == fp) || (0 == aBytes)) { + return -1; + } + + RK_S32 rd_bytes = fread(buf, 1, aBytes, fp); + if(rd_bytes != aBytes){ + mpp_log("read %u bytes from file fail, actually only %#x bytes is read.", (RK_U32)aBytes, rd_bytes); + return -1; + } + mpp_log("read %d bytes from file sucessfully, the first 4 bytes: %08x", rd_bytes, *((RK_U32*)buf)); + + return ret; +} + +static void jpeg_show_usage() +{ + mpp_log("usage: parserDemo [options] input_file, \n\n"); + + mpp_log("Getting help:\n"); + mpp_log("-help --print options of vpu api demo\n"); +} + +static void jpeg_show_options(int count, OptionInfo *options) +{ + int i; + for (i = 0; i < count; i++) { + mpp_log("-%s %-16s\t%s\n", + options[i].name, options[i].argname, options[i].help); + } +} + +static RK_S32 jpeg_show_help() +{ + mpp_log("usage: parserDemo [options] input_file, \n\n"); + jpeg_show_options(sizeof(jpeg_parserCmd)/sizeof(OptionInfo), jpeg_parserCmd); + return 0; +} + +static RK_S32 jpeg_parse_options(int argc, char **argv, parserDemoCmdCtx* cmdCxt) +{ + mpp_log("jpeg_parse_options enter\n"); + const char *opt; + RK_S32 optindex, handleoptions = 1, ret = 0; + + if ((argc < 2) || (cmdCxt == NULL)) { + mpp_log("parser demo, input parameter invalid\n"); + jpeg_show_usage(); + return MPP_ERR_STREAM; + } + + /* parse options */ + optindex = 1; + while (optindex < argc) { + opt = (const char*)argv[optindex++]; + + if (handleoptions && opt[0] == '-' && opt[1] != '\0') { + if (opt[1] == '-') { + if (opt[2] != '\0') { + opt++; + } else { + handleoptions = 0; + continue; + } + } + + opt++; + + switch (*opt) { + case 'i': + if (argv[optindex]) { + memcpy(cmdCxt->input_file, argv[optindex], strlen(argv[optindex])); + cmdCxt->input_file[strlen(argv[optindex])] = '\0'; + cmdCxt->have_input = 1; + } else { + mpp_log("input file is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + break; + case 'o': + if (argv[optindex]) { + memcpy(cmdCxt->output_file, argv[optindex], strlen(argv[optindex])); + cmdCxt->output_file[strlen(argv[optindex])] = '\0'; + cmdCxt->have_output = 1; + break; + } else { + mpp_log("out file is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + case 'd': + cmdCxt->disable_debug = 1; + break; + case 'w': + if (argv[optindex]) { + cmdCxt->width = atoi(argv[optindex]); + break; + } else { + mpp_log("input width is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + case 'h': + if ((*(opt + 1) != '\0') && !strncmp(opt, "help", 4)) { + jpeg_show_help(); + ret = PARSER_DEMO_PARSE_HELP_OK; + goto PARSE_OPINIONS_OUT; + } else if (argv[optindex]) { + cmdCxt->height = atoi(argv[optindex]); + } else { + mpp_log("input height is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + break; + + default: + if ((*(opt + 1) != '\0') && argv[optindex]) { + if (!strncmp(opt, "vframes", 7)) { + cmdCxt->record_frames = atoi(argv[optindex]); + } else if (!strncmp(opt, "ss", 2)) { + cmdCxt->record_start_ms = atoi(argv[optindex]); + } else { + ret = -1; + goto PARSE_OPINIONS_OUT; + } + } else { + ret = -1; + goto PARSE_OPINIONS_OUT; + } + break; + } + + optindex += ret; + } + } + +PARSE_OPINIONS_OUT: + if (ret < 0) { + mpp_log("vpu api demo, input parameter invalid\n"); + jpeg_show_usage(); + return MPP_ERR_STREAM; + } + mpp_log("jpeg_parse_options exit\n"); + return ret; +} + +MPP_RET jpegd_test_deinit(jpegdDemoCtx *ctx) +{ + FUN_TEST("Enter"); + MppDec *pApi = &(ctx->api); + if (pApi->parser) { + parser_deinit(pApi->parser); + pApi->parser = NULL; + } + if (pApi->hal) { + mpp_hal_deinit(pApi->hal); + pApi->hal = NULL; + } + if (pApi->frame_slots) { + mpp_buf_slot_deinit(pApi->frame_slots); + pApi->frame_slots = NULL; + } + if (pApi->packet_slots) { + mpp_buf_slot_deinit(pApi->packet_slots); + pApi->packet_slots = NULL; + } + + if (ctx->pic_buf) { + mpp_buffer_put(ctx->pic_buf); + } + if (ctx->frmbuf_grp) { + mpp_err("frmbuf_grp deinit"); + mpp_buffer_group_put(ctx->frmbuf_grp); + } + if (ctx->strmbuf_grp) { + mpp_err("strmbuf_grp deinit"); + mpp_buffer_group_put(ctx->strmbuf_grp); + } + if(ctx->strmbuf) { + mpp_err("strmbuf free"); + mpp_free(ctx->strmbuf); + } + if(ctx->pOutFile){ + mpp_err("close output file"); + fclose(ctx->pOutFile); + ctx->pOutFile = NULL; + } + + FUN_TEST("Exit"); + return MPP_OK; +} + +MPP_RET jpegd_test_init(parserDemoCmdCtx *cmd, jpegdDemoCtx *ctx) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + MppDec *pMppDec = NULL; + ParserCfg parser_cfg; + MppHalCfg hal_cfg; + + memset(ctx, 0, sizeof(jpegdDemoCtx)); + ctx->cfg = cmd; + + //demo configure + ctx->pOutFile = fopen("/data/spurs.yuv", "wb+"); + if(NULL == ctx->pOutFile){ + JPEGD_ERROR_LOG("create spurs.yuv failed"); + } + + //malloc buffers for software + CHECK_MEM(ctx->strmbuf = mpp_malloc_size(RK_U8, JPEGD_STREAM_BUFF_SIZE)); + + //malloc buffers for hardware + if (ctx->frmbuf_grp == NULL) { + ret = mpp_buffer_group_get_internal(&ctx->frmbuf_grp, MPP_BUFFER_TYPE_ION); + if (MPP_OK != ret) { + mpp_err("frmbuf_grp: jpegd mpp_buffer_group_get_internal failed\n"); + goto __FAILED; + } + } + if (ctx->strmbuf_grp == NULL) { + ret = mpp_buffer_group_get_internal(&ctx->strmbuf_grp, MPP_BUFFER_TYPE_ION); + if (MPP_OK != ret) { + mpp_err("strmbuf_grp: jpegd mpp_buffer_group_get_internal failed\n"); + goto __FAILED; + } + } + + //api config + pMppDec = &ctx->api; + pMppDec->coding = MPP_VIDEO_CodingMJPEG; + + CHECK_FUN(mpp_buf_slot_init(&pMppDec->frame_slots)); + CHECK_MEM(pMppDec->frame_slots); + mpp_buf_slot_setup(pMppDec->frame_slots, 2); + + CHECK_FUN(mpp_buf_slot_init(&pMppDec->packet_slots)); + CHECK_MEM(pMppDec->packet_slots); + mpp_buf_slot_setup(pMppDec->packet_slots, 2); + + //parser config + memset(&parser_cfg, 0, sizeof(parser_cfg)); + parser_cfg.coding = pMppDec->coding; + parser_cfg.frame_slots = pMppDec->frame_slots; + parser_cfg.packet_slots = pMppDec->packet_slots; + parser_cfg.task_count = 2; + parser_cfg.need_split = 0; + CHECK_FUN(parser_init(&pMppDec->parser, &parser_cfg)); + + //hal config + memset(&hal_cfg, 0, sizeof(hal_cfg)); + hal_cfg.type = MPP_CTX_DEC; + hal_cfg.coding = pMppDec->coding; + hal_cfg.work_mode = HAL_MODE_LIBVPU; + { + RK_U32 hal_device_id = 0; + //mpp_env_get_u32("h264d_chg_org", &hal_device_id, 1); + hal_device_id = 0; + if (hal_device_id == 1) { + hal_cfg.device_id = HAL_RKVDEC; + } else { + hal_cfg.device_id = HAL_VDPU; + } + } + hal_cfg.frame_slots = pMppDec->frame_slots; + hal_cfg.packet_slots = pMppDec->packet_slots; + hal_cfg.task_count = parser_cfg.task_count; + CHECK_FUN(mpp_hal_init(&pMppDec->hal, &hal_cfg)); + pMppDec->tasks = hal_cfg.tasks; + + memset(&ctx->task, 0, sizeof(ctx->task)); + memset(ctx->task.refer, -1, sizeof(ctx->task.refer)); + ctx->task.input = -1; + + FUN_TEST("Exit"); + return MPP_OK; +__FAILED: + FUN_TEST("Exit"); + return ret; +} + +MPP_RET jpegd_parser_test(parserDemoCmdCtx *cmd) +{ + FUN_TEST("Enter"); + MPP_RET ret = MPP_OK; + MppDec *pMppDec = NULL; + HalDecTask *curtask = NULL; + jpegdDemoCtx DemoCtx; + FILE* pInFile = NULL; + RK_S32 fileSize = 0; + + // 1.jpegd_test_init + jpegd_test_init(cmd, &DemoCtx); + + pMppDec = &DemoCtx.api; + curtask = &DemoCtx.task; + + do { + RK_S32 slot_idx = 0; + + if (cmd->have_input) { + mpp_log("input bitstream w: %d, h: %d, path: %s\n", + cmd->width, cmd->height, cmd->input_file); + + pInFile = fopen(cmd->input_file, "rb"); + if (pInFile == NULL) { + mpp_log("input file not exsist\n"); + goto __FAILED; + } + } else { + mpp_log("please set input bitstream file\n"); + goto __FAILED; + } + + fseek(pInFile, 0L, SEEK_END); + fileSize = ftell(pInFile); + fseek(pInFile, 0L, SEEK_SET); + + // 2.jpegd_readbytes_from_file + ret = jpegd_readbytes_from_file(DemoCtx.strmbuf, fileSize, pInFile); + if(ret != MPP_OK){ + mpp_log("read bytes from file failed\n"); + goto __FAILED; + } + mpp_packet_init(&DemoCtx.pkt, DemoCtx.strmbuf, fileSize); + + // 3.parser_prepare + CHECK_FUN(parser_prepare(pMppDec->parser, DemoCtx.pkt, curtask)); // jpegd_parser_prepare + + if (-1 == curtask->input) { + if (MPP_OK == mpp_buf_slot_get_unused(pMppDec->packet_slots, &slot_idx) ) { + MppBuffer buffer = NULL; + curtask->input = slot_idx; + + mpp_buf_slot_get_prop(pMppDec->packet_slots, slot_idx, SLOT_BUFFER, &buffer); + if (NULL == buffer) { + RK_U32 size = (RK_U32)mpp_buf_slot_get_size(pMppDec->packet_slots); + if (size == 0) { + size = (1024 * 1024); + } + + mpp_buffer_get(DemoCtx.strmbuf_grp, &buffer, size); + if (buffer != NULL){ + mpp_err("mpp_buf_slot_get_prop, buffer:%p, size:%d", buffer, size); + mpp_buf_slot_set_prop(pMppDec->packet_slots, slot_idx, SLOT_BUFFER, buffer); + } + } + + mpp_buffer_write(buffer, 0, + mpp_packet_get_data(curtask->input_packet), + mpp_packet_get_size(curtask->input_packet)); + + mpp_err("%s Line %d, (*input_packet):%p, length:%d", __func__,__LINE__, + mpp_packet_get_data(curtask->input_packet), + mpp_packet_get_size(curtask->input_packet)); + DemoCtx.pkt_buf = buffer; + + mpp_buf_slot_set_flag(pMppDec->packet_slots, curtask->input, SLOT_CODEC_READY); + mpp_buf_slot_set_flag(pMppDec->packet_slots, curtask->input, SLOT_HAL_INPUT); + } + } + + CHECK_FUN(parser_parse(pMppDec->parser, curtask)); // jpegd_parser_parse + + if (curtask->valid) { + HalTaskInfo task_info; + MppBuffer buffer = NULL; + task_info.dec = *curtask; + RK_S32 index = curtask->output; + + if (mpp_buf_slot_is_changed(pMppDec->frame_slots)) { + mpp_buf_slot_ready(pMppDec->frame_slots); + } + + mpp_buf_slot_get_prop(pMppDec->frame_slots, index, SLOT_BUFFER, &buffer); + if (NULL == buffer) { + RK_U32 size = (RK_U32)mpp_buf_slot_get_size(pMppDec->frame_slots); + if (size == 0) { + size = 1920 * 1080 * 5; + } + + mpp_buffer_get(DemoCtx.frmbuf_grp, &buffer, size); + if (buffer){ + mpp_buf_slot_set_prop(pMppDec->frame_slots, index, SLOT_BUFFER, buffer); + mpp_err("frame_slots, buffer:%p, size:%d", buffer, size); + } + + DemoCtx.pic_buf = buffer; + } + + mpp_hal_reg_gen(pMppDec->hal, &task_info); // jpegd_hal_gen_regs + mpp_hal_hw_start(pMppDec->hal, &task_info); // jpegd_hal_start + mpp_hal_hw_wait(pMppDec->hal, &task_info); // jpegd_hal_wait + + parser_reset(pMppDec->parser); //[TEMP] jpegd_parser_reset + + void* pOutYUV = NULL; + pOutYUV = mpp_buffer_get_ptr(DemoCtx.pic_buf); + if (pOutYUV) { + JPEGD_INFO_LOG("pOutYUV:%p", pOutYUV); + JpegSyntaxParam *pTmpSyn = (JpegSyntaxParam *)curtask->syntax.data; + RK_U32 width = pTmpSyn->frame.hwX; + RK_U32 height = pTmpSyn->frame.hwY; + + JPEGD_INFO_LOG("Output Image: %d*%d", width, height); + if (DemoCtx.pOutFile) { + fwrite(pOutYUV, 1, width * height * 3 / 2, DemoCtx.pOutFile); + fflush(DemoCtx.pOutFile); + } + } + } + + /*** parser packet deinit ***/ + if(DemoCtx.pkt_buf) { + mpp_buffer_put(DemoCtx.pkt_buf); + } + if(DemoCtx.pic_buf) { + mpp_buffer_put(DemoCtx.pic_buf); + } + + mpp_buf_slot_clr_flag(pMppDec->packet_slots, curtask->input, SLOT_HAL_INPUT); + mpp_buf_slot_clr_flag(pMppDec->frame_slots, curtask->output, SLOT_HAL_OUTPUT); + + memset(curtask, 0, sizeof(HalDecTask)); + memset(&curtask->refer, -1, sizeof(curtask->refer)); + curtask->input = -1; + + DemoCtx.dec_frm_num ++; + }while(0); + + CHECK_FUN(mpp_dec_flush(pMppDec)); + +__FAILED: + if(pInFile){ + fclose(pInFile); + pInFile = NULL; + } + jpegd_test_deinit(&DemoCtx); + + FUN_TEST("Exit"); + return MPP_OK; +} + +int main(int argc, char **argv) +{ + FUN_TEST("Enter"); + + RK_S32 ret = 0; + parserDemoCmdCtx demoCmdCtx; + parserDemoCmdCtx* cmd = NULL; + + if (argc == 1) { + jpeg_show_usage(); + mpp_log("jpegd test demo complete directly\n"); + return MPP_OK; + } + + mpp_env_get_u32("mpp_debug", &mpp_debug, 0); + + cmd = &demoCmdCtx; + memset((void*)cmd, 0, sizeof(parserDemoCmdCtx)); + if ((ret = jpeg_parse_options(argc, argv, cmd)) != 0) { + if (ret == PARSER_DEMO_PARSE_HELP_OK) { + return MPP_OK; + } + + mpp_log("parse_options fail\n\n"); + jpeg_show_usage(); + return MPP_OK; + } + jpegd_parser_test(cmd); + + FUN_TEST("Exit"); + return MPP_OK; +}