/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*------------------------------------------------------------------------------ Table of contents 1. Include headers 2. External compiler flags 3. Module defines 4. Local function prototypes 5. Functions h264bsdDecodeMacroblockLayer h264bsdMbPartPredMode h264bsdNumMbPart h264bsdNumSubMbPart DecodeMbPred DecodeSubMbPred DecodeResidual DetermineNc CbpIntra16x16 h264bsdPredModeIntra16x16 h264bsdDecodeMacroblock ProcessResidual h264bsdSubMbPartMode ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 1. Include headers ------------------------------------------------------------------------------*/ #include "h264bsd_macroblock_layer.h" #include "h264bsd_slice_header.h" #include "h264bsd_util.h" #include "h264bsd_vlc.h" #include "h264bsd_cavlc.h" #include "h264bsd_nal_unit.h" #include "h264bsd_neighbour.h" #include "h264bsd_transform.h" #include "h264bsd_intra_prediction.h" #include "h264bsd_inter_prediction.h" #ifdef H264DEC_OMXDL #include "omxtypes.h" #include "omxVC.h" #include "armVC.h" #endif /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ 2. External compiler flags -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- 3. Module defines ------------------------------------------------------------------------------*/ #ifdef H264DEC_OMXDL static const u32 chromaIndex[8] = { 256, 260, 288, 292, 320, 324, 352, 356 }; static const u32 lumaIndex[16] = { 0, 4, 64, 68, 8, 12, 72, 76, 128, 132, 192, 196, 136, 140, 200, 204 }; #endif /* mapping of dc coefficients array to luma blocks */ static const u32 dcCoeffIndex[16] = {0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15}; /*------------------------------------------------------------------------------ 4. Local function prototypes ------------------------------------------------------------------------------*/ static u32 DecodeMbPred(strmData_t *pStrmData, mbPred_t *pMbPred, mbType_e mbType, u32 numRefIdxActive); static u32 DecodeSubMbPred(strmData_t *pStrmData, subMbPred_t *pSubMbPred, mbType_e mbType, u32 numRefIdxActive); static u32 DecodeResidual(strmData_t *pStrmData, residual_t *pResidual, mbStorage_t *pMb, mbType_e mbType, u32 codedBlockPattern); #ifdef H264DEC_OMXDL static u32 DetermineNc(mbStorage_t *pMb, u32 blockIndex, u8 *pTotalCoeff); #else static u32 DetermineNc(mbStorage_t *pMb, u32 blockIndex, i16 *pTotalCoeff); #endif static u32 CbpIntra16x16(mbType_e mbType); #ifdef H264DEC_OMXDL static u32 ProcessIntra4x4Residual(mbStorage_t *pMb, u8 *data, u32 constrainedIntraPred, macroblockLayer_t *mbLayer, const u8 **pSrc, image_t *image); static u32 ProcessChromaResidual(mbStorage_t *pMb, u8 *data, const u8 **pSrc ); static u32 ProcessIntra16x16Residual(mbStorage_t *pMb, u8 *data, u32 constrainedIntraPred, u32 intraChromaPredMode, const u8 **pSrc, image_t *image); #else static u32 ProcessResidual(mbStorage_t *pMb, i32 residualLevel[][16], u32 *); #endif /*------------------------------------------------------------------------------ Function name: h264bsdDecodeMacroblockLayer Functional description: Parse macroblock specific information from bit stream. Inputs: pStrmData pointer to stream data structure pMb pointer to macroblock storage structure sliceType type of the current slice numRefIdxActive maximum reference index Outputs: pMbLayer stores the macroblock data parsed from stream Returns: HANTRO_OK success HANTRO_NOK end of stream or error in stream ------------------------------------------------------------------------------*/ u32 h264bsdDecodeMacroblockLayer(strmData_t *pStrmData, macroblockLayer_t *pMbLayer, mbStorage_t *pMb, u32 sliceType, u32 numRefIdxActive) { /* Variables */ u32 tmp, i, value; i32 itmp; mbPartPredMode_e partMode; /* Code */ ASSERT(pStrmData); ASSERT(pMbLayer); #ifdef H264DEC_NEON h264bsdClearMbLayer(pMbLayer, ((sizeof(macroblockLayer_t) + 63) & ~0x3F)); #else H264SwDecMemset(pMbLayer, 0, sizeof(macroblockLayer_t)); #endif tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (IS_I_SLICE(sliceType)) { if ((value + 6) > 31 || tmp != HANTRO_OK) return(HANTRO_NOK); pMbLayer->mbType = (mbType_e)(value + 6); } else { if ((value + 1) > 31 || tmp != HANTRO_OK) return(HANTRO_NOK); pMbLayer->mbType = (mbType_e)(value + 1); } if (pMbLayer->mbType == I_PCM) { i32 *level; while( !h264bsdIsByteAligned(pStrmData) ) { /* pcm_alignment_zero_bit */ tmp = h264bsdGetBits(pStrmData, 1); if (tmp) return(HANTRO_NOK); } level = pMbLayer->residual.level[0]; for (i = 0; i < 384; i++) { value = h264bsdGetBits(pStrmData, 8); if (value == END_OF_STREAM) return(HANTRO_NOK); *level++ = (i32)value; } } else { partMode = h264bsdMbPartPredMode(pMbLayer->mbType); if ( (partMode == PRED_MODE_INTER) && (h264bsdNumMbPart(pMbLayer->mbType) == 4) ) { tmp = DecodeSubMbPred(pStrmData, &pMbLayer->subMbPred, pMbLayer->mbType, numRefIdxActive); } else { tmp = DecodeMbPred(pStrmData, &pMbLayer->mbPred, pMbLayer->mbType, numRefIdxActive); } if (tmp != HANTRO_OK) return(tmp); if (partMode != PRED_MODE_INTRA16x16) { tmp = h264bsdDecodeExpGolombMapped(pStrmData, &value, (u32)(partMode == PRED_MODE_INTRA4x4)); if (tmp != HANTRO_OK) return(tmp); pMbLayer->codedBlockPattern = value; } else { pMbLayer->codedBlockPattern = CbpIntra16x16(pMbLayer->mbType); } if ( pMbLayer->codedBlockPattern || (partMode == PRED_MODE_INTRA16x16) ) { tmp = h264bsdDecodeExpGolombSigned(pStrmData, &itmp); if (tmp != HANTRO_OK || (itmp < -26) || (itmp > 25) ) return(HANTRO_NOK); pMbLayer->mbQpDelta = itmp; tmp = DecodeResidual(pStrmData, &pMbLayer->residual, pMb, pMbLayer->mbType, pMbLayer->codedBlockPattern); pStrmData->strmBuffReadBits = (u32)(pStrmData->pStrmCurrPos - pStrmData->pStrmBuffStart) * 8 + pStrmData->bitPosInWord; if (tmp != HANTRO_OK) return(tmp); } } return(HANTRO_OK); } /*------------------------------------------------------------------------------ Function: h264bsdMbPartPredMode Functional description: Returns the prediction mode of a macroblock type ------------------------------------------------------------------------------*/ mbPartPredMode_e h264bsdMbPartPredMode(mbType_e mbType) { /* Variables */ /* Code */ ASSERT(mbType <= 31); if ((mbType <= P_8x8ref0)) return(PRED_MODE_INTER); else if (mbType == I_4x4) return(PRED_MODE_INTRA4x4); else return(PRED_MODE_INTRA16x16); } /*------------------------------------------------------------------------------ Function: h264bsdNumMbPart Functional description: Returns the amount of macroblock partitions in a macroblock type ------------------------------------------------------------------------------*/ u32 h264bsdNumMbPart(mbType_e mbType) { /* Variables */ /* Code */ ASSERT(h264bsdMbPartPredMode(mbType) == PRED_MODE_INTER); switch (mbType) { case P_L0_16x16: case P_Skip: return(1); case P_L0_L0_16x8: case P_L0_L0_8x16: return(2); /* P_8x8 or P_8x8ref0 */ default: return(4); } } /*------------------------------------------------------------------------------ Function: h264bsdNumSubMbPart Functional description: Returns the amount of sub-partitions in a sub-macroblock type ------------------------------------------------------------------------------*/ u32 h264bsdNumSubMbPart(subMbType_e subMbType) { /* Variables */ /* Code */ ASSERT(subMbType <= P_L0_4x4); switch (subMbType) { case P_L0_8x8: return(1); case P_L0_8x4: case P_L0_4x8: return(2); /* P_L0_4x4 */ default: return(4); } } /*------------------------------------------------------------------------------ Function: DecodeMbPred Functional description: Parse macroblock prediction information from bit stream and store in 'pMbPred'. ------------------------------------------------------------------------------*/ u32 DecodeMbPred(strmData_t *pStrmData, mbPred_t *pMbPred, mbType_e mbType, u32 numRefIdxActive) { /* Variables */ u32 tmp, i, j, value; i32 itmp; /* Code */ ASSERT(pStrmData); ASSERT(pMbPred); switch (h264bsdMbPartPredMode(mbType)) { case PRED_MODE_INTER: /* PRED_MODE_INTER */ if (numRefIdxActive > 1) { for (i = h264bsdNumMbPart(mbType), j = 0; i--; j++) { tmp = h264bsdDecodeExpGolombTruncated(pStrmData, &value, (u32)(numRefIdxActive > 2)); if (tmp != HANTRO_OK || value >= numRefIdxActive) return(HANTRO_NOK); pMbPred->refIdxL0[j] = value; } } for (i = h264bsdNumMbPart(mbType), j = 0; i--; j++) { tmp = h264bsdDecodeExpGolombSigned(pStrmData, &itmp); if (tmp != HANTRO_OK) return(tmp); pMbPred->mvdL0[j].hor = (i16)itmp; tmp = h264bsdDecodeExpGolombSigned(pStrmData, &itmp); if (tmp != HANTRO_OK) return(tmp); pMbPred->mvdL0[j].ver = (i16)itmp; } break; case PRED_MODE_INTRA4x4: for (itmp = 0, i = 0; itmp < 2; itmp++) { value = h264bsdShowBits32(pStrmData); tmp = 0; for (j = 8; j--; i++) { pMbPred->prevIntra4x4PredModeFlag[i] = value & 0x80000000 ? HANTRO_TRUE : HANTRO_FALSE; value <<= 1; if (!pMbPred->prevIntra4x4PredModeFlag[i]) { pMbPred->remIntra4x4PredMode[i] = value>>29; value <<= 3; tmp++; } } if (h264bsdFlushBits(pStrmData, 8 + 3*tmp) == END_OF_STREAM) return(HANTRO_NOK); } /* fall-through */ case PRED_MODE_INTRA16x16: tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (tmp != HANTRO_OK || value > 3) return(HANTRO_NOK); pMbPred->intraChromaPredMode = value; break; } return(HANTRO_OK); } /*------------------------------------------------------------------------------ Function: DecodeSubMbPred Functional description: Parse sub-macroblock prediction information from bit stream and store in 'pMbPred'. ------------------------------------------------------------------------------*/ u32 DecodeSubMbPred(strmData_t *pStrmData, subMbPred_t *pSubMbPred, mbType_e mbType, u32 numRefIdxActive) { /* Variables */ u32 tmp, i, j, value; i32 itmp; /* Code */ ASSERT(pStrmData); ASSERT(pSubMbPred); ASSERT(h264bsdMbPartPredMode(mbType) == PRED_MODE_INTER); for (i = 0; i < 4; i++) { tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (tmp != HANTRO_OK || value > 3) return(HANTRO_NOK); pSubMbPred->subMbType[i] = (subMbType_e)value; } if ( (numRefIdxActive > 1) && (mbType != P_8x8ref0) ) { for (i = 0; i < 4; i++) { tmp = h264bsdDecodeExpGolombTruncated(pStrmData, &value, (u32)(numRefIdxActive > 2)); if (tmp != HANTRO_OK || value >= numRefIdxActive) return(HANTRO_NOK); pSubMbPred->refIdxL0[i] = value; } } for (i = 0; i < 4; i++) { j = 0; for (value = h264bsdNumSubMbPart(pSubMbPred->subMbType[i]); value--; j++) { tmp = h264bsdDecodeExpGolombSigned(pStrmData, &itmp); if (tmp != HANTRO_OK) return(tmp); pSubMbPred->mvdL0[i][j].hor = (i16)itmp; tmp = h264bsdDecodeExpGolombSigned(pStrmData, &itmp); if (tmp != HANTRO_OK) return(tmp); pSubMbPred->mvdL0[i][j].ver = (i16)itmp; } } return(HANTRO_OK); } #ifdef H264DEC_OMXDL /*------------------------------------------------------------------------------ Function: DecodeResidual Functional description: Parse residual information from bit stream and store in 'pResidual'. ------------------------------------------------------------------------------*/ u32 DecodeResidual(strmData_t *pStrmData, residual_t *pResidual, mbStorage_t *pMb, mbType_e mbType, u32 codedBlockPattern) { /* Variables */ u32 i, j; u32 blockCoded; u32 blockIndex; u32 is16x16; OMX_INT nc; OMXResult omxRes; OMX_U8 *pPosCoefBuf; /* Code */ ASSERT(pStrmData); ASSERT(pResidual); pPosCoefBuf = pResidual->posCoefBuf; /* luma DC is at index 24 */ if (h264bsdMbPartPredMode(mbType) == PRED_MODE_INTRA16x16) { nc = (OMX_INT)DetermineNc(pMb, 0, pResidual->totalCoeff); #ifndef H264DEC_NEON omxRes = omxVCM4P10_DecodeCoeffsToPairCAVLC( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[24], &pPosCoefBuf, nc, 16); #else omxRes = armVCM4P10_DecodeCoeffsToPair( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[24], &pPosCoefBuf, nc, 16); #endif if (omxRes != OMX_Sts_NoErr) return(HANTRO_NOK); is16x16 = HANTRO_TRUE; } else is16x16 = HANTRO_FALSE; for (i = 4, blockIndex = 0; i--;) { /* luma cbp in bits 0-3 */ blockCoded = codedBlockPattern & 0x1; codedBlockPattern >>= 1; if (blockCoded) { for (j = 4; j--; blockIndex++) { nc = (OMX_INT)DetermineNc(pMb,blockIndex,pResidual->totalCoeff); if (is16x16) { #ifndef H264DEC_NEON omxRes = omxVCM4P10_DecodeCoeffsToPairCAVLC( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[blockIndex], &pPosCoefBuf, nc, 15); #else omxRes = armVCM4P10_DecodeCoeffsToPair( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[blockIndex], &pPosCoefBuf, nc, 15); #endif } else { #ifndef H264DEC_NEON omxRes = omxVCM4P10_DecodeCoeffsToPairCAVLC( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[blockIndex], &pPosCoefBuf, nc, 16); #else omxRes = armVCM4P10_DecodeCoeffsToPair( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[blockIndex], &pPosCoefBuf, nc, 16); #endif } if (omxRes != OMX_Sts_NoErr) return(HANTRO_NOK); } } else blockIndex += 4; } /* chroma DC block are at indices 25 and 26 */ blockCoded = codedBlockPattern & 0x3; if (blockCoded) { #ifndef H264DEC_NEON omxRes = omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC( (const OMX_U8**) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[25], &pPosCoefBuf); #else omxRes = armVCM4P10_DecodeCoeffsToPair( (const OMX_U8**) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[25], &pPosCoefBuf, 17, 4); #endif if (omxRes != OMX_Sts_NoErr) return(HANTRO_NOK); #ifndef H264DEC_NEON omxRes = omxVCM4P10_DecodeChromaDcCoeffsToPairCAVLC( (const OMX_U8**) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[26], &pPosCoefBuf); #else omxRes = armVCM4P10_DecodeCoeffsToPair( (const OMX_U8**) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[26], &pPosCoefBuf, 17, 4); #endif if (omxRes != OMX_Sts_NoErr) return(HANTRO_NOK); } /* chroma AC */ blockCoded = codedBlockPattern & 0x2; if (blockCoded) { for (i = 8; i--;blockIndex++) { nc = (OMX_INT)DetermineNc(pMb, blockIndex, pResidual->totalCoeff); #ifndef H264DEC_NEON omxRes = omxVCM4P10_DecodeCoeffsToPairCAVLC( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[blockIndex], &pPosCoefBuf, nc, 15); #else omxRes = armVCM4P10_DecodeCoeffsToPair( (const OMX_U8 **) (&pStrmData->pStrmCurrPos), (OMX_S32*) (&pStrmData->bitPosInWord), &pResidual->totalCoeff[blockIndex], &pPosCoefBuf, nc, 15); #endif if (omxRes != OMX_Sts_NoErr) return(HANTRO_NOK); } } return(HANTRO_OK); } #else /*------------------------------------------------------------------------------ Function: DecodeResidual Functional description: Parse residual information from bit stream and store in 'pResidual'. ------------------------------------------------------------------------------*/ u32 DecodeResidual(strmData_t *pStrmData, residual_t *pResidual, mbStorage_t *pMb, mbType_e mbType, u32 codedBlockPattern) { /* Variables */ u32 i, j, tmp; i32 nc; u32 blockCoded; u32 blockIndex; u32 is16x16; i32 (*level)[16]; /* Code */ ASSERT(pStrmData); ASSERT(pResidual); level = pResidual->level; /* luma DC is at index 24 */ if (h264bsdMbPartPredMode(mbType) == PRED_MODE_INTRA16x16) { nc = (i32)DetermineNc(pMb, 0, pResidual->totalCoeff); tmp = h264bsdDecodeResidualBlockCavlc(pStrmData, level[24], nc, 16); if ((tmp & 0xF) != HANTRO_OK) return(tmp); pResidual->totalCoeff[24] = (tmp >> 4) & 0xFF; is16x16 = HANTRO_TRUE; } else is16x16 = HANTRO_FALSE; for (i = 4, blockIndex = 0; i--;) { /* luma cbp in bits 0-3 */ blockCoded = codedBlockPattern & 0x1; codedBlockPattern >>= 1; if (blockCoded) { for (j = 4; j--; blockIndex++) { nc = (i32)DetermineNc(pMb, blockIndex, pResidual->totalCoeff); if (is16x16) { tmp = h264bsdDecodeResidualBlockCavlc(pStrmData, level[blockIndex] + 1, nc, 15); pResidual->coeffMap[blockIndex] = tmp >> 15; } else { tmp = h264bsdDecodeResidualBlockCavlc(pStrmData, level[blockIndex], nc, 16); pResidual->coeffMap[blockIndex] = tmp >> 16; } if ((tmp & 0xF) != HANTRO_OK) return(tmp); pResidual->totalCoeff[blockIndex] = (tmp >> 4) & 0xFF; } } else blockIndex += 4; } /* chroma DC block are at indices 25 and 26 */ blockCoded = codedBlockPattern & 0x3; if (blockCoded) { tmp = h264bsdDecodeResidualBlockCavlc(pStrmData, level[25], -1, 4); if ((tmp & 0xF) != HANTRO_OK) return(tmp); pResidual->totalCoeff[25] = (tmp >> 4) & 0xFF; tmp = h264bsdDecodeResidualBlockCavlc(pStrmData, level[25]+4, -1, 4); if ((tmp & 0xF) != HANTRO_OK) return(tmp); pResidual->totalCoeff[26] = (tmp >> 4) & 0xFF; } /* chroma AC */ blockCoded = codedBlockPattern & 0x2; if (blockCoded) { for (i = 8; i--;blockIndex++) { nc = (i32)DetermineNc(pMb, blockIndex, pResidual->totalCoeff); tmp = h264bsdDecodeResidualBlockCavlc(pStrmData, level[blockIndex] + 1, nc, 15); if ((tmp & 0xF) != HANTRO_OK) return(tmp); pResidual->totalCoeff[blockIndex] = (tmp >> 4) & 0xFF; pResidual->coeffMap[blockIndex] = (tmp >> 15); } } return(HANTRO_OK); } #endif /*------------------------------------------------------------------------------ Function: DetermineNc Functional description: Returns the nC of a block. ------------------------------------------------------------------------------*/ #ifdef H264DEC_OMXDL u32 DetermineNc(mbStorage_t *pMb, u32 blockIndex, u8 *pTotalCoeff) #else u32 DetermineNc(mbStorage_t *pMb, u32 blockIndex, i16 *pTotalCoeff) #endif { /*lint -e702 */ /* Variables */ u32 tmp; i32 n; const neighbour_t *neighbourA, *neighbourB; u8 neighbourAindex, neighbourBindex; /* Code */ ASSERT(blockIndex < 24); /* if neighbour block belongs to current macroblock totalCoeff array * mbStorage has not been set/updated yet -> use pTotalCoeff */ neighbourA = h264bsdNeighbour4x4BlockA(blockIndex); neighbourB = h264bsdNeighbour4x4BlockB(blockIndex); neighbourAindex = neighbourA->index; neighbourBindex = neighbourB->index; if (neighbourA->mb == MB_CURR && neighbourB->mb == MB_CURR) { n = (pTotalCoeff[neighbourAindex] + pTotalCoeff[neighbourBindex] + 1)>>1; } else if (neighbourA->mb == MB_CURR) { n = pTotalCoeff[neighbourAindex]; if (h264bsdIsNeighbourAvailable(pMb, pMb->mbB)) { n = (n + pMb->mbB->totalCoeff[neighbourBindex] + 1) >> 1; } } else if (neighbourB->mb == MB_CURR) { n = pTotalCoeff[neighbourBindex]; if (h264bsdIsNeighbourAvailable(pMb, pMb->mbA)) { n = (n + pMb->mbA->totalCoeff[neighbourAindex] + 1) >> 1; } } else { n = tmp = 0; if (h264bsdIsNeighbourAvailable(pMb, pMb->mbA)) { n = pMb->mbA->totalCoeff[neighbourAindex]; tmp = 1; } if (h264bsdIsNeighbourAvailable(pMb, pMb->mbB)) { if (tmp) n = (n + pMb->mbB->totalCoeff[neighbourBindex] + 1) >> 1; else n = pMb->mbB->totalCoeff[neighbourBindex]; } } return((u32)n); /*lint +e702 */ } /*------------------------------------------------------------------------------ Function: CbpIntra16x16 Functional description: Returns the coded block pattern for intra 16x16 macroblock. ------------------------------------------------------------------------------*/ u32 CbpIntra16x16(mbType_e mbType) { /* Variables */ u32 cbp; u32 tmp; /* Code */ ASSERT(mbType >= I_16x16_0_0_0 && mbType <= I_16x16_3_2_1); if (mbType >= I_16x16_0_0_1) cbp = 15; else cbp = 0; /* tmp is 0 for I_16x16_0_0_0 mb type */ /* ignore lint warning on arithmetic on enum's */ tmp = /*lint -e(656)*/(mbType - I_16x16_0_0_0) >> 2; if (tmp > 2) tmp -= 3; cbp += tmp << 4; return(cbp); } /*------------------------------------------------------------------------------ Function: h264bsdPredModeIntra16x16 Functional description: Returns the prediction mode for intra 16x16 macroblock. ------------------------------------------------------------------------------*/ u32 h264bsdPredModeIntra16x16(mbType_e mbType) { /* Variables */ u32 tmp; /* Code */ ASSERT(mbType >= I_16x16_0_0_0 && mbType <= I_16x16_3_2_1); /* tmp is 0 for I_16x16_0_0_0 mb type */ /* ignore lint warning on arithmetic on enum's */ tmp = /*lint -e(656)*/(mbType - I_16x16_0_0_0); return(tmp & 0x3); } /*------------------------------------------------------------------------------ Function: h264bsdDecodeMacroblock Functional description: Decode one macroblock and write into output image. Inputs: pMb pointer to macroblock specific information mbLayer pointer to current macroblock data from stream currImage pointer to output image dpb pointer to decoded picture buffer qpY pointer to slice QP mbNum current macroblock number constrainedIntraPred flag specifying if neighbouring inter macroblocks are used in intra prediction Outputs: pMb structure is updated with current macroblock currImage decoded macroblock is written into output image Returns: HANTRO_OK success HANTRO_NOK error in macroblock decoding ------------------------------------------------------------------------------*/ u32 h264bsdDecodeMacroblock(mbStorage_t *pMb, macroblockLayer_t *pMbLayer, image_t *currImage, dpbStorage_t *dpb, i32 *qpY, u32 mbNum, u32 constrainedIntraPredFlag, u8* data) { /* Variables */ u32 i, tmp; mbType_e mbType; #ifdef H264DEC_OMXDL const u8 *pSrc; #endif /* Code */ ASSERT(pMb); ASSERT(pMbLayer); ASSERT(currImage); ASSERT(qpY && *qpY < 52); ASSERT(mbNum < currImage->width*currImage->height); mbType = pMbLayer->mbType; pMb->mbType = mbType; pMb->decoded++; h264bsdSetCurrImageMbPointers(currImage, mbNum); if (mbType == I_PCM) { u8 *pData = (u8*)data; #ifdef H264DEC_OMXDL u8 *tot = pMb->totalCoeff; #else i16 *tot = pMb->totalCoeff; #endif i32 *lev = pMbLayer->residual.level[0]; pMb->qpY = 0; /* if decoded flag > 1 -> mb has already been successfully decoded and * written to output -> do not write again */ if (pMb->decoded > 1) { for (i = 24; i--;) *tot++ = 16; return HANTRO_OK; } for (i = 24; i--;) { *tot++ = 16; for (tmp = 16; tmp--;) *pData++ = (u8)(*lev++); } h264bsdWriteMacroblock(currImage, (u8*)data); return(HANTRO_OK); } else { #ifdef H264DEC_OMXDL if (h264bsdMbPartPredMode(mbType) == PRED_MODE_INTER) { tmp = h264bsdInterPrediction(pMb, pMbLayer, dpb, mbNum, currImage, (u8*)data); if (tmp != HANTRO_OK) return (tmp); } #endif if (mbType != P_Skip) { H264SwDecMemcpy(pMb->totalCoeff, pMbLayer->residual.totalCoeff, 27*sizeof(*pMb->totalCoeff)); /* update qpY */ if (pMbLayer->mbQpDelta) { *qpY = *qpY + pMbLayer->mbQpDelta; if (*qpY < 0) *qpY += 52; else if (*qpY >= 52) *qpY -= 52; } pMb->qpY = (u32)*qpY; #ifdef H264DEC_OMXDL pSrc = pMbLayer->residual.posCoefBuf; if (h264bsdMbPartPredMode(mbType) == PRED_MODE_INTER) { OMXResult res; u8 *p; u8 *totalCoeff = pMb->totalCoeff; for (i = 0; i < 16; i++, totalCoeff++) { p = data + lumaIndex[i]; if (*totalCoeff) { res = omxVCM4P10_DequantTransformResidualFromPairAndAdd( &pSrc, p, 0, p, 16, 16, *qpY, *totalCoeff); if (res != OMX_Sts_NoErr) return (HANTRO_NOK); } } } else if (h264bsdMbPartPredMode(mbType) == PRED_MODE_INTRA4x4) { tmp = ProcessIntra4x4Residual(pMb, data, constrainedIntraPredFlag, pMbLayer, &pSrc, currImage); if (tmp != HANTRO_OK) return (tmp); } else if (h264bsdMbPartPredMode(mbType) == PRED_MODE_INTRA16x16) { tmp = ProcessIntra16x16Residual(pMb, data, constrainedIntraPredFlag, pMbLayer->mbPred.intraChromaPredMode, &pSrc, currImage); if (tmp != HANTRO_OK) return (tmp); } tmp = ProcessChromaResidual(pMb, data, &pSrc); #else tmp = ProcessResidual(pMb, pMbLayer->residual.level, pMbLayer->residual.coeffMap); #endif if (tmp != HANTRO_OK) return (tmp); } else { H264SwDecMemset(pMb->totalCoeff, 0, 27*sizeof(*pMb->totalCoeff)); pMb->qpY = (u32)*qpY; } #ifdef H264DEC_OMXDL /* if decoded flag > 1 -> mb has already been successfully decoded and * written to output -> do not write again */ if (pMb->decoded > 1) return HANTRO_OK; h264bsdWriteMacroblock(currImage, data); #else if (h264bsdMbPartPredMode(mbType) != PRED_MODE_INTER) { tmp = h264bsdIntraPrediction(pMb, pMbLayer, currImage, mbNum, constrainedIntraPredFlag, (u8*)data); if (tmp != HANTRO_OK) return (tmp); } else { tmp = h264bsdInterPrediction(pMb, pMbLayer, dpb, mbNum, currImage, (u8*)data); if (tmp != HANTRO_OK) return (tmp); } #endif } return HANTRO_OK; } #ifdef H264DEC_OMXDL /*------------------------------------------------------------------------------ Function: ProcessChromaResidual Functional description: Process the residual data of chroma with inverse quantization and inverse transform. ------------------------------------------------------------------------------*/ u32 ProcessChromaResidual(mbStorage_t *pMb, u8 *data, const u8 **pSrc ) { u32 i; u32 chromaQp; i16 *pDc; i16 dc[4 + 4] = {0,0,0,0,0,0,0,0}; u8 *totalCoeff; OMXResult result; u8 *p; /* chroma DC processing. First chroma dc block is block with index 25 */ chromaQp = h264bsdQpC[CLIP3(0, 51, (i32)pMb->qpY + pMb->chromaQpIndexOffset)]; if (pMb->totalCoeff[25]) { pDc = dc; result = omxVCM4P10_TransformDequantChromaDCFromPair( pSrc, pDc, (i32)chromaQp); if (result != OMX_Sts_NoErr) return (HANTRO_NOK); } if (pMb->totalCoeff[26]) { pDc = dc+4; result = omxVCM4P10_TransformDequantChromaDCFromPair( pSrc, pDc, (i32)chromaQp); if (result != OMX_Sts_NoErr) return (HANTRO_NOK); } pDc = dc; totalCoeff = pMb->totalCoeff + 16; for (i = 0; i < 8; i++, pDc++, totalCoeff++) { /* chroma prediction */ if (*totalCoeff || *pDc) { p = data + chromaIndex[i]; result = omxVCM4P10_DequantTransformResidualFromPairAndAdd( pSrc, p, pDc, p, 8, 8, (i32)chromaQp, *totalCoeff); if (result != OMX_Sts_NoErr) return (HANTRO_NOK); } } return(HANTRO_OK); } /*------------------------------------------------------------------------------ Function: ProcessIntra16x16Residual Functional description: Process the residual data of luma with inverse quantization and inverse transform. ------------------------------------------------------------------------------*/ u32 ProcessIntra16x16Residual(mbStorage_t *pMb, u8 *data, u32 constrainedIntraPred, u32 intraChromaPredMode, const u8** pSrc, image_t *image) { u32 i; i16 *pDc; i16 dc[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; u8 *totalCoeff; OMXResult result; u8 *p; totalCoeff = pMb->totalCoeff; if (totalCoeff[24]) { pDc = dc; result = omxVCM4P10_TransformDequantLumaDCFromPair( pSrc, pDc, (i32)pMb->qpY); if (result != OMX_Sts_NoErr) return (HANTRO_NOK); } /* Intra 16x16 pred */ if (h264bsdIntra16x16Prediction(pMb, data, image->luma, image->width*16, constrainedIntraPred) != HANTRO_OK) return(HANTRO_NOK); for (i = 0; i < 16; i++, totalCoeff++) { p = data + lumaIndex[i]; pDc = &dc[dcCoeffIndex[i]]; if (*totalCoeff || *pDc) { result = omxVCM4P10_DequantTransformResidualFromPairAndAdd( pSrc, p, pDc, p, 16, 16, (i32)pMb->qpY, *totalCoeff); if (result != OMX_Sts_NoErr) return (HANTRO_NOK); } } if (h264bsdIntraChromaPrediction(pMb, data + 256, image, intraChromaPredMode, constrainedIntraPred) != HANTRO_OK) return(HANTRO_NOK); return HANTRO_OK; } /*------------------------------------------------------------------------------ Function: ProcessIntra4x4Residual Functional description: Process the residual data of luma with inverse quantization and inverse transform. ------------------------------------------------------------------------------*/ u32 ProcessIntra4x4Residual(mbStorage_t *pMb, u8 *data, u32 constrainedIntraPred, macroblockLayer_t *mbLayer, const u8 **pSrc, image_t *image) { u32 i; u8 *totalCoeff; OMXResult result; u8 *p; totalCoeff = pMb->totalCoeff; for (i = 0; i < 16; i++, totalCoeff++) { p = data + lumaIndex[i]; if (h264bsdIntra4x4Prediction(pMb, p, mbLayer, image->luma, image->width*16, constrainedIntraPred, i) != HANTRO_OK) return(HANTRO_NOK); if (*totalCoeff) { result = omxVCM4P10_DequantTransformResidualFromPairAndAdd( pSrc, p, NULL, p, 16, 16, (i32)pMb->qpY, *totalCoeff); if (result != OMX_Sts_NoErr) return (HANTRO_NOK); } } if (h264bsdIntraChromaPrediction(pMb, data + 256, image, mbLayer->mbPred.intraChromaPredMode, constrainedIntraPred) != HANTRO_OK) return(HANTRO_NOK); return HANTRO_OK; } #else /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ Function: ProcessResidual Functional description: Process the residual data of one macroblock with inverse quantization and inverse transform. ------------------------------------------------------------------------------*/ u32 ProcessResidual(mbStorage_t *pMb, i32 residualLevel[][16], u32 *coeffMap) { /* Variables */ u32 i; u32 chromaQp; i32 (*blockData)[16]; i32 (*blockDc)[16]; i16 *totalCoeff; i32 *chromaDc; const u32 *dcCoeffIdx; /* Code */ ASSERT(pMb); ASSERT(residualLevel); /* set pointers to DC coefficient blocks */ blockDc = residualLevel + 24; blockData = residualLevel; totalCoeff = pMb->totalCoeff; if (h264bsdMbPartPredMode(pMb->mbType) == PRED_MODE_INTRA16x16) { if (totalCoeff[24]) { h264bsdProcessLumaDc(*blockDc, pMb->qpY); } dcCoeffIdx = dcCoeffIndex; for (i = 16; i--; blockData++, totalCoeff++, coeffMap++) { /* set dc coefficient of luma block */ (*blockData)[0] = (*blockDc)[*dcCoeffIdx++]; if ((*blockData)[0] || *totalCoeff) { if (h264bsdProcessBlock(*blockData, pMb->qpY, 1, *coeffMap) != HANTRO_OK) return(HANTRO_NOK); } else MARK_RESIDUAL_EMPTY(*blockData); } } else { for (i = 16; i--; blockData++, totalCoeff++, coeffMap++) { if (*totalCoeff) { if (h264bsdProcessBlock(*blockData, pMb->qpY, 0, *coeffMap) != HANTRO_OK) return(HANTRO_NOK); } else MARK_RESIDUAL_EMPTY(*blockData); } } /* chroma DC processing. First chroma dc block is block with index 25 */ chromaQp = h264bsdQpC[CLIP3(0, 51, (i32)pMb->qpY + pMb->chromaQpIndexOffset)]; if (pMb->totalCoeff[25] || pMb->totalCoeff[26]) h264bsdProcessChromaDc(residualLevel[25], chromaQp); chromaDc = residualLevel[25]; for (i = 8; i--; blockData++, totalCoeff++, coeffMap++) { /* set dc coefficient of chroma block */ (*blockData)[0] = *chromaDc++; if ((*blockData)[0] || *totalCoeff) { if (h264bsdProcessBlock(*blockData, chromaQp, 1,*coeffMap) != HANTRO_OK) return(HANTRO_NOK); } else MARK_RESIDUAL_EMPTY(*blockData); } return(HANTRO_OK); } #endif /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ Function: h264bsdSubMbPartMode Functional description: Returns the macroblock's sub-partition mode. ------------------------------------------------------------------------------*/ subMbPartMode_e h264bsdSubMbPartMode(subMbType_e subMbType) { /* Variables */ /* Code */ ASSERT(subMbType < 4); return((subMbPartMode_e)subMbType); }