//*@@@+++@@@@****************************************************************** // // Copyright © Microsoft Corp. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // • Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // • 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 HOLDER 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 #include #include "strcodec.h" #include "encode.h" #ifdef MEM_TRACE #define TRACE_MALLOC 1 #define TRACE_NEW 0 #define TRACE_HEAP 0 #include "memtrace.h" #endif /** local function definitions **/ #ifdef X86OPT_INLINE __forceinline #endif static Int EncodeBlock (Bool bChroma, const Int *aLocalCoef, Int iNumNonzero, struct CAdaptiveHuffman **pAHexpt, Int iContextOffset, BitIOInfo* pOut, UInt iLocation); /************************************************************************* EncodeSignificantAbsLevel *************************************************************************/ #ifdef X86OPT_INLINE //__forceinline #endif static Void EncodeSignificantAbsLevel (UInt iAbsLevel, struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pOut) { Int iIndex, iFixed, aIndex[] = { 0,1,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5 }; Int aFixedLength[] = { 0, 0, 1, 2, 2, 2 }; assert(iAbsLevel > 0); iAbsLevel--; if (iAbsLevel >= 16) { Int i = iAbsLevel; iIndex = 6; /** find leftmost bit **/ i >>= 5; iFixed = 4; while (i) { /** caution - infinite loop if not careful **/ iFixed++; assert (iFixed < 30); i >>= 1; } pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1], pAHexpt->m_pTable[iIndex * 2 + 2]); if (iFixed > 18) { putBit16z (pOut, 15, 4); if (iFixed > 21) { putBit16z (pOut, 3, 2); putBit16 (pOut, iFixed - 22, 3); // 22 - 29 } else putBit16z (pOut, iFixed - 19, 2); // 19 20 21 } else { putBit16z(pOut, (iFixed - 4), 4); } putBit32(pOut, iAbsLevel, iFixed); } else { iIndex = aIndex[iAbsLevel]; iFixed = aFixedLength[iIndex]; pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1], pAHexpt->m_pTable[iIndex * 2 + 2]); putBit32(pOut, iAbsLevel, iFixed); } } /************************************************************************* EncodeMacroblockDC *************************************************************************/ Void encodeQPIndex(BitIOInfo* pIO, U8 iIndex,U8 cBits) { if(iIndex == 0) putBit16z(pIO, 0, 1); else{ putBit16z(pIO, 1, 1); putBit16z(pIO, iIndex - 1, cBits); } } Int EncodeMacroblockDC (CWMImageStrCodec *pSC, CCodingContext *pContext, Int iMBX, Int iMBY) { CWMITile * pTile = pSC->pTile + pSC->cTileColumn; BitIOInfo* pIO = pContext->m_pIODC; CWMIMBInfo *pMBInfo = &pSC->MBInfo; Int iIndex, j = 0; struct CAdaptiveHuffman *pAH; Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean; Int iModelBits = pContext->m_aModelDC.m_iFlcBits[0]; COLORFORMAT cf = pSC->m_param.cfColorFormat; const Int iChannels = (Int) pSC->m_param.cNumChannels; UNREFERENCED_PARAMETER( iMBX ); UNREFERENCED_PARAMETER( iMBY ); writeIS_L1(pSC, pIO); if(pSC->m_param.bTranscode == FALSE){ pMBInfo->iQIndexLP = (U8)(pTile->cNumQPLP > 1 ? (rand() % pTile->cNumQPLP) : 0); pMBInfo->iQIndexHP = (U8)(pTile->cNumQPHP > 1 ? (rand() % pTile->cNumQPHP) : 0); } if(pTile->cBitsHP == 0 && pTile->cNumQPHP > 1) // use LP QP pMBInfo->iQIndexHP = pMBInfo->iQIndexLP; if(pSC->WMISCP.bfBitstreamFormat == SPATIAL && pSC->WMISCP.sbSubband != SB_DC_ONLY){ if(pTile->cBitsLP > 0) // MB-based LP QP index encodeQPIndex(pIO, pMBInfo->iQIndexLP, pTile->cBitsLP); if( pSC->WMISCP.sbSubband != SB_NO_HIGHPASS && pTile->cBitsHP > 0) // MB-based HP QP index encodeQPIndex(pIO, pMBInfo->iQIndexHP, pTile->cBitsHP); } if(pSC->m_param.bTranscode == FALSE) pSC->Quantize(pSC); predMacroblockEnc(pSC); /** code path for Y_ONLY, CMYK and N_CHANNEL DC **/ if(cf == Y_ONLY || cf == CMYK || cf == NCOMPONENT) { Int iQDC, iDC, iSign; for (j = 0; j < iChannels; j++) { iDC = pMBInfo->iBlockDC[j][0]; iSign = (iDC < 0); iDC = abs(iDC); iQDC = iDC >> iModelBits; /** send luminance DC **/ if (iQDC) { putBit16z(pIO, 1, 1); EncodeSignificantAbsLevel((UInt) iQDC, pContext->m_pAHexpt[3], pIO); *pLM += 1; } else { putBit16z(pIO, 0, 1); } putBit16(pIO, iDC, iModelBits); if (iDC) { putBit16z(pIO, iSign, 1); } pLM = aLaplacianMean + 1; iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; } } else { /** code path for YUV DC **/ Int iDCY, iDCU, iDCV, iQDCY, iQDCU, iQDCV; pAH = pContext->m_pAHexpt[2]; iQDCY = abs(iDCY = pMBInfo->iBlockDC[0][0]); iQDCU = abs(iDCU = pMBInfo->iBlockDC[1][0]); iQDCV = abs(iDCV = pMBInfo->iBlockDC[2][0]); if (iModelBits) { iQDCY >>= iModelBits; } iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; if (iModelBits) { iQDCU >>= iModelBits; iQDCV >>= iModelBits; } iModelBits = pContext->m_aModelDC.m_iFlcBits[0]; iIndex = (iQDCY != 0) * 4 + (iQDCU != 0) * 2 + (iQDCV != 0); putBit16z(pIO, pAH->m_pTable[iIndex * 2 + 1], pAH->m_pTable[iIndex * 2 + 2]); /** send luminance DC **/ if (iQDCY) { EncodeSignificantAbsLevel((UInt) iQDCY, pContext->m_pAHexpt[3], pIO); *pLM += 1; } putBit16(pIO, abs(iDCY), iModelBits); if (iDCY) { putBit16z(pIO, (iDCY < 0), 1); } /** send chroma DC **/ pLM = aLaplacianMean + 1; iModelBits = pContext->m_aModelDC.m_iFlcBits[1]; if (iQDCU) { EncodeSignificantAbsLevel((UInt) iQDCU, pContext->m_pAHexpt[4], pIO); *pLM += 1; } putBit16(pIO, abs(iDCU), iModelBits); if (iDCU) { putBit16z(pIO, (iDCU < 0), 1); } if (iQDCV) { EncodeSignificantAbsLevel((UInt) iQDCV, pContext->m_pAHexpt[4], pIO); *pLM += 1; } putBit16(pIO, abs(iDCV), iModelBits); if (iDCV) { putBit16z(pIO, (iDCV < 0), 1); } } UpdateModelMB (cf, iChannels, aLaplacianMean, &(pContext->m_aModelDC)); if (pSC->m_bResetContext && pSC->WMISCP.sbSubband == SB_DC_ONLY) { AdaptDiscriminant(pContext->m_pAHexpt[2]); AdaptDiscriminant(pContext->m_pAHexpt[3]); AdaptDiscriminant(pContext->m_pAHexpt[4]); } return ICERR_OK; } /************************************************************************* Scan block with zero model bits *************************************************************************/ #ifdef X86OPT_INLINE __forceinline #endif static Int AdaptiveScanZero (const PixelI *pCoeffs, CAdaptiveScan *pScan, Int *pRLCoeffs, const Int iCount) { Int k, iRun = 1, iLevel, iNumNonzero = 0; iLevel = pCoeffs[pScan[1].uScan]; if (iLevel) { pScan[1].uTotal++; pRLCoeffs[iNumNonzero * 2] = 0; pRLCoeffs[iNumNonzero * 2 + 1] = iLevel; iNumNonzero++; iRun = 0; } for (k = 2; k < iCount; k++) { iLevel = pCoeffs[pScan[k].uScan]; iRun++; if (iLevel) { pScan[k].uTotal++; if (pScan[k].uTotal > pScan[k - 1].uTotal) { CAdaptiveScan cTemp = pScan[k]; pScan[k] = pScan[k - 1]; pScan[k - 1] = cTemp; } pRLCoeffs[iNumNonzero * 2] = iRun - 1; pRLCoeffs[iNumNonzero * 2 + 1] = iLevel; iNumNonzero++; iRun = 0; } } return iNumNonzero; } /************************************************************************* Scan block with nonzero model bits, all trimmed *************************************************************************/ #ifdef X86OPT_INLINE __forceinline #endif static Int AdaptiveScanTrim (const PixelI *pCoeffs, CAdaptiveScan *pScan, const Int iModelBits, Int *pRLCoeffs, const Int iCount) { Int k, iRun = 1, iLevel, iNumNonzero = 0; Int iTemp; unsigned int iThOff = (1 << iModelBits) - 1, iTh = iThOff * 2 + 1; iLevel = pCoeffs[pScan[1].uScan]; if ((unsigned int)(iLevel + iThOff) >= iTh) { iTemp = abs (iLevel) >> iModelBits; pScan[1].uTotal++; pRLCoeffs[iNumNonzero * 2] = 0; pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; iNumNonzero++; iRun = 0; } for (k = 2; k < iCount; k++) { iRun++; iLevel = pCoeffs[pScan[k].uScan]; if ((unsigned int)(iLevel + iThOff) >= iTh) { iTemp = abs (iLevel) >> iModelBits; pScan[k].uTotal++; if (pScan[k].uTotal > pScan[k - 1].uTotal) { CAdaptiveScan cTemp = pScan[k]; pScan[k] = pScan[k - 1]; pScan[k - 1] = cTemp; } pRLCoeffs[iNumNonzero * 2] = iRun - 1; pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; iNumNonzero++; iRun = 0; } } return iNumNonzero; } /************************************************************************* Scan block with nonzero model bits *************************************************************************/ /** saves around 1.5% at QP=1 (no SIMD opt) **/ #define USE_GRES_LUT #ifdef USE_GRES_LUT static const Int gRes[] = { 65*2+1, 63*2+1, 61*2+1, 59*2+1, 57*2+1, 55*2+1, 53*2+1, 51*2+1, 49*2+1, 47*2+1, 45*2+1, 43*2+1, 41*2+1, 39*2+1, 37*2+1, 35*2+1, 33*2+1, 31*2+1, 29*2+1, 27*2+1, 25*2+1, 23*2+1, 21*2+1, 19*2+1, 17*2+1, 15*2+1, 13*2+1, 11*2+1, 9*2+1, 7*2+1, 5*2+1, 3*2+1, 0, 2*2+1, 4*2+1, 6*2+1, 8*2+1, 10*2+1, 12*2+1, 14*2+1, 16*2+1, 18*2+1, 20*2+1, 22*2+1, 24*2+1, 26*2+1, 28*2+1, 30*2+1, 32*2+1, 34*2+1, 36*2+1, 38*2+1, 40*2+1, 42*2+1, 44*2+1, 46*2+1, 48*2+1, 50*2+1, 52*2+1, 54*2+1, 56*2+1, 58*2+1, 60*2+1, 62*2+1, 64*2+1 }; #endif // USE_GRES_LUT #ifdef X86OPT_INLINE //__forceinline #endif static Int AdaptiveScan (const PixelI *pCoeffs, Int *pResidual, CAdaptiveScan *pScan, const Int iModelBits, const Int iTrimBits, Int *pRLCoeffs, const Int iCount) { if (iModelBits == 0) { return AdaptiveScanZero (pCoeffs, pScan, pRLCoeffs, iCount); } else if (iModelBits <= iTrimBits) { return AdaptiveScanTrim (pCoeffs, pScan, iModelBits, pRLCoeffs, iCount); } else if (iTrimBits == 0 #ifdef USE_GRES_LUT && iModelBits < 6 #endif // USE_GRES_LUT ) { Int k, iRun = 0, iLevel, iNumNonzero = 0; Int iTemp, iTemp1; const unsigned int iThOff = (1 << iModelBits) - 1, iTh = iThOff * 2 + 1; iLevel = pCoeffs[pScan[1].uScan]; if ((unsigned int)(iLevel + iThOff) >= iTh) { iTemp1 = abs (iLevel); iTemp = iTemp1 >> iModelBits; pResidual[pScan[1].uScan] = (iTemp1 & iThOff) * 2; pScan[1].uTotal++; pRLCoeffs[iNumNonzero * 2] = iRun; pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; iNumNonzero++; iRun = 0; } else { iRun++; #ifdef USE_GRES_LUT pResidual[pScan[1].uScan] = gRes[(iLevel + 32)]; #else // USE_GRES_LUT iTemp = -(iLevel < 0); pResidual[pScan[1].uScan] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); #endif // USE_GRES_LUT } for (k = 2; k < iCount; k++) { const Int sk = pScan[k].uScan; //pResidual++; iLevel = pCoeffs[sk]; if ((unsigned int)(iLevel + iThOff) >= iTh) { const Int iSign = -(iLevel < 0); iTemp1 = (iSign ^ iLevel) - iSign; iTemp = iTemp1 >> iModelBits; pResidual[sk] = (iTemp1 & iThOff) * 2; pScan[k].uTotal++; if (pScan[k].uTotal > pScan[k - 1].uTotal) { CAdaptiveScan cTemp = pScan[k]; pScan[k] = pScan[k - 1]; pScan[k - 1] = cTemp; } pRLCoeffs[iNumNonzero * 2] = iRun; pRLCoeffs[iNumNonzero * 2 + 1] = (iTemp ^ iSign) - iSign; iNumNonzero++; iRun = 0; } else { iRun++; #ifdef USE_GRES_LUT pResidual[sk] = gRes[(iLevel + 32)]; #else // USE_GRES_LUT iTemp = -(iLevel < 0); pResidual[sk] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); #endif // USE_GRES_LUT ////(abs(iLevel) * 4) + ((iLevel < 0) * 2) + (iLevel != 0); } } return iNumNonzero; } else { Int k, iRun = 0, iLevel, iNumNonzero = 0; Int iTemp, iTemp1; const unsigned int iThOff = (1 << iModelBits) - 1, iTh = iThOff * 2 + 1; iLevel = pCoeffs[pScan[1].uScan]; //pResidual++; if ((unsigned int)(iLevel + iThOff) >= iTh) { iTemp1 = abs (iLevel); iTemp = iTemp1 >> iModelBits; pResidual[pScan[1].uScan] = ((iTemp1 & iThOff) >> iTrimBits) * 2; pScan[1].uTotal++; pRLCoeffs[iNumNonzero * 2] = iRun; pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; iNumNonzero++; iRun = 0; } else { iRun++; iTemp = -(iLevel < 0); iLevel = ((iLevel + iTemp) >> iTrimBits) - iTemp; // round towards zero iTemp = -(iLevel < 0); pResidual[pScan[1].uScan] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); } for (k = 2; k < iCount; k++) { const Int sk = pScan[k].uScan; //pResidual++; iLevel = pCoeffs[sk]; if ((unsigned int)(iLevel + iThOff) >= iTh) { iTemp1 = abs (iLevel); iTemp = iTemp1 >> iModelBits; pResidual[sk] = ((iTemp1 & iThOff) >> iTrimBits) * 2; pScan[k].uTotal++; if (pScan[k].uTotal > pScan[k - 1].uTotal) { CAdaptiveScan cTemp = pScan[k]; pScan[k] = pScan[k - 1]; pScan[k - 1] = cTemp; } pRLCoeffs[iNumNonzero * 2] = iRun; pRLCoeffs[iNumNonzero * 2 + 1] = (iLevel < 0) ? -iTemp : iTemp; iNumNonzero++; iRun = 0; } else { iRun++; iTemp = -(iLevel < 0); iLevel = ((iLevel + iTemp) >> iTrimBits) - iTemp; // round towards zero iTemp = -(iLevel < 0); pResidual[sk] = (iLevel ^ iTemp) * 4 + (6 & iTemp) + (iLevel != 0); } } return iNumNonzero; } } /************************************************************************* EncodeMacroblockLowpass *************************************************************************/ Int EncodeMacroblockLowpass (CWMImageStrCodec *pSC, CCodingContext *pContext, Int iMBX, Int iMBY) { const COLORFORMAT cf = pSC->m_param.cfColorFormat; const Int iChannels = (Int) pSC->m_param.cNumChannels; Int iFullChannels = (cf == YUV_420 || cf == YUV_422) ? 1 : iChannels; CWMIMBInfo *pMBInfo = &pSC->MBInfo; BitIOInfo* pIO = pContext->m_pIOLP; CAdaptiveScan *pScan = pContext->m_aScanLowpass; Int k, /*iPrevRun = -1,*/ iRun = 0;// iLastIndex = 0; Int iModelBits = pContext->m_aModelLP.m_iFlcBits[0]; PixelI aBuf[2][8]; Int aLaplacianMean[2] = {0, 0}, *pLM = aLaplacianMean; Int iChannel, iVal; Int aRLCoeffs[MAX_CHANNELS][32], iNumCoeffs[MAX_CHANNELS]; const I32 *aDC[MAX_CHANNELS]; Int aResidual[MAX_CHANNELS][16]; Void (*putBits)(BitIOInfo* pIO, U32 uiBits, U32 cBits) = putBit16; UNREFERENCED_PARAMETER( iMBX ); UNREFERENCED_PARAMETER( iMBY ); if (iChannels > MAX_CHANNELS) return ICERR_ERROR; if((pSC->WMISCP.bfBitstreamFormat != SPATIAL) && (pSC->pTile[pSC->cTileColumn].cBitsLP > 0)) // MB-based LP QP index encodeQPIndex(pIO, pMBInfo->iQIndexLP, pSC->pTile[pSC->cTileColumn].cBitsLP); // set arrays for (k = 0; k < iChannels; k++) { aDC[k] = pMBInfo->iBlockDC[k]; } /** reset adaptive scan totals **/ if (pSC->m_bResetRGITotals) { int iScale = 2; int iWeight = iScale * 16; pScan[0].uTotal = MAXTOTAL; for (k = 1; k < 16; k++) { pScan[k].uTotal = iWeight; iWeight -= iScale; } } /** scan 4x4 transform **/ for (iChannel = 0; iChannel < iFullChannels; iChannel++) { iNumCoeffs[iChannel] = AdaptiveScan (aDC[iChannel], aResidual[iChannel], pScan, iModelBits, 0, aRLCoeffs[iChannel], 16); iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; } if (cf == YUV_420 || cf == YUV_422) { /** interleave U and V **/ static const Int aRemap[] = { 4, 1,2,3, 5,6,7 }; const Int *pRemap = aRemap + (cf == YUV_420); const Int iCount = (cf == YUV_420) ? 6 : 14; Int iCoef = 0; iRun = 0; iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; for (k = 0; k < iCount; k++) { Int iIndex = pRemap[k >> 1]; Int iDC = aDC[(k & 1) + 1][iIndex]; aBuf[k & 1][iIndex] = iVal = abs (iDC) >> iModelBits; if (iVal) { aRLCoeffs[1][iCoef * 2] = iRun; aRLCoeffs[1][iCoef * 2 + 1] = (iDC < 0) ? -iVal : iVal; iCoef++; iRun = 0; } else { iRun++; } } iNumCoeffs[1] = iCoef; } /** in raw mode, this can take 6% of the bits in the extreme low rate case!!! **/ if (cf == YUV_420 || cf == YUV_422) iFullChannels = 2; if (cf == YUV_420 || cf == YUV_422 || cf == YUV_444) { int iCBP, iMax = iFullChannels * 4 - 5; /* actually (1 << iNChannels) - 1 **/ int iCountM = pContext->m_iCBPCountMax, iCountZ = pContext->m_iCBPCountZero; iCBP = (iNumCoeffs[0] > 0) + (iNumCoeffs[1] > 0) * 2; if (iFullChannels == 3) iCBP += (iNumCoeffs[2] > 0) * 4; if (iCountZ <= 0 || iCountM < 0) { iVal = iCBP; if (iCountM < iCountZ) { iVal = iMax - iCBP; } if (iVal == 0) putBit16z(pIO, 0, 1); else if (iVal == 1) putBit16z(pIO, (iFullChannels + 1) & 0x6, iFullChannels); // 2 or 4 else putBit16z(pIO, iVal + iMax + 1, iFullChannels + 1); // cbp + 4 or cbp + 8 } else { putBit16z(pIO, iCBP, iFullChannels); } iCountM += 1 - 4 * (iCBP == iMax);//(b + c - 2*a); iCountZ += 1 - 4 * (iCBP == 0);//(a + b - 2*c); if (iCountM < -8) iCountM = -8; else if (iCountM > 7) iCountM = 7; pContext->m_iCBPCountMax = iCountM; if (iCountZ < -8) iCountZ = -8; else if (iCountZ > 7) iCountZ = 7; pContext->m_iCBPCountZero = iCountZ; } else { /** 1 or N channel **/ for (iChannel = 0; iChannel < iChannels; iChannel++) { putBit16z(pIO, (iNumCoeffs[iChannel] > 0), 1); } } // set appropriate function pointer if (pContext->m_aModelLP.m_iFlcBits[0] > 14 || pContext->m_aModelLP.m_iFlcBits[1] > 14) { putBits = putBit32; } iModelBits = pContext->m_aModelLP.m_iFlcBits[0]; for (iChannel = 0; iChannel < iFullChannels; iChannel++) { const Int *pRL = aRLCoeffs[iChannel]; Int iCoef = iNumCoeffs[iChannel]; if (iCoef) { (*pLM) += iCoef; if(EncodeBlock (iChannel > 0, pRL, iCoef, pContext->m_pAHexpt, CTDC, pIO, 1 + 9 * ((cf == YUV_420) && (iChannel == 1)) + ((cf == YUV_422) && (iChannel == 1))) != ICERR_OK) return ICERR_ERROR; } if (iModelBits) { if ((cf == YUV_420 || cf == YUV_422) && iChannel) { // 420/422 chroma for (k = 1; k < ((cf == YUV_420) ? 4 : 8); k++) { putBits(pIO, abs(aDC[1][k]), iModelBits); if (aBuf[0][k] == 0 && aDC[1][k]) { putBit16z(pIO, (aDC[1][k] < 0), 1); } putBits(pIO, abs(aDC[2][k]), iModelBits); if (aBuf[1][k] == 0 && aDC[2][k]) { putBit16z(pIO, (aDC[2][k] < 0), 1); } } } else { // normal case for (k = 1; k < 16; k++) { putBit16z(pIO, aResidual[iChannel][k] >> 1, iModelBits + (aResidual[iChannel][k] & 1)); } } } pLM = aLaplacianMean + 1; iModelBits = pContext->m_aModelLP.m_iFlcBits[1]; } writeIS_L1(pSC, pIO); UpdateModelMB (cf, iChannels, aLaplacianMean, &pContext->m_aModelLP); if (pSC->m_bResetContext) { AdaptLowpassEnc(pContext); } return ICERR_OK; } /************************************************************************* Adapt *************************************************************************/ Void AdaptLowpassEnc(CCodingContext *pSC) { Int kk; for (kk = 0; kk < CONTEXTX + CTDC; kk++) { /** adapt fixed code (index 0 and 1) as well **/ AdaptDiscriminant (pSC->m_pAHexpt[kk]); } } Void AdaptHighpassEnc(CCodingContext *pSC) { Int kk; //Adapt (pSC->m_pAdaptHuffCBPCY, FALSE); AdaptDiscriminant (pSC->m_pAdaptHuffCBPCY); AdaptDiscriminant (pSC->m_pAdaptHuffCBPCY1); for (kk = 0; kk < CONTEXTX; kk++) { /** adapt fixed code **/ AdaptDiscriminant (pSC->m_pAHexpt[kk + CONTEXTX + CTDC]); } } /************************************************************************* Experimental code -- encodeBlock SR = <0 1 2> == alphabet 12: pAHexpt[0] == alphabet 6: pAHexpt[1] == pAHexpt[2] == alphabet 4: pAHexpt[3] == (SR may be last or insignificant only) alphabet f(run) (this can be extended to 6 contexts - SL and SR') pAHexpt[4] == alphabet f(lev) (this can be extended to 9 contexts) pAHexpt[5-6] == first symbol pAHexpt[7-8] == condition on SRn no use *************************************************************************/ #ifdef X86OPT_INLINE __forceinline #endif static Void EncodeSignificantRun (Int iRun, Int iMaxRun, struct CAdaptiveHuffman *pAHexpt, BitIOInfo* pOut) { Int iIndex, iFLC, iBin; static const Int aIndex[] = { 0,1,2,2,3,3,4,4,4,4,4,4,4,4, 0,1,2,2,3,3,4,4,4,4,0,0,0,0, 0,1,2,3,4,4 }; if (iMaxRun < 5) { //if (iMaxRun == 4) { //static const Int gCode[] = { 0, 1, 1, 1 }; static const Int gLen[] = { 3, 3, 2, 1 }; if (iMaxRun > 1) putBit16z(pOut, (iMaxRun != iRun), gLen[iMaxRun - iRun] - (4 - iMaxRun)); //} //else if (iMaxRun == 3) { // if (iRun == 1) { // putBit16z(pOut, 1, 1); // } // else { // putBit16z(pOut, 3 ^ iRun, 2); // } //} //else if (iMaxRun == 2) { // putBit16z(pOut, 2 - iRun, 1); //} return; } iBin = gSignificantRunBin[iMaxRun]; iIndex = aIndex[iRun + iBin * 14 - 1]; iFLC = gSignificantRunFixedLength[iIndex + iBin * 5]; putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1], pAHexpt->m_pTable[iIndex * 2 + 2]); //this always uses table 0 //pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; putBit16(pOut, iRun + 1, iFLC); } #ifdef X86OPT_INLINE __forceinline #endif static Void EncodeFirstIndex (Bool bChroma, Int iLoc, Int iCont, Int iIndex, Int iSign, struct CAdaptiveHuffman **ppAHexpt, BitIOInfo* pOut) { // Int iContext = iCont + 1 + bChroma * 3; struct CAdaptiveHuffman *pAHexpt = ppAHexpt[bChroma * 3]; UNREFERENCED_PARAMETER( iLoc ); UNREFERENCED_PARAMETER( iCont ); pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; pAHexpt->m_iDiscriminant1 += pAHexpt->m_pDelta1[iIndex]; putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1] * 2 + iSign, pAHexpt->m_pTable[iIndex * 2 + 2] + 1); return; } #ifdef X86OPT_INLINE __forceinline #endif static Void EncodeIndex (Bool bChroma, Int iLoc, Int iCont, Int iIndex, Int iSign, struct CAdaptiveHuffman **ppAHexpt, BitIOInfo* pOut) { Int iContext = iCont + 1 + bChroma * 3; if (iLoc < 15) { struct CAdaptiveHuffman *pAHexpt = ppAHexpt[iContext]; pAHexpt->m_iDiscriminant += pAHexpt->m_pDelta[iIndex]; pAHexpt->m_iDiscriminant1 += pAHexpt->m_pDelta1[iIndex]; putBit16z(pOut, pAHexpt->m_pTable[iIndex * 2 + 1] * 2 + iSign, pAHexpt->m_pTable[iIndex * 2 + 2] + 1); } else if (iLoc == 15) { static const U32 gCode[] = { 0, 6, 2, 7 }; static const U32 gLen[] = { 1, 3, 2, 3 }; putBit16z(pOut, gCode[iIndex] * 2 + iSign, gLen[iIndex] + 1); return; } else {//if (iLoc == 16) { putBit16z(pOut, iIndex * 2 + iSign, 1 + 1); return; } } #ifdef X86OPT_INLINE __forceinline #endif static Int EncodeBlock (Bool bChroma, const Int *aLocalCoef, Int iNumNonzero, struct CAdaptiveHuffman **pAHexpt, Int iContextOffset, BitIOInfo* pOut, UInt iLocation) { Int iSR, iSL, iSRn, iIndex, k, iCont, iLev; /** first symbol **/ iLev = aLocalCoef[1]; iSR = (aLocalCoef[0] == 0); iSL = ((unsigned int) (iLev + 1) > 2U); iSRn = 1; if (iNumNonzero == 1) { iSRn = 0; } else if (aLocalCoef[2] > 0) { iSRn = 2; } iIndex = iSRn * 4 + iSL * 2 + iSR; EncodeFirstIndex (bChroma, iLocation, 0, iIndex, (iLev < 0), pAHexpt + iContextOffset, pOut); iCont = iSR & iSRn; if (iSL) { EncodeSignificantAbsLevel ((UInt)(abs(iLev) - 1), pAHexpt[6 + iContextOffset + iCont], pOut); } if (iSR == 0) { EncodeSignificantRun (aLocalCoef[0], 15 - iLocation, pAHexpt[0], pOut); } iLocation += aLocalCoef[0] + 1; for (k = 1; k < iNumNonzero; k++) { if (iSRn == 2) { EncodeSignificantRun (aLocalCoef[k * 2], 15 - iLocation, pAHexpt[0], pOut); } iLocation += aLocalCoef[k * 2] + 1; iSRn = 1; if (k == iNumNonzero - 1) { iSRn = 0; } else if (aLocalCoef[k * 2 + 2] > 0) { iSRn = 2; } //iSL = (abs(aLocalCoef[k * 2 + 1]) > 1); iLev = aLocalCoef[k * 2 + 1]; iSL = ((unsigned int) (iLev + 1) > 2U); iIndex = iSRn * 2 + iSL; EncodeIndex (bChroma, iLocation, iCont, iIndex, (iLev < 0), pAHexpt + iContextOffset, pOut); iCont &= iSRn; /** big difference! **/ if (iSL) { EncodeSignificantAbsLevel ((UInt)(abs(iLev) - 1), pAHexpt[6 + iContextOffset + iCont], pOut); } //else { // putBit16z(pOut, (iLev < 0), 1); //} } return ICERR_OK; } /************************************************************************* CodeCoeffs *************************************************************************/ #ifdef X86OPT_INLINE __forceinline #endif static Int CodeCoeffs (CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY, BitIOInfo* pIO, BitIOInfo* pIOFL) { const COLORFORMAT cf = pSC->m_param.cfColorFormat; const Int iChannels = (Int) pSC->m_param.cNumChannels; const Int iPlanes = (cf == YUV_420 || cf == YUV_422) ? 1 : iChannels; CWMIMBInfo * pMBInfo = &pSC->MBInfo; CAdaptiveScan *pScan; Int iBlock, iNBlocks = 4; Int iSubblock, iIndex = 0; Int i, k; const Int iNumCoeffs = 16; Int iModelBits = pContext->m_aModelAC.m_iFlcBits[0], iFlex = 0, iTrim = 0, iMask = 0; Int aLaplacianMean[2] = { 0, 0}, *pLM = aLaplacianMean; Bool bChroma = FALSE; UNREFERENCED_PARAMETER( iMBX ); UNREFERENCED_PARAMETER( iMBY ); assert (iModelBits < 16); if (pContext->m_iTrimFlexBits <= iModelBits && pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) { iTrim = pContext->m_iTrimFlexBits; iFlex = iModelBits - pContext->m_iTrimFlexBits; iMask = (1 << iFlex) - 1; } if(pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) writeIS_L1(pSC, pIOFL); /** set scan arrays **/ if (pMBInfo->iOrientation == 1) { pScan = pContext->m_aScanVert; } else { pScan = pContext->m_aScanHoriz; } /** write out coefficients **/ for (i = 0; i < iPlanes; i++) { Int iPattern = pMBInfo->iCBP[i]; if (cf == YUV_420) { iNBlocks = 6; iPattern += (pMBInfo->iCBP[1] << 16) + (pMBInfo->iCBP[2] << 20); } else if (cf == YUV_422) { iNBlocks = 8; iPattern += (pMBInfo->iCBP[1] << 16) + (pMBInfo->iCBP[2] << 24); } for (iBlock = iIndex = 0; iBlock < iNBlocks; iBlock++) { writeIS_L2(pSC, pIO); if (pIO != pIOFL) writeIS_L2(pSC, pIOFL); for (iSubblock = 0; iSubblock < 4; iSubblock++, iPattern >>= 1, iIndex ++) { const PixelI *pCoeffs = NULL; if(iBlock < 4){ pCoeffs = pSC->pPlane[i] + blkOffset[iIndex]; } else if(cf == YUV_420){ pCoeffs = pSC->pPlane[iBlock - 3] + blkOffsetUV[iSubblock]; } else if(cf == YUV_422){ pCoeffs = pSC->pPlane[1 + ((iBlock - 4) >> 1)] + blkOffsetUV_422[(iBlock & 1) * 4 + iSubblock]; } /** put AC bits **/ if ((iPattern & 1) == 0) { if (iFlex) { /** FLC only, all else is skipped **/ for (k = 1; k < iNumCoeffs; k++) { Int data = pCoeffs[dctIndex[0][k]]; Int atdata = (abs(data) >> iTrim); Int word = atdata & iMask, len = iFlex; if (atdata) { word += word + (data < 0); len++; } putBit16z(pIOFL, word, len); } } } else { // WARNING!!! interaction between lowpass coefficients and highpass scan ordering - may lead to break in decoding when model bits is nonzero! // Fix is to use same scan order in model bits transmission, and defer update of scan order to end of block /** collect coefficients **/ Int aLocalCoef[32], iNumNonzero = 0; Int aResidual[16]; iNumNonzero = AdaptiveScan (pCoeffs, aResidual, pScan, iModelBits, iTrim, aLocalCoef, 16); (*pLM) += iNumNonzero; EncodeBlock (bChroma, aLocalCoef, iNumNonzero, pContext->m_pAHexpt, CTDC + CONTEXTX, pIO, 1); if (iFlex) { for (k = 1; k < iNumCoeffs; k++) { putBit16z(pIOFL, aResidual[dctIndex[0][k]] >> 1, iFlex + (aResidual[dctIndex[0][k]] & 1)); } } } } if (iBlock == 3) { iModelBits = pContext->m_aModelAC.m_iFlcBits[1]; assert (iModelBits < 16); pLM = aLaplacianMean + 1; bChroma = TRUE; iTrim = iFlex = iMask = 0; if (pContext->m_iTrimFlexBits <= iModelBits && pSC->WMISCP.sbSubband != SB_NO_FLEXBITS) { iTrim = pContext->m_iTrimFlexBits; iFlex = iModelBits - iTrim; iMask = (1 << iFlex) - 1; } } } } /** update model at end of MB **/ UpdateModelMB (cf, iChannels, aLaplacianMean, &pContext->m_aModelAC); return ICERR_OK; } /************************************************************************* CodeCBP *************************************************************************/ static Void CodeCBP (CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY, BitIOInfo *pIO) { const COLORFORMAT cf = pSC->m_param.cfColorFormat; const Int iChannel = (cf == NCOMPONENT || cf == CMYK) ? (Int) pSC->m_param.cNumChannels : 1; Int iDiffCBPCY, iDiffCBPCU = 0, iDiffCBPCV = 0, iDY; Int iBlock, i, k; static const Int aNumOnes[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; static const Int aTabLen[] = { 0, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 2, 2, 0 }; static const Int aTabCode[] = { 0, 0, 1, 0, 2, 1, 4, 3, 3, 5, 6, 2, 7, 1, 0, 0 }; CAdaptiveHuffman *pAH; Int iCount, iPattern, iCode, iCodeU = 0, iCodeV = 0; UNREFERENCED_PARAMETER( iMBX ); UNREFERENCED_PARAMETER( iMBY ); predCBPEnc(pSC, pContext); writeIS_L1(pSC, pIO); iDiffCBPCU = pSC->MBInfo.iDiffCBP[1]; iDiffCBPCV = pSC->MBInfo.iDiffCBP[2]; for (i = 0; i < iChannel; i++) { iDiffCBPCY = pSC->MBInfo.iDiffCBP[i]; if(cf == YUV_420){ // PackCBP420 iDiffCBPCY = (iDiffCBPCY & 0xf) + ((iDiffCBPCU & 1) << 4) + ((iDiffCBPCV & 1) << 5) + ((iDiffCBPCY & 0x00f0) << 2) + ((iDiffCBPCU & 2) << 9) + ((iDiffCBPCV & 2) << 10) + ((iDiffCBPCY & 0x0f00) << 4) + ((iDiffCBPCU & 4) << 14) + ((iDiffCBPCV & 4) << 15) + ((iDiffCBPCY & 0xf000) << 6) + ((iDiffCBPCU & 8) << 19) + ((iDiffCBPCV & 8) << 20); } else if(cf == YUV_422){// PackCBP422 iDiffCBPCY = (iDiffCBPCY & 0xf) + ((iDiffCBPCU & 1) << 4) + ((iDiffCBPCU & 4) << 3) + ((iDiffCBPCV & 1) << 6) + ((iDiffCBPCV & 4) << 5) + ((iDiffCBPCY & 0x00f0) << 4) + ((iDiffCBPCU & 2) << 11) + ((iDiffCBPCU & 8) << 10) + ((iDiffCBPCV & 2) << 13) + ((iDiffCBPCV & 8) << 12) + ((iDiffCBPCY & 0x0f00) << 8) + ((iDiffCBPCU & 16) << 16) + ((iDiffCBPCU & 64) << 15) + ((iDiffCBPCV & 16) << 18) + ((iDiffCBPCV & 64) << 17) + ((iDiffCBPCY & 0xf000) << 12) + ((iDiffCBPCU & 32) << 23) + ((iDiffCBPCU & 128) << 22) + ((iDiffCBPCV & 32) << 25) + ((iDiffCBPCV & 128) << 24); } /** send CBPCY **/ iPattern = 0; iDY = iDiffCBPCY; if (cf == YUV_444) { iDY |= (iDiffCBPCU | iDiffCBPCV); } for (iBlock = 0; iBlock < 4; iBlock++) { if(cf == YUV_422) { iPattern |= ((iDY & 0xff) != 0) * 0x10; iDY >>= 8; } else if (cf == YUV_420) { iPattern |= ((iDY & 0x3f) != 0) * 0x10; iDY >>= 6; } else { iPattern |= ((iDY & 0xf) != 0) * 0x10; iDY >>= 4; } iPattern >>= 1; } pAH = pContext->m_pAdaptHuffCBPCY1; iCount = aNumOnes[iPattern]; putBit16z(pIO, pAH->m_pTable[iCount * 2 + 1], pAH->m_pTable[iCount * 2 + 2]); pAH->m_iDiscriminant += pAH->m_pDelta[iCount]; if (aTabLen[iPattern]) { putBit16z(pIO, aTabCode[iPattern], aTabLen[iPattern]); } for (iBlock = 0; iBlock < 4; iBlock++) { switch (cf) { case YUV_444: iCode = iDiffCBPCY & 0xf; iCodeU = iDiffCBPCU & 0xf; iCodeV = iDiffCBPCV & 0xf; iCode |= ((iCodeU != 0) << 4); iCode |= ((iCodeV != 0) << 5); iDiffCBPCY >>= 4; iDiffCBPCU >>= 4; iDiffCBPCV >>= 4; break; case YUV_422: iCode = iDiffCBPCY & 0xff; iDiffCBPCY >>= 8; break; case YUV_420: iCode = iDiffCBPCY & 0x3f; iDiffCBPCY >>= 6; break; default: iCode = iDiffCBPCY & 0xf; iDiffCBPCY >>= 4; } if (iCode) { static const Int gTab0[16] = { 0,1,1,2, 1,3,3,4, 1,3,3,4, 2,4,4,5 }; static const Int gFL0[16] = { 0,2,2,1, 2,2,2,2, 2,2,2,2, 1,2,2,0 }; static const Int gCode0[16] = { 0,0,1,0, 2,0,1,0, 3,2,3,1, 1,2,3,0 }; int val, iChroma = (iCode >> 4); iCode &= 0xf; if(cf == YUV_422) { iCodeU = (iChroma & 3); iCodeV = ((iChroma >> 2) & 3); iChroma = (iCodeU == 0 ? 0 : 1); if(iCodeV != 0) { iChroma += 2; } } if (iChroma) { if (gTab0[iCode] > 2) { val = 8; } else { val = gTab0[iCode] + 6 - 1; } } else { val = gTab0[iCode] - 1; } pAH = pContext->m_pAdaptHuffCBPCY; putBit16z(pIO, pAH->m_pTable[val * 2 + 1], pAH->m_pTable[val * 2 + 2]); pAH->m_iDiscriminant += pAH->m_pDelta[val]; if (iChroma) { if (iChroma == 1) putBit16z(pIO, 1, 1); else putBit16z(pIO, 3 - iChroma, 2); } if (val == 8) { if (gTab0[iCode] == 3) { putBit16z(pIO, 1, 1); } else { putBit16z(pIO, 5 - gTab0[iCode], 2); } } if (gFL0[iCode]) { putBit16z(pIO, gCode0[iCode], gFL0[iCode]); } if (cf == YUV_444) { pAH = pContext->m_pAHexpt[1]; iPattern = iCodeU; for (k = 0; k < 2; k++) { if (iPattern) { iCount = aNumOnes[iPattern]; iCount--; putBit16z(pIO, pAH->m_pTable[iCount * 2 + 1], pAH->m_pTable[iCount * 2 + 2]); if (aTabLen[iPattern]) { putBit16z(pIO, aTabCode[iPattern], aTabLen[iPattern]); } } iPattern = iCodeV; } } else if (cf == YUV_422){ iPattern = iCodeU; for(k = 0; k < 2; k ++) { if(iPattern) { if (iPattern == 1) putBit16z(pIO, 1, 1); else { putBit16z(pIO, 3 - iPattern, 2); } } iPattern = iCodeV; } } } } } } /************************************************************************* macroblock encode function using 4x4 transforms *************************************************************************/ Int EncodeMacroblockHighpass(CWMImageStrCodec * pSC, CCodingContext *pContext, Int iMBX, Int iMBY) { BitIOInfo* pIO = pContext->m_pIOAC; BitIOInfo* pIOFL = pContext->m_pIOFL; if((pSC->WMISCP.bfBitstreamFormat != SPATIAL) && (pSC->pTile[pSC->cTileColumn].cBitsHP > 0)) // MB-based HP QP index encodeQPIndex(pIO, pSC->MBInfo.iQIndexHP, pSC->pTile[pSC->cTileColumn].cBitsHP); /** reset adaptive scan totals **/ if (pSC->m_bResetRGITotals) { Int iScale = 2; Int iWeight = iScale * 16; Int k; pContext->m_aScanHoriz[0].uTotal = pContext->m_aScanVert[0].uTotal = MAXTOTAL; for (k = 1; k < 16; k++) { pContext->m_aScanHoriz[k].uTotal = pContext->m_aScanVert[k].uTotal = iWeight; iWeight -= iScale; } } CodeCBP(pSC, pContext, iMBX, iMBY, pIO); if(CodeCoeffs(pSC, pContext, iMBX, iMBY, pIO, pIOFL) != ICERR_OK) return ICERR_ERROR; if (pSC->m_bResetContext) { AdaptHighpassEnc(pContext); } return ICERR_OK; }