www.pudn.com > T264-src-0.02.zip > deblock.c
/***************************************************************************** * * T264 AVC CODEC * * Copyright(C) 2004-2005 llcc* 2004-2005 visionany * * 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_4x4 || mode == I_16x16) static 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 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 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) { // NOTE: b frame does not support 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) { 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; } // xxx b slice condition 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)); } } } } static __inline void EdgeLoop(T264_t* t, uint8_t p[4], uint8_t q[4], uint8_t indexA, int32_t alpha, int32_t beta, uint8_t bS, int32_t is_chroma) { int32_t ap, aq, tmp; uint8_t p_new[4]; uint8_t q_new[4]; ap = ABS(p[2] - p[0]); aq = ABS(q[2] - q[0]); p_new[0] = p[0]; p_new[1] = p[1]; p_new[2] = p[2]; p_new[3] = p[3]; q_new[0] = q[0]; q_new[1] = q[1]; q_new[2] = q[2]; q_new[3] = q[3]; if (bS < 4) { int32_t tc0, tc, delta; tc0 = deblock_threshold_tc0[indexA][bS - 1]; if (is_chroma == 0) { tc = tc0; if (ap < beta) { p_new[1] = p[1] + clip3(((p[2] + ((p[0] + q[0] + 1) >> 1) - (p[1] << 1)) >> 1), -tc0, tc0); tc ++; } if (aq < beta) { q_new[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; p_new[0] = CLIP1(tmp); tmp = q[0] - delta; q_new[0] = CLIP1(tmp); p[0] = p_new[0]; p[1] = p_new[1]; q[0] = q_new[0]; q[1] = q_new[1]; } else { if (ABS(p[0] - q[0]) < ((alpha >> 2) + 2)) { if (is_chroma == 0) { if (ap < beta) { p_new[0] = (p[2] + 2 * p[1] + 2 * p[0] + 2 * q[0] + q[1] + 4) >> 3; p_new[1] = (p[2] + p[1] + p[0] + q[0] + 2) >> 2; p_new[2] = (2 * p[3] + 3 * p[2] + p[1] + p[0] + q[0] + 4) >> 3; } else { p_new[0] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; } if (aq < beta) { q_new[0] = (p[1] + 2 * p[0] + 2 * q[0] + 2 * q[1] + q[2] + 4) >> 3; q_new[1] = (p[0] + q[0] + q[1] + q[2] + 2) >> 2; q_new[2] = (2 * q[3] + 3 * q[2] + q[1] + q[0] + p[0] + 4) >> 3; } else { q_new[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } else { p_new[0] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; q_new[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } } else { p_new[0] = (2 * p[1] + p[0] + q[1] + 2 ) >> 2; q_new[0] = (2 * q[1] + q[0] + p[1] + 2 ) >> 2; } p[0] = p_new[0]; p[1] = p_new[1]; p[2] = p_new[2]; q[0] = q_new[0]; q[1] = q_new[1]; q[2] = q_new[2]; } } 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]; q[1] = dst[1]; q[2] = dst[2]; q[3] = dst[3]; p[3] = dst[-4]; p[2] = dst[-3]; p[1] = dst[-2]; p[0] = dst[-1]; if (ABS(p[0] - q[0]) < alpha && ABS(p[1] - p[0]) < beta && ABS(q[1] - q[0]) < beta) { ap = ABS(p[2] - p[0]); aq = ABS(q[2] - q[0]); if (bS < 4) { int32_t tc0, tc, delta; tc0 = deblock_threshold_tc0[indexA][bS - 1]; if (is_chroma == 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) { if (ap < beta) { 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) { 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; } } } } } } static __inline void deblock_mb(T264_t* t, int32_t y, int32_t x) { int32_t dir; 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 bS[4]; uint8_t* dst_y, *dst_u, *dst_v; int32_t mb_xy = t->mb_stride * y + x; cur = &t->rec->mb[mb_xy]; dst_y = t->rec->Y[0] + (y << 4) * t->edged_stride + (x << 4); dst_u = t->rec->U + (y << 3) * t->edged_stride_uv + (x << 3); dst_v = t->rec->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 for(dir = 0 ; dir < 2 ; dir ++) { j = (dir == 0 && x == 0) || (dir == 1 && y == 0) ? 1 : 0; for( ; j < 4 ; j ++) { if (j == 0) { if (dir == 0) { prev = &t->rec->mb[mb_xy - 1]; } else { prev = &t->rec->mb[mb_xy - t->mb_stride]; } } else { prev = cur; } get_strength(t, bS, dir, j, cur, prev); for(i = 0 ; i < 16 ; i ++) { if (bS[i / 4] > 0) { if (dir == 0) { EdgeLoopH(t, dst_y + (0 + 4 * j + i * t->edged_stride), t->edged_stride, indexA, alpha, beta, bS[i / 4], 0); } else { EdgeLoopV(t, dst_y + (i + (j * 4 + 0) * t->edged_stride), t->edged_stride, indexA, alpha, beta, bS[i / 4], 0); } } } if (!(j & 1)) { for(i = 0 ; i < 8 ; i ++) { if (bS[i / 2] > 0) { if (dir == 0) { EdgeLoopH(t, dst_u + (0 + 2 * j + i * t->edged_stride_uv), t->edged_stride_uv, indexAc, alphac, betac, bS[i / 2], 1); EdgeLoopH(t, dst_v + (0 + 2 * j + i * t->edged_stride_uv), t->edged_stride_uv, indexAc, alphac, betac, bS[i / 2], 1); } else { EdgeLoopV(t, dst_u + (i + (j * 2 + 0) * t->edged_stride_uv), t->edged_stride_uv, indexAc, alphac, betac, bS[i / 2], 1); EdgeLoopV(t, dst_v + (i + (j * 2 + 0) * t->edged_stride_uv), t->edged_stride_uv, indexAc, alphac, betac, bS[i / 2], 1); } } } } } } } 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); } } }