| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * 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. |
| * ------------------------------------------------------------------- |
| */ |
| #include "mp4dec_lib.h" |
| #include "post_proc.h" |
| |
| #ifdef PV_POSTPROC_ON |
| |
| void CombinedHorzVertRingFilter( |
| uint8 *rec, |
| int width, |
| int height, |
| int16 *QP_store, |
| int chr, |
| uint8 *pp_mod) |
| { |
| |
| /*---------------------------------------------------------------------------- |
| ; Define all local variables |
| ----------------------------------------------------------------------------*/ |
| int index, counter; |
| int br, bc, incr, mbr, mbc; |
| int QP = 1; |
| int v[5]; |
| uint8 *ptr, *ptr_c, *ptr_n; |
| int w1, w2, w3, w4; |
| int pp_w, pp_h, brwidth; |
| int sum, delta; |
| int a3_0, a3_1, a3_2, A3_0; |
| /* for Deringing Threshold approach (MPEG4)*/ |
| int max_diff, thres, v0, h0, min_blk, max_blk; |
| int cnthflag; |
| |
| /*---------------------------------------------------------------------------- |
| ; Function body here |
| ----------------------------------------------------------------------------*/ |
| /* Calculate the width and height of the area in blocks (divide by 8) */ |
| pp_w = (width >> 3); |
| pp_h = (height >> 3); |
| |
| /* Set up various values needed for updating pointers into rec */ |
| w1 = width; /* Offset to next row in pixels */ |
| w2 = width << 1; /* Offset to two rows in pixels */ |
| w3 = w1 + w2; /* Offset to three rows in pixels */ |
| w4 = w2 << 1; /* Offset to four rows in pixels */ |
| incr = width - BLKSIZE; /* Offset to next row after processing block */ |
| |
| /* Work through the area hortizontally by two rows per step */ |
| for (mbr = 0; mbr < pp_h; mbr += 2) |
| { |
| /* brwidth contains the block number of the leftmost block |
| * of the current row */ |
| brwidth = mbr * pp_w; |
| |
| /* Work through the area vertically by two columns per step */ |
| for (mbc = 0; mbc < pp_w; mbc += 2) |
| { |
| /* if the data is luminance info, get the correct |
| * quantization paramenter. One parameter per macroblock */ |
| if (!chr) |
| { |
| /* brwidth/4 is the macroblock number and mbc/2 is the macroblock col number*/ |
| QP = QP_store[(brwidth>>2) + (mbc>>1)]; |
| } |
| |
| /****************** Horiz. Filtering ********************/ |
| /* Process four blocks for the filtering */ |
| /********************************************************/ |
| /* Loop over two rows of blocks */ |
| for (br = mbr + 1; br < mbr + 3; br++) /* br is the row counter in blocks */ |
| { |
| /* Set brwidth to the first (leftmost) block number of the next row */ |
| /* brwidth is used as an index when counting blocks */ |
| brwidth += pp_w; |
| |
| /* Loop over two columns of blocks in the row */ |
| for (bc = mbc; bc < mbc + 2; bc++) /* bc is the column counter in blocks */ |
| { |
| /****** check boundary for deblocking ************/ |
| /* Execute if the row and column counters are within the area */ |
| if (br < pp_h && bc < pp_w) |
| { |
| /* Set the ptr to the first pixel of the first block of the second row |
| * brwidth * 64 is the pixel row offset |
| * bc * 8 is the pixel column offset */ |
| ptr = rec + (brwidth << 6) + (bc << 3); |
| |
| /* Set the index to the current block of the second row counting in blocks */ |
| index = brwidth + bc; |
| |
| /* if the data is chrominance info, get the correct |
| * quantization paramenter. One parameter per block. */ |
| if (chr) |
| { |
| QP = QP_store[index]; |
| } |
| |
| /* Execute hard horizontal filter if semaphore for horizontal deblocking |
| * is set for the current block and block immediately above it */ |
| if (((pp_mod[index]&0x02) != 0) && ((pp_mod[index-pp_w]&0x02) != 0)) |
| { /* Hard filter */ |
| |
| /* Set HorzHflag (bit 4) in the pp_mod location */ |
| pp_mod[index-pp_w] |= 0x10; /* 4/26/00 reuse pp_mod for HorzHflag*/ |
| |
| /* Filter across the 8 pixels of the block */ |
| for (index = BLKSIZE; index > 0; index--) |
| { |
| /* Difference between the current pixel and the pixel above it */ |
| a3_0 = *ptr - *(ptr - w1); |
| |
| /* if the magnitude of the difference is greater than the KThH threshold |
| * and within the quantization parameter, apply hard filter */ |
| if ((a3_0 > KThH || a3_0 < -KThH) && a3_0<QP && a3_0> -QP) |
| { |
| ptr_c = ptr - w3; /* Points to pixel three rows above */ |
| ptr_n = ptr + w1; /* Points to pixel one row below */ |
| v[0] = (int)(*(ptr_c - w3)); |
| v[1] = (int)(*(ptr_c - w2)); |
| v[2] = (int)(*(ptr_c - w1)); |
| v[3] = (int)(*ptr_c); |
| v[4] = (int)(*(ptr_c + w1)); |
| |
| sum = v[0] |
| + v[1] |
| + v[2] |
| + *ptr_c |
| + v[4] |
| + (*(ptr_c + w2)) |
| + (*(ptr_c + w3)); /* Current pixel */ |
| |
| delta = (sum + *ptr_c + 4) >> 3; /* Average pixel values with rounding */ |
| *(ptr_c) = (uint8) delta; |
| |
| /* Move pointer down one row of pixels (points to pixel two rows |
| * above current pixel) */ |
| ptr_c += w1; |
| |
| for (counter = 0; counter < 5; counter++) |
| { |
| /* Subtract off highest pixel and add in pixel below */ |
| sum = sum - v[counter] + *ptr_n; |
| /* Average the pixel values with rounding */ |
| delta = (sum + *ptr_c + 4) >> 3; |
| *ptr_c = (uint8)(delta); |
| |
| /* Increment pointers to next pixel row */ |
| ptr_c += w1; |
| ptr_n += w1; |
| } |
| } |
| /* Increment pointer to next pixel */ |
| ++ptr; |
| } /* index*/ |
| } |
| else |
| { /* soft filter*/ |
| |
| /* Clear HorzHflag (bit 4) in the pp_mod location */ |
| pp_mod[index-pp_w] &= 0xef; /* reset 1110,1111 */ |
| |
| for (index = BLKSIZE; index > 0; index--) |
| { |
| /* Difference between the current pixel and the pixel above it */ |
| a3_0 = *(ptr) - *(ptr - w1); |
| |
| /* if the magnitude of the difference is greater than the KTh threshold, |
| * apply soft filter */ |
| if ((a3_0 > KTh || a3_0 < -KTh)) |
| { |
| |
| /* Sum of weighted differences */ |
| a3_0 += ((*(ptr - w2) - *(ptr + w1)) << 1) + (a3_0 << 2); |
| |
| /* Check if sum is less than the quantization parameter */ |
| if (PV_ABS(a3_0) < (QP << 3)) |
| { |
| a3_1 = *(ptr - w2) - *(ptr - w3); |
| a3_1 += ((*(ptr - w4) - *(ptr - w1)) << 1) + (a3_1 << 2); |
| |
| a3_2 = *(ptr + w2) - *(ptr + w1); |
| a3_2 += ((*(ptr) - *(ptr + w3)) << 1) + (a3_2 << 2); |
| |
| A3_0 = PV_ABS(a3_0) - PV_MIN(PV_ABS(a3_1), PV_ABS(a3_2)); |
| |
| if (A3_0 > 0) |
| { |
| A3_0 += A3_0 << 2; |
| A3_0 = (A3_0 + 32) >> 6; |
| if (a3_0 > 0) |
| { |
| A3_0 = -A3_0; |
| } |
| |
| delta = (*(ptr - w1) - *(ptr)) >> 1; |
| if (delta >= 0) |
| { |
| if (delta >= A3_0) |
| { |
| delta = PV_MAX(A3_0, 0); |
| } |
| } |
| else |
| { |
| if (A3_0 > 0) |
| { |
| delta = 0; |
| } |
| else |
| { |
| delta = PV_MAX(A3_0, delta); |
| } |
| } |
| |
| *(ptr - w1) = (uint8)(*(ptr - w1) - delta); |
| *(ptr) = (uint8)(*(ptr) + delta); |
| } |
| } /*threshold*/ |
| } |
| /* Increment pointer to next pixel */ |
| ++ptr; |
| } /*index*/ |
| } /* Soft filter*/ |
| }/* boundary checking*/ |
| }/*bc*/ |
| }/*br*/ |
| brwidth -= (pp_w << 1); |
| |
| |
| /****************** Vert. Filtering *********************/ |
| /* Process four blocks for the filtering */ |
| /********************************************************/ |
| /* Loop over two rows of blocks */ |
| for (br = mbr; br < mbr + 2; br++) /* br is the row counter in blocks */ |
| { |
| for (bc = mbc + 1; bc < mbc + 3; bc++) /* bc is the column counter in blocks */ |
| { |
| /****** check boundary for deblocking ************/ |
| /* Execute if the row and column counters are within the area */ |
| if (br < pp_h && bc < pp_w) |
| { |
| /* Set the ptr to the first pixel of the first block of the second row |
| * brwidth * 64 is the pixel row offset |
| * bc * 8 is the pixel column offset */ |
| ptr = rec + (brwidth << 6) + (bc << 3); |
| |
| /* Set the index to the current block of the second row counting in blocks */ |
| index = brwidth + bc; |
| |
| /* if the data is chrominance info, get the correct |
| * quantization paramenter. One parameter per block. */ |
| if (chr) |
| { |
| QP = QP_store[index]; |
| } |
| |
| /* Execute hard vertical filter if semaphore for vertical deblocking |
| * is set for the current block and block immediately left of it */ |
| if (((pp_mod[index-1]&0x01) != 0) && ((pp_mod[index]&0x01) != 0)) |
| { /* Hard filter */ |
| |
| /* Set VertHflag (bit 5) in the pp_mod location of previous block*/ |
| pp_mod[index-1] |= 0x20; /* 4/26/00 reuse pp_mod for VertHflag*/ |
| |
| /* Filter across the 8 pixels of the block */ |
| for (index = BLKSIZE; index > 0; index--) |
| { |
| /* Difference between the current pixel |
| * and the pixel to left of it */ |
| a3_0 = *ptr - *(ptr - 1); |
| |
| /* if the magnitude of the difference is greater than the KThH threshold |
| * and within the quantization parameter, apply hard filter */ |
| if ((a3_0 > KThH || a3_0 < -KThH) && a3_0<QP && a3_0> -QP) |
| { |
| ptr_c = ptr - 3; |
| ptr_n = ptr + 1; |
| v[0] = (int)(*(ptr_c - 3)); |
| v[1] = (int)(*(ptr_c - 2)); |
| v[2] = (int)(*(ptr_c - 1)); |
| v[3] = (int)(*ptr_c); |
| v[4] = (int)(*(ptr_c + 1)); |
| |
| sum = v[0] |
| + v[1] |
| + v[2] |
| + *ptr_c |
| + v[4] |
| + (*(ptr_c + 2)) |
| + (*(ptr_c + 3)); |
| |
| delta = (sum + *ptr_c + 4) >> 3; |
| *(ptr_c) = (uint8) delta; |
| |
| /* Move pointer down one pixel to the right */ |
| ptr_c += 1; |
| for (counter = 0; counter < 5; counter++) |
| { |
| /* Subtract off highest pixel and add in pixel below */ |
| sum = sum - v[counter] + *ptr_n; |
| /* Average the pixel values with rounding */ |
| delta = (sum + *ptr_c + 4) >> 3; |
| *ptr_c = (uint8)(delta); |
| |
| /* Increment pointers to next pixel */ |
| ptr_c += 1; |
| ptr_n += 1; |
| } |
| } |
| /* Increment pointers to next pixel row */ |
| ptr += w1; |
| } /* index*/ |
| } |
| else |
| { /* soft filter*/ |
| |
| /* Clear VertHflag (bit 5) in the pp_mod location */ |
| pp_mod[index-1] &= 0xdf; /* reset 1101,1111 */ |
| for (index = BLKSIZE; index > 0; index--) |
| { |
| /* Difference between the current pixel and the pixel above it */ |
| a3_0 = *(ptr) - *(ptr - 1); |
| |
| /* if the magnitude of the difference is greater than the KTh threshold, |
| * apply soft filter */ |
| if ((a3_0 > KTh || a3_0 < -KTh)) |
| { |
| |
| /* Sum of weighted differences */ |
| a3_0 += ((*(ptr - 2) - *(ptr + 1)) << 1) + (a3_0 << 2); |
| |
| /* Check if sum is less than the quantization parameter */ |
| if (PV_ABS(a3_0) < (QP << 3)) |
| { |
| a3_1 = *(ptr - 2) - *(ptr - 3); |
| a3_1 += ((*(ptr - 4) - *(ptr - 1)) << 1) + (a3_1 << 2); |
| |
| a3_2 = *(ptr + 2) - *(ptr + 1); |
| a3_2 += ((*(ptr) - *(ptr + 3)) << 1) + (a3_2 << 2); |
| |
| A3_0 = PV_ABS(a3_0) - PV_MIN(PV_ABS(a3_1), PV_ABS(a3_2)); |
| |
| if (A3_0 > 0) |
| { |
| A3_0 += A3_0 << 2; |
| A3_0 = (A3_0 + 32) >> 6; |
| if (a3_0 > 0) |
| { |
| A3_0 = -A3_0; |
| } |
| |
| delta = (*(ptr - 1) - *(ptr)) >> 1; |
| if (delta >= 0) |
| { |
| if (delta >= A3_0) |
| { |
| delta = PV_MAX(A3_0, 0); |
| } |
| } |
| else |
| { |
| if (A3_0 > 0) |
| { |
| delta = 0; |
| } |
| else |
| { |
| delta = PV_MAX(A3_0, delta); |
| } |
| } |
| |
| *(ptr - 1) = (uint8)(*(ptr - 1) - delta); |
| *(ptr) = (uint8)(*(ptr) + delta); |
| } |
| } /*threshold*/ |
| } |
| ptr += w1; |
| } /*index*/ |
| } /* Soft filter*/ |
| } /* boundary*/ |
| } /*bc*/ |
| /* Increment pointer to next row of pixels */ |
| brwidth += pp_w; |
| }/*br*/ |
| brwidth -= (pp_w << 1); |
| |
| /****************** Deringing ***************************/ |
| /* Process four blocks for the filtering */ |
| /********************************************************/ |
| /* Loop over two rows of blocks */ |
| for (br = mbr; br < mbr + 2; br++) |
| { |
| /* Loop over two columns of blocks in the row */ |
| for (bc = mbc; bc < mbc + 2; bc++) |
| { |
| /* Execute if the row and column counters are within the area */ |
| if (br < pp_h && bc < pp_w) |
| { |
| /* Set the index to the current block */ |
| index = brwidth + bc; |
| |
| /* Execute deringing if semaphore for deringing (bit-3 of pp_mod) |
| * is set for the current block */ |
| if ((pp_mod[index]&0x04) != 0) |
| { |
| /* Don't process deringing if on an edge block */ |
| if (br > 0 && bc > 0 && br < pp_h - 1 && bc < pp_w - 1) |
| { |
| /* cnthflag = weighted average of HorzHflag of current, |
| * one above, previous blocks*/ |
| cnthflag = ((pp_mod[index] & 0x10) + |
| (pp_mod[index-pp_w] & 0x10) + |
| ((pp_mod[index-1] >> 1) & 0x10) + |
| ((pp_mod[index] >> 1) & 0x10)) >> 4; /* 4/26/00*/ |
| |
| /* Do the deringing if decision flags indicate it's necessary */ |
| if (cnthflag < 3) |
| { |
| /* if the data is chrominance info, get the correct |
| * quantization paramenter. One parameter per block. */ |
| if (chr) |
| { |
| QP = QP_store[index]; |
| } |
| |
| /* Set amount to change luminance if it needs to be changed |
| * based on quantization parameter */ |
| max_diff = (QP >> 2) + 4; |
| |
| /* Set pointer to first pixel of current block */ |
| ptr = rec + (brwidth << 6) + (bc << 3); |
| |
| /* Find minimum and maximum value of pixel block */ |
| FindMaxMin(ptr, &min_blk, &max_blk, incr); |
| |
| /* threshold determination */ |
| thres = (max_blk + min_blk + 1) >> 1; |
| |
| /* If pixel range is greater or equal than DERING_THR, smooth the region */ |
| if ((max_blk - min_blk) >= DERING_THR) /*smooth 8x8 region*/ |
| #ifndef NoMMX |
| { |
| /* smooth all pixels in the block*/ |
| DeringAdaptiveSmoothMMX(ptr, width, thres, max_diff); |
| } |
| #else |
| { |
| /* Setup the starting point of the region to smooth */ |
| v0 = (br << 3) - 1; |
| h0 = (bc << 3) - 1; |
| |
| /*smooth 8x8 region*/ |
| AdaptiveSmooth_NoMMX(rec, v0, h0, v0 + 1, h0 + 1, thres, width, max_diff); |
| } |
| #endif |
| }/*cnthflag*/ |
| } /*dering br==1 or bc==1 (boundary block)*/ |
| else /* Process the boundary blocks */ |
| { |
| /* Decide to perform deblocking based on the semaphore flags |
| * of the neighboring blocks in each case. A certain number of |
| * hard filtering flags have to be set in order to signal need |
| * for smoothing */ |
| if (br > 0 && br < pp_h - 1) |
| { |
| if (bc > 0) |
| { |
| cnthflag = ((pp_mod[index-pp_w] & 0x10) + |
| (pp_mod[index] & 0x10) + |
| ((pp_mod[index-1] >> 1) & 0x10)) >> 4; |
| } |
| else |
| { |
| cnthflag = ((pp_mod[index] & 0x10) + |
| (pp_mod[index-pp_w] & 0x10) + |
| ((pp_mod[index] >> 1) & 0x10)) >> 4; |
| } |
| } |
| else if (bc > 0 && bc < pp_w - 1) |
| { |
| if (br > 0) |
| { |
| cnthflag = ((pp_mod[index-pp_w] & 0x10) + |
| ((pp_mod[index-1] >> 1) & 0x10) + |
| ((pp_mod[index] >> 1) & 0x10)) >> 4; |
| } |
| else |
| { |
| cnthflag = ((pp_mod[index] & 0x10) + |
| ((pp_mod[index-1] >> 1) & 0x10) + |
| ((pp_mod[index] >> 1) & 0x10)) >> 4; |
| } |
| } |
| else /* at the corner do default*/ |
| { |
| cnthflag = 0; |
| } |
| |
| /* Do the deringing if decision flags indicate it's necessary */ |
| if (cnthflag < 2) |
| { |
| |
| /* if the data is chrominance info, get the correct |
| * quantization paramenter. One parameter per block. */ |
| if (chr) |
| { |
| QP = QP_store[index]; |
| } |
| |
| /* Set amount to change luminance if it needs to be changed |
| * based on quantization parameter */ |
| max_diff = (QP >> 2) + 4; |
| |
| /* Set pointer to first pixel of current block */ |
| ptr = rec + (brwidth << 6) + (bc << 3); |
| |
| /* Find minimum and maximum value of pixel block */ |
| FindMaxMin(ptr, &min_blk, &max_blk, incr); |
| |
| /* threshold determination */ |
| thres = (max_blk + min_blk + 1) >> 1; |
| |
| /* Setup the starting point of the region to smooth |
| * This is going to be a 4x4 region */ |
| v0 = (br << 3) + 1; |
| h0 = (bc << 3) + 1; |
| |
| /* If pixel range is greater or equal than DERING_THR, smooth the region */ |
| if ((max_blk - min_blk) >= DERING_THR) |
| { |
| /* Smooth 4x4 region */ |
| AdaptiveSmooth_NoMMX(rec, v0, h0, v0 - 3, h0 - 3, thres, width, max_diff); |
| } |
| }/*cnthflag*/ |
| } /* br==0, bc==0*/ |
| } /* dering*/ |
| } /*boundary condition*/ |
| }/*bc*/ |
| brwidth += pp_w; |
| }/*br*/ |
| brwidth -= (pp_w << 1); |
| }/*mbc*/ |
| brwidth += (pp_w << 1); |
| }/*mbr*/ |
| |
| /*---------------------------------------------------------------------------- |
| ; Return nothing or data or data pointer |
| ----------------------------------------------------------------------------*/ |
| return ; |
| } |
| #endif |