/*------------------------------------------------------------------------------ -- -- -- This software is confidential and proprietary and may be used -- -- only as expressly authorized by a licensing agreement from -- -- -- -- Rockchip Products . -- -- -- -- (C) COPYRIGHT 2014 ROCKCHIP PRODUCTS -- -- ALL RIGHTS RESERVED -- -- -- -- The entire notice above must be reproduced -- -- on all copies and should not be removed. -- -- -- -------------------------------------------------------------------------------- -- -- Description : JPEG decoder API source file -- ------------------------------------------------------------------------------ -- -- -- ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ Table of contents 1. Include headers 2. External compiler flags 3. Module defines 4. Local function prototypes 5. Functions - JpegDecInit - JpegDecRelease - JpegDecGetImageInfo - JpegDecDecode ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 1. Include headers ------------------------------------------------------------------------------*/ #include "dwl.h" #include "vpu_type.h" #include "jpegdecapi.h" #include "jpegdeccontainer.h" #include "jpegdecmarkers.h" #include "jpegdecinternal.h" #include "jpegdecutils.h" #include "jpegdechdrs.h" #include "jpegdecscan.h" #include "jpegregdrv.h" #include "vpu.h" #define LOG_TAG "JPEG_DEC" #include "allocator_drm.h" #define ALOGV printf #define ALOGD printf #define ALOGI printf #define ALOGW printf #define ALOGE printf /*------------------------------------------------------------------------------ Version Information - DO NOT CHANGE! ------------------------------------------------------------------------------*/ #define JPG_MAJOR_VERSION 1 #define JPG_MINOR_VERSION 1 #define JPG_BUILD_MAJOR 1 #define JPG_BUILD_MINOR 149 #define JPG_SW_BUILD ((JPG_BUILD_MAJOR * 1000) + JPG_BUILD_MINOR) /*------------------------------------------------------------------------------ 2. External compiler flags ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 3. Module defines ------------------------------------------------------------------------------*/ #define JPEGDEC_API_TRC printf #define JPEGDEC_CLEAR_IRQ rk_SetRegisterFile(PTR_JPGC->reghandle, \ HWIF_DEC_IRQ_STAT, 0); \ rk_SetRegisterFile(PTR_JPGC->reghandle, \ HWIF_DEC_IRQ, 0); /*------------------------------------------------------------------------------ 4. Local function prototypes ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 5. Functions ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ Function name: JpegDecInit Functional description: Init jpeg decoder Inputs: JpegDecInst * decInst a reference to the jpeg decoder instance is stored here Outputs: JPEGDEC_OK JPEGDEC_INITFAIL JPEGDEC_PARAM_ERROR JPEGDEC_DWL_ERROR JPEGDEC_MEMFAIL ------------------------------------------------------------------------------*/ JpegDecRet JpegDecInit(JpegDecInst * pDecInst, RK_U32 color_conv) { JpegDecContainer *pJpegCont; int socket;; RK_U32 i = 0; RK_U32 asicID; RK_U32 fuseStatus = 0; RK_U32 extensionsSupported; DWLInitParam_t dwlInit; //JPEGDEC_API_TRC("JpegDecInit#\n"); /* check that right shift on negative numbers is performed signed */ /*lint -save -e* following check causes multiple lint messages */ if (((-1) >> 1) != (-1)) { printf("JpegDecInit# ERROR: Right shift is not signed\n"); return (JPEGDEC_INITFAIL); } /*lint -restore */ if (pDecInst == NULL) { printf("JpegDecInit# ERROR: decInst == NULL \n"); return (JPEGDEC_PARAM_ERROR); } *pDecInst = NULL; /* return NULL instance for any error */ //JPEGDEC_API_TRC("Ready to VPUClientInit#\n"); socket = VPUClientInit(color_conv ? VPU_DEC_PP : VPU_DEC); //ALOGD("VPUClientInit has done.the socket number is %d\n",socket); if (socket <= 0) { printf("JpegDecInit# ERROR: DWL Init failed,socket = %d\n", socket); return (JPEGDEC_DWL_ERROR); } /* check for proper hardware */ asicID = 0x91900000; { /* check that JPEG decoding supported in HW */ VPUHwDecConfig_t hwCfg; memset(&hwCfg, 0, sizeof(VPUHwDecConfig_t)); hwCfg.jpegESupport = 1; hwCfg.jpegSupport = 1; //VPUGetDecHwCfg(&hwCfg); if (!hwCfg.jpegSupport) { JPEGDEC_API_TRC(("JpegDecInit# ERROR: JPEG not supported in HW\n")); (void) VPUClientRelease(socket);; return JPEGDEC_FORMAT_NOT_SUPPORTED; } /* check progressive support */ if ((asicID >> 16) != 0x6731U) { /* progressive decoder */ if (hwCfg.jpegSupport == JPEG_BASELINE) fuseStatus = 1; } extensionsSupported = hwCfg.jpegESupport; } dwlInit.clientType = DWL_CLIENT_TYPE_JPEG_DEC; /* Initialize Wrapper */ pJpegCont = (JpegDecContainer *) DWLmalloc(sizeof(JpegDecContainer)); if (pJpegCont == NULL) { (void) VPUClientRelease(socket); return (JPEGDEC_MEMFAIL); } memset(pJpegCont, 0, sizeof(JpegDecContainer)); pJpegCont->socket = socket; pJpegCont->vpumem_ctx = NULL; pJpegCont->reghandle = get_rkdecregister_handle(); if ( pJpegCont->reghandle == NULL) { printf("pJpegCont->reghandle = NULL, VPUClientRelease \n"); (void) VPUClientRelease(socket); return (JPEGDEC_MEMFAIL); } set_rkdecregister_map(pJpegCont->reghandle, (RK_U32*)pJpegCont->jpegRegs); /* reset internal structures */ JpegDecClearStructs(pJpegCont); /* Reset shadow registers */ for (i = 1; i < DEC_RK70_REGISTERS; i++) { pJpegCont->jpegRegs[i] = 0; } memset(&pJpegCont->ioctl_info, 0, sizeof(JpegdIocRegInfo)); pJpegCont->ioctl_info.extra_info.magic = EXTRA_INFO_MAGIC; pJpegCont->ioctl_info.extra_info.cnt = 1; /* pp_chroma_out and chroma_out */ /* these parameters are defined in deccfg.h */ rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_OUT_ENDIAN, DEC_RK70_OUTPUT_PICTURE_ENDIAN); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_IN_ENDIAN, DEC_RK70_INPUT_DATA_ENDIAN); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_STRENDIAN_E, DEC_RK70_INPUT_STREAM_ENDIAN); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_MAX_BURST, DEC_RK70_BUS_BURST_LENGTH); if ((asicID >> 16) == 0x6731U) { rk_SetRegisterFile(pJpegCont->reghandle, HWIF_PRIORITY_MODE, DEC_RK70_ASIC_SERVICE_PRIORITY); } else { rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_SCMD_DIS, DEC_RK70_SCMD_DISABLE); } rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_LATENCY, DEC_RK70_LATENCY_COMPENSATION); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_DATA_DISC_E, DEC_RK70_DATA_DISCARD_ENABLE); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_OUTSWAP32_E, DEC_RK70_OUTPUT_SWAP_32_ENABLE); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_INSWAP32_E, DEC_RK70_INPUT_DATA_SWAP_32_ENABLE); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_STRSWAP32_E, DEC_RK70_INPUT_STREAM_SWAP_32_ENABLE); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_OUT_TILED_E, 0); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_TIMEOUT_E, 1); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_CLK_GATE_E, 1); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_IRQ_DIS, 0); /* set AXI RW IDs */ rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_AXI_RD_ID, (DEC_RK70_AXI_ID_R & 0xFFU)); rk_SetRegisterFile(pJpegCont->reghandle, HWIF_DEC_AXI_WR_ID, (DEC_RK70_AXI_ID_W & 0xFFU)); /* save HW version so we dont need to check it all * the time when deciding the control stuff */ pJpegCont->is8190 = (asicID >> 16) != 0x6731U ? 1 : 0; /* set HW related config's */ if (pJpegCont->is8190) { pJpegCont->fuseBurned = fuseStatus; /* max */ pJpegCont->maxSupportedWidth = JPEGDEC_MAX_WIDTH_8190; pJpegCont->maxSupportedHeight = JPEGDEC_MAX_HEIGHT_8190; pJpegCont->maxSupportedPixelAmount = JPEGDEC_MAX_PIXEL_AMOUNT_8190; pJpegCont->maxSupportedSliceSize = JPEGDEC_MAX_SLICE_SIZE_8190; } else { /* max */ pJpegCont->maxSupportedWidth = JPEGDEC_MAX_WIDTH; pJpegCont->maxSupportedHeight = JPEGDEC_MAX_HEIGHT; pJpegCont->maxSupportedPixelAmount = JPEGDEC_MAX_PIXEL_AMOUNT; pJpegCont->maxSupportedSliceSize = JPEGDEC_MAX_SLICE_SIZE; } /* min */ pJpegCont->minSupportedWidth = JPEGDEC_MIN_WIDTH; pJpegCont->minSupportedHeight = JPEGDEC_MIN_HEIGHT; pJpegCont->extensionsSupported = extensionsSupported; *pDecInst = (JpegDecContainer *) pJpegCont; printf("JpegDecInit# OK\n"); return (JPEGDEC_OK); } /*------------------------------------------------------------------------------ Function name: JpegDecRelease Functional description: Release Jpeg decoder Inputs: JpegDecInst decInst jpeg decoder instance void ------------------------------------------------------------------------------*/ void JpegDecRelease(JpegDecInst decInst) { JpegDecContainer *PTR_JPGC = ((JpegDecContainer *) decInst); int socket; //JPEGDEC_API_TRC("JpegDecRelease#"); if (PTR_JPGC == NULL) { JPEGDEC_API_TRC("JpegDecRelease# ERROR: decInst == NULL"); return; } socket = PTR_JPGC->socket; if (PTR_JPGC->vlc.acTable0.vals) { DWLfree(PTR_JPGC->vlc.acTable0.vals); } if (PTR_JPGC->vlc.acTable1.vals) { DWLfree(PTR_JPGC->vlc.acTable1.vals); } if (PTR_JPGC->vlc.acTable2.vals) { DWLfree(PTR_JPGC->vlc.acTable2.vals); } if (PTR_JPGC->vlc.acTable3.vals) { DWLfree(PTR_JPGC->vlc.acTable3.vals); } if (PTR_JPGC->vlc.dcTable0.vals) { DWLfree(PTR_JPGC->vlc.dcTable0.vals); } if (PTR_JPGC->vlc.dcTable1.vals) { DWLfree(PTR_JPGC->vlc.dcTable1.vals); } if (PTR_JPGC->vlc.dcTable2.vals) { DWLfree(PTR_JPGC->vlc.dcTable2.vals); } if (PTR_JPGC->vlc.dcTable3.vals) { DWLfree(PTR_JPGC->vlc.dcTable3.vals); } if (PTR_JPGC->frame.pBuffer) { DWLfree(PTR_JPGC->frame.pBuffer); } /* progressive */ if (PTR_JPGC->info.pCoeffBase.vir_addr) { #ifdef DRM_LINUX if (allocator_drm.free) allocator_drm.free(PTR_JPGC->ctx, &(PTR_JPGC->info.pCoeffBase)); #else VPUFreeLinear(&(PTR_JPGC->info.pCoeffBase)); #endif PTR_JPGC->info.pCoeffBase.vir_addr = NULL; } if (PTR_JPGC->info.tmpStrm.vir_addr) { //VPUFreeLinear(&(PTR_JPGC->info.tmpStrm)); if (allocator_drm.free) allocator_drm.free(PTR_JPGC->ctx, &(PTR_JPGC->info.tmpStrm)); PTR_JPGC->info.tmpStrm.vir_addr = NULL; } if (PTR_JPGC->frame.pTableBase.vir_addr) { #ifdef DRM_LINUX if (allocator_drm.free) allocator_drm.free(PTR_JPGC->ctx, &(PTR_JPGC->frame.pTableBase)); #else VPUFreeLinear(&(PTR_JPGC->frame.pTableBase)); #endif PTR_JPGC->frame.pTableBase.vir_addr = NULL; } /* if not user allocated memories */ if (!PTR_JPGC->info.userAllocMem) { if (PTR_JPGC->asicBuff.outLumaBuffer.vir_addr != NULL) { #ifdef DRM_LINUX if (allocator_drm.free) allocator_drm.free(PTR_JPGC->ctx, &(PTR_JPGC->asicBuff.outLumaBuffer)); #else VPUFreeLinear( &(PTR_JPGC->asicBuff.outLumaBuffer)); #endif PTR_JPGC->asicBuff.outLumaBuffer.vir_addr = NULL; } /*if(PTR_JPGC->asicBuff.outChromaBuffer.vir_addr != NULL) { VPUFreeLinear(&(PTR_JPGC->asicBuff.outChromaBuffer)); PTR_JPGC->asicBuff.outChromaBuffer.vir_addr = NULL; } if(PTR_JPGC->asicBuff.outChromaBuffer2.vir_addr != NULL) { VPUFreeLinear(&(PTR_JPGC->asicBuff.outChromaBuffer2)); PTR_JPGC->asicBuff.outChromaBuffer2.vir_addr = NULL; }*/ } else { PTR_JPGC->asicBuff.outLumaBuffer.vir_addr = NULL; PTR_JPGC->asicBuff.outChromaBuffer.vir_addr = NULL; } if (PTR_JPGC->reghandle != NULL) { release_rkdecregister_handle(PTR_JPGC->reghandle); PTR_JPGC->reghandle = NULL; } if (decInst) { DWLfree(PTR_JPGC); } VPUClientRelease(socket); JPEGDEC_API_TRC("JpegDecRelease# OK\n"); return; } /*------------------------------------------------------------------------------ Function name: JpegDecGetImageInfo Functional description: Get image information of the JFIF Inputs: JpegDecInst decInst jpeg decoder instance JpegDecInput *pDecIn input stream information JpegDecImageInfo *pImageInfo structure where the image info is written Outputs: JPEGDEC_OK JPEGDEC_ERROR JPEGDEC_UNSUPPORTED JPEGDEC_PARAM_ERROR JPEGDEC_INCREASE_BUFFER JPEGDEC_INVALID_STREAM_LENGTH JPEGDEC_INVALID_INPUT_BUFFER_SIZE ------------------------------------------------------------------------------*/ /* Get image information of the JFIF */ JpegDecRet JpegDecGetImageInfo(JpegDecInst decInst, JpegDecInput * pDecIn, JpegDecImageInfo * pImageInfo) { JpegDecContainer *PTR_JPGC = ((JpegDecContainer *) decInst); RK_U32 Nf = 0; RK_U32 Ns = 0; RK_U32 NsThumb = 0; RK_U32 i, j = 0; RK_U32 init = 0; RK_U32 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; RK_U32 Vmax = 0; RK_U32 headerLength = 0; RK_U32 currentByte = 0; RK_U32 currentBytes = 0; RK_U32 appLength = 0; RK_U32 appBits = 0; RK_U32 thumbnail = 0; RK_U32 errorCode = 0; #ifdef JPEGDEC_ERROR_RESILIENCE RK_U32 errorResilience = 0; RK_U32 errorResilienceThumb = 0; #endif /* JPEGDEC_ERROR_RESILIENCE */ StreamStorage stream; //JPEGDEC_API_TRC("JpegDecGetImageInfo check param\n"); /* check pointers & parameters */ if (decInst == NULL || pDecIn == NULL || pImageInfo == NULL || RK70_CHECK_VIRTUAL_ADDRESS(pDecIn->streamBuffer.pVirtualAddress)/* || RK70_CHECK_BUS_ADDRESS(pDecIn->streamBuffer.busAddress)*/) { JPEGDEC_API_TRC("JpegDecGetImageInfo JPEGDEC_PARAM_ERROR\n"); return (JPEGDEC_PARAM_ERROR); } /* Check the stream lenth */ if (pDecIn->streamLength < 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pDecIn->streamLength\n"); return (JPEGDEC_INVALID_STREAM_LENGTH); } /* Check the stream lenth */ if ((pDecIn->streamLength > DEC_RK70_MAX_STREAM) && (pDecIn->bufferSize < JPEGDEC_RK70_MIN_BUFFER || pDecIn->bufferSize > JPEGDEC_RK70_MAX_BUFFER)) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pDecIn->bufferSize = %d,pDecIn->streamLength = %d\n", pDecIn->bufferSize, pDecIn->streamLength); return (JPEGDEC_INVALID_INPUT_BUFFER_SIZE); } /* Check the stream buffer size */ if (pDecIn->bufferSize && (pDecIn->bufferSize < JPEGDEC_RK70_MIN_BUFFER || pDecIn->bufferSize > JPEGDEC_RK70_MAX_BUFFER)) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pDecIn->bufferSize = %d\n", pDecIn->bufferSize); return (JPEGDEC_INVALID_INPUT_BUFFER_SIZE); } /* Check the stream buffer size */ /*if(pDecIn->bufferSize && ((pDecIn->bufferSize % 8) != 0)) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: JPEGDEC_INVALID_INPUT_BUFFER_SIZE\n"); return (JPEGDEC_INVALID_INPUT_BUFFER_SIZE); }*/ /* reset sampling factors */ for (i = 0; i < MAX_NUMBER_OF_COMPONENTS; i++) { H[i] = 0; V[i] = 0; Htn[i] = 0; Vtn[i] = 0; } /* imageInfo initialization */ pImageInfo->displayWidth = 0; pImageInfo->displayHeight = 0; pImageInfo->outputWidth = 0; pImageInfo->outputHeight = 0; pImageInfo->version = 0; pImageInfo->units = 0; pImageInfo->xDensity = 0; pImageInfo->yDensity = 0; pImageInfo->outputFormat = 0; /* Default value to "Thumbnail" */ pImageInfo->thumbnailType = JPEGDEC_NO_THUMBNAIL; pImageInfo->displayWidthThumb = 0; pImageInfo->displayHeightThumb = 0; pImageInfo->outputWidthThumb = 0; pImageInfo->outputHeightThumb = 0; pImageInfo->outputFormatThumb = 0; /* utils initialization */ stream.bitPosInByte = 0; stream.pCurrPos = (RK_U8 *) pDecIn->streamBuffer.pVirtualAddress; stream.pStartOfStream = (RK_U8 *) pDecIn->streamBuffer.pVirtualAddress; stream.readBits = 0; stream.appnFlag = 0; /* stream length */ if (!pDecIn->bufferSize) stream.streamLength = pDecIn->streamLength; else stream.streamLength = pDecIn->bufferSize; //JPEGDEC_API_TRC("JpegDecGetImageInfo start get marker\n"); /* Read decoding parameters */ for (stream.readBits = 0; (stream.readBits / 8) < stream.streamLength; stream.readBits++) { /* Look for marker prefix byte from stream */ if ((currentByte == 0xFF) || JpegDecGetByte(&(stream)) == 0xFF) { currentByte = JpegDecGetByte(&(stream)); /* switch to certain header decoding */ switch (currentByte) { /* baseline marker */ case SOF0: /* progresive marker */ case SOF2: //JPEGDEC_API_TRC("JpegDecGetImageInfo get SOF2\n"); if (currentByte == SOF0) pImageInfo->codingMode = PTR_JPGC->info.operationType = JPEGDEC_BASELINE; else pImageInfo->codingMode = PTR_JPGC->info.operationType = JPEGDEC_PROGRESSIVE; /* Frame header */ i++; Hmax = 0; Vmax = 0; /* SOF0/SOF2 length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* Sample precision (only 8 bits/sample supported) */ currentByte = JpegDecGetByte(&(stream)); if (currentByte != 8) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Sample precision"); return (JPEGDEC_UNSUPPORTED); } /* Number of Lines */ pImageInfo->outputHeight = JpegDecGet2Bytes(&(stream)); pImageInfo->displayHeight = pImageInfo->outputHeight; if (pImageInfo->outputHeight < 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pImageInfo->outputHeight Unsupported"); return (JPEGDEC_UNSUPPORTED); } #ifdef JPEGDEC_ERROR_RESILIENCE if ((pImageInfo->outputHeight & 0xF) && (pImageInfo->outputHeight & 0xF) <= 8) errorResilience = 1; #endif /* JPEGDEC_ERROR_RESILIENCE */ /* round up to next multiple-of-16 */ pImageInfo->outputHeight += 0xf; pImageInfo->outputHeight &= ~(0xf); PTR_JPGC->frame.hwY = pImageInfo->outputHeight; /* Number of Samples per Line */ pImageInfo->outputWidth = JpegDecGet2Bytes(&(stream)); pImageInfo->displayWidth = pImageInfo->outputWidth; if (pImageInfo->outputWidth < 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pImageInfo->outputWidth unsupported"); return (JPEGDEC_UNSUPPORTED); } pImageInfo->outputWidth += 0xf; pImageInfo->outputWidth &= ~(0xf); PTR_JPGC->frame.hwX = pImageInfo->outputWidth; /* check for minimum and maximum dimensions */ if (pImageInfo->outputWidth < PTR_JPGC->minSupportedWidth || pImageInfo->outputHeight < PTR_JPGC->minSupportedHeight || pImageInfo->outputWidth > PTR_JPGC->maxSupportedWidth || pImageInfo->outputHeight > PTR_JPGC->maxSupportedHeight || (pImageInfo->outputWidth * pImageInfo->outputHeight) > PTR_JPGC->maxSupportedPixelAmount) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Unsupported size"); return (JPEGDEC_UNSUPPORTED); } /* Number of Image Components per Frame */ Nf = JpegDecGetByte(&(stream)); if (Nf != 3 && Nf != 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Number of Image Components per Frame"); return (JPEGDEC_UNSUPPORTED); } for (j = 0; j < Nf; j++) { /* jump over component identifier */ if (JpegDecFlushBits(&(stream), 8) == STRM_ERROR) { errorCode = 1; break; } /* Horizontal sampling factor */ currentByte = JpegDecGetByte(&(stream)); H[j] = (currentByte >> 4); /* Vertical sampling factor */ V[j] = (currentByte & 0xF); /* jump over Tq */ if (JpegDecFlushBits(&(stream), 8) == STRM_ERROR) { errorCode = 1; break; } if (H[j] > Hmax) Hmax = H[j]; if (V[j] > Vmax) Vmax = V[j]; } if (Hmax == 0 || Vmax == 0) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Hmax == 0 || Vmax == 0"); return (JPEGDEC_UNSUPPORTED); } #ifdef JPEGDEC_ERROR_RESILIENCE if (H[0] == 2 && V[0] == 2 && H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) { pImageInfo->outputFormat = JPEGDEC_YCbCr420_SEMIPLANAR; } else { /* check if fill needed */ if (errorResilience) { pImageInfo->outputHeight -= 16; pImageInfo->displayHeight = pImageInfo->outputHeight; } } #endif /* JPEGDEC_ERROR_RESILIENCE */ /* 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; PTR_JPGC->frame.numMcuInRow = (PTR_JPGC->frame.hwX / 16); PTR_JPGC->frame.numMcuInFrame = ((PTR_JPGC->frame.hwX * PTR_JPGC->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; PTR_JPGC->frame.numMcuInRow = (PTR_JPGC->frame.hwX / 16); PTR_JPGC->frame.numMcuInFrame = ((PTR_JPGC->frame.hwX * PTR_JPGC->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; PTR_JPGC->frame.numMcuInRow = (PTR_JPGC->frame.hwX / 8); PTR_JPGC->frame.numMcuInFrame = ((PTR_JPGC->frame.hwX * PTR_JPGC->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; PTR_JPGC->frame.numMcuInRow = (PTR_JPGC->frame.hwX / 8); PTR_JPGC->frame.numMcuInFrame = ((PTR_JPGC->frame.hwX * PTR_JPGC->frame.hwY) / 64); } else if (PTR_JPGC->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; PTR_JPGC->frame.hwX = pImageInfo->outputWidth; } /* check for maximum dimensions */ if (pImageInfo->outputWidth > PTR_JPGC->maxSupportedWidth || (pImageInfo->outputWidth * pImageInfo->outputHeight) > PTR_JPGC->maxSupportedPixelAmount) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Unsupported size"); return (JPEGDEC_UNSUPPORTED); } pImageInfo->outputFormat = JPEGDEC_YCbCr411_SEMIPLANAR; PTR_JPGC->frame.numMcuInRow = (PTR_JPGC->frame.hwX / 32); PTR_JPGC->frame.numMcuInFrame = ((PTR_JPGC->frame.hwX * PTR_JPGC->frame.hwY) / 256); } else if (PTR_JPGC->extensionsSupported && H[0] == 1 && V[0] == 1 && H[1] == 1 && V[1] == 1 && H[2] == 1 && V[2] == 1) { pImageInfo->outputFormat = JPEGDEC_YCbCr444_SEMIPLANAR; PTR_JPGC->frame.numMcuInRow = (PTR_JPGC->frame.hwX / 8); PTR_JPGC->frame.numMcuInFrame = ((PTR_JPGC->frame.hwX * PTR_JPGC->frame.hwY) / 64); } else { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Unsupported YCbCr format"); return (JPEGDEC_UNSUPPORTED); } /* restore output format */ PTR_JPGC->info.yCbCrMode = PTR_JPGC->info.getInfoYCbCrMode = pImageInfo->outputFormat; break; case SOS: /* SOS length */ //JPEGDEC_API_TRC("JpegDecGetImageInfo get SOS\n"); headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* check if interleaved or non-ibnterleaved */ Ns = JpegDecGetByte(&(stream)); if (Ns == MIN_NUMBER_OF_COMPONENTS && pImageInfo->outputFormat != JPEGDEC_YCbCr400 && pImageInfo->codingMode == JPEGDEC_BASELINE) { pImageInfo->codingMode = PTR_JPGC->info.operationType = JPEGDEC_NONINTERLEAVED; } /* jump over SOS header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } if ((stream.readBits + 8) < (8 * stream.streamLength)) { PTR_JPGC->info.init = 1; init = 1; } else { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Needs to increase input buffer"); return (JPEGDEC_INCREASE_INPUT_BUFFER); } break; case DQT: /* DQT length */ //JPEGDEC_API_TRC("JpegDecGetImageInfo get DQT\n"); headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* jump over DQT header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } break; case DHT: /* DHT length */ //JPEGDEC_API_TRC("JpegDecGetImageInfo get DHT\n"); headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* jump over DHT header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } break; case DRI: /* DRI length */ //JPEGDEC_API_TRC("JpegDecGetImageInfo get DRI\n"); headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } #if 0 /* jump over DRI header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } #endif headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } PTR_JPGC->frame.Ri = headerLength; break; /* application segments */ case APP0: //JPEGDEC_API_TRC("JpegDecGetImageInfo get APP0\n"); /* reset */ appBits = 0; appLength = 0; stream.appnFlag = 0; /* APP0 length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } appLength = headerLength; if (appLength < 16) { stream.appnFlag = 1; if (JpegDecFlushBits(&(stream), ((appLength * 8) - 16)) == STRM_ERROR) { errorCode = 1; break; } break; } appBits += 16; /* check identifier */ currentBytes = JpegDecGet2Bytes(&(stream)); appBits += 16; if (currentBytes != 0x4A46) { stream.appnFlag = 1; if (JpegDecFlushBits(&(stream), ((appLength * 8) - appBits)) == STRM_ERROR) { errorCode = 1; break; } break; } currentBytes = JpegDecGet2Bytes(&(stream)); appBits += 16; if (currentBytes != 0x4946 && currentBytes != 0x5858) { stream.appnFlag = 1; if (JpegDecFlushBits(&(stream), ((appLength * 8) - appBits)) == STRM_ERROR) { errorCode = 1; break; } break; } /* APP0 Extended */ if (currentBytes == 0x5858) { thumbnail = 1; } currentByte = JpegDecGetByte(&(stream)); appBits += 8; if (currentByte != 0x00) { stream.appnFlag = 1; if (JpegDecFlushBits(&(stream), ((appLength * 8) - appBits)) == STRM_ERROR) { errorCode = 1; break; } stream.appnFlag = 0; break; } /* APP0 Extended thumb type */ if (thumbnail) { /* extension code */ currentByte = JpegDecGetByte(&(stream)); if (currentByte == JPEGDEC_THUMBNAIL_JPEG) { pImageInfo->thumbnailType = JPEGDEC_THUMBNAIL_JPEG; appBits += 8; stream.appnFlag = 1; /* check thumbnail data */ Hmax = 0; Vmax = 0; /* Read decoding parameters */ for (; (stream.readBits / 8) < stream.streamLength; stream.readBits++) { /* Look for marker prefix byte from stream */ appBits += 8; if (JpegDecGetByte(&(stream)) == 0xFF) { /* switch to certain header decoding */ appBits += 8; currentByte = JpegDecGetByte(&(stream)); switch (currentByte) { /* baseline marker */ case SOF0: /* progresive marker */ case SOF2: if (currentByte == SOF0) pImageInfo->codingModeThumb = PTR_JPGC->info.operationTypeThumb = JPEGDEC_BASELINE; else pImageInfo->codingModeThumb = PTR_JPGC->info.operationTypeThumb = JPEGDEC_PROGRESSIVE; /* Frame header */ i++; /* jump over Lf field */ if (JpegDecFlushBits(&(stream), 16) == STRM_ERROR) { errorCode = 1; break; } appBits += 16; /* Sample precision (only 8 bits/sample supported) */ currentByte = JpegDecGetByte(&(stream)); appBits += 8; if (currentByte != 8) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Thumbnail Sample precision"); return (JPEGDEC_UNSUPPORTED); } /* Number of Lines */ pImageInfo->outputHeightThumb = JpegDecGet2Bytes(&(stream)); appBits += 16; pImageInfo->displayHeightThumb = pImageInfo->outputHeightThumb; if (pImageInfo->outputHeightThumb < 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pImageInfo->outputHeightThumb unsupported"); return (JPEGDEC_UNSUPPORTED); } #ifdef JPEGDEC_ERROR_RESILIENCE if ((pImageInfo->outputHeightThumb & 0xF) && (pImageInfo->outputHeightThumb & 0xF) <= 8) errorResilienceThumb = 1; #endif /* JPEGDEC_ERROR_RESILIENCE */ /* round up to next multiple-of-16 */ pImageInfo->outputHeightThumb += 0xf; pImageInfo->outputHeightThumb &= ~(0xf); /* Number of Samples per Line */ pImageInfo->outputWidthThumb = JpegDecGet2Bytes(&(stream)); appBits += 16; pImageInfo->displayWidthThumb = pImageInfo->outputWidthThumb; if (pImageInfo->outputWidthThumb < 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: pImageInfo->outputWidthThumb unsupported"); return (JPEGDEC_UNSUPPORTED); } pImageInfo->outputWidthThumb += 0xf; pImageInfo->outputWidthThumb &= ~(0xf); if (pImageInfo->outputWidthThumb < PTR_JPGC->minSupportedWidth || pImageInfo->outputHeightThumb < PTR_JPGC->minSupportedHeight || pImageInfo->outputWidthThumb > JPEGDEC_MAX_WIDTH_TN || pImageInfo->outputHeightThumb > JPEGDEC_MAX_HEIGHT_TN) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Thumbnail Unsupported size"); return (JPEGDEC_UNSUPPORTED); } /* Number of Image Components per Frame */ Nf = JpegDecGetByte(&(stream)); appBits += 8; if (Nf != 3 && Nf != 1) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Thumbnail Number of Image Components per Frame"); return (JPEGDEC_UNSUPPORTED); } for (j = 0; j < Nf; j++) { /* jump over component identifier */ if (JpegDecFlushBits(&(stream), 8) == STRM_ERROR) { errorCode = 1; break; } appBits += 8; /* Horizontal sampling factor */ currentByte = JpegDecGetByte(&(stream)); appBits += 8; Htn[j] = (currentByte >> 4); /* Vertical sampling factor */ Vtn[j] = (currentByte & 0xF); /* jump over Tq */ if (JpegDecFlushBits(&(stream), 8) == STRM_ERROR) { errorCode = 1; break; } appBits += 8; if (Htn[j] > Hmax) Hmax = Htn[j]; if (Vtn[j] > Vmax) Vmax = Vtn[j]; } if (Hmax == 0 || Vmax == 0) { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Thumbnail Hmax == 0 || Vmax == 0"); return (JPEGDEC_UNSUPPORTED); } #ifdef JPEGDEC_ERROR_RESILIENCE 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 { /* check if fill needed */ if (errorResilienceThumb) { pImageInfo->outputHeightThumb -= 16; pImageInfo->displayHeightThumb = pImageInfo->outputHeightThumb; } } #endif /* JPEGDEC_ERROR_RESILIENCE */ /* 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 (PTR_JPGC->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 (PTR_JPGC->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 { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Thumbnail Unsupported YCbCr format"); return (JPEGDEC_UNSUPPORTED); } PTR_JPGC->info.initThumb = 1; initThumb = 1; break; case SOS: /* SOS length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* check if interleaved or non-ibnterleaved */ NsThumb = JpegDecGetByte(&(stream)); if (NsThumb == MIN_NUMBER_OF_COMPONENTS && pImageInfo->outputFormatThumb != JPEGDEC_YCbCr400 && pImageInfo->codingModeThumb == JPEGDEC_BASELINE) { pImageInfo->codingModeThumb = PTR_JPGC->info.operationTypeThumb = JPEGDEC_NONINTERLEAVED; } /* jump over SOS header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } if ((stream.readBits + 8) < (8 * stream.streamLength)) { PTR_JPGC->info.init = 1; init = 1; } else { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Needs to increase input buffer"); return (JPEGDEC_INCREASE_INPUT_BUFFER); } break; case DQT: /* DQT length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR) { errorCode = 1; break; } /* jump over DQT header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } appBits += (headerLength * 8); break; case DHT: /* DHT length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR) { errorCode = 1; break; } /* jump over DHT header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } appBits += (headerLength * 8); break; case DRI: /* DRI length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR) { errorCode = 1; break; } /* jump over DRI header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.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 = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR) { errorCode = 1; break; } /* jump over APPn header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } appBits += (headerLength * 8); break; case DNL: /* DNL length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR) { errorCode = 1; break; } /* jump over DNL header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } appBits += (headerLength * 8); break; case COM: /* COM length */ headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR) { errorCode = 1; break; } /* jump over COM header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } appBits += (headerLength * 8); break; /* unsupported coding styles */ 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: JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR: Unsupported coding styles"); return (JPEGDEC_UNSUPPORTED); default: break; } if (PTR_JPGC->info.initThumb && initThumb) { /* flush the rest of thumbnail data */ if (JpegDecFlushBits (&(stream), ((appLength * 8) - appBits)) == STRM_ERROR) { errorCode = 1; break; } stream.appnFlag = 0; break; } } else { if (!PTR_JPGC->info.initThumb && pDecIn->bufferSize) return (JPEGDEC_INCREASE_INPUT_BUFFER); else return (JPEGDEC_STRM_ERROR); } } break; } else { appBits += 8; pImageInfo->thumbnailType = JPEGDEC_THUMBNAIL_NOT_SUPPORTED_FORMAT; stream.appnFlag = 1; if (JpegDecFlushBits (&(stream), ((appLength * 8) - appBits)) == STRM_ERROR) { errorCode = 1; break; } stream.appnFlag = 0; break; } } else { /* version */ pImageInfo->version = JpegDecGet2Bytes(&(stream)); appBits += 16; /* units */ currentByte = JpegDecGetByte(&(stream)); 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 = JpegDecGet2Bytes(&(stream)); appBits += 16; /* Ydensity */ pImageInfo->yDensity = JpegDecGet2Bytes(&(stream)); appBits += 16; /* jump over rest of header data */ stream.appnFlag = 1; if (JpegDecFlushBits(&(stream), ((appLength * 8) - appBits)) == STRM_ERROR) { errorCode = 1; break; } 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: /* APPn length */ //JPEGDEC_API_TRC("JpegDecGetImageInfo get other APP\n"); headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* jump over APPn header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } break; case DNL: /* DNL length */ //JPEGDEC_API_TRC("JpegDecGetImageInfo get DNL\n"); headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* jump over DNL header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } break; case COM: headerLength = JpegDecGet2Bytes(&(stream)); if (headerLength == STRM_ERROR || ((stream.readBits + ((headerLength * 8) - 16)) > (8 * stream.streamLength))) { errorCode = 1; break; } /* jump over COM header */ if (headerLength != 0) { stream.readBits += ((headerLength * 8) - 16); stream.pCurrPos += (((headerLength * 8) - 16) / 8); } break; /* unsupported coding styles */ 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: JPEGDEC_API_TRC("JpegDecGetImageInfo error Unsupported coding styles"); return (JPEGDEC_UNSUPPORTED); default: break; } if (PTR_JPGC->info.init && init) break; if (errorCode) { if (pDecIn->bufferSize) { JPEGDEC_API_TRC("JpegDecGetImageInfo Image info failed!"); return (JPEGDEC_INCREASE_INPUT_BUFFER); } else { JPEGDEC_API_TRC("JpegDecGetImageInfo Stream error"); return (JPEGDEC_STRM_ERROR); } } } else { JPEGDEC_API_TRC("JpegDecGetImageInfo Could not get marker"); if (!PTR_JPGC->info.init) return (JPEGDEC_INCREASE_INPUT_BUFFER); else return (JPEGDEC_STRM_ERROR); } } if (PTR_JPGC->info.init) { if (pDecIn->bufferSize) PTR_JPGC->info.initBufferSize = pDecIn->bufferSize; //JPEGDEC_API_TRC("JpegDecGetImageInfo OK\n"); return (JPEGDEC_OK); } else { JPEGDEC_API_TRC("JpegDecGetImageInfo ERROR\n"); return (JPEGDEC_ERROR); } } /*------------------------------------------------------------------------------ Function name: JpegDecDecode Functional description: Decode JFIF Inputs: JpegDecInst decInst jpeg decoder instance JpegDecInput *pDecIn pointer to structure where the decoder stores input information JpegDecOutput *pDecOut pointer to structure where the decoder stores output frame information Outputs: JPEGDEC_FRAME_READY JPEGDEC_PARAM_ERROR JPEGDEC_INVALID_STREAM_LENGTH JPEGDEC_INVALID_INPUT_BUFFER_SIZE JPEGDEC_UNSUPPORTED JPEGDEC_ERROR JPEGDEC_STRM_ERROR JPEGDEC_HW_BUS_ERROR JPEGDEC_DWL_HW_TIMEOUT JPEGDEC_SYSTEM_ERROR JPEGDEC_HW_RESERVED JPEGDEC_STRM_PROCESSED ------------------------------------------------------------------------------*/ JpegDecRet JpegDecDecode(JpegDecInst decInst, JpegDecInput * pDecIn, JpegDecOutput * pDecOut) { JpegDecContainer* PTR_JPGC = ((JpegDecContainer *) decInst); FrameInfo *JPG_FRM = &PTR_JPGC->frame; DecInfo *JPG_INFO = &PTR_JPGC->info; RK_S32 dwlret = -1; RK_U32 i = 0; RK_U32 currentByte = 0; RK_U32 currentBytes = 0; RK_U32 appLength = 0; RK_U32 appBits = 0; RK_U32 asic_status = 0; RK_U32 HINTdec = 0; RK_U32 asicSliceBit = 0; RK_U32 intDec = 0; RK_U32 currentPos = 0; RK_U32 endOfImage = 0; RK_U32 nonInterleavedRdy = 0; JpegDecRet infoRet; JpegDecRet retCode; /* Returned code container */ JpegDecImageInfo infoTmp; RK_U32 mcuSizeDivider = 0; RK_U32 findhufftable = 0; /* check null */ if (decInst == NULL || pDecIn == NULL || RK70_CHECK_VIRTUAL_ADDRESS(pDecIn->streamBuffer.pVirtualAddress) /*|| RK70_CHECK_BUS_ADDRESS(pDecIn->streamBuffer.busAddress)*/ || pDecOut == NULL) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: NULL parameter"); return (JPEGDEC_PARAM_ERROR); } /* check image decoding type,full image or thumbnail */ if (pDecIn->decImageType != 0 && pDecIn->decImageType != 1) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: decImageType"); return (JPEGDEC_PARAM_ERROR); } /* check user allocated null */ if ((pDecIn->pictureBufferY.pVirtualAddress == NULL && pDecIn->pictureBufferY.busAddress != 0) || (pDecIn->pictureBufferY.pVirtualAddress != NULL && pDecIn->pictureBufferY.busAddress == 0) || (pDecIn->pictureBufferCbCr.pVirtualAddress == NULL && pDecIn->pictureBufferCbCr.busAddress != 0) || (pDecIn->pictureBufferCbCr.pVirtualAddress != NULL && pDecIn->pictureBufferCbCr.busAddress == 0)) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: NULL parameter"); return (JPEGDEC_PARAM_ERROR); } /* Check the stream lenth */ if (pDecIn->streamLength < 1) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: pDecIn->streamLength"); return (JPEGDEC_INVALID_STREAM_LENGTH); } /* check the input buffer settings ==> * checks are discarded for last buffer */ if (!PTR_JPGC->info.streamEndFlag) { /* Check the stream lenth */ if (!PTR_JPGC->info.inputBufferEmpty && (pDecIn->streamLength > DEC_RK70_MAX_STREAM) && (pDecIn->bufferSize < JPEGDEC_RK70_MIN_BUFFER || pDecIn->bufferSize > JPEGDEC_RK70_MAX_BUFFER)) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: pDecIn->bufferSize"); return (JPEGDEC_INVALID_INPUT_BUFFER_SIZE); } /* Check the stream buffer size */ if (!PTR_JPGC->info.inputBufferEmpty && pDecIn->bufferSize && (pDecIn->bufferSize < JPEGDEC_RK70_MIN_BUFFER || pDecIn->bufferSize > JPEGDEC_RK70_MAX_BUFFER)) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: pDecIn->bufferSize"); return (JPEGDEC_INVALID_INPUT_BUFFER_SIZE); } if (!PTR_JPGC->info.inputBufferEmpty && PTR_JPGC->info.init && (pDecIn->bufferSize < PTR_JPGC->info.initBufferSize)) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Increase input buffer size!\n"); return (JPEGDEC_INVALID_INPUT_BUFFER_SIZE); } } if (!PTR_JPGC->info.init && !PTR_JPGC->info.SliceReadyForPause && !PTR_JPGC->info.inputBufferEmpty) { infoRet = JpegDecGetImageInfo(decInst, pDecIn, &infoTmp); if (infoRet != JPEGDEC_OK) { JPEGDEC_API_TRC(("JpegDecDecode# ERROR: Image info failed!")); return (infoRet); } } /* Store the stream parameters */ if (PTR_JPGC->info.progressiveScanReady == 0 && PTR_JPGC->info.nonInterleavedScanReady == 0) { PTR_JPGC->stream.bitPosInByte = 0; PTR_JPGC->stream.pCurrPos = (RK_U8 *) pDecIn->streamBuffer.pVirtualAddress; PTR_JPGC->stream.streamBus = pDecIn->streamBuffer.busAddress; PTR_JPGC->stream.pStartOfStream = (RK_U8 *) pDecIn->streamBuffer.pVirtualAddress; PTR_JPGC->stream.readBits = 0; PTR_JPGC->stream.streamLength = pDecIn->streamLength; PTR_JPGC->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 { PTR_JPGC->image.headerReady = 0; } /* set mcu/slice value */ PTR_JPGC->info.sliceMbSetValue = pDecIn->sliceMbSet; /* check HW supported features */ if (!PTR_JPGC->is8190) { /* return if not valid HW and unsupported operation type */ if (PTR_JPGC->info.operationType == JPEGDEC_NONINTERLEAVED || PTR_JPGC->info.operationType == JPEGDEC_PROGRESSIVE) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Operation type not supported"); return (JPEGDEC_UNSUPPORTED); } if (PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr400 || PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr440 || PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr444_SEMIPLANAR) mcuSizeDivider = 2; else mcuSizeDivider = 1; /* check slice config */ if ((pDecIn->sliceMbSet * (JPG_FRM->numMcuInRow / mcuSizeDivider)) > PTR_JPGC->maxSupportedSliceSize) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: sliceMbSet > JPEGDEC_MAX_SLICE_SIZE"); return (JPEGDEC_PARAM_ERROR); } /* check frame size */ if ((!pDecIn->sliceMbSet) && JPG_FRM->numMcuInFrame > PTR_JPGC->maxSupportedSliceSize) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: mcuInFrame > JPEGDEC_MAX_SLICE_SIZE"); return (JPEGDEC_PARAM_ERROR); } } else { /* check if fuse was burned */ if (PTR_JPGC->fuseBurned) { /* return if not valid HW and unsupported operation type */ if (PTR_JPGC->info.operationType == JPEGDEC_PROGRESSIVE) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Operation type not supported"); return (JPEGDEC_UNSUPPORTED); } } /* check slice config */ if ((pDecIn->sliceMbSet && pDecIn->decImageType == JPEGDEC_IMAGE && PTR_JPGC->info.operationType != JPEGDEC_BASELINE) || (pDecIn->sliceMbSet && pDecIn->decImageType == JPEGDEC_THUMBNAIL && PTR_JPGC->info.operationTypeThumb != JPEGDEC_BASELINE)) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Slice mode not supported for this operation type"); return (JPEGDEC_SLICE_MODE_UNSUPPORTED); } /* check if frame size over 16M */ if ((!pDecIn->sliceMbSet) && ((JPG_FRM->hwX * JPG_FRM->hwY) > JPEGDEC_MAX_PIXEL_AMOUNT)) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Resolution > 16M ==> use slice mode!"); return (JPEGDEC_PARAM_ERROR); } if (PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr400 || PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr440 || PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr444_SEMIPLANAR) mcuSizeDivider = 2; else mcuSizeDivider = 1; /* check slice config */ if ((pDecIn->sliceMbSet * (JPG_FRM->numMcuInRow / mcuSizeDivider)) > PTR_JPGC->maxSupportedSliceSize) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: sliceMbSet > JPEGDEC_MAX_SLICE_SIZE"); return (JPEGDEC_PARAM_ERROR); } } /* check slice size */ if (pDecIn->sliceMbSet && !PTR_JPGC->info.SliceReadyForPause && !PTR_JPGC->info.inputBufferEmpty) { if (PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr400 || PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr440 || PTR_JPGC->info.getInfoYCbCrMode == JPEGDEC_YCbCr444_SEMIPLANAR) mcuSizeDivider = 2; else mcuSizeDivider = 1; if ((pDecIn->sliceMbSet * (JPG_FRM->numMcuInRow / mcuSizeDivider)) > JPG_FRM->numMcuInFrame) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: (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 (PTR_JPGC->info.inputBufferEmpty) { /* Store the stream parameters */ PTR_JPGC->stream.bitPosInByte = 0; PTR_JPGC->stream.pCurrPos = (RK_U8 *) pDecIn->streamBuffer.pVirtualAddress; PTR_JPGC->stream.streamBus = pDecIn->streamBuffer.busAddress; PTR_JPGC->stream.pStartOfStream = (RK_U8 *) pDecIn->streamBuffer.pVirtualAddress; /* update hw parameters */ PTR_JPGC->info.inputStreaming = 1; if (pDecIn->bufferSize) PTR_JPGC->info.inputBufferLen = pDecIn->bufferSize; else PTR_JPGC->info.inputBufferLen = pDecIn->streamLength; /* decoded stream */ PTR_JPGC->info.decodedStreamLen += PTR_JPGC->info.inputBufferLen; } /* update user allocated output */ PTR_JPGC->info.givenOutLuma.vir_addr = pDecIn->pictureBufferY.pVirtualAddress; PTR_JPGC->info.givenOutLuma.phy_addr = pDecIn->pictureBufferY.busAddress; PTR_JPGC->info.givenOutChroma.vir_addr = pDecIn->pictureBufferCbCr.pVirtualAddress; PTR_JPGC->info.givenOutChroma.phy_addr = pDecIn->pictureBufferCbCr.busAddress; PTR_JPGC->info.givenOutChroma2.vir_addr = pDecIn->pictureBufferCr.pVirtualAddress; PTR_JPGC->info.givenOutChroma2.phy_addr = pDecIn->pictureBufferCr.busAddress; if (PTR_JPGC->info.progressiveFinish) { /* output set */ if (PTR_JPGC->ppInstance == NULL) { pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.outLuma.vir_addr; ASSERT(pDecOut->outputPictureY.pVirtualAddress); /* output set */ pDecOut->outputPictureY.busAddress = PTR_JPGC->info.outLuma.phy_addr; ASSERT(pDecOut->outputPictureY.busAddress); /* if not grayscale */ if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.outChroma.vir_addr; ASSERT(pDecOut->outputPictureCbCr.pVirtualAddress); pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.outChroma.phy_addr; ASSERT(pDecOut->outputPictureCbCr.busAddress); pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.outChroma2.vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.outChroma2.phy_addr; } } printf("JpegDecInitHWEmptyScan ******************\n"); JpegDecInitHWEmptyScan(PTR_JPGC, PTR_JPGC->info.pfCompId); { VPU_CMD_TYPE cmd; RK_S32 len; dwlret = VPUClientWaitResult(PTR_JPGC->socket, PTR_JPGC->jpegRegs, DEC_RK70_REGISTERS, &cmd, &len); if ((VPU_SUCCESS != dwlret) || (cmd != VPU_SEND_CONFIG_ACK_OK)) dwlret = DWL_HW_WAIT_ERROR; } ASSERT(dwlret == DWL_HW_WAIT_OK); JpegRefreshRegs(PTR_JPGC); asic_status = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_IRQ_STAT); ASSERT(asic_status == 1); i = PTR_JPGC->info.pfCompId + 1; while (i < 3 && PTR_JPGC->info.pfNeeded[i] == 0) i++; if (i == 3) { PTR_JPGC->info.progressiveFinish = 0; return (JPEGDEC_FRAME_READY); } else { PTR_JPGC->info.pfCompId = i; return (JPEGDEC_SCAN_PROCESSED); } } printf("hw_decode %d******************\n", __LINE__); /* check if input streaming used */ if (!PTR_JPGC->info.SliceReadyForPause && !PTR_JPGC->info.inputBufferEmpty && pDecIn->bufferSize) { PTR_JPGC->info.inputStreaming = 1; PTR_JPGC->info.inputBufferLen = pDecIn->bufferSize; PTR_JPGC->info.decodedStreamLen += PTR_JPGC->info.inputBufferLen; } /* find markers and go ! */ do { /* if slice mode/slice done return to hw handling */ if (PTR_JPGC->image.headerReady && PTR_JPGC->info.SliceReadyForPause) break; /* Look for marker prefix byte from stream */ if ((currentByte == 0xFF) || (JpegDecGetByte(&(PTR_JPGC->stream)) == 0xFF)) { currentByte = JpegDecGetByte(&(PTR_JPGC->stream)); /* switch to certain header decoding */ switch (currentByte) { case 0x00: break; case SOF0: case SOF2: /* Baseline/Progressive */ PTR_JPGC->frame.codingType = currentByte; /* Set operation type */ if (PTR_JPGC->frame.codingType == SOF0) PTR_JPGC->info.operationType = JPEGDEC_BASELINE; else PTR_JPGC->info.operationType = JPEGDEC_PROGRESSIVE; retCode = JpegDecDecodeFrameHdr(PTR_JPGC); if (retCode != JPEGDEC_OK) { if (retCode == JPEGDEC_STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Stream error \n"); return (retCode); } else { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: JpegDecDecodeFrameHdr err \n"); return (retCode); } } break; /* Start of Scan */ case SOS: /* reset image ready */ PTR_JPGC->image.imageReady = 0; retCode = JpegDecDecodeScan(PTR_JPGC); PTR_JPGC->image.headerReady = 1; if (retCode != JPEGDEC_OK) { if (retCode == JPEGDEC_STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Stream error \n"); return (retCode); } else { JPEGDEC_API_TRC ("JpegDecDecode# JpegDecDecodeScan err\n"); return (retCode); } } if (PTR_JPGC->stream.bitPosInByte) { /* delete stuffing bits */ currentByte = (8 - PTR_JPGC->stream.bitPosInByte); if (JpegDecFlushBits (&(PTR_JPGC->stream), 8 - PTR_JPGC->stream.bitPosInByte) == STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Stream error \n"); return (JPEGDEC_STRM_ERROR); } } JPEGDEC_API_TRC("JpegDecDecode# Stuffing bits deleted\n"); if (PTR_JPGC->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; /* Start of Huffman tables */ case DHT: retCode = JpegDecDecodeHuffmanTables(PTR_JPGC); if (retCode != JPEGDEC_OK) { if (retCode == JPEGDEC_STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Stream error\n"); return (retCode); } else { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: JpegDecDecodeHuffmanTables err\n"); return (retCode); } } findhufftable = 1; break; /* start of Quantisation Tables */ case DQT: retCode = JpegDecDecodeQuantTables(PTR_JPGC); if (retCode != JPEGDEC_OK) { if (retCode == JPEGDEC_STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Stream error\n"); return (retCode); } else { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: JpegDecDecodeQuantTables err\n"); return (retCode); } } break; /* Start of Image */ case SOI: /* no actions needed, continue */ break; /* End of Image */ case EOI: if (PTR_JPGC->image.imageReady) { JPEGDEC_API_TRC("JpegDecDecode# EOI: OK\n"); return (JPEGDEC_FRAME_READY); } else { JPEGDEC_API_TRC("JpegDecDecode# ERROR: EOI: NOK\n"); return (JPEGDEC_ERROR); } /* Define Restart Interval */ case DRI: currentBytes = JpegDecGet2Bytes(&(PTR_JPGC->stream)); if (currentBytes == STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Read bits\n"); return (JPEGDEC_STRM_ERROR); } PTR_JPGC->frame.Ri = JpegDecGet2Bytes(&(PTR_JPGC->stream)); PTR_JPGC->dri_en = 0xffd0; //find dri break; /* Restart with modulo 8 count m */ case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7: /* initialisation of DC predictors to zero value !!! */ for (i = 0; i < MAX_NUMBER_OF_COMPONENTS; i++) { PTR_JPGC->scan.pred[i] = 0; } break; /* unsupported features */ case DNL: 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: return (JPEGDEC_UNSUPPORTED); /* application data & comments */ case APP0: //JPEGDEC_API_TRC("JpegDecDecode# APP0 in Decode"); /* APP0 Extended Thumbnail */ if (pDecIn->decImageType == JPEGDEC_THUMBNAIL) { /* reset */ appBits = 0; appLength = 0; /* length */ appLength = JpegDecGet2Bytes(&(PTR_JPGC->stream)); appBits += 16; /* check identifier */ currentBytes = JpegDecGet2Bytes(&(PTR_JPGC->stream)); appBits += 16; if (currentBytes != 0x4A46) { PTR_JPGC->stream.appnFlag = 1; if (JpegDecFlushBits (&(PTR_JPGC->stream), ((appLength * 8) - appBits)) == STRM_ERROR) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Stream error\n"); return (JPEGDEC_STRM_ERROR); } PTR_JPGC->stream.appnFlag = 0; break; } currentBytes = JpegDecGet2Bytes(&(PTR_JPGC->stream)); appBits += 16; if (currentBytes != 0x5858) { PTR_JPGC->stream.appnFlag = 1; if (JpegDecFlushBits (&(PTR_JPGC->stream), ((appLength * 8) - appBits)) == STRM_ERROR) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Stream error\n"); return (JPEGDEC_STRM_ERROR); } PTR_JPGC->stream.appnFlag = 0; break; } currentByte = JpegDecGetByte(&(PTR_JPGC->stream)); appBits += 8; if (currentByte != 0x00) { PTR_JPGC->stream.appnFlag = 1; if (JpegDecFlushBits (&(PTR_JPGC->stream), ((appLength * 8) - appBits)) == STRM_ERROR) { JPEGDEC_API_TRC ("JpegDecDecode# ERROR: Stream error"); return (JPEGDEC_STRM_ERROR); } PTR_JPGC->stream.appnFlag = 0; break; } /* extension code */ currentByte = JpegDecGetByte(&(PTR_JPGC->stream)); PTR_JPGC->stream.appnFlag = 0; if (currentByte != JPEGDEC_THUMBNAIL_JPEG) { JPEGDEC_API_TRC(("JpegDecDecode# ERROR: thumbnail unsupported")); return (JPEGDEC_UNSUPPORTED); } /* thumbnail mode */ JPEGDEC_API_TRC("JpegDecDecode# Thumbnail data ok!"); PTR_JPGC->stream.thumbnail = 1; break; } else { /* Flush unsupported thumbnail */ currentBytes = JpegDecGet2Bytes(&(PTR_JPGC->stream)); PTR_JPGC->stream.appnFlag = 1; if (JpegDecFlushBits (&(PTR_JPGC->stream), ((currentBytes - 2) * 8)) == STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Stream error"); return (JPEGDEC_STRM_ERROR); } PTR_JPGC->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: currentBytes = JpegDecGet2Bytes(&(PTR_JPGC->stream)); if (currentBytes == STRM_ERROR) { JPEGDEC_API_TRC("JpegDecDecode# ERROR: Read bits "); return (JPEGDEC_STRM_ERROR); } /* jump over not supported header */ if (currentBytes != 0) { PTR_JPGC->stream.readBits += ((currentBytes * 8) - 16); PTR_JPGC->stream.pCurrPos += (((currentBytes * 8) - 16) / 8); } break; default: break; } } else { if (currentByte == 0xFFFFFFFF) { break; } } if (PTR_JPGC->image.headerReady) break; } while ((PTR_JPGC->stream.readBits >> 3) <= PTR_JPGC->stream.streamLength); if (!findhufftable) { JpegDefaultHuffmanTables(PTR_JPGC); } retCode = JPEGDEC_OK; /* Handle decoded image here */ if (PTR_JPGC->image.headerReady) { /* loop until decoding control should return for user */ do { if (PTR_JPGC->ppInstance != NULL) { PTR_JPGC->ppControl.usePipeline = 1; } /* check if we had to load imput buffer or not */ if (!PTR_JPGC->info.inputBufferEmpty) { /* if slice mode ==> set slice height */ if (PTR_JPGC->info.sliceMbSetValue && PTR_JPGC->ppControl.usePipeline == 0) { JpegDecSliceSizeCalculation(PTR_JPGC); ALOGV(" JpegDecSliceSizeCalculation sliceHeight is %d.PTR_JPGC->info.sliceMbSetValue is %d\n", PTR_JPGC->info.sliceHeight, PTR_JPGC->info.sliceMbSetValue); } /* Start HW or continue after pause */ if (!PTR_JPGC->info.SliceReadyForPause) { if (!PTR_JPGC->info.progressiveScanReady || PTR_JPGC->info.nonInterleavedScanReady) { retCode = JpegDecInitHW(PTR_JPGC); PTR_JPGC->info.nonInterleavedScanReady = 0; if (retCode != JPEGDEC_OK) { /* return JPEGDEC_HW_RESERVED */ return retCode; } } else { JPEGDEC_API_TRC ("JpegDecDecode# Continue HW decoding after progressive scan ready\n"); JpegDecInitHWProgressiveContinue(PTR_JPGC); PTR_JPGC->info.progressiveScanReady = 0; } } else { JPEGDEC_API_TRC ("JpegDecDecode# Continue HW decoding after slice ready\n"); JpegDecInitHWContinue(PTR_JPGC); } PTR_JPGC->info.SliceCount++; } else { JPEGDEC_API_TRC("JpegDecDecode# Continue HW decoding after input buffer has been loaded\n"); JpegDecInitHWInputBuffLoad(PTR_JPGC); /* buffer loaded ==> reset flag */ PTR_JPGC->info.inputBufferEmpty = 0; } #ifdef JPEGDEC_PERFORMANCE dwlret = DWL_HW_WAIT_OK; #else /* wait hw ready */ { VPU_CMD_TYPE cmd; RK_S32 len; dwlret = VPUClientWaitResult(PTR_JPGC->socket, PTR_JPGC->jpegRegs, DEC_RK70_REGISTERS, &cmd, &len); if ((VPU_SUCCESS != dwlret) || (cmd != VPU_SEND_CONFIG_ACK_OK)) dwlret = DWL_HW_WAIT_ERROR; } printf("VPUClientWaitResult 0 mjpeg! \n"); //ALOGE("after reg[1]=0x%x\n",PTR_JPGC->jpegRegs[1]); if (0){ int i; for (i = 0; i < 159; i++) { printf("after reg[%d]=0x%08x\n", i, PTR_JPGC->jpegRegs[i]); } } #endif /* #ifdef JPEGDEC_PERFORMANCE */ /* Refresh regs */ JpegRefreshRegs(PTR_JPGC); if (dwlret == DWL_HW_WAIT_OK) { /* check && reset status */ asic_status = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_IRQ_STAT); //ALOGE("asic_status : 0x%x", asic_status); if (asic_status & JPEGDEC_RK70_IRQ_BUS_ERROR) { JPEGDEC_API_TRC ("JpegDecDecode# JPEGDEC_RK70_IRQ_BUS_ERROR"); /* clear interrupts */ JPEGDEC_CLEAR_IRQ; /* update asicRunning */ PTR_JPGC->asicRunning = 0; PTR_JPGC->image.imageReady = 0; PTR_JPGC->image.headerReady = 0; //clear status for next decoder, add by wjm return JPEGDEC_HW_BUS_ERROR; } else if (asic_status & JPEGDEC_RK70_IRQ_STREAM_ERROR || asic_status & JPEGDEC_RK70_IRQ_TIMEOUT) { if (asic_status & JPEGDEC_RK70_IRQ_STREAM_ERROR) JPEGDEC_API_TRC ("JpegDecDecode# JPEGDEC_RK70_IRQ_STREAM_ERROR \n"); else JPEGDEC_API_TRC ("JpegDecDecode# JPEGDEC_RK70_IRQ_TIMEOUT \n"); /* clear interrupts */ JPEGDEC_CLEAR_IRQ; /* update asicRunning */ PTR_JPGC->asicRunning = 0; /* output set */ if (PTR_JPGC->ppInstance == NULL) { pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.outLuma.vir_addr; ASSERT(pDecOut->outputPictureY.pVirtualAddress); /* output set */ pDecOut->outputPictureY.busAddress = PTR_JPGC->info.outLuma.phy_addr; ASSERT(pDecOut->outputPictureY.busAddress); /* if not grayscale */ if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.outChroma.vir_addr; ASSERT(pDecOut->outputPictureCbCr.pVirtualAddress); pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.outChroma.phy_addr; ASSERT(pDecOut->outputPictureCbCr.busAddress); pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.outChroma2.vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.outChroma2.phy_addr; } } PTR_JPGC->image.imageReady = 0; PTR_JPGC->image.headerReady = 0; //clear status for next decoder, add by wjm if ((asic_status & JPEGDEC_RK70_IRQ_TIMEOUT) && (PTR_JPGC->frame.Y % 16) && (PTR_JPGC->info.yCbCrMode == JPEGDEC_YUV422 || PTR_JPGC->info.yCbCrMode == JPEGDEC_YUV444 || PTR_JPGC->info.yCbCrMode == JPEGDEC_YUV411)) { return JPEGDEC_FRAME_READY; } else { return JPEGDEC_STRM_ERROR; } } else if (asic_status & JPEGDEC_RK70_IRQ_BUFFER_EMPTY) { /* check if frame is ready */ if (!(asic_status & JPEGDEC_RK70_IRQ_DEC_RDY)) { JPEGDEC_API_TRC ("JpegDecDecode# JPEGDEC_RK70_IRQ_BUFFER_EMPTY/STREAM PROCESSED"); /* clear interrupts */ rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_BUFFER_INT, 0); /* flag to load buffer */ PTR_JPGC->info.inputBufferEmpty = 1; /* check if all stream should be processed with the * next buffer ==> may affect to some API checks */ if ((PTR_JPGC->info.decodedStreamLen + PTR_JPGC->info.inputBufferLen) >= PTR_JPGC->stream.streamLength) { PTR_JPGC->info.streamEndFlag = 1; } /* output set */ if (PTR_JPGC->ppInstance == NULL) { pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.outLuma.vir_addr; ASSERT(pDecOut->outputPictureY.pVirtualAddress); /* output set */ pDecOut->outputPictureY.busAddress = PTR_JPGC->info.outLuma.phy_addr; ASSERT(pDecOut->outputPictureY.busAddress); /* if not grayscale */ if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.outChroma.vir_addr; ASSERT(pDecOut->outputPictureCbCr. pVirtualAddress); pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.outChroma.phy_addr; ASSERT(pDecOut->outputPictureCbCr.busAddress); pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.outChroma2.vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.outChroma2.phy_addr; } } return JPEGDEC_STRM_PROCESSED; } } rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_RDY_INT, 0); HINTdec = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_IRQ); if (HINTdec) { JPEGDEC_API_TRC("JpegDecDecode# CLEAR interrupt"); rk_SetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_IRQ, 0); } /* check if slice ready */ asicSliceBit = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_JPEG_SLICE_H); intDec = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_SLICE_INT); /* slice ready ==> reset interrupt */ if (asicSliceBit && intDec) { /* if RK70 pp not in use */ if (PTR_JPGC->ppInstance == NULL) PTR_JPGC->info.SliceReadyForPause = 1; else PTR_JPGC->info.SliceReadyForPause = 0; if (PTR_JPGC->ppInstance != NULL && !PTR_JPGC->ppControl.usePipeline) { PTR_JPGC->info.SliceReadyForPause = 1; } /* if user allocated memory return given base */ if (PTR_JPGC->info.userAllocMem == 1 && PTR_JPGC->info.SliceReadyForPause == 1) { /* output addresses */ pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.givenOutLuma.vir_addr; pDecOut->outputPictureY.busAddress = PTR_JPGC->info.givenOutLuma.phy_addr; if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.givenOutChroma.vir_addr; pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.givenOutChroma.phy_addr; pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.givenOutChroma2.vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.givenOutChroma2.phy_addr; } } /* if not user allocated memory return slice base */ if (PTR_JPGC->info.userAllocMem == 0 && PTR_JPGC->info.SliceReadyForPause == 1) { /* output addresses */ pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.outLuma.vir_addr; pDecOut->outputPictureY.busAddress = PTR_JPGC->info.outLuma.phy_addr; if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.outChroma.vir_addr; pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.outChroma.phy_addr; pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.outChroma2.vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.outChroma2.phy_addr; } } /* No slice output in case decoder + PP (no pipeline) */ if (PTR_JPGC->ppInstance != NULL && PTR_JPGC->ppControl.usePipeline == 0) { /* output addresses */ pDecOut->outputPictureY.pVirtualAddress = NULL; pDecOut->outputPictureY.busAddress = 0; if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = NULL; pDecOut->outputPictureCbCr.busAddress = 0; pDecOut->outputPictureCr.pVirtualAddress = NULL; pDecOut->outputPictureCr.busAddress = 0; } JPEGDEC_API_TRC(("JpegDecDecode# Decoder + PP (Rotation/Flip), Slice ready\n")); /* PP not in pipeline, continue do <==> while */ PTR_JPGC->info.noSliceIrqForUser = 1; } else { JPEGDEC_API_TRC(("JpegDecDecode# Slice ready")); return JPEGDEC_SLICE_READY; } } else { if (PTR_JPGC->info.operationType == JPEGDEC_PROGRESSIVE || PTR_JPGC->info.operationType == JPEGDEC_NONINTERLEAVED) { currentPos = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_RLC_VLC_BASE); /* update input buffer address */ PTR_JPGC->stream.pCurrPos = ((RK_U8 *) currentPos - 10); PTR_JPGC->stream.bitPosInByte = 0; PTR_JPGC->stream.readBits = ((PTR_JPGC->stream.pCurrPos - PTR_JPGC->stream.pStartOfStream) * 8); /* default if data ends */ endOfImage = 1; /* check if last scan is decoded */ for (i = 0; i < ((PTR_JPGC->stream.streamLength - (PTR_JPGC->stream.readBits / 8))); i++) { currentByte = PTR_JPGC->stream.pCurrPos[i]; if (currentByte == 0xFF) { currentByte = PTR_JPGC->stream.pCurrPos[i + 1]; if (currentByte == 0xD9) { endOfImage = 1; break; } else if (currentByte == 0xC4 || currentByte == 0xDA) { endOfImage = 0; break; } } } currentByte = 0; PTR_JPGC->info.SliceCount = 0; PTR_JPGC->info.SliceReadyForPause = 0; /* if not the last scan of the stream */ if (endOfImage == 0) { /* output set */ if (PTR_JPGC->ppInstance == NULL && !PTR_JPGC->info.noSliceIrqForUser) { pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.outLuma.vir_addr; ASSERT(pDecOut->outputPictureY.pVirtualAddress); /* output set */ pDecOut->outputPictureY.busAddress = PTR_JPGC->info.outLuma.phy_addr; ASSERT(pDecOut->outputPictureY.busAddress); /* if not grayscale */ if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.outChroma.vir_addr; ASSERT(pDecOut->outputPictureCbCr. pVirtualAddress); pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.outChroma.phy_addr; ASSERT(pDecOut->outputPictureCbCr. busAddress); pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.outChroma2. vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.outChroma2.phy_addr; } } /* PP not in pipeline, continue do <==> while */ PTR_JPGC->info.noSliceIrqForUser = 0; if (PTR_JPGC->info.operationType == JPEGDEC_PROGRESSIVE) PTR_JPGC->info.progressiveScanReady = 1; else PTR_JPGC->info.nonInterleavedScanReady = 1; /* return control to application if progressive */ if (PTR_JPGC->info.operationType != JPEGDEC_NONINTERLEAVED) { /* non-interleaved scan ==> no output */ if (PTR_JPGC->info.nonInterleaved == 0) PTR_JPGC->info.noSliceIrqForUser = 1; else { JPEGDEC_API_TRC ("JpegDecDecode# SCAN PROCESSED"); return (JPEGDEC_SCAN_PROCESSED); } } else { /* set decoded component */ PTR_JPGC->info.components[PTR_JPGC->info. componentId] = 1; /* check if we have decoded all components */ if (PTR_JPGC->info.components[0] == 1 && PTR_JPGC->info.components[1] == 1 && PTR_JPGC->info.components[2] == 1) { /* continue decoding next scan */ PTR_JPGC->info.noSliceIrqForUser = 0; nonInterleavedRdy = 0; } else { /* continue decoding next scan */ PTR_JPGC->info.noSliceIrqForUser = 1; nonInterleavedRdy = 0; } } } else { if (PTR_JPGC->info.operationType == JPEGDEC_NONINTERLEAVED) { /* set decoded component */ PTR_JPGC->info.components[PTR_JPGC->info. componentId] = 1; /* check if we have decoded all components */ if (PTR_JPGC->info.components[0] == 1 && PTR_JPGC->info.components[1] == 1 && PTR_JPGC->info.components[2] == 1) { /* continue decoding next scan */ PTR_JPGC->info.noSliceIrqForUser = 0; nonInterleavedRdy = 1; } else { /* continue decoding next scan */ PTR_JPGC->info.noSliceIrqForUser = 1; nonInterleavedRdy = 0; } } } } else { /* PP not in pipeline, continue do <==> while */ PTR_JPGC->info.noSliceIrqForUser = 0; } } /* output set */ if (PTR_JPGC->ppInstance == NULL && !PTR_JPGC->info.noSliceIrqForUser) { pDecOut->outputPictureY.pVirtualAddress = PTR_JPGC->info.outLuma.vir_addr; ASSERT(pDecOut->outputPictureY.pVirtualAddress); /* output set */ pDecOut->outputPictureY.busAddress = PTR_JPGC->info.outLuma.phy_addr; ASSERT(pDecOut->outputPictureY.busAddress); /* if not grayscale */ if (PTR_JPGC->image.sizeChroma) { pDecOut->outputPictureCbCr.pVirtualAddress = PTR_JPGC->info.outChroma.vir_addr; ASSERT(pDecOut->outputPictureCbCr.pVirtualAddress); pDecOut->outputPictureCbCr.busAddress = PTR_JPGC->info.outChroma.phy_addr; ASSERT(pDecOut->outputPictureCbCr.busAddress); pDecOut->outputPictureCr.pVirtualAddress = PTR_JPGC->info.outChroma2.vir_addr; pDecOut->outputPictureCr.busAddress = PTR_JPGC->info.outChroma2.phy_addr; } } if (PTR_JPGC->info.noSliceIrqForUser == 0) { /* update asicRunning */ PTR_JPGC->asicRunning = 0; /* set image ready */ PTR_JPGC->image.imageReady = 1; PTR_JPGC->info.noSliceIrqForUser = 0; } /* get the current stream address */ if (PTR_JPGC->info.operationType == JPEGDEC_PROGRESSIVE || (PTR_JPGC->info.operationType == JPEGDEC_NONINTERLEAVED && nonInterleavedRdy == 0)) { retCode = JpegDecNextScanHdrs(PTR_JPGC); if (retCode != JPEGDEC_OK && retCode != JPEGDEC_FRAME_READY) { /* return */ return retCode; } } } else if (dwlret == DWL_HW_WAIT_TIMEOUT) { JPEGDEC_API_TRC("SCAN: DWL HW TIMEOUT\n"); /* update asicRunning */ PTR_JPGC->asicRunning = 0; return (JPEGDEC_DWL_HW_TIMEOUT); } else if (dwlret == DWL_HW_WAIT_ERROR) { JPEGDEC_API_TRC("SCAN: DWL HW ERROR\n"); /* update asicRunning */ PTR_JPGC->asicRunning = 0; return (JPEGDEC_SYSTEM_ERROR); } } while (!PTR_JPGC->image.imageReady); } if (PTR_JPGC->image.imageReady) { /* reset image status */ PTR_JPGC->image.imageReady = 0; PTR_JPGC->image.headerReady = 0; if (PTR_JPGC->info.operationType == JPEGDEC_BASELINE) { return (JPEGDEC_FRAME_READY); } else { if (endOfImage == 0) return (JPEGDEC_SCAN_PROCESSED); else { if (PTR_JPGC->frame.Nf != 1) { /* determine first component that needs to be cheated */ i = 0; while (i < 3 && PTR_JPGC->info.pfNeeded[i] == 0) i++; if (i == 3) return (JPEGDEC_FRAME_READY); JpegDecInitHWEmptyScan(PTR_JPGC, i++); /* wait hw ready */ { VPU_CMD_TYPE cmd; RK_S32 len; dwlret = VPUClientWaitResult(PTR_JPGC->socket, PTR_JPGC->reghandle, DEC_RK70_REGISTERS, &cmd, &len); if ((VPU_SUCCESS != dwlret) || (cmd != VPU_SEND_CONFIG_ACK_OK)) dwlret = DWL_HW_WAIT_ERROR; } //printf("VPUClientWaitResult 2! \n"); ASSERT(dwlret == DWL_HW_WAIT_OK); JpegRefreshRegs(PTR_JPGC); asic_status = rk_GetRegisterFile(PTR_JPGC->reghandle, HWIF_DEC_IRQ_STAT); ASSERT(asic_status == 1); while (i < 3 && PTR_JPGC->info.pfNeeded[i] == 0) i++; if (i == 3) return (JPEGDEC_FRAME_READY); else { PTR_JPGC->info.progressiveFinish = 1; PTR_JPGC->info.pfCompId = i; return (JPEGDEC_SCAN_PROCESSED); } } else return (JPEGDEC_FRAME_READY); } } } else { JPEGDEC_API_TRC("JpegDecDecode# ERROR\n"); return (JPEGDEC_ERROR); } } /*------------------------------------------------------------------------------ 5.6. Function name: JpegGetAPIVersion Purpose: Returns version information about this API Input: void Output: JpegDecApiVersion ------------------------------------------------------------------------------*/ JpegDecApiVersion JpegGetAPIVersion() { JpegDecApiVersion ver; ver.major = JPG_MAJOR_VERSION; ver.minor = JPG_MINOR_VERSION; //JPEGDEC_API_TRC("JpegGetAPIVersion# OK\n"); return ver; } /*------------------------------------------------------------------------------ 5.7. Function name: JpegDecGetBuild Purpose: Returns the SW and HW build information Input: void Output: JpegDecGetBuild ------------------------------------------------------------------------------*/ JpegDecBuild JpegDecGetBuild(void) { JpegDecBuild ver; VPUHwDecConfig_t hwCfg; DWLmemset(&ver, 0, sizeof(ver)); ver.swBuild = JPG_SW_BUILD; ver.hwBuild = 0x91900000; memset(&hwCfg, 0, sizeof(VPUHwDecConfig_t)); hwCfg.jpegESupport = 1; hwCfg.jpegSupport = 1; // while (VPUGetDecHwCfg(&hwCfg)) // usleep(10); SET_DEC_BUILD_SUPPORT(ver.hwConfig, hwCfg); //JPEGDEC_API_TRC("JpegDecGetBuild# OK\n"); return (ver); }