// SPDX-License-Identifier: LGPL-2.1 OR BSD-3-Clause /* * Copyright (c) 2018, Chips&Media * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "jpuapifunc.h" #include "regdefine.h" #include "jpulog.h" /****************************************************************************** Codec Instance Slot Management ******************************************************************************/ // gGetBits defined but not used //static Uint32 tGetBits(JpgDecInfo *jpg, int endian, int byteCnt); const char lendian[4] = {0x49, 0x49, 0x2A, 0x00}; const char bendian[4] = {0x4D, 0x4D, 0x00, 0x2A}; const char *jfif = "JFIF"; const char *jfxx = "JFXX"; const char *exif = "Exif"; Uint8 sJpuCompInfoTable[5][24] = { { 00, 02, 02, 00, 00, 00, 01, 01, 01, 01, 01, 01, 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00 }, //420 { 00, 02, 01, 00, 00, 00, 01, 01, 01, 01, 01, 01, 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00 }, //422H { 00, 01, 02, 00, 00, 00, 01, 01, 01, 01, 01, 01, 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00 }, //422V { 00, 01, 01, 00, 00, 00, 01, 01, 01, 01, 01, 01, 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00 }, //444 { 00, 01, 01, 00, 00, 00, 01, 00, 00, 00, 00, 00, 02, 00, 00, 00, 00, 00, 03, 00, 00, 00, 00, 00 }, //400 }; Uint8 sJpuCompInfoTable_EX[5][24] = { { 00, 02, 02, 00, 02, 02, 01, 01, 01, 01, 03, 03, 02, 01, 01, 01, 03, 03, 03, 00, 00, 00, 00, 00 }, //420 { 00, 02, 01, 00, 02, 02, 01, 01, 01, 01, 03, 03, 02, 01, 01, 01, 03, 03, 03, 00, 00, 00, 00, 00 }, //422H { 00, 01, 02, 00, 02, 02, 01, 01, 01, 01, 03, 03, 02, 01, 01, 01, 03, 03, 03, 00, 00, 00, 00, 00 }, //422V { 00, 01, 01, 00, 02, 02, 01, 01, 01, 01, 03, 03, 02, 01, 01, 01, 03, 03, 03, 00, 00, 00, 00, 00 }, //444 { 00, 01, 01, 00, 00, 00, 01, 00, 00, 00, 00, 00, 02, 00, 00, 00, 00, 00, 03, 00, 00, 00, 00, 00 }, //400 }; /* * The parameters of input source: iPackMode * The parameters of jpeg sample : iFormat */ Uint32 GetDec8bitBusReqNum(FrameFormat iFormat, PackedFormat oPackMode) { Uint32 num = 0; if (oPackMode == PACKED_FORMAT_NONE) { switch (iFormat) { case FORMAT_400: num = 2; break; case FORMAT_420: num = 4; break; case FORMAT_422: num = 4; break; case FORMAT_440: num = 8; break; case FORMAT_444: num = 8; break; default: num = 0; break; } } else { switch (oPackMode) { case PACKED_FORMAT_422_YUYV: case PACKED_FORMAT_422_YVYU: case PACKED_FORMAT_422_UYVY: case PACKED_FORMAT_422_VYUY: if (iFormat == FORMAT_400) num = 1; else if (iFormat == FORMAT_420) num = 2; else if (iFormat == FORMAT_422) num = 2; else num = 4; break; case PACKED_FORMAT_444: num = 8; break; default: num = 0; break; } } return num; } Uint32 GetDec12bitBusReqNum(FrameFormat iFormat, PackedFormat oPackMode) { Uint32 num = 0; if (oPackMode == PACKED_FORMAT_NONE) { switch (iFormat) { case FORMAT_400: num = 1; break; case FORMAT_420: num = 2; break; case FORMAT_422: num = 2; break; case FORMAT_440: num = 4; break; case FORMAT_444: num = 4; break; default: num = 0; break; } } else { switch (oPackMode) { case PACKED_FORMAT_422_YUYV: case PACKED_FORMAT_422_YVYU: case PACKED_FORMAT_422_UYVY: case PACKED_FORMAT_422_VYUY: if (iFormat == FORMAT_400) num = 1; else if (iFormat == FORMAT_420) num = 1; else if (iFormat == FORMAT_422) num = 1; else if (iFormat == FORMAT_440) num = 2; else if (iFormat == FORMAT_444) num = 2; else num = 0; break; case PACKED_FORMAT_444: num = 4; break; default: num = 0; break; } } return num; } /* * The parameters of input source: packMode * The parameters of jpeg sample : oFormat */ Uint32 GetEnc8bitBusReqNum(PackedFormat iPackMode, FrameFormat oFormat) { Uint32 num = 0; if (iPackMode == PACKED_FORMAT_NONE) { switch (oFormat) { case FORMAT_400: num = 4; break; case FORMAT_440: num = 8; break; case FORMAT_444: num = 8; break; default: num = 4; break; } } else { switch (iPackMode) { case PACKED_FORMAT_422_YUYV: case PACKED_FORMAT_422_YVYU: case PACKED_FORMAT_422_UYVY: case PACKED_FORMAT_422_VYUY: if (oFormat == FORMAT_400) num = 2; else if (oFormat == FORMAT_440) num = 4; else if (oFormat == FORMAT_444) num = 4; else num = 2; break; case PACKED_FORMAT_444: num = 8; break; default: num = 0; break; } } return num; } /* * The parameters of input source: packMode * The parameters of jpeg sample : oFormat */ Uint32 GetEnc12bitBusReqNum(PackedFormat iPackMode, FrameFormat oFormat) { Uint32 num = 0; if (iPackMode == PACKED_FORMAT_NONE) { switch (oFormat) { case FORMAT_400: num = 2; break; case FORMAT_440: num = 4; break; case FORMAT_444: num = 4; break; default: num = 2; break; } } else { switch (iPackMode) { case PACKED_FORMAT_422_YUYV: case PACKED_FORMAT_422_YVYU: case PACKED_FORMAT_422_UYVY: case PACKED_FORMAT_422_VYUY: num = (oFormat == FORMAT_440 || oFormat == FORMAT_444) ? 2 : 1; break; case PACKED_FORMAT_444: num = 4; break; default: num = 0; break; } } return num; } /* * GetJpgInstance() obtains a instance. * It stores a pointer to the allocated instance in *ppInst * and returns JPG_RET_SUCCESS on success. * Failure results in 0(null pointer) in *ppInst and JPG_RET_FAILURE. */ JpgRet GetJpgInstance(JpgInst ** ppInst) { Int32 i; Uint32 handleSize; JpgInst* pJpgInst = 0; jpu_instance_pool_t* jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return JPG_RET_INVALID_HANDLE; for (i = 0; i < MAX_NUM_INSTANCE; i++) { pJpgInst = (JpgInst *)jip->jpgInstPool[i]; if (!pJpgInst) { return JPG_RET_FAILURE; } if (!pJpgInst->inUse) break; } if (i == MAX_NUM_INSTANCE) { *ppInst = 0; return JPG_RET_FAILURE; } pJpgInst->inUse = TRUE; handleSize = sizeof(JpgDecInfo); if (handleSize < sizeof(JpgEncInfo)) { handleSize = sizeof(JpgEncInfo); } if ((pJpgInst->JpgInfo=(void*)malloc(handleSize)) == NULL) { return JPG_RET_INSUFFICIENT_RESOURCE; } memset((void*)pJpgInst->JpgInfo, 0x00, sizeof(handleSize)); *ppInst = pJpgInst; jip->jpu_instance_num++; if (jdi_open_instance(pJpgInst->instIndex) < 0) { return JPG_RET_FAILURE; } return JPG_RET_SUCCESS; } void FreeJpgInstance(JpgInst * pJpgInst) { jpu_instance_pool_t *jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return; pJpgInst->inUse = 0; jip->jpu_instance_num--; jdi_close_instance(pJpgInst->instIndex); free(pJpgInst->JpgInfo); pJpgInst->JpgInfo = NULL; } JpgRet CheckJpgInstValidity(JpgInst * pci) { int i; jpu_instance_pool_t *jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return JPG_RET_FAILURE; for (i = 0; i < MAX_NUM_INSTANCE; ++i) { if ((JpgInst *)jip->jpgInstPool[i] == pci) return JPG_RET_SUCCESS; } return JPG_RET_INVALID_HANDLE; } /****************************************************************************** API Subroutines ******************************************************************************/ JpgRet CheckJpgDecOpenParam(JpgDecOpenParam * pop) { if (pop == 0) { return JPG_RET_INVALID_PARAM; } if (pop->bitstreamBuffer % 8) { return JPG_RET_INVALID_PARAM; } if (pop->bitstreamBufferSize % 1024 || pop->bitstreamBufferSize < 1024) { return JPG_RET_INVALID_PARAM; } if (pop->chromaInterleave != CBCR_SEPARATED && pop->chromaInterleave != CBCR_INTERLEAVE && pop->chromaInterleave != CRCB_INTERLEAVE) { return JPG_RET_INVALID_PARAM; } if (pop->rotation != 0 && pop->rotation != 90 && pop->rotation != 180 && pop->rotation != 270) { return JPG_RET_INVALID_PARAM; } if ((Uint32)pop->mirror > (Uint32)MIRDIR_HOR_VER) { return JPG_RET_INVALID_PARAM; } if (pop->outputFormat == FORMAT_400 || pop->outputFormat == FORMAT_440) { return JPG_RET_INVALID_PARAM; } if (pop->packedFormat > PACKED_FORMAT_444) { return JPG_RET_INVALID_PARAM; } if (pop->packedFormat != PACKED_FORMAT_NONE) { if (pop->chromaInterleave != CBCR_SEPARATED) { return JPG_RET_INVALID_PARAM; } } return JPG_RET_SUCCESS; } int JpgDecHuffTabSetUp(JpgDecInfo *jpg, int instRegIndex) { int i, j; int HuffData; // 16BITS int HuffLength; int temp; // MIN Tables JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x003); //DC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMin[0][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //DC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMin[2][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //AC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMin[1][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //AC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMin[3][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } // MAX Tables JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x403); JpuWriteInstReg(instRegIndex, MJPEG_HUFF_ADDR_REG, 0x440); //DC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMax[0][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //DC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMax[2][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //AC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMax[1][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //AC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMax[3][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } // PTR Tables JpuWriteInstReg (instRegIndex, MJPEG_HUFF_CTRL_REG, 0x803); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_ADDR_REG, 0x880); //DC Luma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[0][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //DC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[2][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //AC Luma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[1][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //AC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[3][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } // VAL Tables JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0xC03); // VAL DC Luma HuffLength = 0; for(i=0; i<12; i++) HuffLength += jpg->huffBits[0][i]; if (HuffLength > 256) return 0; for (i=0; ihuffVal[0][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<12-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL DC Chroma HuffLength = 0; for(i=0; i<12; i++) HuffLength += jpg->huffBits[2][i]; if (HuffLength > 256) return 0; for (i=0; ihuffVal[2][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<12-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL AC Luma HuffLength = 0; for(i=0; i<162; i++) HuffLength += jpg->huffBits[1][i]; if (HuffLength > 256) return 0; for (i=0; ihuffVal[1][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<162-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL AC Chroma HuffLength = 0; for(i=0; i<162; i++) HuffLength += jpg->huffBits[3][i]; if (HuffLength > 256) return 0; for (i=0; ihuffVal[3][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<162-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // end SerPeriHuffTab JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x000); return 1; } int JpgDecHuffTabSetUp_12b(JpgDecInfo *jpg, int instRegIndex) { int i, j; int HuffData; // 16BITS int HuffLength; int temp; // MIN Tables JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x003); //DC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMin[0][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //DC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMin[2][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //AC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMin[1][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //AC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMin[3][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //DC EX1 for(j=0; j<16; j++) { HuffData = jpg->huffMin[4][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } //AC EX1 for(j=0; j<16; j++) { HuffData = jpg->huffMin[5][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit } // MAX Tables JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x403); JpuWriteInstReg(instRegIndex, MJPEG_HUFF_ADDR_REG, 0x480); //DC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMax[0][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //DC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMax[2][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //AC Luma for(j=0; j<16; j++) { HuffData = jpg->huffMax[1][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //AC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffMax[3][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //DC EX1 for(j=0; j<16; j++) { HuffData = jpg->huffMax[4][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } //AC EX1 for(j=0; j<16; j++) { HuffData = jpg->huffMax[5][j]; temp = (HuffData & 0x8000) >> 15; temp = (temp << 15) | (temp << 14) | (temp << 13) | (temp << 12) | (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | (temp << 7 ) | (temp << 6) | (temp <<5) | (temp<<4) | (temp<<3) | (temp<<2) | (temp<<1)| (temp) ; JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); } // PTR Tables JpuWriteInstReg (instRegIndex, MJPEG_HUFF_CTRL_REG, 0x803); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_ADDR_REG, 0x900); //DC Luma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[0][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //DC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[2][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //AC Luma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[1][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //AC Chroma for(j=0; j<16; j++) { HuffData = jpg->huffPtr[3][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //DC EX1 for(j=0; j<16; j++) { HuffData = jpg->huffPtr[4][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } //AC EX1 for(j=0; j<16; j++) { HuffData = jpg->huffPtr[5][j]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } // VAL Tables JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0xC03); // VAL DC Luma HuffLength = 0; for(i=0; i<16; i++) { HuffLength += jpg->huffBits[0][i]; } if (HuffLength > 256) { return 0; } for (i=0; ihuffVal[0][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<16-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL DC Chroma HuffLength = 0; for(i=0; i<16; i++) { HuffLength += jpg->huffBits[2][i]; } if (HuffLength > 256) { return 0; } for (i=0; ihuffVal[2][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<16-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL AC Luma HuffLength = 0; for(i=0; i<256; i++) { HuffLength += jpg->huffBits[1][i]; } if (HuffLength > 256) { return 0; } for (i=0; ihuffVal[1][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<256-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL AC Chroma HuffLength = 0; for(i=0; i<256; i++) { HuffLength += jpg->huffBits[3][i]; } if (HuffLength > 256) { return 0; } for (i=0; ihuffVal[3][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<256-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL DC EX1 HuffLength = 0; for(i=0; i<16; i++) { HuffLength += jpg->huffBits[4][i]; } if (HuffLength > 256) { return 0; } for (i=0; ihuffVal[4][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<16-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // VAL AC EX1 HuffLength = 0; for(i=0; i<256; i++) { HuffLength += jpg->huffBits[5][i]; } if (HuffLength > 256) { return 0; } for (i=0; ihuffVal[5][i]; temp = (HuffData & 0x80) >> 7; temp = (temp<<23)|(temp<<22)|(temp<<21)|(temp<<20)|(temp<<19)|(temp<<18)|(temp<<17)|(temp<<16)|(temp<<15)|(temp<<14)|(temp<<13)|(temp<<12)|(temp<<11)|(temp<<10)|(temp<<9)|(temp<<8)|(temp<<7)|(temp<<6)|(temp<<5)|(temp<<4)|(temp<<3)|(temp<<2)|(temp<<1)|(temp); JpuWriteInstReg (instRegIndex, MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); } for (i=0; i<256-HuffLength; i++) { JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); } // end SerPeriHuffTab JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x000); return 1; } int JpgDecQMatTabSetUp(JpgDecInfo *jpg, int instRegIndex) { int i; int table; int val; // SetPeriQMatTab // Comp 0 JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x03); table = jpg->cInfoTab[0][3]; if (table >= 4) return 0; for (i=0; i<64; i++) { val = jpg->qMatTab[table][i]; JpuWriteInstReg(instRegIndex, MJPEG_QMAT_DATA_REG, val); } JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x00); // Comp 1 JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x43); table = jpg->cInfoTab[1][3]; if (table >= 4) return 0; for (i=0; i<64; i++) { val = jpg->qMatTab[table][i]; JpuWriteInstReg(instRegIndex, MJPEG_QMAT_DATA_REG, val); } JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x00); // Comp 2 JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x83); table = jpg->cInfoTab[2][3]; if (table >= 4) return 0; for (i=0; i<64; i++) { val = jpg->qMatTab[table][i]; JpuWriteInstReg(instRegIndex, MJPEG_QMAT_DATA_REG, val); } JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x00); return 1; } void JpgDecGramSetup(JpgDecInfo * jpg, int instRegIndex) { int dExtBitBufCurPos; int dExtBitBufBaseAddr; int dMibStatus; dMibStatus = 1; dExtBitBufCurPos = jpg->pagePtr; dExtBitBufBaseAddr = jpg->streamBufStartAddr; JpuWriteInstReg(instRegIndex, MJPEG_BBC_CUR_POS_REG, dExtBitBufCurPos); JpuWriteInstReg(instRegIndex, MJPEG_BBC_EXT_ADDR_REG, dExtBitBufBaseAddr + (dExtBitBufCurPos << 8)); JpuWriteInstReg(instRegIndex, MJPEG_BBC_INT_ADDR_REG, (dExtBitBufCurPos & 1) << 6); JpuWriteInstReg(instRegIndex, MJPEG_BBC_DATA_CNT_REG, JPU_GBU_SIZE / 4); // 64 * 4 byte == 32 * 8 byte JpuWriteInstReg(instRegIndex, MJPEG_BBC_COMMAND_REG, (jpg->streamEndian << 1) | 0); while (dMibStatus == 1) { dMibStatus = JpuReadInstReg(instRegIndex, MJPEG_BBC_BUSY_REG); } dMibStatus = 1; dExtBitBufCurPos = dExtBitBufCurPos + 1; JpuWriteInstReg(instRegIndex, MJPEG_BBC_CUR_POS_REG, dExtBitBufCurPos); JpuWriteInstReg(instRegIndex, MJPEG_BBC_EXT_ADDR_REG, dExtBitBufBaseAddr + (dExtBitBufCurPos << 8)); JpuWriteInstReg(instRegIndex, MJPEG_BBC_INT_ADDR_REG, (dExtBitBufCurPos & 1) << 6); JpuWriteInstReg(instRegIndex, MJPEG_BBC_DATA_CNT_REG, JPU_GBU_SIZE / 4); // 64 * 4 byte == 32 * 8 byte JpuWriteInstReg(instRegIndex, MJPEG_BBC_COMMAND_REG, (jpg->streamEndian << 1) | 0); while (dMibStatus == 1) { dMibStatus = JpuReadInstReg(instRegIndex, MJPEG_BBC_BUSY_REG); } dExtBitBufCurPos = dExtBitBufCurPos + 1; JpuWriteInstReg(instRegIndex, MJPEG_BBC_CUR_POS_REG, dExtBitBufCurPos); // next unit page pointer JpuWriteInstReg(instRegIndex, MJPEG_BBC_CTRL_REG, (jpg->streamEndian<< 1) | 1); JpuWriteInstReg(instRegIndex, MJPEG_GBU_WPTR_REG, jpg->wordPtr); JpuWriteInstReg(instRegIndex, MJPEG_GBU_BBSR_REG, 0); JpuWriteInstReg(instRegIndex, MJPEG_GBU_BBER_REG, ((JPU_GBU_SIZE / 4) * 2) - 1); if (jpg->pagePtr & 1) { JpuWriteInstReg(instRegIndex, MJPEG_GBU_BBIR_REG, 0); JpuWriteInstReg(instRegIndex, MJPEG_GBU_BBHR_REG, 0); } else { JpuWriteInstReg(instRegIndex, MJPEG_GBU_BBIR_REG, JPU_GBU_SIZE / 4); // 64 * 4 byte == 32 * 8 byte JpuWriteInstReg(instRegIndex, MJPEG_GBU_BBHR_REG, JPU_GBU_SIZE / 4); // 64 * 4 byte == 32 * 8 byte } JpuWriteInstReg(instRegIndex, MJPEG_GBU_CTRL_REG, 4); JpuWriteInstReg(instRegIndex, MJPEG_GBU_FF_RPTR_REG, jpg->bitPtr); } enum { SAMPLE_420 = 0xA, SAMPLE_H422 = 0x9, SAMPLE_V422 = 0x6, SAMPLE_444 = 0x5, SAMPLE_400 = 0x1 }; const BYTE cDefHuffBits[8][16] = { { // DC index 0 (Luminance DC) 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } , { // AC index 0 (Luminance AC) 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D } , { // DC index 1 (Chrominance DC) 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 } , { // AC index 1 (Chrominance AC) 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77 } }; const BYTE cDefHuffVal[8][162] = { { // DC index 0 (Luminance DC) 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B } , { // AC index 0 (Luminance AC) 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA } , { // DC index 1 (Chrominance DC) 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B } , { // AC index 1 (Chrominance AC) 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA } }; const BYTE cDefHuffBits_ES[8][16] = { { // DC index 0 (Luminance DC) 0x00, 0x02, 0x03, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, { // AC index 0 (Luminance AC) 0x00, 0x01, 0x04, 0x02, 0x02, 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xEB }, { // DC index 1 (Chrominance DC) 0x00, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { // AC index 1 (Chrominance AC) 0x00, 0x01, 0x03, 0x02, 0x05, 0x01, 0x05, 0x05, 0x03, 0x07, 0x04, 0x04, 0x03, 0x04, 0x06, 0xCB }, { // DC EX1 (Luminance DC) 0x00, 0x02, 0x03, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, { // AC EX1 (Luminance AC) 0x00, 0x01, 0x04, 0x02, 0x02, 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xEB }, { // DC EX2 (Chrominance DC) 0x00, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { // AC EX2 (Chrominance AC) 0x00, 0x01, 0x03, 0x02, 0x05, 0x01, 0x05, 0x05, 0x03, 0x07, 0x04, 0x04, 0x03, 0x04, 0x06, 0xCB } }; const BYTE cDefHuffVal_ES[8][256] = { { // DC index 0 (Luminance DC) 0x08, 0x09, 0x06, 0x07, 0x0A, 0x05, 0x03, 0x04, 0x0B, 0x02, 0x00, 0x01, 0x0C }, { // AC index 0 (Luminance AC) 0x02,0x01,0x03,0x04,0x05,0x06,0x07,0x08,0x12,0x09,0x11,0x13,0x00,0x14,0x21,0x22, 0x15,0x0a,0x23,0x31,0x16,0x32,0x17,0x24,0x33,0x41,0x18,0x25,0x42,0x51,0x0b,0x26, 0x19,0x43,0x52,0x61,0x35,0x62,0x71,0x0c,0x0d,0x0e,0x0f,0x10,0x1a,0x1b,0x1c,0x1d, 0x1e,0x1f,0x20,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x34,0x36,0x37, 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, 0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c, 0x5d,0x5e,0x5f,0x60,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, 0x6f,0x70,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }, { // DC index 1 (Chrominance DC) 0x06, 0x07, 0x05, 0x08, 0x04, 0x09, 0x02, 0x03, 0x0A, 0x01, 0x0B, 0x00, 0x0C }, { // AC index 1 (Chrominance AC) 0x01,0x02,0x03,0x11,0x04,0x21,0x00,0x05,0x06,0x12,0x31,0x41,0x07,0x13,0x22,0x51, 0x61,0x08,0x14,0x32,0x71,0x81,0x42,0x91,0xa1,0x09,0x15,0x23,0x52,0xb1,0xc1,0xf0, 0x16,0x62,0xd1,0xe1,0x0a,0x24,0x72,0xf1,0x17,0x82,0x92,0x33,0x43,0x53,0xb2,0x0b, 0x0c,0x18,0x35,0xa2,0xc2,0x0d,0x0e,0x0f,0x10,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, 0x20,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x34,0x36,0x37, 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, 0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d, 0x5e,0x5f,0x60,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, 0x70,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x83, 0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x93,0x94,0x95, 0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa3,0xa4,0xa5,0xa6,0xa7, 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9, 0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,0xd0,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc, 0xdd,0xde,0xdf,0xe0,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed, 0xee,0xef,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }, { // DC EX1 (Luminance DC) 0x08, 0x09, 0x06, 0x07, 0x0A, 0x05, 0x03, 0x04, 0x0B, 0x02, 0x00, 0x01, 0x0C }, { // AC EX1 (Luminance AC) 0x02,0x01,0x03,0x04,0x05,0x06,0x07,0x08,0x12,0x09,0x11,0x13,0x00,0x14,0x21,0x22, 0x15,0x0a,0x23,0x31,0x16,0x32,0x17,0x24,0x33,0x41,0x18,0x25,0x42,0x51,0x0b,0x26, 0x19,0x43,0x52,0x61,0x35,0x62,0x71,0x0c,0x0d,0x0e,0x0f,0x10,0x1a,0x1b,0x1c,0x1d, 0x1e,0x1f,0x20,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x34,0x36,0x37, 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, 0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c, 0x5d,0x5e,0x5f,0x60,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, 0x6f,0x70,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }, { // DC EX2 (Chrominance DC) 0x06, 0x07, 0x05, 0x08, 0x04, 0x09, 0x02, 0x03, 0x0A, 0x01, 0x0B, 0x00, 0x0C }, { // AC EX2 (Chrominance AC) 0x01,0x02,0x03,0x11,0x04,0x21,0x00,0x05,0x06,0x12,0x31,0x41,0x07,0x13,0x22,0x51, 0x61,0x08,0x14,0x32,0x71,0x81,0x42,0x91,0xa1,0x09,0x15,0x23,0x52,0xb1,0xc1,0xf0, 0x16,0x62,0xd1,0xe1,0x0a,0x24,0x72,0xf1,0x17,0x82,0x92,0x33,0x43,0x53,0xb2,0x0b, 0x0c,0x18,0x35,0xa2,0xc2,0x0d,0x0e,0x0f,0x10,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, 0x20,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x34,0x36,0x37, 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, 0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d, 0x5e,0x5f,0x60,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, 0x70,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x83, 0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x93,0x94,0x95, 0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa3,0xa4,0xa5,0xa6,0xa7, 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9, 0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,0xd0,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc, 0xdd,0xde,0xdf,0xe0,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed, 0xee,0xef,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff } }; enum { Marker = 0xFF, FF_Marker = 0x00, SOI_Marker = 0xFFD8, // Start of image EOI_Marker = 0xFFD9, // End of image JFIF_CODE = 0xFFE0, // Application EXIF_CODE = 0xFFE1, DRI_Marker = 0xFFDD, // Define restart interval RST_Marker = 0xD, // 0xD0 ~0xD7 DQT_Marker = 0xFFDB, // Define quantization table(s) DHT_Marker = 0xFFC4, // Define Huffman table(s) SOF_Marker = 0xFFC0, // Start of frame : Baseline DCT SOS_Marker = 0xFFDA, // Start of scan SOF_Marker_ES = 0xFFC1, // Start of frame : Extended Sequential }; int check_start_code(JpgDecInfo *jpg) { if (show_bits(&jpg->gbc, 8) == 0xFF) return 1; else return 0; } int find_start_code(JpgDecInfo *jpg) { int word; for(;;) { if (get_bits_left(&jpg->gbc) <= 16) { ////printf("hit end of stream\n"); return 0; } word = show_bits(&jpg->gbc, 16); if ((word > 0xFF00) && (word < 0xFFFF)) break; get_bits(&jpg->gbc, 8); } return word; } int find_start_soi_code(JpgDecInfo *jpg) { int word; for(;;) { if (get_bits_left(&jpg->gbc) <= 16) { ////printf("hit end of stream\n"); return 0; } word = show_bits(&jpg->gbc, 16); if ((word > 0xFF00) && (word < 0xFFFF)) { if (word != SOI_Marker) get_bits(&jpg->gbc, 8); break; } get_bits(&jpg->gbc, 8); } return word; } int decode_app_header(JpgDecInfo *jpg) { int length; if (get_bits_left(&jpg->gbc) < 16) return 0; length = get_bits(&jpg->gbc, 16); length -= 2; while(length-- > 0) { if (get_bits_left(&jpg->gbc) < 8) return 0; get_bits(&jpg->gbc, 8); } return 1; } int decode_dri_header(JpgDecInfo *jpg) { //Length, Lr if (get_bits_left(&jpg->gbc) < 16*2) return 0; get_bits(&jpg->gbc, 16); jpg->rstIntval = get_bits(&jpg->gbc, 16); return 1; } int decode_dqt_header(JpgDecInfo *jpg) { int Pq; int Tq; int i; int tmp; if (get_bits_left(&jpg->gbc) < 16) return 0; // Lq, Length of DQT get_bits(&jpg->gbc, 16); do { if (get_bits_left(&jpg->gbc) < 4+4+8*64) return 0; // Pq, Quantization Precision tmp = get_bits(&jpg->gbc, 8); // Tq, Quantization table destination identifier Pq = (tmp>>4) & 0xf; Tq = tmp&0xf; if (Tq == 0) jpg->q_prec0 = Pq; else if (Tq == 1) jpg->q_prec1 = Pq; else if (Tq == 2) jpg->q_prec2 = Pq; else if (Tq == 3) jpg->q_prec3 = Pq; else return 0; for (i=0; i<64; i++){ if (Pq) jpg->qMatTab[Tq][i] = (short)get_bits(&jpg->gbc, 16) & 0xffff; else jpg->qMatTab[Tq][i] = (BYTE)get_bits(&jpg->gbc, 8) & 0x00ff; } } while(!check_start_code(jpg)); return 1; } int decode_dth_header(JpgDecInfo *jpg) { int Tc; int Th; int ThTc; int bitCnt; int i; int tmp; // Length, Lh if (get_bits_left(&jpg->gbc) < 16) return 0; get_bits(&jpg->gbc, 16); do { if (get_bits_left(&jpg->gbc) < 8 + 8*16) return 0; // Table class - DC, AC tmp = get_bits(&jpg->gbc, 8); // Table destination identifier Tc = (tmp>>4) & 0xf; Th = tmp&0xf; // DC_ID0 (0x00) -> 0 // AC_ID0 (0x10) -> 1 // DC_ID1 (0x01) -> 2 // AC_ID1 (0x11) -> 3 // DC_EX1 (0x02) -> 4 // AC_EX1 (0x12) -> 5 // DC_EX2 (0x03) -> 6 // AC_EX2 (0x13) -> 7 //Since only DC_ID0, DC_ID1, if th is 2 or 3, always set userHuffTab /* According to ITU-T.81 Table B.5, maximum Tc value is 1 and maximum Th value is 3.*/ if (Tc > 1 || Th > 3) { return 0; } ThTc = ((Th&3)<<1) | (Tc&1); if (jpg->numHuffmanTable >= THTC_LIST_CNT) return 0; jpg->thtc[jpg->numHuffmanTable++] = ThTc; // Get Huff Bits list bitCnt = 0; for (i=0; i<16; i++) { jpg->huffBits[ThTc][i] = (BYTE)get_bits(&jpg->gbc, 8); bitCnt += jpg->huffBits[ThTc][i]; } if (bitCnt > 256) return 0; if (get_bits_left(&jpg->gbc) < 8*bitCnt) return 0; // Get Huff Val list for (i=0; ihuffVal[ThTc][i] = (BYTE)get_bits(&jpg->gbc, 8); } } while(!check_start_code(jpg)); return 1; } int decode_sof_header(JpgDecInfo *jpg) { int samplePrecision; int sampleFactor; int i; int Tqi; BYTE compID; int hSampFact[3] = {0,}; int vSampFact[3] = {0,}; int picX, picY; int numComp; int tmp; if (get_bits_left(&jpg->gbc) < 16+8+16+16+8) return 0; // LF, Length of SOF get_bits(&jpg->gbc, 16); // Sample Precision: Baseline(8), P samplePrecision = get_bits(&jpg->gbc, 8); jpg->bitDepth = samplePrecision; jpg->jpg12bit = (samplePrecision == 12) ? 1 : 0; picY = get_bits(&jpg->gbc, 16); if (picY > MAX_MJPG_PIC_WIDTH) { //printf("Picture Vertical Size limits Maximum size\n"); return 0; } picX = get_bits(&jpg->gbc, 16); if (picX > MAX_MJPG_PIC_HEIGHT) { //printf("Picture Horizontal Size limits Maximum size\n"); return 0; } //Number of Components in Frame: Nf numComp = get_bits(&jpg->gbc, 8); if (numComp > 3) { //printf("Picture Horizontal Size limits Maximum size\n"); return 0; } if (get_bits_left(&jpg->gbc) < numComp*(8+4+4+8)) return 0; for (i=0; igbc, 8); tmp = get_bits(&jpg->gbc, 8); // Horizontal Sampling Factor, Hi hSampFact[i] = (tmp>>4) & 0xf; // Vertical Sampling Factor, Vi vSampFact[i] = tmp&0xf; // Quantization Table Selector, Tqi Tqi = get_bits(&jpg->gbc, 8); jpg->cInfoTab[i][0] = compID; jpg->cInfoTab[i][1] = (BYTE)hSampFact[i]; jpg->cInfoTab[i][2] = (BYTE)vSampFact[i]; jpg->cInfoTab[i][3] = (BYTE)Tqi; } //if ( hSampFact[0]>2 || vSampFact[0]>2 || ( numComp == 3 && ( hSampFact[1]!=1 || hSampFact[2]!=1 || vSampFact[1]!=1 || vSampFact[2]!=1) ) ) //printf("Not Supported Sampling Factor\n"); if (numComp == 1) sampleFactor = SAMPLE_400; else sampleFactor = ((hSampFact[0]&3)<<2) | (vSampFact[0]&3); switch(sampleFactor) { case SAMPLE_420: jpg->format = FORMAT_420; break; case SAMPLE_H422: jpg->format = FORMAT_422; break; case SAMPLE_V422: jpg->format = FORMAT_440; break; case SAMPLE_444: jpg->format = FORMAT_444; break; default: // 4:0:0 jpg->format = FORMAT_400; break; } jpg->picWidth = picX; jpg->picHeight = picY; return 1; } int decode_sos_header(JpgDecInfo *jpg) { int i, j; int len; int numComp; int compID; int ecsPtr; int ss, se, ah, al; int dcHufTblIdx[3] = {0,}; int acHufTblIdx[3] = {0,}; int tmp; if (get_bits_left(&jpg->gbc) < 8) return 0; // Length, Ls len = get_bits(&jpg->gbc, 16); jpg->ecsPtr = get_bits_count(&jpg->gbc)/8 + len - 2 ; ecsPtr = jpg->ecsPtr+jpg->frameOffset; //printf("ecsPtr=0x%x frameOffset=0x%x, ecsOffset=0x%x, wrPtr=0x%x, rdPtr0x%x\n", jpg->ecsPtr, jpg->frameOffset, ecsPtr, jpg->streamWrPtr, jpg->streamRdPtr); jpg->pagePtr = ecsPtr >> 8; //page unit ecsPtr/256; jpg->wordPtr = (ecsPtr & 0xF0) >> 2; // word unit ((ecsPtr % 256) & 0xF0) / 4; if (jpg->pagePtr & 1) jpg->wordPtr += 64; if (jpg->wordPtr & 1) jpg->wordPtr -= 1; // to make even. jpg->bitPtr = (ecsPtr & 0xF) << 3; // bit unit (ecsPtr & 0xF) * 8; if (get_bits_left(&jpg->gbc) < 8) return 0; //Number of Components in Scan: Ns numComp = get_bits(&jpg->gbc, 8); if (numComp > 3) return 0; if (get_bits_left(&jpg->gbc) < numComp*(8+4+4)) return 0; for (i=0; igbc, 8); tmp = get_bits(&jpg->gbc, 8); // dc entropy coding table selector, Tdj dcHufTblIdx[i] = (tmp>>4) & 0xf; // ac entropy coding table selector, Taj acHufTblIdx[i] = tmp&0xf; for (j=0; jcInfoTab[j][0]) { jpg->cInfoTab[j][4] = (BYTE)dcHufTblIdx[i]; jpg->cInfoTab[j][5] = (BYTE)acHufTblIdx[i]; } } } if (get_bits_left(&jpg->gbc) < 8+8+4+4) return 0; // Ss 0 ss = get_bits(&jpg->gbc, 8); // Se 3F se = get_bits(&jpg->gbc, 8); tmp = get_bits(&jpg->gbc, 8); // Ah 0 ah = (i>>4) & 0xf; // Al 0 al = tmp&0xf; if ((ss != 0) || (se != 0x3F) || (ah != 0) || (al != 0)) { //printf("The Jpeg Image must be another profile\n"); return 0; } return 1; } static void genDecHuffTab(JpgDecInfo *jpg, int tabNum) { unsigned char *huffPtr, *huffBits; Uint32 *huffMax, *huffMin; int ptrCnt =0; int huffCode = 0; int zeroFlag = 0; int dataFlag = 0; int i; huffBits = jpg->huffBits[tabNum]; huffPtr = jpg->huffPtr[tabNum]; huffMax = jpg->huffMax[tabNum]; huffMin = jpg->huffMin[tabNum]; for (i=0; i<16; i++) { if (huffBits[i]) // if there is bit cnt value { huffPtr[i] = (BYTE)ptrCnt; ptrCnt += huffBits[i]; huffMin[i] = huffCode; huffMax[i] = huffCode + (huffBits[i] - 1); dataFlag = 1; zeroFlag = 0; } else { huffPtr[i] = 0xFF; huffMin[i] = 0xFFFF; huffMax[i] = 0xFFFF; zeroFlag = 1; } if (dataFlag == 1) { if (zeroFlag == 1) huffCode <<= 1; else huffCode = (huffMax[i] + 1) << 1; } } } int JpuGbuInit(vpu_getbit_context_t *ctx, BYTE *buffer, int size) { ctx->buffer = buffer; ctx->index = 0; ctx->size = size/8; return 1; } int JpuGbuGetUsedBitCount(vpu_getbit_context_t *ctx) { return ctx->index*8; } int JpuGbuGetLeftBitCount(vpu_getbit_context_t *ctx) { return (ctx->size*8) - JpuGbuGetUsedBitCount(ctx); } unsigned int JpuGbuGetBit(vpu_getbit_context_t *ctx, int bit_num) { BYTE *p; unsigned int b = 0x0; if (bit_num > JpuGbuGetLeftBitCount(ctx)) return (unsigned int)-1; p = ctx->buffer + ctx->index; if (bit_num == 8) { b = *p; ctx->index++; } else if(bit_num == 16) { b = *p++<<8; b |= *p++; ctx->index += 2; } else if(bit_num == 32) { b = *p++<<24; b |= (*p++<<16); b |= (*p++<<8); b |= (*p++<<0); ctx->index += 4; } return b; } unsigned int JpuGguShowBit(vpu_getbit_context_t *ctx, int bit_num) { BYTE *p; unsigned int b = 0x0; if (bit_num > JpuGbuGetLeftBitCount(ctx)) return (unsigned int)-1; p = ctx->buffer + ctx->index; if (bit_num == 8) { b = *p; } else if(bit_num == 16) { b = *p++<<8; b |= *p++; } else if(bit_num == 32) { b = *p++<<24; b |= (*p++<<16); b |= (*p++<<8); b |= (*p++<<0); } return b; } static int wraparound_bistream_data(JpgDecInfo *jpg, int return_type) { BYTE *dst; BYTE *src; BYTE *data; int data_size; int src_size; int dst_size; data_size = jpg->streamWrPtr - jpg->streamBufStartAddr; data = (BYTE *)malloc(data_size); if (data) JpuReadMem(jpg->streamBufStartAddr, data, data_size, jpg->streamEndian); src_size = jpg->streamBufSize - jpg->frameOffset; src = (BYTE *)malloc(src_size); dst_size = ((src_size+(JPU_GBU_SIZE-1))&~(JPU_GBU_SIZE-1)); dst = (BYTE *)malloc(dst_size); if (dst && src) { memset(dst, 0x00, dst_size); JpuReadMem(jpg->streamBufStartAddr+jpg->frameOffset, src, src_size, jpg->streamEndian); memcpy(dst+(dst_size-src_size), src, src_size); JpuWriteMem(jpg->streamBufStartAddr, dst, dst_size, jpg->streamEndian); if (data) JpuWriteMem(jpg->streamBufStartAddr+dst_size, data, data_size, jpg->streamEndian); } if(src) free(src); if(dst) free(dst); if (data) free(data); if (return_type == -2) {// header wraparound jpg->streamWrPtr = jpg->streamBufStartAddr+dst_size+data_size; jpg->consumeByte = 0; return -2; } else if(return_type == -1){ // ecsPtr wraparound jpg->streamWrPtr = jpg->streamBufStartAddr+dst_size+data_size; jpg->frameOffset = 0; return -1; } return 0; } static void CheckUserHuffmanTable(JpgDecInfo* jpg) { Uint32 ThTc, i, bitCnt; for (ThTc=0; ThTcthtc[ThTc] == -1) break; bitCnt = 0; for (i=0; i<16; i++) { bitCnt += jpg->huffBits[ThTc][i]; if (jpg->jpg12bit) { jpg->userHuffTab = (cDefHuffBits_ES[ThTc][i] != jpg->huffBits[ThTc][i]); } else { jpg->userHuffTab = (cDefHuffBits[ThTc][i] != jpg->huffBits[ThTc][i]); } if (jpg->userHuffTab == TRUE) return; } if (bitCnt > 256) return; // Get Huff Val list for (i=0; ijpg12bit) { jpg->userHuffTab = (cDefHuffVal_ES[ThTc][i] != jpg->huffVal[ThTc][i]); } else { jpg->userHuffTab = (cDefHuffVal[ThTc][i] != jpg->huffVal[ThTc][i]); } if (jpg->userHuffTab == TRUE) return; } } } int JpegDecodeHeader(JpgDecInfo *jpg) { unsigned int code; int ret; int i; int temp; int wrOffset; BYTE *b = jpg->pBitStream+jpg->frameOffset; int size; BOOL yuv400_4Blocks = TRUE; /* process 4block at a time for improving performance */ for (i=0; ithtc[i] = -1; } jpg->numHuffmanTable = 0; ret = 1; if (jpg->streamWrPtr == jpg->streamBufStartAddr) { size = jpg->streamBufSize-jpg->frameOffset; wrOffset = jpg->streamBufSize; } else { if (jpg->frameOffset >= (int)(jpg->streamWrPtr-jpg->streamBufStartAddr)) size = jpg->streamBufSize - jpg->frameOffset; else size = (jpg->streamWrPtr-jpg->streamBufStartAddr)-jpg->frameOffset; wrOffset = (jpg->streamWrPtr-jpg->streamBufStartAddr); } if (!b || !size) { ret = -1; goto DONE_DEC_HEADER; } // find start code of next frame if (!jpg->ecsPtr) { int nextOffset = 0; int soiOffset = 0; if (jpg->consumeByte != 0) // meaning is frameIdx > 0 { nextOffset = jpg->consumeByte; if (nextOffset <= 0) nextOffset = 2; //in order to consume start code. } //consume to find the start code of next frame. b += nextOffset; size -= nextOffset; if (size < 0) { jpg->consumeByte -= (b - (jpg->pBitStream+jpg->streamBufSize)); if (jpg->consumeByte < 0) { ret = 0; goto DONE_DEC_HEADER; } ret = -1; goto DONE_DEC_HEADER; } init_get_bits(&jpg->gbc, b, size*8); for (;;) { code = find_start_soi_code(jpg); if (code == 0) { ret = -1; goto DONE_DEC_HEADER; } if (code == SOI_Marker) break; } soiOffset = get_bits_count(&jpg->gbc)/8; b += soiOffset; size -= soiOffset; jpg->frameOffset += (soiOffset+ nextOffset); } if (jpg->headerSize > 0 && (jpg->headerSize > (jpg->streamBufSize - jpg->frameOffset - JPU_GBU_SIZE))) { // if header size is smaller than room of stream end. copy the buffer to bistream start. return wraparound_bistream_data(jpg, -2); } init_get_bits(&jpg->gbc, b, size*8); // Initialize component information table for (i=0; i<4; i++) { jpg->cInfoTab[i][0] = 0; jpg->cInfoTab[i][1] = 0; jpg->cInfoTab[i][2] = 0; jpg->cInfoTab[i][3] = 0; jpg->cInfoTab[i][4] = 0; jpg->cInfoTab[i][5] = 0; } for (;;) { if (find_start_code(jpg) == 0) { ret = -1; goto DONE_DEC_HEADER; } code = get_bits(&jpg->gbc, 16); //getbit 2byte switch (code) { case SOI_Marker: break; case JFIF_CODE: case EXIF_CODE: if (!decode_app_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } break; case DRI_Marker: if (!decode_dri_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } break; case DQT_Marker: if (!decode_dqt_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } break; case DHT_Marker: if (!decode_dth_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } break; case SOF_Marker: case SOF_Marker_ES: if (!decode_sof_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } break; case SOS_Marker: if (!decode_sos_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } if (!jpg->headerSize) jpg->headerSize = jpg->ecsPtr; // we assume header size of all frame is same for mjpeg case goto DONE_DEC_HEADER; case EOI_Marker: goto DONE_DEC_HEADER; default: switch (code&0xFFF0) { case 0xFFE0: // 0xFFEX case 0xFFF0: // 0xFFFX if (get_bits_left(&jpg->gbc) <=0 ) { { ret = -1; goto DONE_DEC_HEADER; } } else { if (!decode_app_header(jpg)) { ret = -1; goto DONE_DEC_HEADER; } break; } default: //in case, restart marker is founded. if( (code&0xFFF0) >= 0xFFD0 && (code&0xFFF0) <= 0xFFD7) break; else //printf("code = [%x]\n", code); return 0; } break; } } DONE_DEC_HEADER: if (ret == -1) { if (wrOffset < jpg->frameOffset) return -2; if (0 == get_bits_left(&jpg->gbc)) { return -2; } return -1; } if (!jpg->ecsPtr) return 0; if (wrOffset - (jpg->frameOffset+jpg->ecsPtr) < JPU_GBU_SIZE && jpg->streamEndflag == 0) { return -1; } // this bellow is workaround to avoid the case that JPU is run over without interrupt. if (jpg->streamBufSize - (jpg->frameOffset+jpg->ecsPtr) < JPU_GBU_SIZE) return wraparound_bistream_data(jpg, -1); CheckUserHuffmanTable(jpg); // Generate Huffman table information if (jpg->jpg12bit){ for(i=0; i<8; i++) genDecHuffTab(jpg, i); }else{ for(i=0; i<4; i++) genDecHuffTab(jpg, i); } // Q Idx temp = jpg->cInfoTab[0][3]; temp = temp << 1 | jpg->cInfoTab[1][3]; temp = temp << 1 | jpg->cInfoTab[2][3]; jpg->Qidx = temp; // Huff Idx[DC, AC] temp = jpg->cInfoTab[0][4]; if (jpg->jpg12bit == 0){ temp = temp << 1 | jpg->cInfoTab[1][4]; temp = temp << 1 | jpg->cInfoTab[2][4]; }else{ temp = temp << 2 | jpg->cInfoTab[1][4]; temp = temp << 2 | jpg->cInfoTab[2][4]; } jpg->huffDcIdx = temp; temp = jpg->cInfoTab[0][5]; if (jpg->jpg12bit == 0){ temp = temp << 1 | jpg->cInfoTab[1][5]; temp = temp << 1 | jpg->cInfoTab[2][5]; }else{ temp = temp << 2 | jpg->cInfoTab[1][5]; temp = temp << 2 | jpg->cInfoTab[2][5]; } jpg->huffAcIdx = temp; switch(jpg->format) { case FORMAT_420: jpg->mcuBlockNum = 6; jpg->compNum = 3; jpg->compInfo[1] = 5; jpg->compInfo[2] = 5; jpg->alignedWidth = ((jpg->picWidth+15)&~15); jpg->alignedHeight = ((jpg->picHeight+15)&~15); jpg->mcuWidth = 16; jpg->mcuHeight = 16; break; case FORMAT_422: jpg->mcuBlockNum = 4; jpg->compNum = 3; jpg->compInfo[1] = 5; jpg->compInfo[2] = 5; jpg->alignedWidth = ((jpg->picWidth+15)&~15); jpg->alignedHeight = ((jpg->picHeight+7)&~7); jpg->mcuWidth = 16; jpg->mcuHeight = 8; break; case FORMAT_440: jpg->mcuBlockNum = 4; jpg->compNum = 3; jpg->compInfo[1] = 5; jpg->compInfo[2] = 5; jpg->alignedWidth = ((jpg->picWidth+7)&~7); jpg->alignedHeight = ((jpg->picHeight+15)&~15); jpg->mcuWidth = 8; jpg->mcuHeight = 16; break; case FORMAT_444: jpg->mcuBlockNum = 3; jpg->compNum = 3; jpg->compInfo[1] = 5; jpg->compInfo[2] = 5; jpg->alignedWidth = ((jpg->picWidth+7)&~7); jpg->alignedHeight = ((jpg->picHeight+7)&~7); jpg->mcuWidth = 8; jpg->mcuHeight = 8; break; case FORMAT_400: jpg->compNum = 1; jpg->compInfo[1] = 0; jpg->compInfo[2] = 0; jpg->alignedWidth = ((jpg->picWidth+7)&~7); jpg->alignedHeight = ((jpg->picHeight+7)&~7); if (jpg->roiEnable == TRUE) { Uint32 offsetX = JPU_FLOOR(8, jpg->roiOffsetX); yuv400_4Blocks = (BOOL)((offsetX%32) == 0); } if (yuv400_4Blocks == TRUE) { jpg->mcuBlockNum = 4; jpg->mcuWidth = 32; jpg->mcuHeight = 8; } else { jpg->mcuBlockNum = 1; jpg->mcuWidth = 8; jpg->mcuHeight = 8; } break; default: return 0; } jpg->compInfo[0] = (jpg->mcuWidth >> 3) << 3 | (jpg->mcuHeight >> 3); jpg->busReqNum = (jpg->jpg12bit == FALSE) ? GetDec8bitBusReqNum(jpg->format, jpg->packedFormat) : GetDec12bitBusReqNum(jpg->format, jpg->packedFormat); return 1; } JpgRet CheckJpgEncOpenParam(JpgEncOpenParam * pop, JPUCap* cap) { int picWidth; int picHeight; if (pop == 0) { return JPG_RET_INVALID_PARAM; } picWidth = pop->picWidth; picHeight = pop->picHeight; if (pop->bitstreamBuffer % 8) { return JPG_RET_INVALID_PARAM; } if ((pop->bitstreamBufferSize - (4096)) < 4096) { return JPG_RET_INVALID_PARAM; } if ((pop->bitstreamBufferSize - (4096)) % 4096) { return JPG_RET_INVALID_PARAM; } if (picWidth < 16 || picWidth > MAX_MJPG_PIC_WIDTH ) { return JPG_RET_INVALID_PARAM; } if (picHeight < 16 || picHeight > MAX_MJPG_PIC_HEIGHT ) { return JPG_RET_INVALID_PARAM; } if (pop->intrEnableBit == 0) { return JPG_RET_INVALID_PARAM; } if (pop->jpg12bit == TRUE && cap->support12bit == FALSE) { return JPG_RET_NOT_SUPPORT; } return JPG_RET_SUCCESS; } JpgRet CheckJpgEncParam(JpgEncHandle handle, JpgEncParam * param) { JpgInst *pJpgInst; JpgEncInfo *pEncInfo; pJpgInst = handle; pEncInfo = &pJpgInst->JpgInfo->encInfo; if (param == 0) { return JPG_RET_INVALID_PARAM; } if (pEncInfo->packedFormat != PACKED_FORMAT_NONE) { if (pEncInfo->packedFormat == PACKED_FORMAT_444) { if (param->sourceFrame->stride < pEncInfo->picWidth*2) { return JPG_RET_INVALID_PARAM; } } if (pEncInfo->packedFormat == PACKED_FORMAT_444) { if (param->sourceFrame->stride < pEncInfo->picWidth*3) { return JPG_RET_INVALID_PARAM; } } } return JPG_RET_SUCCESS; } int JpgEncGenHuffTab(JpgEncInfo * pEncInfo, int tabNum) { int p, i, l, lastp, si, maxsymbol; int huffsize[256] = {0,}; int huffcode[256] = {0,}; int code; BYTE *bitleng, *huffval; Uint32 *ehufco, *ehufsi; if (tabNum > 3) return 0; bitleng = pEncInfo->pHuffBits[tabNum]; huffval = pEncInfo->pHuffVal[tabNum]; ehufco = pEncInfo->huffCode[tabNum]; ehufsi = pEncInfo->huffSize[tabNum]; maxsymbol = tabNum & 1 ? 256 : 16; /* Figure C.1: make table of Huffman code length for each symbol */ p = 0; for (l=1; l<=16; l++) { i = bitleng[l-1]; if (i < 0 || p + i > maxsymbol) return 0; while (i--) huffsize[p++] = l; } lastp = p; /* Figure C.2: generate the codes themselves */ /* We also validate that the counts represent a legal Huffman code tree. */ code = 0; si = huffsize[0]; p = 0; while(p < lastp){ while (huffsize[p] == si) { huffcode[p++] = code; code++; } if (code >= (1 << si)) return 0; code <<= 1; si++; } memset(ehufsi, 0, sizeof(int) * 256); memset(ehufco, 0, sizeof(int) * 256); /* Figure C.3: generate encoding tables */ /* These are code and size indexed by symbol value */ for(i=0; i<256; i++) ehufsi[i] = 0x00; for(i=0; i<256; i++) ehufco[i] = 0x00; for (p=0; p= maxsymbol || ehufsi[i]) return 0; ehufco[i] = huffcode[p]; ehufsi[i] = huffsize[p]; } return 1; } int JpgEncLoadHuffTab(JpgInst *pJpgInst, int instRegIndex) { int i, j, t; int huffData; JpgEncInfo * pEncInfo; pEncInfo = &pJpgInst->JpgInfo->encInfo; for (i=0; i<4; i++) JpgEncGenHuffTab(pEncInfo, i); JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x3); for (j=0; j<4; j++) { t = (j==0) ? AC_TABLE_INDEX0 : (j==1) ? AC_TABLE_INDEX1 : (j==2) ? DC_TABLE_INDEX0 : DC_TABLE_INDEX1; for (i=0; i<256; i++) { if ((t==DC_TABLE_INDEX0 || t==DC_TABLE_INDEX1) && (i>15)) // DC break; if ((pEncInfo->huffSize[t][i] == 0) && (pEncInfo->huffCode[t][i] == 0)) huffData = 0; else { huffData = (pEncInfo->huffSize[t][i] - 1); // Code length (1 ~ 16), 4-bit huffData = (huffData << 16) | (pEncInfo->huffCode[t][i] ); // Code word, 16-bit } JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, huffData); } } JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x0); return 1; } int JpgEncLoadHuffTab_12b(JpgInst *pJpgInst, int instRegIndex) { int i, j, t; int huffData; JpgEncInfo * pEncInfo; pEncInfo = &pJpgInst->JpgInfo->encInfo; for (i=0; i<8; i++) JpgEncGenHuffTab(pEncInfo, i); JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x3); for (j=0; j<8; j++) { t = (j==0) ? AC_TABLE_INDEX0 : (j==1) ? AC_TABLE_INDEX1 : (j==2) ? DC_TABLE_INDEX0 : (j==3)? DC_TABLE_INDEX1 : (j==4) ? AC_TABLE_INDEX2 : (j==5) ? AC_TABLE_INDEX3 : (j==6) ? DC_TABLE_INDEX2 : DC_TABLE_INDEX3; for (i=0; i<256; i++) { //only support 3 huffman tables if (t==DC_TABLE_INDEX3 || t==AC_TABLE_INDEX3) break; if ((t==DC_TABLE_INDEX0 || t==DC_TABLE_INDEX1 || t==DC_TABLE_INDEX2 || t==DC_TABLE_INDEX3) && (i>15)) // DC break; if ((pEncInfo->huffSize[t][i] == 0) && (pEncInfo->huffCode[t][i] == 0)) huffData = 0; else { huffData = (pEncInfo->huffSize[t][i] - 1); // Code length (1 ~ 16), 4-bit huffData = (huffData << 16) | (pEncInfo->huffCode[t][i] ); // Code word, 16-bit } JpuWriteInstReg(instRegIndex, MJPEG_HUFF_DATA_REG, huffData); } } JpuWriteInstReg(instRegIndex, MJPEG_HUFF_CTRL_REG, 0x0); return 1; } int JpgEncLoadQMatTab(JpgInst *pJpgInst, int instRegIndex) { #ifdef WIN32 __int64 dividend = 0x80000; __int64 quotient; __int64 dividend_32b = 0x80000000; #else long long int dividend = 0x80000; long long int quotient; long long int dividend_32b = 0x80000000; #endif int quantID; int divisor; int comp; int i, t; int qprec = 0; JpgEncInfo * pEncInfo; pEncInfo = &pJpgInst->JpgInfo->encInfo; for (comp=0; comp<3; comp++) { quantID = pEncInfo->pCInfoTab[comp][3]; if (quantID >= 4) return 0; t = (comp==0)? Q_COMPONENT0 : (comp==1)? Q_COMPONENT1 : Q_COMPONENT2; JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, 0x3 + t); if (pEncInfo->jpg12bit != 0){ if (comp == 0) qprec = pEncInfo->q_prec0; else qprec = pEncInfo->q_prec1; } for (i=0; i<64; i++) { divisor = pEncInfo->pQMatTab[quantID][i]; if (qprec) quotient= dividend_32b / divisor; else quotient= dividend / divisor; // enhace bit precision & rounding Q if (qprec){ JpuWriteInstReg(instRegIndex, MJPEG_QMAT_DATA_REG, (int)(divisor & 0xFFFF)); JpuWriteInstReg(instRegIndex, MJPEG_QMAT_DATA_REG, (int)(quotient & 0xFFFFFFFF)); }else JpuWriteInstReg(instRegIndex, MJPEG_QMAT_DATA_REG, (int)(divisor<<20)|(int)(quotient & 0xFFFFF)); } JpuWriteInstReg(instRegIndex, MJPEG_QMAT_CTRL_REG, t); } return 1; } #define PUT_BYTE(_p, _b) \ if (tot++ > len) return 0; \ *_p++ = (unsigned char)(_b); int JpgEncEncodeHeader(JpgEncHandle handle, JpgEncParamSet * para) { JpgInst *pJpgInst; JpgEncInfo *pEncInfo; BYTE *p; int tot, len, pad; BYTE *pCInfoTab[4]; int frameFormat; Int32 i; Uint32 width, height; tot = 0; pJpgInst = handle; pEncInfo = &pJpgInst->JpgInfo->encInfo; p = para->pParaSet; len = para->size; // SOI Header PUT_BYTE(p, 0xff); PUT_BYTE(p, 0xD8); if (!para->disableAPPMarker) { // APP9 Header PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xE9); PUT_BYTE(p, 0x00); PUT_BYTE(p, 0x04); PUT_BYTE(p, (pEncInfo->frameIdx >> 8)); PUT_BYTE(p, (pEncInfo->frameIdx & 0xFF)); } // DRI header if (pEncInfo->rstIntval) { PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xDD); PUT_BYTE(p, 0x00); PUT_BYTE(p, 0x04); PUT_BYTE(p, (pEncInfo->rstIntval >> 8)); PUT_BYTE(p, (pEncInfo->rstIntval & 0xff)); } // DQT Header PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xDB); if (para->quantMode == JPG_TBL_NORMAL) { PUT_BYTE(p, 0x00); if (pEncInfo->q_prec0 == TRUE) { PUT_BYTE(p, 0x83); } else { PUT_BYTE(p, 0x43); } if (pEncInfo->q_prec0 == TRUE) { PUT_BYTE(p, 0x10); // Pq } else { PUT_BYTE(p, 0x00); // Pq } for (i=0; i<64; i++) { if (pEncInfo->q_prec0 == TRUE) { Uint16 q = pEncInfo->pQMatTab[0][i]; PUT_BYTE(p, (q>>8)&0xff); PUT_BYTE(p, q&0xff); } else { PUT_BYTE(p, pEncInfo->pQMatTab[0][i]); } } if (pEncInfo->format != FORMAT_400) { PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xDB); PUT_BYTE(p, 0x00); if (pEncInfo->q_prec1 == TRUE) { PUT_BYTE(p, 0x83); } else { PUT_BYTE(p, 0x43); } if (pEncInfo->q_prec1 == TRUE) { PUT_BYTE(p, 0x11); // Pq } else { PUT_BYTE(p, 0x01); // Pq } for (i=0; i<64; i++) { if (pEncInfo->q_prec1 == TRUE) { Uint16 q = pEncInfo->pQMatTab[1][i]; PUT_BYTE(p, (q>>8)&0xff); PUT_BYTE(p, q&0xff); } else { PUT_BYTE(p, pEncInfo->pQMatTab[1][i]); } } } } else// if (para->quantMode == JPG_TBL_MERGE) { if (pEncInfo->format != FORMAT_400) { Uint16 qLength = 0x84; if (pEncInfo->q_prec0 == TRUE) { qLength += 64; } if (pEncInfo->q_prec1 == TRUE) { qLength += 64; } PUT_BYTE(p, (qLength>>8)&0xff); PUT_BYTE(p, qLength&0xff); } else { Uint16 qLength = 0x43; if (pEncInfo->q_prec0 == TRUE) { qLength += 64; } PUT_BYTE(p, (qLength>>8)&0xff); PUT_BYTE(p, qLength&0xff); } PUT_BYTE(p, 0x00 | (pEncInfo->q_prec0 << 4)); // Luma for (i=0; i<64; i++) { if (pEncInfo->q_prec0 == TRUE) { Uint16 q = pEncInfo->pQMatTab[0][i]; PUT_BYTE(p, (q>>8)&0xff); PUT_BYTE(p, q&0xff); } else { PUT_BYTE(p, pEncInfo->pQMatTab[0][i]); } } if (pEncInfo->format != FORMAT_400) { PUT_BYTE(p, 0x01 | (pEncInfo->q_prec1 << 4)); // Croma for (i=0; i<64; i++) { if (pEncInfo->q_prec0 == TRUE) { Uint16 q = pEncInfo->pQMatTab[1][i]; PUT_BYTE(p, (q>>8)&0xff); PUT_BYTE(p, q&0xff); } else { PUT_BYTE(p, pEncInfo->pQMatTab[1][i]); } } } } // DHT Header PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xC4); if (para->huffMode == JPG_TBL_NORMAL) { Int32 numHuffValDC = pEncInfo->jpg12bit == TRUE ? 13 : 12; Int32 numHuffValAC = pEncInfo->jpg12bit == TRUE ? 256: 162; Uint16 LhDC = pEncInfo->jpg12bit == TRUE ? 32 : 31; Uint16 LhAC = pEncInfo->jpg12bit == TRUE ? 275 : 181; /* Lh: Huffman table definition length */ PUT_BYTE(p, (LhDC>>8)); PUT_BYTE(p, LhDC&0xff); PUT_BYTE(p, 0x00); /* TcTh : DC : ID0 */ for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[0][i]); } for (i=0; ipHuffVal[0][i]); } PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xC4); PUT_BYTE(p, (LhAC>>8)); PUT_BYTE(p, LhAC&0xff); PUT_BYTE(p, 0x10); /* TcTh = AC : ID0 */ for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[1][i]); } for (i=0; ipHuffVal[1][i]); } if (pEncInfo->format != FORMAT_400) { PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xC4); PUT_BYTE(p, (LhDC>>8)&0xff); PUT_BYTE(p, LhDC&0xff); PUT_BYTE(p, 0x01); for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[2][i]); } for (i=0; ipHuffVal[2][i]); } PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xC4); PUT_BYTE(p, (LhAC>>8)&0xff); PUT_BYTE(p, LhAC&0xff); PUT_BYTE(p, 0x11); for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[3][i]); } for (i=0; ipHuffVal[3][i]); } if (pEncInfo->jpg12bit == TRUE) { PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xC4); PUT_BYTE(p, (LhDC>>8)&0xff); PUT_BYTE(p, LhDC&0xff); PUT_BYTE(p, 0x02); /* TcTh = DC : ID2 */ for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[4][i]); } for (i=0; ipHuffVal[4][i]); } PUT_BYTE(p, 0xFF); PUT_BYTE(p, 0xC4); PUT_BYTE(p, (LhAC>>8)&0xff); PUT_BYTE(p, LhAC&0xff); PUT_BYTE(p, 0x12); /* TcTh = AC : ID2 */ for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[5][i]); } for (i=0; ipHuffVal[5][i]); } } } } else// if (para->huffMode == JPG_TBL_MERGE) { if (pEncInfo->format != FORMAT_400) { PUT_BYTE(p, 0x01); PUT_BYTE(p, 0xA2); //PUT_BYTE(p, 2 + 1*4 + 28 + 178 + 28 + 178 ); } else { PUT_BYTE(p, 0x00); PUT_BYTE(p, 0xD4); //PUT_BYTE(p, 2 + 1*4 + 28 + 178 ); } PUT_BYTE(p, 0x00); for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[0][i]); } for (i=0; i<12; i++) { PUT_BYTE(p, pEncInfo->pHuffVal[0][i]); } PUT_BYTE(p, 0x10); for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[1][i]); } for (i=0; i<162; i++) { PUT_BYTE(p, pEncInfo->pHuffVal[1][i]); } if (pEncInfo->format != FORMAT_400) { PUT_BYTE(p, 0x01); for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[2][i]); } for (i=0; i<12; i++) { PUT_BYTE(p, pEncInfo->pHuffVal[2][i]); } PUT_BYTE(p, 0x11); for (i=0; i<16; i++) { PUT_BYTE(p, pEncInfo->pHuffBits[3][i]); } for (i=0; i<162; i++) { PUT_BYTE(p, pEncInfo->pHuffVal[3][i]); } } } // SOF header PUT_BYTE(p, 0xFF); PUT_BYTE(p, (pEncInfo->jpg12bit == TRUE ? 0xC1 : 0xC0)); PUT_BYTE(p, (((8+(pEncInfo->compNum*3)) >> 8) & 0xFF)); PUT_BYTE(p, ((8+(pEncInfo->compNum*3)) & 0xFF)); PUT_BYTE(p, (pEncInfo->jpg12bit == TRUE ? 12 : 8)); width = pEncInfo->picWidth; height = pEncInfo->picHeight; frameFormat = pEncInfo->format; if (pEncInfo->rotationIndex == 1 || pEncInfo->rotationIndex == 3) { // rotation angle = rotationIndex x 90; width = pEncInfo->picHeight; height = pEncInfo->picWidth; if (frameFormat == FORMAT_422) frameFormat = FORMAT_440; else if (frameFormat == FORMAT_440) frameFormat = FORMAT_422; } PUT_BYTE(p, (height >> 8)); PUT_BYTE(p, (height & 0xFF)); PUT_BYTE(p, (width >> 8)); PUT_BYTE(p, (width & 0xFF)); PUT_BYTE(p, pEncInfo->compNum); pCInfoTab[0] = sJpuCompInfoTable[frameFormat]; pCInfoTab[1] = pCInfoTab[0] + 6; pCInfoTab[2] = pCInfoTab[1] + 6; pCInfoTab[3] = pCInfoTab[2] + 6; for (i=0; icompNum; i++) { PUT_BYTE(p, (i+1)); PUT_BYTE(p, ((pCInfoTab[i][1]<<4) & 0xF0) + (pCInfoTab[i][2] & 0x0F)); PUT_BYTE(p, pCInfoTab[i][3]); } if (para->enableSofStuffing) { pad = 0; if (tot % 8) { pad = tot % 8; pad = 8-pad; for (i=0; iframeIdx++; para->size = tot; return tot; } void JpgEncSetQualityFactor(JpgEncHandle handle, Uint32 quality, BOOL useStdTable) { JpgInst *pJpgInst; JpgEncInfo *pEncInfo; Uint32 scaleFactor; Uint32 i; Uint32 temp; pJpgInst = handle; pEncInfo = &pJpgInst->JpgInfo->encInfo; /* These are the sample quantization tables given in JPEG spec section K.1. * The spec says that the values given produce "good" quality, and * when divided by 2, "very good" quality. */ static const Uint32 std_luminance_quant_tbl[64] = { 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99 }; static const Uint32 std_chrominance_quant_tbl[64] = { 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }; Uint32 pLumaQTable[64]; Uint32 pChromaQTable[64]; Uint32 qSize = 1, qTableSize; Uint32 minQvalue = MIN_Q8_ELEMENT; if (quality <= 0) quality = 1; if (quality > 100) quality = 100; for (i = 0; i<64; i++) { pLumaQTable[i] = (useStdTable == TRUE) ? std_luminance_quant_tbl[i] : (Int32)pEncInfo->pQMatTab[DC_TABLE_INDEX0][i]; } for (i = 0; i<64; i++) { pChromaQTable[i] = (useStdTable == TRUE) ? std_chrominance_quant_tbl[i] : (Int32)pEncInfo->pQMatTab[AC_TABLE_INDEX0][i]; } minQvalue = (pEncInfo->jpg12bit == TRUE) ? MIN_Q16_ELEMENT : MIN_Q8_ELEMENT; /* The basic table is used as-is (scaling 100) for a quality of 50. * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table * to make all the table entries 1 (hence, minimum quantization loss). * Qualities 1..50 are converted to scaling percentage 5000/Q. */ if (quality < 50) scaleFactor = 5000 / quality; else scaleFactor = 200 - quality * 2; for (i = 0; i < 64; i++) { temp = (pLumaQTable[i] * scaleFactor + 50) / 100; /* limit the values to the valid range */ temp = (temp < minQvalue) ? minQvalue : temp; if (temp > 32767) temp = 32767; /* max quantizer needed for 12 bits */ if (pEncInfo->q_prec0 == FALSE && temp > 255) temp = 255; /* limit to baseline range if requested */ pEncInfo->pQMatTab[DC_TABLE_INDEX0][i] = temp; } for (i = 0; i < 64; i++) { temp = (pChromaQTable[i] * scaleFactor + 50) / 100; /* limit the values to the valid range */ temp = (temp < minQvalue) ? minQvalue : temp; if (temp > 32767) temp = 32767; /* max quantizer needed for 12 bits */ if (pEncInfo->q_prec1 == FALSE && temp > 255) temp = 255; /* limit to baseline range if requested */ pEncInfo->pQMatTab[AC_TABLE_INDEX0][i] = temp; } qSize = pEncInfo->jpg12bit ? 2 : 1; //setting of qmatrix table information #ifdef USE_CNM_DEFAULT_QMAT_TABLE memset((void*)pEncInfo->pQMatTab[DC_TABLE_INDEX0], 0x00, 64 * qSize); memcpy((void*)pEncInfo->pQMatTab[DC_TABLE_INDEX0], (void*)lumaQ2, 64 * qSize); memset((void*)pEncInfo->pQMatTab[AC_TABLE_INDEX0], 0x00, 64 * qSize); memcpy((void*)ppEncInfo->pQMatTab[AC_TABLE_INDEX0], (void*)chromaBQ2, 64 * qSize); #endif qTableSize = 64 * qSize; memcpy((void*)pEncInfo->pQMatTab[DC_TABLE_INDEX1], (void*)pEncInfo->pQMatTab[DC_TABLE_INDEX0], qTableSize); memcpy((void*)pEncInfo->pQMatTab[AC_TABLE_INDEX1], (void*)pEncInfo->pQMatTab[AC_TABLE_INDEX0], qTableSize); } JpgRet JpgEnterLock() { jdi_lock(); return JPG_RET_SUCCESS; } JpgRet JpgLeaveLock() { jdi_unlock(); return JPG_RET_SUCCESS; } JpgRet JpgSetClockGateEx(Uint32 on, Uint32 instIdx) { JpgInst *inst; jpu_instance_pool_t *jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return JPG_RET_FAILURE; inst = (JpgInst *)jip->instPendingInst[instIdx]; if(inst && !on) return JPG_RET_SUCCESS; jdi_set_clock_gate(on); return JPG_RET_SUCCESS; } JpgInst *GetJpgPendingInstEx(Uint32 instIdx) { jpu_instance_pool_t *jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return NULL; if (instIdx >= MAX_NUM_INSTANCE) return NULL; return jip->instPendingInst[instIdx]; } void SetJpgPendingInstEx(JpgInst *inst, Uint32 instIdx) { jpu_instance_pool_t *jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return; if (instIdx >= MAX_NUM_INSTANCE) return; jip->instPendingInst[instIdx] = inst; } void ClearJpgPendingInstEx(Uint32 instIdx) { jpu_instance_pool_t *jip; jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); if (!jip) return; if (instIdx >= MAX_NUM_INSTANCE) return; if(jip->instPendingInst[instIdx]) jip->instPendingInst[instIdx] = 0; }