www.pudn.com > T264.rar > deblock.c
/***************************************************************************** * * T264 AVC CODEC * * Copyright(C) 2004-2005 llcc* 2004-2005 visionany * Added support for B frame,20041223 Cloud Wu * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation ; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY ; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ****************************************************************************/ #include "stdio.h" #include "T264.h" #include "assert.h" #define IS_INTRA(mode) (mode <= I_16x16) static const uint8_t deblock_threshold_a[] = { 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 }; static const uint8_t deblock_threshold_b[] = { 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 }; static const uint8_t deblock_threshold_tc0[][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 } }; static void __inline get_strength(T264_t* t, uint8_t bS[4], int32_t dir, int32_t edge, T264_mb_context_t* cur, T264_mb_context_t* prev) { int32_t row_stride, col_stride; int32_t n; if (dir == 0) { row_stride = 4; col_stride = 1; } else { row_stride = 1; col_stride = 4; } if (IS_INTRA(cur->mb_mode) || IS_INTRA(prev->mb_mode)) { bS[0] = bS[1] = bS[2] = bS[3] = (edge == 0) ? 4 : 3; } else { for(n = 0 ; n < 4 ; n ++) { int32_t pos = n * row_stride + edge * col_stride; int32_t pos_n; if (cur == prev) { //If is macro blcok border pos_n = dir == 0 ? pos - 1 : pos - 4; } else { pos_n = dir == 0 ? 4 * n + 3 : 12 + n; } if (cur->nnz[pos] || prev->nnz[pos_n]) { bS[n] = 2; } else if (t->slice_type == SLICE_P) { int32_t ref, ref_n; ref = cur->vec[0][pos].refno; ref_n = prev->vec[0][pos_n].refno; assert(cur->vec[0][pos].refno != -2); assert(prev->vec[0][pos_n].refno != -2); bS[n] = ((ref != ref_n) | (ABS(cur->vec[0][pos].x - prev->vec[0][pos_n].x) >= 4) | (ABS(cur->vec[0][pos].y - prev->vec[0][pos_n].y) >= 4)); } else { int32_t ref0,ref1, ref_n0,ref_n1; ref0 = cur->vec[0][pos].refno; ref1 = cur->vec[1][pos].refno; ref_n0 = prev->vec[0][pos_n].refno; ref_n1 = prev->vec[1][pos_n].refno; ref0 = ref0 < 0? -1 : ref0; ref1 = ref1 < 0? -1 : ref1 + MAX_REFFRAMES; ref_n0 = ref_n0 < 0? -1 : ref_n0; ref_n1 = ref_n1 < 0? -1 : ref_n1 + MAX_REFFRAMES; assert(ref0 > -1 || ref1 > -1); if((ref0 == ref_n0 && ref1 == ref_n1) || (ref1 == ref_n0 && ref0 == ref_n1)) { bS[n] = 0; if(ref0 == ref1) { //if all use the same reference frame bS[n] = ( (ABS(cur->vec[0][pos].x - prev->vec[0][pos_n].x) >= 4) | (ABS(cur->vec[0][pos].y - prev->vec[0][pos_n].y) >= 4) | (ABS(cur->vec[1][pos].x - prev->vec[1][pos_n].x) >= 4) | (ABS(cur->vec[1][pos].y - prev->vec[1][pos_n].y) >= 4)) && ( (ABS(cur->vec[0][pos].x - prev->vec[1][pos_n].x) >= 4) | (ABS(cur->vec[0][pos].y - prev->vec[1][pos_n].y) >= 4) | (ABS(cur->vec[1][pos].x - prev->vec[0][pos_n].x) >= 4) | (ABS(cur->vec[1][pos].y - prev->vec[0][pos_n].y) >= 4)); }else { if(ref0 == ref_n0) { //if list0 reference frame are the same bS[n] = (ABS(cur->vec[0][pos].x - prev->vec[0][pos_n].x) >= 4) | (ABS(cur->vec[0][pos].y - prev->vec[0][pos_n].y) >= 4) | (ABS(cur->vec[1][pos].x - prev->vec[1][pos_n].x) >= 4) | (ABS(cur->vec[1][pos].y - prev->vec[1][pos_n].y) >= 4); }else { bS[n] = (ABS(cur->vec[0][pos].x - prev->vec[1][pos_n].x) >= 4) | (ABS(cur->vec[0][pos].y - prev->vec[1][pos_n].y) >= 4) | (ABS(cur->vec[1][pos].x - prev->vec[0][pos_n].x) >= 4) | (ABS(cur->vec[1][pos].y - prev->vec[0][pos_n].y) >= 4); } } }else { bS[n] =1; } } } } } static __inline void EdgeLoopH(T264_t* t, uint8_t* dst, int32_t stride, uint8_t indexA, int32_t alpha, int32_t beta, uint8_t bS, int32_t is_chroma) { int32_t ap, aq, tmp; uint8_t p[4]; uint8_t q[4]; q[0] = dst[0]; p[0] = dst[-1]; if (ABS(p[0] - q[0]) < alpha) { p[1] = dst[-2]; if (ABS(p[1] - p[0]) < beta) { q[1] = dst[1]; if (ABS(q[1] - q[0]) < beta) { if (bS < 4) { int32_t tc0, tc, delta; tc0 = deblock_threshold_tc0[indexA][bS - 1]; if (is_chroma == 0) { q[2] = dst[2]; p[2] = dst[-3]; ap = ABS(p[2] - p[0]); aq = ABS(q[2] - q[0]); tc = tc0; if (ap < beta) { dst[-2] = p[1] + clip3(((p[2] + ((p[0] + q[0] + 1) >> 1) - (p[1] << 1)) >> 1), -tc0, tc0); tc ++; } if (aq < beta) { dst[1] = q[1] + clip3(((q[2] + ((p[0] + q[0] + 1) >> 1) - (q[1] << 1)) >> 1), -tc0, tc0); tc ++; } } else { tc = tc0 + 1; } delta = clip3(((((q[0] - p[0]) << 2) + (p[1] - q[1]) + 4) >> 3), -tc, tc); tmp = p[0] + delta; dst[-1] = CLIP1(tmp); tmp = q[0] - delta; dst[0] = CLIP1(tmp); } else { if (ABS(p[0] - q[0]) < ((alpha >> 2) + 2)) { if (is_chroma == 0) { q[2] = dst[2]; p[2] = dst[-3]; ap = ABS(p[2] - p[0]); aq = ABS(q[2] - q[0]); if (ap < beta) { p[3] = dst[-4]; dst[-1] = (p[2] + 2 * p[1] + 2 * p[0] + 2 * q[0] + q[1] + 4) >> 3; dst[-2] = (p[2] + p[1] + p[0] + q[0] + 2) >> 2; dst[-3] = (2 * p[3] + 3 * p[2] + p[1] + p[0] + q[0] + 4) >> 3; } else { dst[-1] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; } if (aq < beta) { q[3] = dst[3]; dst[0] = (p[1] + 2 * p[0] + 2 * q[0] + 2 * q[1] + q[2] + 4) >> 3; dst[1] = (p[0] + q[0] + q[1] + q[2] + 2) >> 2; dst[2] = (2 * q[3] + 3 * q[2] + q[1] + q[0] + p[0] + 4) >> 3; } else { dst[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } else { dst[-1] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; dst[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } else { dst[-1] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; dst[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } } } } } static __inline void EdgeLoopV(T264_t* t, uint8_t* dst, int32_t stride, uint8_t indexA, int32_t alpha, int32_t beta, uint8_t bS, int32_t is_chroma) { int32_t ap, aq, tmp; uint8_t p[4]; uint8_t q[4]; q[0] = dst[0]; p[0] = dst[-1 * stride]; if (ABS(p[0] - q[0]) < alpha) { p[1] = dst[-2 * stride]; if (ABS(p[1] - p[0]) < beta) { q[1] = dst[1 * stride]; if (ABS(q[1] - q[0]) < beta) { if (bS < 4) { int32_t tc0, tc, delta; tc0 = deblock_threshold_tc0[indexA][bS - 1]; if (is_chroma == 0) { q[2] = dst[2 * stride]; p[2] = dst[-3 * stride]; ap = ABS(p[2] - p[0]); aq = ABS(q[2] - q[0]); tc = tc0; if (ap < beta) { dst[-2 * stride] = p[1] + clip3(((p[2] + ((p[0] + q[0] + 1) >> 1) - (p[1] << 1)) >> 1), -tc0, tc0); tc ++; } if (aq < beta) { dst[1 * stride] = q[1] + clip3(((q[2] + ((p[0] + q[0] + 1) >> 1) - (q[1] << 1)) >> 1), -tc0, tc0); tc ++; } } else { tc = tc0 + 1; } delta = clip3(((((q[0] - p[0]) << 2) + (p[1] - q[1]) + 4) >> 3), -tc, tc); tmp = p[0] + delta; dst[-1 * stride] = CLIP1(tmp); tmp = q[0] - delta; dst[0] = CLIP1(tmp); } else { if (ABS(p[0] - q[0]) < ((alpha >> 2) + 2)) { if (is_chroma == 0) { q[2] = dst[2 * stride]; p[2] = dst[-3 * stride]; ap = ABS(p[2] - p[0]); aq = ABS(q[2] - q[0]); if (ap < beta) { p[3] = dst[-4 * stride]; dst[-1 * stride] = (p[2] + 2 * p[1] + 2 * p[0] + 2 * q[0] + q[1] + 4) >> 3; dst[-2 * stride] = (p[2] + p[1] + p[0] + q[0] + 2) >> 2; dst[-3 * stride] = (2 * p[3] + 3 * p[2] + p[1] + p[0] + q[0] + 4) >> 3; } else { dst[-1 * stride] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; } if (aq < beta) { q[3] = dst[3 * stride]; dst[0 * stride] = (p[1] + 2 * p[0] + 2 * q[0] + 2 * q[1] + q[2] + 4) >> 3; dst[1 * stride] = (p[0] + q[0] + q[1] + q[2] + 2) >> 2; dst[2 * stride] = (2 * q[3] + 3 * q[2] + q[1] + q[0] + p[0] + 4) >> 3; } else { dst[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } else { dst[-1 * stride] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; dst[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } else { dst[-1 * stride] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; dst[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } } } } } void __inline deblock_mb_chroma(T264_t*t, int32_t x, int32_t y, uint8_t* dst_uv, uint8_t bSV[4][4], uint8_t bSH[4][4], uint8_t indexAc, int32_t alphac, int32_t betac) { uint8_t* dst; int32_t i; if (x != 0) { dst = dst_uv; for(i = 0 ; i < 4 ; i ++) { if (bSV[0][i] > 0) { EdgeLoopH(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSV[0][i], 1); dst += t->edged_stride_uv; EdgeLoopH(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSV[0][i], 1); dst += t->edged_stride_uv; } else { dst += 2 * t->edged_stride_uv; } } } { dst = dst_uv + 4; for(i = 0 ; i < 4 ; i ++) { if (bSV[2][i] > 0) { EdgeLoopH(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSV[2][i], 1); dst += t->edged_stride_uv; EdgeLoopH(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSV[2][i], 1); dst += t->edged_stride_uv; } else { dst += 2 * t->edged_stride_uv; } } } // u if (y != 0) { dst = dst_uv; for(i = 0 ; i < 4 ; i ++) { if (bSH[0][i] > 0) { EdgeLoopV(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSH[0][i], 1); dst ++; EdgeLoopV(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSH[0][i], 1); dst ++; } else { dst += 2; } } } { dst = dst_uv + 4 * t->edged_stride_uv; for(i = 0 ; i < 4 ; i ++) { if (bSH[2][i] > 0) { EdgeLoopV(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSH[2][i], 1); dst ++; EdgeLoopV(t, dst, t->edged_stride_uv, indexAc, alphac, betac, bSH[2][i], 1); dst ++; } else { dst += 2; } } } } void __inline deblock_mb_chroma_(T264_t*t, int32_t x, int32_t y, uint8_t* org_dst_u, uint8_t* org_dst_v, uint8_t bSV[4][4], uint8_t bSH[4][4], uint8_t indexAc, int32_t alphac, int32_t betac) { uint8_t* dst_u, *dst_v; int32_t i; if (x != 0) { dst_u = org_dst_u; dst_v = org_dst_v; for(i = 0 ; i < 4 ; i ++) { if (bSV[0][i] > 0) { EdgeLoopH(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSV[0][i], 1); dst_u += t->edged_stride_uv; EdgeLoopH(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSV[0][i], 1); dst_u += t->edged_stride_uv; EdgeLoopH(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSV[0][i], 1); dst_v += t->edged_stride_uv; EdgeLoopH(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSV[0][i], 1); dst_v += t->edged_stride_uv; } else { dst_u += 2 * t->edged_stride_uv; dst_v += 2 * t->edged_stride_uv; } } } { dst_u = org_dst_u + 4; dst_v = org_dst_v + 4; for(i = 0 ; i < 4 ; i ++) { if (bSV[2][i] > 0) { EdgeLoopH(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSV[2][i], 1); dst_u += t->edged_stride_uv; EdgeLoopH(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSV[2][i], 1); dst_u += t->edged_stride_uv; EdgeLoopH(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSV[2][i], 1); dst_v += t->edged_stride_uv; EdgeLoopH(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSV[2][i], 1); dst_v += t->edged_stride_uv; } else { dst_u += 2 * t->edged_stride_uv; dst_v += 2 * t->edged_stride_uv; } } } // u if (y != 0) { dst_u = org_dst_u; dst_v = org_dst_v; for(i = 0 ; i < 4 ; i ++) { if (bSH[0][i] > 0) { EdgeLoopV(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSH[0][i], 1); dst_u ++; EdgeLoopV(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSH[0][i], 1); dst_u ++; EdgeLoopV(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSH[0][i], 1); dst_v ++; EdgeLoopV(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSH[0][i], 1); dst_v ++; } else { dst_u += 2; dst_v += 2; } } } { dst_u = org_dst_u + 4 * t->edged_stride_uv; dst_v = org_dst_v + 4 * t->edged_stride_uv; for(i = 0 ; i < 4 ; i ++) { if (bSH[2][i] > 0) { EdgeLoopV(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSH[2][i], 1); dst_u ++; EdgeLoopV(t, dst_u, t->edged_stride_uv, indexAc, alphac, betac, bSH[2][i], 1); dst_u ++; EdgeLoopV(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSH[2][i], 1); dst_v ++; EdgeLoopV(t, dst_v, t->edged_stride_uv, indexAc, alphac, betac, bSH[2][i], 1); dst_v ++; } else { dst_u += 2; dst_v += 2; } } } } void deblock_mb(T264_t* t, int32_t y, int32_t x, T264_frame_t* f) { int32_t i, j; T264_mb_context_t* cur, *prev; uint8_t qpav, qpavc; uint8_t indexA, indexB, indexAc, indexBc; int32_t alpha, beta, alphac, betac; uint8_t bSV[4][4]; uint8_t bSH[4][4]; uint8_t* dst_y, *dst_u, *dst_v; int32_t mb_xy = t->mb_stride * y + x; uint8_t* dst; cur = &f->mb[mb_xy]; dst_y = f->Y[0] + (y << 4) * t->edged_stride + (x << 4); dst_u = f->U + (y << 3) * t->edged_stride_uv + (x << 3); dst_v = f->V + (y << 3) * t->edged_stride_uv + (x << 3); // xxx current mb_qp_delta == 0 !! qpav = (cur->mb_qp_delta + cur->mb_qp_delta + t->qp_y + t->qp_y + 1) >> 1; indexA = clip3(qpav + 0, 0, 51); indexB = clip3(qpav + 0, 0, 51); alpha = deblock_threshold_a[indexA]; beta = deblock_threshold_b[indexB]; qpavc = (cur->mb_qp_delta + cur->mb_qp_delta + t->qp_uv + t->qp_uv + 1) >> 1; indexAc = clip3(qpavc + 0, 0, 51); indexBc = clip3(qpavc + 0, 0, 51); alphac = deblock_threshold_a[indexAc]; betac = deblock_threshold_b[indexBc]; // vertical first // mb edge if (x != 0) { prev = &f->mb[mb_xy - 1]; get_strength(t, bSV[0], 0, 0, cur, prev); dst = dst_y; for(i = 0 ; i < 4 ; i ++) { if (bSV[0][i] > 0) { EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[0][i], 0); dst += t->edged_stride; EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[0][i], 0); dst += t->edged_stride; EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[0][i], 0); dst += t->edged_stride; EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[0][i], 0); dst += t->edged_stride; } else { dst += 4 * t->edged_stride; } } } for(j = 1 ; j < 4 ; j ++) { prev = cur; get_strength(t, bSV[j], 0, j, cur, prev); dst = dst_y + 4 * j; for(i = 0 ; i < 4 ; i ++) { if (bSV[j][i] > 0) { EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[j][i], 0); dst += t->edged_stride; EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[j][i], 0); dst += t->edged_stride; EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[j][i], 0); dst += t->edged_stride; EdgeLoopH(t, dst, t->edged_stride, indexA, alpha, beta, bSV[j][i], 0); dst += t->edged_stride; } else { dst += 4 * t->edged_stride; } } } // mb edge if (y != 0) { prev = &f->mb[mb_xy - t->mb_stride]; get_strength(t, bSH[0], 1, 0, cur, prev); dst = dst_y; for(i = 0 ; i < 4 ; i ++) { if (bSH[0][i] > 0) { EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[0][i], 0); dst ++; EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[0][i], 0); dst ++; EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[0][i], 0); dst ++; EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[0][i], 0); dst ++; } else { dst += 4; } } } for(j = 1 ; j < 4 ; j ++) { prev = cur; get_strength(t, bSH[j], 1, j, cur, prev); dst = dst_y + 4 * j * t->edged_stride; for(i = 0 ; i < 4 ; i ++) { if (bSH[j][i] > 0) { EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[j][i], 0); dst ++; EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[j][i], 0); dst ++; EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[j][i], 0); dst ++; EdgeLoopV(t, dst, t->edged_stride, indexA, alpha, beta, bSH[j][i], 0); dst ++; } else { dst += 4; } } } deblock_mb_chroma(t, x, y, dst_u, bSV, bSH, indexAc, alphac, betac); deblock_mb_chroma(t, x, y, dst_v, bSV, bSH, indexAc, alphac, betac); } void T264_deblock_frame(T264_t* t, T264_frame_t* f) { int32_t i, j; for (i = 0 ; i < t->mb_height ; i ++) { for (j = 0 ; j < t->mb_width ; j ++) { deblock_mb(t, i, j, f); } } }