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); 
        } 
    } 
}