/* * Copyright (C) 2009 The Android Open Source Project * Modified for use by h264bsd standalone library * * 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 h264bsdFilterPicture FilterVerLumaEdge FilterHorLumaEdge FilterHorLuma FilterVerChromaEdge FilterHorChromaEdge FilterHorChroma InnerBoundaryStrength EdgeBoundaryStrength GetBoundaryStrengths IsSliceBoundaryOnLeft IsSliceBoundaryOnTop GetMbFilteringFlags GetLumaEdgeThresholds GetChromaEdgeThresholds FilterLuma FilterChroma ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 1. Include headers ------------------------------------------------------------------------------*/ #include "basetype.h" #include "h264bsd_util.h" #include "h264bsd_macroblock_layer.h" #include "h264bsd_deblocking.h" #include "h264bsd_dpb.h" #ifdef H264DEC_OMXDL #include "omxtypes.h" #include "omxVC.h" #include "armVC.h" #endif /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ 2. External compiler flags -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- 3. Module defines ------------------------------------------------------------------------------*/ /* Switch off the following Lint messages for this file: * Info 701: Shift left of signed quantity (int) * Info 702: Shift right of signed quantity (int) */ /*lint -e701 -e702 */ /* array of alpha values, from the standard */ static const u8 alphas[52] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,5,6,7,8,9,10, 12,13,15,17,20,22,25,28,32,36,40,45,50,56,63,71,80,90,101,113,127,144,162, 182,203,226,255,255}; /* array of beta values, from the standard */ static const u8 betas[52] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,3,3,3,3,4,4, 4,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18}; #ifndef H264DEC_OMXDL /* array of tc0 values, from the standard, each triplet corresponds to a * column in the table. Indexing goes as tc0[indexA][bS-1] */ static const u8 tc0[52][3] = { {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, {0,0,0},{0,0,1},{0,0,1},{0,0,1},{0,0,1},{0,1,1},{0,1,1},{1,1,1}, {1,1,1},{1,1,1},{1,1,1},{1,1,2},{1,1,2},{1,1,2},{1,1,2},{1,2,3}, {1,2,3},{2,2,3},{2,2,4},{2,3,4},{2,3,4},{3,3,5},{3,4,6},{3,4,6}, {4,5,7},{4,5,8},{4,6,9},{5,7,10},{6,8,11},{6,8,13},{7,10,14},{8,11,16}, {9,12,18},{10,13,20},{11,15,23},{13,17,25} }; #else /* array of tc0 values, from the standard, each triplet corresponds to a * column in the table. Indexing goes as tc0[indexA][bS] */ static const u8 tc0[52][5] = { {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 1, 0}, {0, 0, 0, 1, 0}, {0, 0, 0, 1, 0}, {0, 0, 0, 1, 0}, {0, 0, 1, 1, 0}, {0, 0, 1, 1, 0}, {0, 1, 1, 1, 0}, {0, 1, 1, 1, 0}, {0, 1, 1, 1, 0}, {0, 1, 1, 1, 0}, {0, 1, 1, 2, 0}, {0, 1, 1, 2, 0}, {0, 1, 1, 2, 0}, {0, 1, 1, 2, 0}, {0, 1, 2, 3, 0}, {0, 1, 2, 3, 0}, {0, 2, 2, 3, 0}, {0, 2, 2, 4, 0}, {0, 2, 3, 4, 0}, {0, 2, 3, 4, 0}, {0, 3, 3, 5, 0}, {0, 3, 4, 6, 0}, {0, 3, 4, 6, 0}, {0, 4, 5, 7, 0}, {0, 4, 5, 8, 0}, {0, 4, 6, 9, 0}, {0, 5, 7, 10, 0}, {0, 6, 8, 11, 0}, {0, 6, 8, 13, 0}, {0, 7, 10, 14, 0}, {0, 8, 11, 16, 0}, {0, 9, 12, 18, 0}, {0, 10, 13, 20, 0}, {0, 11, 15, 23, 0}, {0, 13, 17, 25, 0} }; #endif #ifndef H264DEC_OMXDL /* mapping of raster scan block index to 4x4 block index */ static const u32 mb4x4Index[16] = {0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15}; typedef struct { const u8 *tc0; u32 alpha; u32 beta; } edgeThreshold_t; typedef struct { u32 top; u32 left; } bS_t; enum { TOP = 0, LEFT = 1, INNER = 2 }; #endif /* H264DEC_OMXDL */ #define FILTER_LEFT_EDGE 0x04 #define FILTER_TOP_EDGE 0x02 #define FILTER_INNER_EDGE 0x01 /* clipping table defined in intra_prediction.c */ extern const u8 h264bsdClip[]; /*------------------------------------------------------------------------------ 4. Local function prototypes ------------------------------------------------------------------------------*/ static u32 InnerBoundaryStrength(mbStorage_t *mb1, u32 i1, u32 i2); #ifndef H264DEC_OMXDL static u32 EdgeBoundaryStrength(mbStorage_t *mb1, mbStorage_t *mb2, u32 i1, u32 i2); #else static u32 InnerBoundaryStrength2(mbStorage_t *mb1, u32 i1, u32 i2); static u32 EdgeBoundaryStrengthLeft(mbStorage_t *mb1, mbStorage_t *mb2); static u32 EdgeBoundaryStrengthTop(mbStorage_t *mb1, mbStorage_t *mb2); #endif static u32 IsSliceBoundaryOnLeft(mbStorage_t *mb); static u32 IsSliceBoundaryOnTop(mbStorage_t *mb); static u32 GetMbFilteringFlags(mbStorage_t *mb); #ifndef H264DEC_OMXDL static u32 GetBoundaryStrengths(mbStorage_t *mb, bS_t *bs, u32 flags); static void FilterLuma(u8 *data, bS_t *bS, edgeThreshold_t *thresholds, u32 imageWidth); static void FilterChroma(u8 *cb, u8 *cr, bS_t *bS, edgeThreshold_t *thresholds, u32 imageWidth); static void FilterVerLumaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, u32 imageWidth); static void FilterHorLumaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 imageWidth); static void FilterHorLuma( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 imageWidth); static void FilterVerChromaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, u32 imageWidth); static void FilterHorChromaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 imageWidth); static void FilterHorChroma( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 imageWidth); static void GetLumaEdgeThresholds( edgeThreshold_t *thresholds, mbStorage_t *mb, u32 filteringFlags); static void GetChromaEdgeThresholds( edgeThreshold_t *thresholds, mbStorage_t *mb, u32 filteringFlags, i32 chromaQpIndexOffset); #else /* H264DEC_OMXDL */ static u32 GetBoundaryStrengths(mbStorage_t *mb, u8 (*bs)[16], u32 flags); static void GetLumaEdgeThresholds( mbStorage_t *mb, u8 (*alpha)[2], u8 (*beta)[2], u8 (*threshold)[16], u8 (*bs)[16], u32 filteringFlags ); static void GetChromaEdgeThresholds( mbStorage_t *mb, u8 (*alpha)[2], u8 (*beta)[2], u8 (*threshold)[8], u8 (*bs)[16], u32 filteringFlags, i32 chromaQpIndexOffset); #endif /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ Function: IsSliceBoundaryOnLeft Functional description: Function to determine if there is a slice boundary on the left side of a macroblock. ------------------------------------------------------------------------------*/ u32 IsSliceBoundaryOnLeft(mbStorage_t *mb) { /* Variables */ /* Code */ ASSERT(mb && mb->mbA); if (mb->sliceId != mb->mbA->sliceId) return(HANTRO_TRUE); else return(HANTRO_FALSE); } /*------------------------------------------------------------------------------ Function: IsSliceBoundaryOnTop Functional description: Function to determine if there is a slice boundary above the current macroblock. ------------------------------------------------------------------------------*/ u32 IsSliceBoundaryOnTop(mbStorage_t *mb) { /* Variables */ /* Code */ ASSERT(mb && mb->mbB); if (mb->sliceId != mb->mbB->sliceId) return(HANTRO_TRUE); else return(HANTRO_FALSE); } /*------------------------------------------------------------------------------ Function: GetMbFilteringFlags Functional description: Function to determine which edges of a macroblock has to be filtered. Output is a bit-wise OR of FILTER_LEFT_EDGE, FILTER_TOP_EDGE and FILTER_INNER_EDGE, depending on which edges shall be filtered. ------------------------------------------------------------------------------*/ u32 GetMbFilteringFlags(mbStorage_t *mb) { /* Variables */ u32 flags = 0; /* Code */ ASSERT(mb); /* nothing will be filtered if disableDeblockingFilterIdc == 1 */ if (mb->disableDeblockingFilterIdc != 1) { flags |= FILTER_INNER_EDGE; /* filterLeftMbEdgeFlag, left mb is MB_A */ if (mb->mbA && ((mb->disableDeblockingFilterIdc != 2) || !IsSliceBoundaryOnLeft(mb))) flags |= FILTER_LEFT_EDGE; /* filterTopMbEdgeFlag */ if (mb->mbB && ((mb->disableDeblockingFilterIdc != 2) || !IsSliceBoundaryOnTop(mb))) flags |= FILTER_TOP_EDGE; } return(flags); } /*------------------------------------------------------------------------------ Function: InnerBoundaryStrength Functional description: Function to calculate boundary strength value bs for an inner edge of a macroblock. Macroblock type is checked before this is called -> no intra mb condition here. ------------------------------------------------------------------------------*/ u32 InnerBoundaryStrength(mbStorage_t *mb1, u32 ind1, u32 ind2) { i32 tmp1, tmp2; i32 mv1, mv2, mv3, mv4; tmp1 = mb1->totalCoeff[ind1]; tmp2 = mb1->totalCoeff[ind2]; mv1 = mb1->mv[ind1].hor; mv2 = mb1->mv[ind2].hor; mv3 = mb1->mv[ind1].ver; mv4 = mb1->mv[ind2].ver; if (tmp1 || tmp2) { return 2; } else if ( ((u32)ABS(mv1 - mv2) >= 4) || ((u32)ABS(mv3 - mv4) >= 4) || (mb1->refAddr[ind1 >> 2] != mb1->refAddr[ind2 >> 2]) ) { return 1; } else return 0; } /*------------------------------------------------------------------------------ Function: InnerBoundaryStrength2 Functional description: Function to calculate boundary strength value bs for an inner edge of a macroblock. The function is the same as InnerBoundaryStrength but without checking totalCoeff. ------------------------------------------------------------------------------*/ u32 InnerBoundaryStrength2(mbStorage_t *mb1, u32 ind1, u32 ind2) { i32 tmp1, tmp2, tmp3, tmp4; tmp1 = mb1->mv[ind1].hor; tmp2 = mb1->mv[ind2].hor; tmp3 = mb1->mv[ind1].ver; tmp4 = mb1->mv[ind2].ver; if ( ((u32)ABS(tmp1 - tmp2) >= 4) || ((u32)ABS(tmp3 - tmp4) >= 4) || (mb1->refAddr[ind1 >> 2] != mb1->refAddr[ind2 >> 2])) { return 1; } else return 0; } #ifndef H264DEC_OMXDL /*------------------------------------------------------------------------------ Function: EdgeBoundaryStrength Functional description: Function to calculate boundary strength value bs for left- or top-most edge of a macroblock. Macroblock types are checked before this is called -> no intra mb conditions here. ------------------------------------------------------------------------------*/ u32 EdgeBoundaryStrength(mbStorage_t *mb1, mbStorage_t *mb2, u32 ind1, u32 ind2) { if (mb1->totalCoeff[ind1] || mb2->totalCoeff[ind2]) { return 2; } else if ((mb1->refAddr[ind1 >> 2] != mb2->refAddr[ind2 >> 2]) || ((u32)ABS(mb1->mv[ind1].hor - mb2->mv[ind2].hor) >= 4) || ((u32)ABS(mb1->mv[ind1].ver - mb2->mv[ind2].ver) >= 4)) { return 1; } else return 0; } #else /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ Function: EdgeBoundaryStrengthTop Functional description: Function to calculate boundary strength value bs for top-most edge of a macroblock. Macroblock types are checked before this is called -> no intra mb conditions here. ------------------------------------------------------------------------------*/ u32 EdgeBoundaryStrengthTop(mbStorage_t *mb1, mbStorage_t *mb2) { u32 topBs = 0; u32 tmp1, tmp2, tmp3, tmp4; tmp1 = mb1->totalCoeff[0]; tmp2 = mb2->totalCoeff[10]; tmp3 = mb1->totalCoeff[1]; tmp4 = mb2->totalCoeff[11]; if (tmp1 || tmp2) { topBs = 2<<0; } else if (((u32)ABS(mb1->mv[0].hor - mb2->mv[10].hor) >= 4) || ((u32)ABS(mb1->mv[0].ver - mb2->mv[10].ver) >= 4) || (mb1->refAddr[0] != mb2->refAddr[10 >> 2])) { topBs = 1<<0; } tmp1 = mb1->totalCoeff[4]; tmp2 = mb2->totalCoeff[14]; if (tmp3 || tmp4) { topBs += 2<<8; } else if (((u32)ABS(mb1->mv[1].hor - mb2->mv[11].hor) >= 4) || ((u32)ABS(mb1->mv[1].ver - mb2->mv[11].ver) >= 4) || (mb1->refAddr[0] != mb2->refAddr[11 >> 2])) { topBs += 1<<8; } tmp3 = mb1->totalCoeff[5]; tmp4 = mb2->totalCoeff[15]; if (tmp1 || tmp2) { topBs += 2<<16; } else if (((u32)ABS(mb1->mv[4].hor - mb2->mv[14].hor) >= 4) || ((u32)ABS(mb1->mv[4].ver - mb2->mv[14].ver) >= 4) || (mb1->refAddr[4 >> 2] != mb2->refAddr[14 >> 2])) { topBs += 1<<16; } if (tmp3 || tmp4) { topBs += 2<<24; } else if (((u32)ABS(mb1->mv[5].hor - mb2->mv[15].hor) >= 4) || ((u32)ABS(mb1->mv[5].ver - mb2->mv[15].ver) >= 4) || (mb1->refAddr[5 >> 2] != mb2->refAddr[15 >> 2])) { topBs += 1<<24; } return topBs; } /*------------------------------------------------------------------------------ Function: EdgeBoundaryStrengthLeft Functional description: Function to calculate boundary strength value bs for left- edge of a macroblock. Macroblock types are checked before this is called -> no intra mb conditions here. ------------------------------------------------------------------------------*/ u32 EdgeBoundaryStrengthLeft(mbStorage_t *mb1, mbStorage_t *mb2) { u32 leftBs = 0; u32 tmp1, tmp2, tmp3, tmp4; tmp1 = mb1->totalCoeff[0]; tmp2 = mb2->totalCoeff[5]; tmp3 = mb1->totalCoeff[2]; tmp4 = mb2->totalCoeff[7]; if (tmp1 || tmp2) { leftBs = 2<<0; } else if (((u32)ABS(mb1->mv[0].hor - mb2->mv[5].hor) >= 4) || ((u32)ABS(mb1->mv[0].ver - mb2->mv[5].ver) >= 4) || (mb1->refAddr[0] != mb2->refAddr[5 >> 2])) { leftBs = 1<<0; } tmp1 = mb1->totalCoeff[8]; tmp2 = mb2->totalCoeff[13]; if (tmp3 || tmp4) { leftBs += 2<<8; } else if (((u32)ABS(mb1->mv[2].hor - mb2->mv[7].hor) >= 4) || ((u32)ABS(mb1->mv[2].ver - mb2->mv[7].ver) >= 4) || (mb1->refAddr[0] != mb2->refAddr[7 >> 2])) { leftBs += 1<<8; } tmp3 = mb1->totalCoeff[10]; tmp4 = mb2->totalCoeff[15]; if (tmp1 || tmp2) { leftBs += 2<<16; } else if (((u32)ABS(mb1->mv[8].hor - mb2->mv[13].hor) >= 4) || ((u32)ABS(mb1->mv[8].ver - mb2->mv[13].ver) >= 4) || (mb1->refAddr[8 >> 2] != mb2->refAddr[13 >> 2])) { leftBs += 1<<16; } if (tmp3 || tmp4) { leftBs += 2<<24; } else if (((u32)ABS(mb1->mv[10].hor - mb2->mv[15].hor) >= 4) || ((u32)ABS(mb1->mv[10].ver - mb2->mv[15].ver) >= 4) || (mb1->refAddr[10 >> 2] != mb2->refAddr[15 >> 2])) { leftBs += 1<<24; } return leftBs; } #endif /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ Function: h264bsdFilterPicture Functional description: Perform deblocking filtering for a picture. Filter does not copy the original picture anywhere but filtering is performed directly on the original image. Parameters controlling the filtering process are computed based on information in macroblock structures of the filtered macroblock, macroblock above and macroblock on the left of the filtered one. Inputs: image pointer to image to be filtered mb pointer to macroblock data structure of the top-left macroblock of the picture Outputs: image filtered image stored here Returns: none ------------------------------------------------------------------------------*/ #ifndef H264DEC_OMXDL void h264bsdFilterPicture( image_t *image, mbStorage_t *mb) { /* Variables */ u32 flags; u32 picSizeInMbs, mbRow, mbCol; u32 picWidthInMbs; u8 *data; mbStorage_t *pMb; bS_t bS[16]; edgeThreshold_t thresholds[3]; /* Code */ ASSERT(image); ASSERT(mb); ASSERT(image->data); ASSERT(image->width); ASSERT(image->height); picWidthInMbs = image->width; data = image->data; picSizeInMbs = picWidthInMbs * image->height; pMb = mb; for (mbRow = 0, mbCol = 0; mbRow < image->height; pMb++) { flags = GetMbFilteringFlags(pMb); if (flags) { /* GetBoundaryStrengths function returns non-zero value if any of * the bS values for the macroblock being processed was non-zero */ if (GetBoundaryStrengths(pMb, bS, flags)) { /* luma */ GetLumaEdgeThresholds(thresholds, pMb, flags); data = image->data + mbRow * picWidthInMbs * 256 + mbCol * 16; FilterLuma((u8*)data, bS, thresholds, picWidthInMbs*16); /* chroma */ GetChromaEdgeThresholds(thresholds, pMb, flags, pMb->chromaQpIndexOffset); data = image->data + picSizeInMbs * 256 + mbRow * picWidthInMbs * 64 + mbCol * 8; FilterChroma((u8*)data, data + 64*picSizeInMbs, bS, thresholds, picWidthInMbs*8); } } mbCol++; if (mbCol == picWidthInMbs) { mbCol = 0; mbRow++; } } } int sample = 0; unsigned int hashA = 0; unsigned int hashB = 0; unsigned int hashC = 0; unsigned int hashD = 0; /*------------------------------------------------------------------------------ Function: FilterVerLumaEdge Functional description: Filter one vertical 4-pixel luma edge. ------------------------------------------------------------------------------*/ void FilterVerLumaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, u32 imageWidth) { /* Variables */ i32 delta, tc, tmp; u32 i; i32 p0, q0, p1, q1, p2, q2; u32 tmpFlag; const u8 *clp = h264bsdClip + 512; u32 alpha = thresholds->alpha; u32 beta = thresholds->beta; i32 val; /* Code */ ASSERT(data); ASSERT(bS && bS <= 4); ASSERT(thresholds); if (bS < 4) { tc = thresholds->tc0[bS-1]; tmp = tc; for (i = 4; i; i--, data += imageWidth) { p1 = data[-2]; p0 = data[-1]; q0 = data[0]; q1 = data[1]; if ( ((u32)ABS(p0 - q0) < alpha) && ((u32)ABS(p1 - p0) < beta) && ((u32)ABS(q1 - q0) < beta) ) { p2 = data[-3]; q2 = data[2]; if ((u32)ABS(p2 - p0) < beta) { val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1; data[-2] = (p1 + CLIP3(-tc, tc, val)); tmp++; } if ((u32)ABS(q2 - q0) < beta) { val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1; data[1] = (q1 + CLIP3(-tc, tc, val)); tmp++; } val = (((q0 - p0) << 2) + (p1 - q1) + 4) >> 3; delta = CLIP3(-tmp, tmp, val); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; tmp = tc; data[-1] = p0; data[ 0] = q0; } // hashA += data[-2] + data[-1] + data[0] + data[1]; } } else { for (i = 4; i; i--, data += imageWidth) { p1 = data[-2]; p0 = data[-1]; q0 = data[0]; q1 = data[1]; if ( ((u32)ABS(p0-q0) < alpha) && ((u32)ABS(p1-p0) < beta) && ((u32)ABS(q1-q0) < beta) ) { tmpFlag = ((u32)ABS(p0 - q0) < ((alpha >> 2) +2)) ? HANTRO_TRUE : HANTRO_FALSE; p2 = data[-3]; q2 = data[2]; if (tmpFlag && (u32)ABS(p2-p0) < beta) { tmp = p1 + p0 + q0; data[-1] = ((p2 + 2 * tmp + q1 + 4) >> 3); data[-2] = ((p2 + tmp + 2) >> 2); data[-3] = ((2 * data[-4] + 3 * p2 + tmp + 4) >> 3); } else data[-1] = (2 * p1 + p0 + q1 + 2) >> 2; if (tmpFlag && (u32)ABS(q2-q0) < beta) { tmp = p0 + q0 + q1; data[0] = ((p1 + 2 * tmp + q2 + 4) >> 3); data[1] = ((tmp + q2 + 2) >> 2); data[2] = ((2 * data[3] + 3 * q2 + tmp + 4) >> 3); } else data[0] = ((2 * q1 + q0 + p1 + 2) >> 2); } } } } /*------------------------------------------------------------------------------ Function: FilterHorLumaEdge Functional description: Filter one horizontal 4-pixel luma edge ------------------------------------------------------------------------------*/ void FilterHorLumaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 imageWidth) { /* Variables */ i32 delta, tc, tmp; u32 i; u8 p0, q0, p1, q1, p2, q2; const u8 *clp = h264bsdClip + 512; i32 val; /* Code */ ASSERT(data); ASSERT(bS < 4); ASSERT(thresholds); // if (sample ++ % (1024 * 128) == 0) { // printf("Hash A: %d, Hash B: %d\n", hashA, hashB); // } tc = thresholds->tc0[bS-1]; tmp = tc; for (i = 4; i; i--, data++) { p1 = data[-imageWidth*2]; p0 = data[-imageWidth]; q0 = data[0]; q1 = data[imageWidth]; if ( ((u32)ABS(p0-q0) < thresholds->alpha) && ((u32)ABS(p1-p0) < thresholds->beta) && ((u32)ABS(q1-q0) < thresholds->beta) ) { p2 = data[-imageWidth*3]; if ((u32)ABS(p2-p0) < thresholds->beta) { val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1; data[-imageWidth*2] = (p1 + CLIP3(-tc, tc, val)); tmp++; } q2 = data[imageWidth*2]; if ((u32)ABS(q2-q0) < thresholds->beta) { val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1; data[imageWidth] = (q1 + CLIP3(-tc, tc, val)); tmp++; } val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3); delta = CLIP3(-tmp, tmp, val); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; tmp = tc; data[-imageWidth] = p0; data[ 0] = q0; } // hashB += data[-imageWidth*2] + data[-imageWidth] + data[0] + data[imageWidth]; } } /*------------------------------------------------------------------------------ Function: FilterHorLuma Functional description: Filter all four successive horizontal 4-pixel luma edges. This can be done when bS is equal to all four edges. ------------------------------------------------------------------------------*/ void FilterHorLuma( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 imageWidth) { /* Variables */ i32 delta, tc, tmp; u32 i; i32 p0, q0, p1, q1, p2, q2; u32 tmpFlag; const u8 *clp = h264bsdClip + 512; u32 alpha = thresholds->alpha; u32 beta = thresholds->beta; i32 val; /* Code */ ASSERT(data); ASSERT(bS <= 4); ASSERT(thresholds); // if (sample ++ % (1024 * 64) == 0) { // printf("Hash A: %d, Hash B: %d\n", hashA, hashB); // } if (bS < 4) { tc = thresholds->tc0[bS-1]; tmp = tc; for (i = 16; i; i--, data++) { p1 = data[-imageWidth*2]; p0 = data[-imageWidth]; q0 = data[0]; q1 = data[imageWidth]; if ( ((u32)ABS(p0 - q0) < alpha) && ((u32)ABS(p1 - p0) < beta) && ((u32)ABS(q1 - q0) < beta) ) { p2 = data[-imageWidth*3]; if ((u32)ABS(p2 - p0) < beta) { val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1; data[-imageWidth*2] = (u8)(p1 + CLIP3(-tc, tc, val)); tmp++; } q2 = data[imageWidth*2]; if ((u32)ABS(q2-q0) < beta) { val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1; data[imageWidth] = (u8)(q1 + CLIP3(-tc, tc, val)); tmp++; } val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3); delta = CLIP3(-tmp, tmp, val); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; tmp = tc; data[-imageWidth] = p0; data[ 0] = q0; } } } else { for (i = 16; i; i--, data++) { p1 = data[-imageWidth*2]; p0 = data[-imageWidth]; q0 = data[0]; q1 = data[imageWidth]; if ( ((u32)ABS(p0 - q0) < alpha) && ((u32)ABS(p1 - p0) < beta) && ((u32)ABS(q1 - q0) < beta) ) { tmpFlag = ((u32)ABS(p0 - q0) < ((alpha >> 2) +2)) ? HANTRO_TRUE : HANTRO_FALSE; p2 = data[-imageWidth*3]; q2 = data[imageWidth*2]; if (tmpFlag && (u32)ABS(p2 - p0) < beta) { tmp = p1 + p0 + q0; data[-imageWidth] = (u8)((p2 + 2 * tmp + q1 + 4) >> 3); data[-imageWidth*2] = (u8)((p2 + tmp + 2) >> 2); data[-imageWidth*3] = (u8)((2 * data[-imageWidth*4] + 3 * p2 + tmp + 4) >> 3); } else data[-imageWidth] = (u8)((2 * p1 + p0 + q1 + 2) >> 2); if (tmpFlag && (u32)ABS(q2 - q0) < beta) { tmp = p0 + q0 + q1; data[ 0] = (u8)((p1 + 2 * tmp + q2 + 4) >> 3); data[imageWidth] = (u8)((tmp + q2 + 2) >> 2); data[imageWidth*2] = (u8)((2 * data[imageWidth*3] + 3 * q2 + tmp + 4) >> 3); } else data[0] = (2 * q1 + q0 + p1 + 2) >> 2; } } } // hashA += data[-imageWidth*2] + data[-imageWidth] + data[0] + data[imageWidth]; } /*------------------------------------------------------------------------------ Function: FilterVerChromaEdge Functional description: Filter one vertical 2-pixel chroma edge ------------------------------------------------------------------------------*/ void FilterVerChromaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, u32 width) { /* Variables */ i32 delta, tc; u8 p0, q0, p1, q1; const u8 *clp = h264bsdClip + 512; /* Code */ ASSERT(data); ASSERT(bS <= 4); ASSERT(thresholds); p1 = data[-2]; p0 = data[-1]; q0 = data[0]; q1 = data[1]; if ( ((u32)ABS(p0-q0) < thresholds->alpha) && ((u32)ABS(p1-p0) < thresholds->beta) && ((u32)ABS(q1-q0) < thresholds->beta) ) { if (bS < 4) { tc = thresholds->tc0[bS-1] + 1; delta = CLIP3(-tc, tc, ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; data[-1] = p0; data[ 0] = q0; } else { data[-1] = (2 * p1 + p0 + q1 + 2) >> 2; data[ 0] = (2 * q1 + q0 + p1 + 2) >> 2; } } data += width; p1 = data[-2]; p0 = data[-1]; q0 = data[0]; q1 = data[1]; if ( ((u32)ABS(p0-q0) < thresholds->alpha) && ((u32)ABS(p1-p0) < thresholds->beta) && ((u32)ABS(q1-q0) < thresholds->beta) ) { if (bS < 4) { tc = thresholds->tc0[bS-1] + 1; delta = CLIP3(-tc, tc, ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; data[-1] = p0; data[ 0] = q0; } else { data[-1] = (2 * p1 + p0 + q1 + 2) >> 2; data[ 0] = (2 * q1 + q0 + p1 + 2) >> 2; } } } /*------------------------------------------------------------------------------ Function: FilterHorChromaEdge Functional description: Filter one horizontal 2-pixel chroma edge ------------------------------------------------------------------------------*/ void FilterHorChromaEdge( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 width) { /* Variables */ i32 delta, tc; u32 i; u8 p0, q0, p1, q1; const u8 *clp = h264bsdClip + 512; /* Code */ ASSERT(data); ASSERT(bS < 4); ASSERT(thresholds); tc = thresholds->tc0[bS-1] + 1; for (i = 2; i; i--, data++) { p1 = data[-width*2]; p0 = data[-width]; q0 = data[0]; q1 = data[width]; if ( ((u32)ABS(p0-q0) < thresholds->alpha) && ((u32)ABS(p1-p0) < thresholds->beta) && ((u32)ABS(q1-q0) < thresholds->beta) ) { delta = CLIP3(-tc, tc, ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; data[-width] = p0; data[ 0] = q0; } } } /*------------------------------------------------------------------------------ Function: FilterHorChroma Functional description: Filter all four successive horizontal 2-pixel chroma edges. This can be done if bS is equal for all four edges. ------------------------------------------------------------------------------*/ void FilterHorChroma( u8 *data, u32 bS, edgeThreshold_t *thresholds, i32 width) { /* Variables */ i32 delta, tc; u32 i; u8 p0, q0, p1, q1; const u8 *clp = h264bsdClip + 512; /* Code */ ASSERT(data); ASSERT(bS <= 4); ASSERT(thresholds); if (bS < 4) { tc = thresholds->tc0[bS-1] + 1; for (i = 8; i; i--, data++) { p1 = data[-width*2]; p0 = data[-width]; q0 = data[0]; q1 = data[width]; if ( ((u32)ABS(p0-q0) < thresholds->alpha) && ((u32)ABS(p1-p0) < thresholds->beta) && ((u32)ABS(q1-q0) < thresholds->beta) ) { delta = CLIP3(-tc, tc, ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)); p0 = clp[p0 + delta]; q0 = clp[q0 - delta]; data[-width] = p0; data[ 0] = q0; } } } else { for (i = 8; i; i--, data++) { p1 = data[-width*2]; p0 = data[-width]; q0 = data[0]; q1 = data[width]; if ( ((u32)ABS(p0-q0) < thresholds->alpha) && ((u32)ABS(p1-p0) < thresholds->beta) && ((u32)ABS(q1-q0) < thresholds->beta) ) { data[-width] = (2 * p1 + p0 + q1 + 2) >> 2; data[ 0] = (2 * q1 + q0 + p1 + 2) >> 2; } } } } void GetBoundaryStrengthsA(mbStorage_t *mb, bS_t *bS) { bS[4].top = mb->totalCoeff[2] || mb->totalCoeff[0] ? 2 : 0; bS[5].top = mb->totalCoeff[3] || mb->totalCoeff[1] ? 2 : 0; bS[6].top = mb->totalCoeff[6] || mb->totalCoeff[4] ? 2 : 0; bS[7].top = mb->totalCoeff[7] || mb->totalCoeff[5] ? 2 : 0; bS[8].top = mb->totalCoeff[8] || mb->totalCoeff[2] ? 2 : 0; bS[9].top = mb->totalCoeff[9] || mb->totalCoeff[3] ? 2 : 0; bS[10].top = mb->totalCoeff[12] || mb->totalCoeff[6] ? 2 : 0; bS[11].top = mb->totalCoeff[13] || mb->totalCoeff[7] ? 2 : 0; bS[12].top = mb->totalCoeff[10] || mb->totalCoeff[8] ? 2 : 0; bS[13].top = mb->totalCoeff[11] || mb->totalCoeff[9] ? 2 : 0; bS[14].top = mb->totalCoeff[14] || mb->totalCoeff[12] ? 2 : 0; bS[15].top = mb->totalCoeff[15] || mb->totalCoeff[13] ? 2 : 0; bS[1].left = mb->totalCoeff[1] || mb->totalCoeff[0] ? 2 : 0; bS[2].left = mb->totalCoeff[4] || mb->totalCoeff[1] ? 2 : 0; bS[3].left = mb->totalCoeff[5] || mb->totalCoeff[4] ? 2 : 0; bS[5].left = mb->totalCoeff[3] || mb->totalCoeff[2] ? 2 : 0; bS[6].left = mb->totalCoeff[6] || mb->totalCoeff[3] ? 2 : 0; bS[7].left = mb->totalCoeff[7] || mb->totalCoeff[6] ? 2 : 0; bS[9].left = mb->totalCoeff[9] || mb->totalCoeff[8] ? 2 : 0; bS[10].left = mb->totalCoeff[12] || mb->totalCoeff[9] ? 2 : 0; bS[11].left = mb->totalCoeff[13] || mb->totalCoeff[12] ? 2 : 0; bS[13].left = mb->totalCoeff[11] || mb->totalCoeff[10] ? 2 : 0; bS[14].left = mb->totalCoeff[14] || mb->totalCoeff[11] ? 2 : 0; bS[15].left = mb->totalCoeff[15] || mb->totalCoeff[14] ? 2 : 0; } /*------------------------------------------------------------------------------ Function: GetBoundaryStrengths Functional description: Function to calculate boundary strengths for all edges of a macroblock. Function returns HANTRO_TRUE if any of the bS values for the macroblock had non-zero value, HANTRO_FALSE otherwise. ------------------------------------------------------------------------------*/ u32 GetBoundaryStrengths(mbStorage_t *mb, bS_t *bS, u32 flags) { /* Variables */ /* this flag is set HANTRO_TRUE as soon as any boundary strength value is * non-zero */ u32 nonZeroBs = HANTRO_FALSE; /* Code */ ASSERT(mb); ASSERT(bS); ASSERT(flags); // if (sample ++ % (1024 * 128) == 0) { // printf("Hash A: %d, Hash B: %d, Hash C: %d, Hash D: %d\n", hashA, hashB, hashC, hashD); // } /* top edges */ if (flags & FILTER_TOP_EDGE) { if (IS_INTRA_MB(*mb) || IS_INTRA_MB(*mb->mbB)) { bS[0].top = bS[1].top = bS[2].top = bS[3].top = 4; nonZeroBs = HANTRO_TRUE; } else { bS[0].top = EdgeBoundaryStrength(mb, mb->mbB, 0, 10); bS[1].top = EdgeBoundaryStrength(mb, mb->mbB, 1, 11); bS[2].top = EdgeBoundaryStrength(mb, mb->mbB, 4, 14); bS[3].top = EdgeBoundaryStrength(mb, mb->mbB, 5, 15); if (bS[0].top || bS[1].top || bS[2].top || bS[3].top) nonZeroBs = HANTRO_TRUE; } } else { bS[0].top = bS[1].top = bS[2].top = bS[3].top = 0; } /* left edges */ if (flags & FILTER_LEFT_EDGE) { if (IS_INTRA_MB(*mb) || IS_INTRA_MB(*mb->mbA)) { bS[0].left = bS[4].left = bS[8].left = bS[12].left = 4; nonZeroBs = HANTRO_TRUE; } else { bS[0].left = EdgeBoundaryStrength(mb, mb->mbA, 0, 5); bS[4].left = EdgeBoundaryStrength(mb, mb->mbA, 2, 7); bS[8].left = EdgeBoundaryStrength(mb, mb->mbA, 8, 13); bS[12].left = EdgeBoundaryStrength(mb, mb->mbA, 10, 15); if (!nonZeroBs && (bS[0].left || bS[4].left || bS[8].left || bS[12].left)) nonZeroBs = HANTRO_TRUE; } } else { bS[0].left = bS[4].left = bS[8].left = bS[12].left = 0; } /* inner edges */ if (IS_INTRA_MB(*mb)) { bS[4].top = bS[5].top = bS[6].top = bS[7].top = bS[8].top = bS[9].top = bS[10].top = bS[11].top = bS[12].top = bS[13].top = bS[14].top = bS[15].top = 3; bS[1].left = bS[2].left = bS[3].left = bS[5].left = bS[6].left = bS[7].left = bS[9].left = bS[10].left = bS[11].left = bS[13].left = bS[14].left = bS[15].left = 3; nonZeroBs = HANTRO_TRUE; } else { /* 16x16 inter mb -> ref addresses or motion vectors cannot differ, * only check if either of the blocks contain coefficients */ if (h264bsdNumMbPart(mb->mbType) == 1) { GetBoundaryStrengthsA(mb, bS); } /* 16x8 inter mb -> ref addresses and motion vectors can be different * only for the middle horizontal edge, for the other top edges it is * enough to check whether the blocks contain coefficients or not. The * same applies to all internal left edges. */ else if (mb->mbType == P_L0_L0_16x8) { bS[4].top = mb->totalCoeff[2] || mb->totalCoeff[0] ? 2 : 0; bS[5].top = mb->totalCoeff[3] || mb->totalCoeff[1] ? 2 : 0; bS[6].top = mb->totalCoeff[6] || mb->totalCoeff[4] ? 2 : 0; bS[7].top = mb->totalCoeff[7] || mb->totalCoeff[5] ? 2 : 0; bS[12].top = mb->totalCoeff[10] || mb->totalCoeff[8] ? 2 : 0; bS[13].top = mb->totalCoeff[11] || mb->totalCoeff[9] ? 2 : 0; bS[14].top = mb->totalCoeff[14] || mb->totalCoeff[12] ? 2 : 0; bS[15].top = mb->totalCoeff[15] || mb->totalCoeff[13] ? 2 : 0; bS[8].top = InnerBoundaryStrength(mb, 8, 2); bS[9].top = InnerBoundaryStrength(mb, 9, 3); bS[10].top = InnerBoundaryStrength(mb, 12, 6); bS[11].top = InnerBoundaryStrength(mb, 13, 7); bS[1].left = mb->totalCoeff[1] || mb->totalCoeff[0] ? 2 : 0; bS[2].left = mb->totalCoeff[4] || mb->totalCoeff[1] ? 2 : 0; bS[3].left = mb->totalCoeff[5] || mb->totalCoeff[4] ? 2 : 0; bS[5].left = mb->totalCoeff[3] || mb->totalCoeff[2] ? 2 : 0; bS[6].left = mb->totalCoeff[6] || mb->totalCoeff[3] ? 2 : 0; bS[7].left = mb->totalCoeff[7] || mb->totalCoeff[6] ? 2 : 0; bS[9].left = mb->totalCoeff[9] || mb->totalCoeff[8] ? 2 : 0; bS[10].left = mb->totalCoeff[12] || mb->totalCoeff[9] ? 2 : 0; bS[11].left = mb->totalCoeff[13] || mb->totalCoeff[12] ? 2 : 0; bS[13].left = mb->totalCoeff[11] || mb->totalCoeff[10] ? 2 : 0; bS[14].left = mb->totalCoeff[14] || mb->totalCoeff[11] ? 2 : 0; bS[15].left = mb->totalCoeff[15] || mb->totalCoeff[14] ? 2 : 0; } /* 8x16 inter mb -> ref addresses and motion vectors can be different * only for the middle vertical edge, for the other left edges it is * enough to check whether the blocks contain coefficients or not. The * same applies to all internal top edges. */ else if (mb->mbType == P_L0_L0_8x16) { bS[4].top = mb->totalCoeff[2] || mb->totalCoeff[0] ? 2 : 0; bS[5].top = mb->totalCoeff[3] || mb->totalCoeff[1] ? 2 : 0; bS[6].top = mb->totalCoeff[6] || mb->totalCoeff[4] ? 2 : 0; bS[7].top = mb->totalCoeff[7] || mb->totalCoeff[5] ? 2 : 0; bS[8].top = mb->totalCoeff[8] || mb->totalCoeff[2] ? 2 : 0; bS[9].top = mb->totalCoeff[9] || mb->totalCoeff[3] ? 2 : 0; bS[10].top = mb->totalCoeff[12] || mb->totalCoeff[6] ? 2 : 0; bS[11].top = mb->totalCoeff[13] || mb->totalCoeff[7] ? 2 : 0; bS[12].top = mb->totalCoeff[10] || mb->totalCoeff[8] ? 2 : 0; bS[13].top = mb->totalCoeff[11] || mb->totalCoeff[9] ? 2 : 0; bS[14].top = mb->totalCoeff[14] || mb->totalCoeff[12] ? 2 : 0; bS[15].top = mb->totalCoeff[15] || mb->totalCoeff[13] ? 2 : 0; bS[1].left = mb->totalCoeff[1] || mb->totalCoeff[0] ? 2 : 0; bS[3].left = mb->totalCoeff[5] || mb->totalCoeff[4] ? 2 : 0; bS[5].left = mb->totalCoeff[3] || mb->totalCoeff[2] ? 2 : 0; bS[7].left = mb->totalCoeff[7] || mb->totalCoeff[6] ? 2 : 0; bS[9].left = mb->totalCoeff[9] || mb->totalCoeff[8] ? 2 : 0; bS[11].left = mb->totalCoeff[13] || mb->totalCoeff[12] ? 2 : 0; bS[13].left = mb->totalCoeff[11] || mb->totalCoeff[10] ? 2 : 0; bS[15].left = mb->totalCoeff[15] || mb->totalCoeff[14] ? 2 : 0; bS[2].left = InnerBoundaryStrength(mb, 4, 1); bS[6].left = InnerBoundaryStrength(mb, 6, 3); bS[10].left = InnerBoundaryStrength(mb, 12, 9); bS[14].left = InnerBoundaryStrength(mb, 14, 11); } else { bS[4].top = InnerBoundaryStrength(mb, mb4x4Index[4], mb4x4Index[0]); bS[5].top = InnerBoundaryStrength(mb, mb4x4Index[5], mb4x4Index[1]); bS[6].top = InnerBoundaryStrength(mb, mb4x4Index[6], mb4x4Index[2]); bS[7].top = InnerBoundaryStrength(mb, mb4x4Index[7], mb4x4Index[3]); bS[8].top = InnerBoundaryStrength(mb, mb4x4Index[8], mb4x4Index[4]); bS[9].top = InnerBoundaryStrength(mb, mb4x4Index[9], mb4x4Index[5]); bS[10].top = InnerBoundaryStrength(mb, mb4x4Index[10], mb4x4Index[6]); bS[11].top = InnerBoundaryStrength(mb, mb4x4Index[11], mb4x4Index[7]); bS[12].top = InnerBoundaryStrength(mb, mb4x4Index[12], mb4x4Index[8]); bS[13].top = InnerBoundaryStrength(mb, mb4x4Index[13], mb4x4Index[9]); bS[14].top = InnerBoundaryStrength(mb, mb4x4Index[14], mb4x4Index[10]); bS[15].top = InnerBoundaryStrength(mb, mb4x4Index[15], mb4x4Index[11]); bS[1].left = InnerBoundaryStrength(mb, mb4x4Index[1], mb4x4Index[0]); bS[2].left = InnerBoundaryStrength(mb, mb4x4Index[2], mb4x4Index[1]); bS[3].left = InnerBoundaryStrength(mb, mb4x4Index[3], mb4x4Index[2]); bS[5].left = InnerBoundaryStrength(mb, mb4x4Index[5], mb4x4Index[4]); bS[6].left = InnerBoundaryStrength(mb, mb4x4Index[6], mb4x4Index[5]); bS[7].left = InnerBoundaryStrength(mb, mb4x4Index[7], mb4x4Index[6]); bS[9].left = InnerBoundaryStrength(mb, mb4x4Index[9], mb4x4Index[8]); bS[10].left = InnerBoundaryStrength(mb, mb4x4Index[10], mb4x4Index[9]); bS[11].left = InnerBoundaryStrength(mb, mb4x4Index[11], mb4x4Index[10]); bS[13].left = InnerBoundaryStrength(mb, mb4x4Index[13], mb4x4Index[12]); bS[14].left = InnerBoundaryStrength(mb, mb4x4Index[14], mb4x4Index[13]); bS[15].left = InnerBoundaryStrength(mb, mb4x4Index[15], mb4x4Index[14]); } if (!nonZeroBs && (bS[4].top || bS[5].top || bS[6].top || bS[7].top || bS[8].top || bS[9].top || bS[10].top || bS[11].top || bS[12].top || bS[13].top || bS[14].top || bS[15].top || bS[1].left || bS[2].left || bS[3].left || bS[5].left || bS[6].left || bS[7].left || bS[9].left || bS[10].left || bS[11].left || bS[13].left || bS[14].left || bS[15].left)) nonZeroBs = HANTRO_TRUE; } return(nonZeroBs); } /*------------------------------------------------------------------------------ Function: GetLumaEdgeThresholds Functional description: Compute alpha, beta and tc0 thresholds for inner, left and top luma edges of a macroblock. ------------------------------------------------------------------------------*/ void GetLumaEdgeThresholds( edgeThreshold_t *thresholds, mbStorage_t *mb, u32 filteringFlags) { /* Variables */ u32 indexA, indexB; u32 qpAv, qp, qpTmp; /* Code */ ASSERT(thresholds); ASSERT(mb); qp = mb->qpY; indexA = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetB); thresholds[INNER].alpha = alphas[indexA]; thresholds[INNER].beta = betas[indexB]; thresholds[INNER].tc0 = tc0[indexA]; if (filteringFlags & FILTER_TOP_EDGE) { qpTmp = mb->mbB->qpY; if (qpTmp != qp) { qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); thresholds[TOP].alpha = alphas[indexA]; thresholds[TOP].beta = betas[indexB]; thresholds[TOP].tc0 = tc0[indexA]; } else { thresholds[TOP].alpha = thresholds[INNER].alpha; thresholds[TOP].beta = thresholds[INNER].beta; thresholds[TOP].tc0 = thresholds[INNER].tc0; } } if (filteringFlags & FILTER_LEFT_EDGE) { qpTmp = mb->mbA->qpY; if (qpTmp != qp) { qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); thresholds[LEFT].alpha = alphas[indexA]; thresholds[LEFT].beta = betas[indexB]; thresholds[LEFT].tc0 = tc0[indexA]; } else { thresholds[LEFT].alpha = thresholds[INNER].alpha; thresholds[LEFT].beta = thresholds[INNER].beta; thresholds[LEFT].tc0 = thresholds[INNER].tc0; } } } /*------------------------------------------------------------------------------ Function: GetChromaEdgeThresholds Functional description: Compute alpha, beta and tc0 thresholds for inner, left and top chroma edges of a macroblock. ------------------------------------------------------------------------------*/ void GetChromaEdgeThresholds( edgeThreshold_t *thresholds, mbStorage_t *mb, u32 filteringFlags, i32 chromaQpIndexOffset) { /* Variables */ u32 indexA, indexB; u32 qpAv, qp, qpTmp; /* Code */ ASSERT(thresholds); ASSERT(mb); qp = mb->qpY; qp = h264bsdQpC[CLIP3(0, 51, (i32)qp + chromaQpIndexOffset)]; indexA = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetB); thresholds[INNER].alpha = alphas[indexA]; thresholds[INNER].beta = betas[indexB]; thresholds[INNER].tc0 = tc0[indexA]; if (filteringFlags & FILTER_TOP_EDGE) { qpTmp = mb->mbB->qpY; if (qpTmp != mb->qpY) { qpTmp = h264bsdQpC[CLIP3(0, 51, (i32)qpTmp + chromaQpIndexOffset)]; qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); thresholds[TOP].alpha = alphas[indexA]; thresholds[TOP].beta = betas[indexB]; thresholds[TOP].tc0 = tc0[indexA]; } else { thresholds[TOP].alpha = thresholds[INNER].alpha; thresholds[TOP].beta = thresholds[INNER].beta; thresholds[TOP].tc0 = thresholds[INNER].tc0; } } if (filteringFlags & FILTER_LEFT_EDGE) { qpTmp = mb->mbA->qpY; if (qpTmp != mb->qpY) { qpTmp = h264bsdQpC[CLIP3(0, 51, (i32)qpTmp + chromaQpIndexOffset)]; qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); thresholds[LEFT].alpha = alphas[indexA]; thresholds[LEFT].beta = betas[indexB]; thresholds[LEFT].tc0 = tc0[indexA]; } else { thresholds[LEFT].alpha = thresholds[INNER].alpha; thresholds[LEFT].beta = thresholds[INNER].beta; thresholds[LEFT].tc0 = thresholds[INNER].tc0; } } } /*------------------------------------------------------------------------------ Function: FilterLuma Functional description: Function to filter all luma edges of a macroblock ------------------------------------------------------------------------------*/ void FilterLuma( u8 *data, bS_t *bS, edgeThreshold_t *thresholds, u32 width) { /* Variables */ u32 vblock; bS_t *tmp; u8 *ptr; u32 offset; /* Code */ ASSERT(data); ASSERT(bS); ASSERT(thresholds); ptr = data; tmp = bS; offset = TOP; /* loop block rows, perform filtering for all vertical edges of the block * row first, then filter each horizontal edge of the row */ for (vblock = 4; vblock--;) { /* only perform filtering if bS is non-zero, first of the four * FilterVerLumaEdge handles the left edge of the macroblock, others * filter inner edges */ if (tmp[0].left) FilterVerLumaEdge(ptr, tmp[0].left, thresholds + LEFT, width); if (tmp[1].left) FilterVerLumaEdge(ptr+4, tmp[1].left, thresholds + INNER, width); if (tmp[2].left) FilterVerLumaEdge(ptr+8, tmp[2].left, thresholds + INNER, width); if (tmp[3].left) FilterVerLumaEdge(ptr+12, tmp[3].left, thresholds + INNER, width); /* if bS is equal for all horizontal edges of the row -> perform * filtering with FilterHorLuma, otherwise use FilterHorLumaEdge for * each edge separately. offset variable indicates top macroblock edge * on the first loop round, inner edge for the other rounds */ if (tmp[0].top == tmp[1].top && tmp[1].top == tmp[2].top && tmp[2].top == tmp[3].top) { if(tmp[0].top) FilterHorLuma(ptr, tmp[0].top, thresholds + offset, (i32)width); } else { if(tmp[0].top) FilterHorLumaEdge(ptr, tmp[0].top, thresholds+offset, (i32)width); if(tmp[1].top) FilterHorLumaEdge(ptr+4, tmp[1].top, thresholds+offset, (i32)width); if(tmp[2].top) FilterHorLumaEdge(ptr+8, tmp[2].top, thresholds+offset, (i32)width); if(tmp[3].top) FilterHorLumaEdge(ptr+12, tmp[3].top, thresholds+offset, (i32)width); } /* four pixel rows ahead, i.e. next row of 4x4-blocks */ ptr += width*4; tmp += 4; offset = INNER; } } /*------------------------------------------------------------------------------ Function: FilterChroma Functional description: Function to filter all chroma edges of a macroblock ------------------------------------------------------------------------------*/ void FilterChroma( u8 *dataCb, u8 *dataCr, bS_t *bS, edgeThreshold_t *thresholds, u32 width) { /* Variables */ u32 vblock; bS_t *tmp; u32 offset; /* Code */ ASSERT(dataCb); ASSERT(dataCr); ASSERT(bS); ASSERT(thresholds); tmp = bS; offset = TOP; /* loop block rows, perform filtering for all vertical edges of the block * row first, then filter each horizontal edge of the row */ for (vblock = 0; vblock < 2; vblock++) { /* only perform filtering if bS is non-zero, first two of the four * FilterVerChromaEdge calls handle the left edge of the macroblock, * others filter the inner edge. Note that as chroma uses bS values * determined for luma edges, each bS is used only for 2 pixels of * a 4-pixel edge */ if (tmp[0].left) { FilterVerChromaEdge(dataCb, tmp[0].left, thresholds + LEFT, width); FilterVerChromaEdge(dataCr, tmp[0].left, thresholds + LEFT, width); } if (tmp[4].left) { FilterVerChromaEdge(dataCb+2*width, tmp[4].left, thresholds + LEFT, width); FilterVerChromaEdge(dataCr+2*width, tmp[4].left, thresholds + LEFT, width); } if (tmp[2].left) { FilterVerChromaEdge(dataCb+4, tmp[2].left, thresholds + INNER, width); FilterVerChromaEdge(dataCr+4, tmp[2].left, thresholds + INNER, width); } if (tmp[6].left) { FilterVerChromaEdge(dataCb+2*width+4, tmp[6].left, thresholds + INNER, width); FilterVerChromaEdge(dataCr+2*width+4, tmp[6].left, thresholds + INNER, width); } /* if bS is equal for all horizontal edges of the row -> perform * filtering with FilterHorChroma, otherwise use FilterHorChromaEdge * for each edge separately. offset variable indicates top macroblock * edge on the first loop round, inner edge for the second */ if (tmp[0].top == tmp[1].top && tmp[1].top == tmp[2].top && tmp[2].top == tmp[3].top) { if(tmp[0].top) { FilterHorChroma(dataCb, tmp[0].top, thresholds+offset, (i32)width); FilterHorChroma(dataCr, tmp[0].top, thresholds+offset, (i32)width); } } else { if (tmp[0].top) { FilterHorChromaEdge(dataCb, tmp[0].top, thresholds+offset, (i32)width); FilterHorChromaEdge(dataCr, tmp[0].top, thresholds+offset, (i32)width); } if (tmp[1].top) { FilterHorChromaEdge(dataCb+2, tmp[1].top, thresholds+offset, (i32)width); FilterHorChromaEdge(dataCr+2, tmp[1].top, thresholds+offset, (i32)width); } if (tmp[2].top) { FilterHorChromaEdge(dataCb+4, tmp[2].top, thresholds+offset, (i32)width); FilterHorChromaEdge(dataCr+4, tmp[2].top, thresholds+offset, (i32)width); } if (tmp[3].top) { FilterHorChromaEdge(dataCb+6, tmp[3].top, thresholds+offset, (i32)width); FilterHorChromaEdge(dataCr+6, tmp[3].top, thresholds+offset, (i32)width); } } tmp += 8; dataCb += width*4; dataCr += width*4; offset = INNER; } } #else /* H264DEC_OMXDL */ /*------------------------------------------------------------------------------ Function: h264bsdFilterPicture Functional description: Perform deblocking filtering for a picture. Filter does not copy the original picture anywhere but filtering is performed directly on the original image. Parameters controlling the filtering process are computed based on information in macroblock structures of the filtered macroblock, macroblock above and macroblock on the left of the filtered one. Inputs: image pointer to image to be filtered mb pointer to macroblock data structure of the top-left macroblock of the picture Outputs: image filtered image stored here Returns: none ------------------------------------------------------------------------------*/ /*lint --e{550} Symbol not accessed */ void h264bsdFilterPicture( image_t *image, mbStorage_t *mb) { /* Variables */ u32 flags; u32 picSizeInMbs, mbRow, mbCol; u32 picWidthInMbs; u8 *data; mbStorage_t *pMb; u8 bS[2][16]; u8 thresholdLuma[2][16]; u8 thresholdChroma[2][8]; u8 alpha[2][2]; u8 beta[2][2]; OMXResult res; /* Code */ ASSERT(image); ASSERT(mb); ASSERT(image->data); ASSERT(image->width); ASSERT(image->height); picWidthInMbs = image->width; data = image->data; picSizeInMbs = picWidthInMbs * image->height; pMb = mb; for (mbRow = 0, mbCol = 0; mbRow < image->height; pMb++) { flags = GetMbFilteringFlags(pMb); if (flags) { /* GetBoundaryStrengths function returns non-zero value if any of * the bS values for the macroblock being processed was non-zero */ if (GetBoundaryStrengths(pMb, bS, flags)) { /* Luma */ GetLumaEdgeThresholds(pMb,alpha,beta,thresholdLuma,bS,flags); data = image->data + mbRow * picWidthInMbs * 256 + mbCol * 16; res = omxVCM4P10_FilterDeblockingLuma_VerEdge_I( data, (OMX_S32)(picWidthInMbs*16), (const OMX_U8*)alpha, (const OMX_U8*)beta, (const OMX_U8*)thresholdLuma, (const OMX_U8*)bS ); res = omxVCM4P10_FilterDeblockingLuma_HorEdge_I( data, (OMX_S32)(picWidthInMbs*16), (const OMX_U8*)alpha+2, (const OMX_U8*)beta+2, (const OMX_U8*)thresholdLuma+16, (const OMX_U8*)bS+16 ); /* Cb */ GetChromaEdgeThresholds(pMb, alpha, beta, thresholdChroma, bS, flags, pMb->chromaQpIndexOffset); data = image->data + picSizeInMbs * 256 + mbRow * picWidthInMbs * 64 + mbCol * 8; res = omxVCM4P10_FilterDeblockingChroma_VerEdge_I( data, (OMX_S32)(picWidthInMbs*8), (const OMX_U8*)alpha, (const OMX_U8*)beta, (const OMX_U8*)thresholdChroma, (const OMX_U8*)bS ); res = omxVCM4P10_FilterDeblockingChroma_HorEdge_I( data, (OMX_S32)(picWidthInMbs*8), (const OMX_U8*)alpha+2, (const OMX_U8*)beta+2, (const OMX_U8*)thresholdChroma+8, (const OMX_U8*)bS+16 ); /* Cr */ data += (picSizeInMbs * 64); res = omxVCM4P10_FilterDeblockingChroma_VerEdge_I( data, (OMX_S32)(picWidthInMbs*8), (const OMX_U8*)alpha, (const OMX_U8*)beta, (const OMX_U8*)thresholdChroma, (const OMX_U8*)bS ); res = omxVCM4P10_FilterDeblockingChroma_HorEdge_I( data, (OMX_S32)(picWidthInMbs*8), (const OMX_U8*)alpha+2, (const OMX_U8*)beta+2, (const OMX_U8*)thresholdChroma+8, (const OMX_U8*)bS+16 ); } } mbCol++; if (mbCol == picWidthInMbs) { mbCol = 0; mbRow++; } } } /*------------------------------------------------------------------------------ Function: GetBoundaryStrengths Functional description: Function to calculate boundary strengths for all edges of a macroblock. Function returns HANTRO_TRUE if any of the bS values for the macroblock had non-zero value, HANTRO_FALSE otherwise. ------------------------------------------------------------------------------*/ u32 GetBoundaryStrengths(mbStorage_t *mb, u8 (*bS)[16], u32 flags) { /* Variables */ /* this flag is set HANTRO_TRUE as soon as any boundary strength value is * non-zero */ u32 nonZeroBs = HANTRO_FALSE; u32 *pTmp; u32 tmp1, tmp2, isIntraMb; /* Code */ ASSERT(mb); ASSERT(bS); ASSERT(flags); isIntraMb = IS_INTRA_MB(*mb); /* top edges */ pTmp = (u32*)&bS[1][0]; if (flags & FILTER_TOP_EDGE) { if (isIntraMb || IS_INTRA_MB(*mb->mbB)) { *pTmp = 0x04040404; nonZeroBs = HANTRO_TRUE; } else { *pTmp = EdgeBoundaryStrengthTop(mb, mb->mbB); if (*pTmp) nonZeroBs = HANTRO_TRUE; } } else { *pTmp = 0; } /* left edges */ pTmp = (u32*)&bS[0][0]; if (flags & FILTER_LEFT_EDGE) { if (isIntraMb || IS_INTRA_MB(*mb->mbA)) { /*bS[0][0] = bS[0][1] = bS[0][2] = bS[0][3] = 4;*/ *pTmp = 0x04040404; nonZeroBs = HANTRO_TRUE; } else { *pTmp = EdgeBoundaryStrengthLeft(mb, mb->mbA); if (!nonZeroBs && *pTmp) nonZeroBs = HANTRO_TRUE; } } else { *pTmp = 0; } /* inner edges */ if (isIntraMb) { pTmp++; *pTmp++ = 0x03030303; *pTmp++ = 0x03030303; *pTmp++ = 0x03030303; pTmp++; *pTmp++ = 0x03030303; *pTmp++ = 0x03030303; *pTmp = 0x03030303; nonZeroBs = HANTRO_TRUE; } else { pTmp = (u32*)mb->totalCoeff; /* 16x16 inter mb -> ref addresses or motion vectors cannot differ, * only check if either of the blocks contain coefficients */ if (h264bsdNumMbPart(mb->mbType) == 1) { tmp1 = *pTmp++; tmp2 = *pTmp++; bS[1][4] = (tmp1 & 0x00FF00FF) ? 2 : 0; /* [2] || [0] */ bS[1][5] = (tmp1 & 0xFF00FF00) ? 2 : 0; /* [3] || [1] */ bS[0][4] = (tmp1 & 0x0000FFFF) ? 2 : 0; /* [1] || [0] */ bS[0][5] = (tmp1 & 0xFFFF0000) ? 2 : 0; /* [3] || [2] */ tmp1 = *pTmp++; bS[1][6] = (tmp2 & 0x00FF00FF) ? 2 : 0; /* [6] || [4] */ bS[1][7] = (tmp2 & 0xFF00FF00) ? 2 : 0; /* [7] || [5] */ bS[0][12] = (tmp2 & 0x0000FFFF) ? 2 : 0; /* [5] || [4] */ bS[0][13] = (tmp2 & 0xFFFF0000) ? 2 : 0; /* [7] || [6] */ tmp2 = *pTmp; bS[1][12] = (tmp1 & 0x00FF00FF) ? 2 : 0; /* [10] || [8] */ bS[1][13] = (tmp1 & 0xFF00FF00) ? 2 : 0; /* [11] || [9] */ bS[0][6] = (tmp1 & 0x0000FFFF) ? 2 : 0; /* [9] || [8] */ bS[0][7] = (tmp1 & 0xFFFF0000) ? 2 : 0; /* [11] || [10] */ bS[1][14] = (tmp2 & 0x00FF00FF) ? 2 : 0; /* [14] || [12] */ bS[1][15] = (tmp2 & 0xFF00FF00) ? 2 : 0; /* [15] || [13] */ bS[0][14] = (tmp2 & 0x0000FFFF) ? 2 : 0; /* [13] || [12] */ bS[0][15] = (tmp2 & 0xFFFF0000) ? 2 : 0; /* [15] || [14] */ { u32 tmp3, tmp4; tmp1 = mb->totalCoeff[8]; tmp2 = mb->totalCoeff[2]; tmp3 = mb->totalCoeff[9]; tmp4 = mb->totalCoeff[3]; bS[1][8] = tmp1 || tmp2 ? 2 : 0; tmp1 = mb->totalCoeff[12]; tmp2 = mb->totalCoeff[6]; bS[1][9] = tmp3 || tmp4 ? 2 : 0; tmp3 = mb->totalCoeff[13]; tmp4 = mb->totalCoeff[7]; bS[1][10] = tmp1 || tmp2 ? 2 : 0; tmp1 = mb->totalCoeff[4]; tmp2 = mb->totalCoeff[1]; bS[1][11] = tmp3 || tmp4 ? 2 : 0; tmp3 = mb->totalCoeff[6]; tmp4 = mb->totalCoeff[3]; bS[0][8] = tmp1 || tmp2 ? 2 : 0; tmp1 = mb->totalCoeff[12]; tmp2 = mb->totalCoeff[9]; bS[0][9] = tmp3 || tmp4 ? 2 : 0; tmp3 = mb->totalCoeff[14]; tmp4 = mb->totalCoeff[11]; bS[0][10] = tmp1 || tmp2 ? 2 : 0; bS[0][11] = tmp3 || tmp4 ? 2 : 0; } } /* 16x8 inter mb -> ref addresses and motion vectors can be different * only for the middle horizontal edge, for the other top edges it is * enough to check whether the blocks contain coefficients or not. The * same applies to all internal left edges. */ else if (mb->mbType == P_L0_L0_16x8) { tmp1 = *pTmp++; tmp2 = *pTmp++; bS[1][4] = (tmp1 & 0x00FF00FF) ? 2 : 0; /* [2] || [0] */ bS[1][5] = (tmp1 & 0xFF00FF00) ? 2 : 0; /* [3] || [1] */ bS[0][4] = (tmp1 & 0x0000FFFF) ? 2 : 0; /* [1] || [0] */ bS[0][5] = (tmp1 & 0xFFFF0000) ? 2 : 0; /* [3] || [2] */ tmp1 = *pTmp++; bS[1][6] = (tmp2 & 0x00FF00FF) ? 2 : 0; /* [6] || [4] */ bS[1][7] = (tmp2 & 0xFF00FF00) ? 2 : 0; /* [7] || [5] */ bS[0][12] = (tmp2 & 0x0000FFFF) ? 2 : 0; /* [5] || [4] */ bS[0][13] = (tmp2 & 0xFFFF0000) ? 2 : 0; /* [7] || [6] */ tmp2 = *pTmp; bS[1][12] = (tmp1 & 0x00FF00FF) ? 2 : 0; /* [10] || [8] */ bS[1][13] = (tmp1 & 0xFF00FF00) ? 2 : 0; /* [11] || [9] */ bS[0][6] = (tmp1 & 0x0000FFFF) ? 2 : 0; /* [9] || [8] */ bS[0][7] = (tmp1 & 0xFFFF0000) ? 2 : 0; /* [11] || [10] */ bS[1][14] = (tmp2 & 0x00FF00FF) ? 2 : 0; /* [14] || [12] */ bS[1][15] = (tmp2 & 0xFF00FF00) ? 2 : 0; /* [15] || [13] */ bS[0][14] = (tmp2 & 0x0000FFFF) ? 2 : 0; /* [13] || [12] */ bS[0][15] = (tmp2 & 0xFFFF0000) ? 2 : 0; /* [15] || [14] */ bS[1][8] = (u8)InnerBoundaryStrength(mb, 8, 2); bS[1][9] = (u8)InnerBoundaryStrength(mb, 9, 3); bS[1][10] = (u8)InnerBoundaryStrength(mb, 12, 6); bS[1][11] = (u8)InnerBoundaryStrength(mb, 13, 7); { u32 tmp3, tmp4; tmp1 = mb->totalCoeff[4]; tmp2 = mb->totalCoeff[1]; tmp3 = mb->totalCoeff[6]; tmp4 = mb->totalCoeff[3]; bS[0][8] = tmp1 || tmp2 ? 2 : 0; tmp1 = mb->totalCoeff[12]; tmp2 = mb->totalCoeff[9]; bS[0][9] = tmp3 || tmp4 ? 2 : 0; tmp3 = mb->totalCoeff[14]; tmp4 = mb->totalCoeff[11]; bS[0][10] = tmp1 || tmp2 ? 2 : 0; bS[0][11] = tmp3 || tmp4 ? 2 : 0; } } /* 8x16 inter mb -> ref addresses and motion vectors can be different * only for the middle vertical edge, for the other left edges it is * enough to check whether the blocks contain coefficients or not. The * same applies to all internal top edges. */ else if (mb->mbType == P_L0_L0_8x16) { tmp1 = *pTmp++; tmp2 = *pTmp++; bS[1][4] = (tmp1 & 0x00FF00FF) ? 2 : 0; /* [2] || [0] */ bS[1][5] = (tmp1 & 0xFF00FF00) ? 2 : 0; /* [3] || [1] */ bS[0][4] = (tmp1 & 0x0000FFFF) ? 2 : 0; /* [1] || [0] */ bS[0][5] = (tmp1 & 0xFFFF0000) ? 2 : 0; /* [3] || [2] */ tmp1 = *pTmp++; bS[1][6] = (tmp2 & 0x00FF00FF) ? 2 : 0; /* [6] || [4] */ bS[1][7] = (tmp2 & 0xFF00FF00) ? 2 : 0; /* [7] || [5] */ bS[0][12] = (tmp2 & 0x0000FFFF) ? 2 : 0; /* [5] || [4] */ bS[0][13] = (tmp2 & 0xFFFF0000) ? 2 : 0; /* [7] || [6] */ tmp2 = *pTmp; bS[1][12] = (tmp1 & 0x00FF00FF) ? 2 : 0; /* [10] || [8] */ bS[1][13] = (tmp1 & 0xFF00FF00) ? 2 : 0; /* [11] || [9] */ bS[0][6] = (tmp1 & 0x0000FFFF) ? 2 : 0; /* [9] || [8] */ bS[0][7] = (tmp1 & 0xFFFF0000) ? 2 : 0; /* [11] || [10] */ bS[1][14] = (tmp2 & 0x00FF00FF) ? 2 : 0; /* [14] || [12] */ bS[1][15] = (tmp2 & 0xFF00FF00) ? 2 : 0; /* [15] || [13] */ bS[0][14] = (tmp2 & 0x0000FFFF) ? 2 : 0; /* [13] || [12] */ bS[0][15] = (tmp2 & 0xFFFF0000) ? 2 : 0; /* [15] || [14] */ bS[0][8] = (u8)InnerBoundaryStrength(mb, 4, 1); bS[0][9] = (u8)InnerBoundaryStrength(mb, 6, 3); bS[0][10] = (u8)InnerBoundaryStrength(mb, 12, 9); bS[0][11] = (u8)InnerBoundaryStrength(mb, 14, 11); { u32 tmp3, tmp4; tmp1 = mb->totalCoeff[8]; tmp2 = mb->totalCoeff[2]; tmp3 = mb->totalCoeff[9]; tmp4 = mb->totalCoeff[3]; bS[1][8] = tmp1 || tmp2 ? 2 : 0; tmp1 = mb->totalCoeff[12]; tmp2 = mb->totalCoeff[6]; bS[1][9] = tmp3 || tmp4 ? 2 : 0; tmp3 = mb->totalCoeff[13]; tmp4 = mb->totalCoeff[7]; bS[1][10] = tmp1 || tmp2 ? 2 : 0; bS[1][11] = tmp3 || tmp4 ? 2 : 0; } } else { tmp1 = *pTmp++; bS[1][4] = (tmp1 & 0x00FF00FF) ? 2 : (u8)InnerBoundaryStrength2(mb, 2, 0); bS[1][5] = (tmp1 & 0xFF00FF00) ? 2 : (u8)InnerBoundaryStrength2(mb, 3, 1); bS[0][4] = (tmp1 & 0x0000FFFF) ? 2 : (u8)InnerBoundaryStrength2(mb, 1, 0); bS[0][5] = (tmp1 & 0xFFFF0000) ? 2 : (u8)InnerBoundaryStrength2(mb, 3, 2); tmp1 = *pTmp++; bS[1][6] = (tmp1 & 0x00FF00FF) ? 2 : (u8)InnerBoundaryStrength2(mb, 6, 4); bS[1][7] = (tmp1 & 0xFF00FF00) ? 2 : (u8)InnerBoundaryStrength2(mb, 7, 5); bS[0][12] = (tmp1 & 0x0000FFFF) ? 2 : (u8)InnerBoundaryStrength2(mb, 5, 4); bS[0][13] = (tmp1 & 0xFFFF0000) ? 2 : (u8)InnerBoundaryStrength2(mb, 7, 6); tmp1 = *pTmp++; bS[1][12] = (tmp1 & 0x00FF00FF) ? 2 : (u8)InnerBoundaryStrength2(mb, 10, 8); bS[1][13] = (tmp1 & 0xFF00FF00) ? 2 : (u8)InnerBoundaryStrength2(mb, 11, 9); bS[0][6] = (tmp1 & 0x0000FFFF) ? 2 : (u8)InnerBoundaryStrength2(mb, 9, 8); bS[0][7] = (tmp1 & 0xFFFF0000) ? 2 : (u8)InnerBoundaryStrength2(mb, 11, 10); tmp1 = *pTmp; bS[1][14] = (tmp1 & 0x00FF00FF) ? 2 : (u8)InnerBoundaryStrength2(mb, 14, 12); bS[1][15] = (tmp1 & 0xFF00FF00) ? 2 : (u8)InnerBoundaryStrength2(mb, 15, 13); bS[0][14] = (tmp1 & 0x0000FFFF) ? 2 : (u8)InnerBoundaryStrength2(mb, 13, 12); bS[0][15] = (tmp1 & 0xFFFF0000) ? 2 : (u8)InnerBoundaryStrength2(mb, 15, 14); bS[1][8] = (u8)InnerBoundaryStrength(mb, 8, 2); bS[1][9] = (u8)InnerBoundaryStrength(mb, 9, 3); bS[1][10] = (u8)InnerBoundaryStrength(mb, 12, 6); bS[1][11] = (u8)InnerBoundaryStrength(mb, 13, 7); bS[0][8] = (u8)InnerBoundaryStrength(mb, 4, 1); bS[0][9] = (u8)InnerBoundaryStrength(mb, 6, 3); bS[0][10] = (u8)InnerBoundaryStrength(mb, 12, 9); bS[0][11] = (u8)InnerBoundaryStrength(mb, 14, 11); } pTmp = (u32*)&bS[0][0]; if (!nonZeroBs && (pTmp[1] || pTmp[2] || pTmp[3] || pTmp[5] || pTmp[6] || pTmp[7]) ) { nonZeroBs = HANTRO_TRUE; } } return(nonZeroBs); } /*------------------------------------------------------------------------------ Function: GetLumaEdgeThresholds Functional description: Compute alpha, beta and tc0 thresholds for inner, left and top luma edges of a macroblock. ------------------------------------------------------------------------------*/ void GetLumaEdgeThresholds( mbStorage_t *mb, u8 (*alpha)[2], u8 (*beta)[2], u8 (*threshold)[16], u8 (*bs)[16], u32 filteringFlags ) { /* Variables */ u32 indexA, indexB; u32 qpAv, qp, qpTmp; u32 i; /* Code */ ASSERT(threshold); ASSERT(bs); ASSERT(beta); ASSERT(alpha); ASSERT(mb); qp = mb->qpY; indexA = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetB); /* Internal edge values */ alpha[0][1] = alphas[indexA]; alpha[1][1] = alphas[indexA]; alpha[1][0] = alphas[indexA]; alpha[0][0] = alphas[indexA]; beta[0][1] = betas[indexB]; beta[1][1] = betas[indexB]; beta[1][0] = betas[indexB]; beta[0][0] = betas[indexB]; /* vertical scan order */ for (i = 0; i < 2; i++) { u32 t1, t2; t1 = bs[i][0]; t2 = bs[i][1]; threshold[i][0] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][2]; threshold[i][1] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][3]; threshold[i][2] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][4]; threshold[i][3] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][5]; threshold[i][4] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][6]; threshold[i][5] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][7]; threshold[i][6] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][8]; threshold[i][7] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][9]; threshold[i][8] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][10]; threshold[i][9] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][11]; threshold[i][10] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][12]; threshold[i][11] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][13]; threshold[i][12] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][14]; threshold[i][13] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][15]; threshold[i][14] = (t1) ? tc0[indexA][t1] : 0; threshold[i][15] = (t2) ? tc0[indexA][t2] : 0; } if (filteringFlags & FILTER_TOP_EDGE) { qpTmp = mb->mbB->qpY; if (qpTmp != qp) { u32 t1, t2, t3, t4; qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); alpha[1][0] = alphas[indexA]; beta[1][0] = betas[indexB]; t1 = bs[1][0]; t2 = bs[1][1]; t3 = bs[1][2]; t4 = bs[1][3]; threshold[1][0] = (t1 && (t1 < 4)) ? tc0[indexA][t1] : 0; threshold[1][1] = (t2 && (t2 < 4)) ? tc0[indexA][t2] : 0; threshold[1][2] = (t3 && (t3 < 4)) ? tc0[indexA][t3] : 0; threshold[1][3] = (t4 && (t4 < 4)) ? tc0[indexA][t4] : 0; } } if (filteringFlags & FILTER_LEFT_EDGE) { qpTmp = mb->mbA->qpY; if (qpTmp != qp) { qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); alpha[0][0] = alphas[indexA]; beta[0][0] = betas[indexB]; threshold[0][0] = (bs[0][0] && (bs[0][0] < 4)) ? tc0[indexA][bs[0][0]] : 0; threshold[0][1] = (bs[0][1] && (bs[0][1] < 4)) ? tc0[indexA][bs[0][1]] : 0; threshold[0][2] = (bs[0][2] && (bs[0][2] < 4)) ? tc0[indexA][bs[0][2]] : 0; threshold[0][3] = (bs[0][3] && (bs[0][3] < 4)) ? tc0[indexA][bs[0][3]] : 0; } } } /*------------------------------------------------------------------------------ Function: GetChromaEdgeThresholds Functional description: Compute alpha, beta and tc0 thresholds for inner, left and top chroma edges of a macroblock. ------------------------------------------------------------------------------*/ void GetChromaEdgeThresholds( mbStorage_t *mb, u8 (*alpha)[2], u8 (*beta)[2], u8 (*threshold)[8], u8 (*bs)[16], u32 filteringFlags, i32 chromaQpIndexOffset) { /* Variables */ u32 indexA, indexB; u32 qpAv, qp, qpTmp; u32 i; /* Code */ ASSERT(threshold); ASSERT(bs); ASSERT(beta); ASSERT(alpha); ASSERT(mb); ASSERT(mb); qp = mb->qpY; qp = h264bsdQpC[CLIP3(0, 51, (i32)qp + chromaQpIndexOffset)]; indexA = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qp + mb->filterOffsetB); alpha[0][1] = alphas[indexA]; alpha[1][1] = alphas[indexA]; alpha[1][0] = alphas[indexA]; alpha[0][0] = alphas[indexA]; beta[0][1] = betas[indexB]; beta[1][1] = betas[indexB]; beta[1][0] = betas[indexB]; beta[0][0] = betas[indexB]; for (i = 0; i < 2; i++) { u32 t1, t2; t1 = bs[i][0]; t2 = bs[i][1]; threshold[i][0] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][2]; threshold[i][1] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][3]; threshold[i][2] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][8]; threshold[i][3] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][9]; threshold[i][4] = (t1) ? tc0[indexA][t1] : 0; t1 = bs[i][10]; threshold[i][5] = (t2) ? tc0[indexA][t2] : 0; t2 = bs[i][11]; threshold[i][6] = (t1) ? tc0[indexA][t1] : 0; threshold[i][7] = (t2) ? tc0[indexA][t2] : 0; } if (filteringFlags & FILTER_TOP_EDGE) { qpTmp = mb->mbB->qpY; if (qpTmp != mb->qpY) { u32 t1, t2, t3, t4; qpTmp = h264bsdQpC[CLIP3(0, 51, (i32)qpTmp + chromaQpIndexOffset)]; qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); alpha[1][0] = alphas[indexA]; beta[1][0] = betas[indexB]; t1 = bs[1][0]; t2 = bs[1][1]; t3 = bs[1][2]; t4 = bs[1][3]; threshold[1][0] = (t1) ? tc0[indexA][t1] : 0; threshold[1][1] = (t2) ? tc0[indexA][t2] : 0; threshold[1][2] = (t3) ? tc0[indexA][t3] : 0; threshold[1][3] = (t4) ? tc0[indexA][t4] : 0; } } if (filteringFlags & FILTER_LEFT_EDGE) { qpTmp = mb->mbA->qpY; if (qpTmp != mb->qpY) { qpTmp = h264bsdQpC[CLIP3(0, 51, (i32)qpTmp + chromaQpIndexOffset)]; qpAv = (qp + qpTmp + 1) >> 1; indexA = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetA); indexB = (u32)CLIP3(0, 51, (i32)qpAv + mb->filterOffsetB); alpha[0][0] = alphas[indexA]; beta[0][0] = betas[indexB]; threshold[0][0] = (bs[0][0]) ? tc0[indexA][bs[0][0]] : 0; threshold[0][1] = (bs[0][1]) ? tc0[indexA][bs[0][1]] : 0; threshold[0][2] = (bs[0][2]) ? tc0[indexA][bs[0][2]] : 0; threshold[0][3] = (bs[0][3]) ? tc0[indexA][bs[0][3]] : 0; } } } #endif /* H264DEC_OMXDL */ /*lint +e701 +e702 */