frame.c 25.9 KB
Newer Older
Laurent Aimar's avatar
Laurent Aimar committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*****************************************************************************
 * frame.c: h264 encoder library
 *****************************************************************************
 * Copyright (C) 2003 Laurent Aimar
 * $Id: frame.c,v 1.1 2004/06/03 19:27:06 fenrir Exp $
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * 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, USA.
 *****************************************************************************/

#include <stdio.h>
#include <string.h>

#include "common.h"

x264_frame_t *x264_frame_new( x264_t *h )
{
31
    x264_frame_t *frame = x264_malloc( sizeof(x264_frame_t) );
32
    int i, j;
Laurent Aimar's avatar
Laurent Aimar committed
33

34
    int i_mb_count = h->mb.i_mb_count;
Laurent Aimar's avatar
Laurent Aimar committed
35 36 37
    int i_stride;
    int i_lines;

38 39
    if( !frame ) return NULL;

40 41
    memset( frame, 0, sizeof(x264_frame_t) );

Laurent Aimar's avatar
Laurent Aimar committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
    /* allocate frame data (+64 for extra data for me) */
    i_stride = ( ( h->param.i_width  + 15 )&0xfffff0 )+ 64;
    i_lines  = ( ( h->param.i_height + 15 )&0xfffff0 );

    frame->i_plane = 3;
    for( i = 0; i < 3; i++ )
    {
        int i_divh = 1;
        int i_divw = 1;
        if( i > 0 )
        {
            if( h->param.i_csp == X264_CSP_I420 )
                i_divh = i_divw = 2;
            else if( h->param.i_csp == X264_CSP_I422 )
                i_divw = 2;
        }
        frame->i_stride[i] = i_stride / i_divw;
        frame->i_lines[i] = i_lines / i_divh;
60 61
        CHECKED_MALLOC( frame->buffer[i],
                        frame->i_stride[i] * ( frame->i_lines[i] + 64 / i_divh ) );
Laurent Aimar's avatar
Laurent Aimar committed
62 63 64 65 66 67 68 69
        frame->plane[i] = ((uint8_t*)frame->buffer[i]) +
                          frame->i_stride[i] * 32 / i_divh + 32 / i_divw;
    }
    frame->i_stride[3] = 0;
    frame->i_lines[3] = 0;
    frame->buffer[3] = NULL;
    frame->plane[3] = NULL;

70 71 72
    frame->filtered[0] = frame->plane[0];
    for( i = 0; i < 3; i++ )
    {
73 74
        CHECKED_MALLOC( frame->buffer[4+i],
                        frame->i_stride[0] * ( frame->i_lines[0] + 64 ) );
75
        frame->filtered[i+1] = ((uint8_t*)frame->buffer[4+i]) +
76
                                frame->i_stride[0] * 32 + 32;
77 78
    }

79
    if( h->frames.b_have_lowres )
80
    {
81 82 83 84
        frame->i_stride_lowres = frame->i_stride[0]/2 + 32;
        frame->i_lines_lowres = frame->i_lines[0]/2;
        for( i = 0; i < 4; i++ )
        {
85 86
            CHECKED_MALLOC( frame->buffer[7+i],
                            frame->i_stride_lowres * ( frame->i_lines[0]/2 + 64 ) );
87 88 89
            frame->lowres[i] = ((uint8_t*)frame->buffer[7+i]) +
                                frame->i_stride_lowres * 32 + 32;
        }
90
    }
91

92 93
    if( h->param.analyse.i_me_method == X264_ME_ESA )
    {
94 95
        CHECKED_MALLOC( frame->buffer[11],
                        frame->i_stride[0] * (frame->i_lines[0] + 64) * sizeof(uint16_t) );
96 97 98
        frame->integral = (uint16_t*)frame->buffer[11] + frame->i_stride[0] * 32 + 32;
    }

Laurent Aimar's avatar
Laurent Aimar committed
99 100 101
    frame->i_poc = -1;
    frame->i_type = X264_TYPE_AUTO;
    frame->i_qpplus1 = 0;
102 103
    frame->i_pts = -1;
    frame->i_frame = -1;
104
    frame->i_frame_num = -1;
Laurent Aimar's avatar
Laurent Aimar committed
105

106 107 108
    CHECKED_MALLOC( frame->mb_type, i_mb_count * sizeof(int8_t));
    CHECKED_MALLOC( frame->mv[0], 2*16 * i_mb_count * sizeof(int16_t) );
    CHECKED_MALLOC( frame->ref[0], 4 * i_mb_count * sizeof(int8_t) );
109 110
    if( h->param.i_bframe )
    {
111 112
        CHECKED_MALLOC( frame->mv[1], 2*16 * i_mb_count * sizeof(int16_t) );
        CHECKED_MALLOC( frame->ref[1], 4 * i_mb_count * sizeof(int8_t) );
113 114 115 116 117 118 119
    }
    else
    {
        frame->mv[1]  = NULL;
        frame->ref[1] = NULL;
    }

120 121
    CHECKED_MALLOC( frame->i_row_bits, i_lines/16 * sizeof(int) );
    CHECKED_MALLOC( frame->i_row_qp, i_lines/16 * sizeof(int) );
122 123
    for( i = 0; i < h->param.i_bframe + 2; i++ )
        for( j = 0; j < h->param.i_bframe + 2; j++ )
124
            CHECKED_MALLOC( frame->i_row_satds[i][j], i_lines/16 * sizeof(int) );
125

Laurent Aimar's avatar
Laurent Aimar committed
126
    return frame;
127 128 129 130

fail:
    x264_frame_delete( frame );
    return NULL;
Laurent Aimar's avatar
Laurent Aimar committed
131 132 133 134
}

void x264_frame_delete( x264_frame_t *frame )
{
135
    int i, j;
136
    for( i = 0; i < 12; i++ )
137
        x264_free( frame->buffer[i] );
138 139 140 141 142
    for( i = 0; i < X264_BFRAME_MAX+2; i++ )
        for( j = 0; j < X264_BFRAME_MAX+2; j++ )
            x264_free( frame->i_row_satds[i][j] );
    x264_free( frame->i_row_bits );
    x264_free( frame->i_row_qp );
143
    x264_free( frame->mb_type );
144 145 146 147
    x264_free( frame->mv[0] );
    x264_free( frame->mv[1] );
    x264_free( frame->ref[0] );
    x264_free( frame->ref[1] );
Laurent Aimar's avatar
Laurent Aimar committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    x264_free( frame );
}

void x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src )
{
    dst->i_type     = src->i_type;
    dst->i_qpplus1  = src->i_qpplus1;
    dst->i_pts      = src->i_pts;

    switch( src->img.i_csp & X264_CSP_MASK )
    {
        case X264_CSP_I420:
            h->csp.i420( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_YV12:
            h->csp.yv12( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_I422:
            h->csp.i422( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_I444:
            h->csp.i444( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_YUYV:
            h->csp.yuyv( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_RGB:
            h->csp.rgb( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_BGR:
            h->csp.bgr( dst, &src->img, h->param.i_width, h->param.i_height );
            break;
        case X264_CSP_BGRA:
            h->csp.bgra( dst, &src->img, h->param.i_width, h->param.i_height );
            break;

        default:
185
            x264_log( h, X264_LOG_ERROR, "Arg invalid CSP\n" );
Laurent Aimar's avatar
Laurent Aimar committed
186 187 188 189 190 191
            break;
    }
}



Loren Merritt's avatar
Loren Merritt committed
192
static void plane_expand_border( uint8_t *pix, int i_stride, int i_height, int i_pad )
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
{
#define PPIXEL(x, y) ( pix + (x) + (y)*i_stride )
    const int i_width = i_stride - 2*i_pad;
    int y;

    for( y = 0; y < i_height; y++ )
    {
        /* left band */
        memset( PPIXEL(-i_pad, y), PPIXEL(0, y)[0], i_pad );
        /* right band */
        memset( PPIXEL(i_width, y), PPIXEL(i_width-1, y)[0], i_pad );
    }
    /* upper band */
    for( y = 0; y < i_pad; y++ )
        memcpy( PPIXEL(-i_pad, -y-1), PPIXEL(-i_pad, 0), i_stride );
    /* lower band */
    for( y = 0; y < i_pad; y++ )
        memcpy( PPIXEL(-i_pad, i_height+y), PPIXEL(-i_pad, i_height-1), i_stride );
#undef PPIXEL
}

Laurent Aimar's avatar
Laurent Aimar committed
214 215
void x264_frame_expand_border( x264_frame_t *frame )
{
216
    int i;
Laurent Aimar's avatar
Laurent Aimar committed
217 218
    for( i = 0; i < frame->i_plane; i++ )
    {
219 220
        int i_pad = i ? 16 : 32;
        plane_expand_border( frame->plane[i], frame->i_stride[i], frame->i_lines[i], i_pad );
Laurent Aimar's avatar
Laurent Aimar committed
221 222 223
    }
}

224 225 226 227
void x264_frame_expand_border_filtered( x264_frame_t *frame )
{
    /* during filtering, 8 extra pixels were filtered on each edge. 
       we want to expand border from the last filtered pixel */
228
    int i;
229
    for( i = 1; i < 4; i++ )
230
        plane_expand_border( frame->filtered[i] - 8*frame->i_stride[0] - 8, frame->i_stride[0], frame->i_lines[0]+2*8, 24 );
231 232
}

233
void x264_frame_expand_border_lowres( x264_frame_t *frame )
234
{
235
    int i;
236
    for( i = 0; i < 4; i++ )
237
        plane_expand_border( frame->lowres[i], frame->i_stride_lowres, frame->i_lines_lowres, 32 );
238 239
}

Loren Merritt's avatar
Loren Merritt committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
void x264_frame_expand_border_mod16( x264_t *h, x264_frame_t *frame )
{
    int i, y;
    for( i = 0; i < frame->i_plane; i++ )
    {
        int i_subsample = i ? 1 : 0;
        int i_width = h->param.i_width >> i_subsample;
        int i_height = h->param.i_height >> i_subsample;
        int i_padx = ( h->sps->i_mb_width * 16 - h->param.i_width ) >> i_subsample;
        int i_pady = ( h->sps->i_mb_height * 16 - h->param.i_height ) >> i_subsample;

        if( i_padx )
        {
            for( y = 0; y < i_height; y++ )
                memset( &frame->plane[i][y*frame->i_stride[i] + i_width],
                         frame->plane[i][y*frame->i_stride[i] + i_width - 1],
                         i_padx );
        }
        if( i_pady )
        {
Loren Merritt's avatar
Loren Merritt committed
260
            for( y = i_height; y < i_height + i_pady; y++ )
Loren Merritt's avatar
Loren Merritt committed
261 262 263 264 265 266 267
                memcpy( &frame->plane[i][y*frame->i_stride[i]],
                        &frame->plane[i][(i_height-1)*frame->i_stride[i]],
                        i_width + i_padx );
        }
    }
}

268

269
/* Deblocking filter */
Laurent Aimar's avatar
Laurent Aimar committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310

static const int i_alpha_table[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
};
static const int i_beta_table[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
};
static const int i_tc0_table[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 }
};

/* From ffmpeg */
static inline int clip_uint8( int a )
{
    if (a&(~255))
        return (-a)>>31;
    else
        return a;
}

Loren Merritt's avatar
Loren Merritt committed
311
static inline void deblock_luma_c( uint8_t *pix, int xstride, int ystride, int alpha, int beta, int8_t *tc0 )
Laurent Aimar's avatar
Laurent Aimar committed
312 313
{
    int i, d;
Loren Merritt's avatar
Loren Merritt committed
314 315 316
    for( i = 0; i < 4; i++ ) {
        if( tc0[i] < 0 ) {
            pix += 4*ystride;
Laurent Aimar's avatar
Laurent Aimar committed
317 318
            continue;
        }
Loren Merritt's avatar
Loren Merritt committed
319 320 321 322 323 324 325 326
        for( d = 0; d < 4; d++ ) {
            const int p2 = pix[-3*xstride];
            const int p1 = pix[-2*xstride];
            const int p0 = pix[-1*xstride];
            const int q0 = pix[ 0*xstride];
            const int q1 = pix[ 1*xstride];
            const int q2 = pix[ 2*xstride];
   
Loren Merritt's avatar
Loren Merritt committed
327 328 329
            if( abs( p0 - q0 ) < alpha &&
                abs( p1 - p0 ) < beta &&
                abs( q1 - q0 ) < beta ) {
Loren Merritt's avatar
Loren Merritt committed
330 331 332 333
   
                int tc = tc0[i];
                int delta;
   
Loren Merritt's avatar
Loren Merritt committed
334
                if( abs( p2 - p0 ) < beta ) {
Loren Merritt's avatar
Loren Merritt committed
335 336
                    pix[-2*xstride] = p1 + x264_clip3( (( p2 + ((p0 + q0 + 1) >> 1)) >> 1) - p1, -tc0[i], tc0[i] );
                    tc++; 
Laurent Aimar's avatar
Laurent Aimar committed
337
                }
Loren Merritt's avatar
Loren Merritt committed
338
                if( abs( q2 - q0 ) < beta ) {
Loren Merritt's avatar
Loren Merritt committed
339 340
                    pix[ 1*xstride] = q1 + x264_clip3( (( q2 + ((p0 + q0 + 1) >> 1)) >> 1) - q1, -tc0[i], tc0[i] );
                    tc++;
Laurent Aimar's avatar
Laurent Aimar committed
341
                }
Loren Merritt's avatar
Loren Merritt committed
342 343 344 345
    
                delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc );
                pix[-1*xstride] = clip_uint8( p0 + delta );    /* p0' */
                pix[ 0*xstride] = clip_uint8( q0 - delta );    /* q0' */
Laurent Aimar's avatar
Laurent Aimar committed
346
            }
Loren Merritt's avatar
Loren Merritt committed
347
            pix += ystride;
Laurent Aimar's avatar
Laurent Aimar committed
348 349 350
        }
    }
}
Loren Merritt's avatar
Loren Merritt committed
351 352 353 354 355 356 357 358
static void deblock_v_luma_c( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 )
{
    deblock_luma_c( pix, stride, 1, alpha, beta, tc0 ); 
}
static void deblock_h_luma_c( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 )
{
    deblock_luma_c( pix, 1, stride, alpha, beta, tc0 );
}
Laurent Aimar's avatar
Laurent Aimar committed
359

Loren Merritt's avatar
Loren Merritt committed
360
static inline void deblock_chroma_c( uint8_t *pix, int xstride, int ystride, int alpha, int beta, int8_t *tc0 )
Laurent Aimar's avatar
Laurent Aimar committed
361 362
{
    int i, d;
Loren Merritt's avatar
Loren Merritt committed
363 364 365 366
    for( i = 0; i < 4; i++ ) {
        const int tc = tc0[i];
        if( tc <= 0 ) {
            pix += 2*ystride;
Laurent Aimar's avatar
Laurent Aimar committed
367 368
            continue;
        }
Loren Merritt's avatar
Loren Merritt committed
369 370 371 372 373 374
        for( d = 0; d < 2; d++ ) {
            const int p1 = pix[-2*xstride];
            const int p0 = pix[-1*xstride];
            const int q0 = pix[ 0*xstride];
            const int q1 = pix[ 1*xstride];

Loren Merritt's avatar
Loren Merritt committed
375 376 377
            if( abs( p0 - q0 ) < alpha &&
                abs( p1 - p0 ) < beta &&
                abs( q1 - q0 ) < beta ) {
Loren Merritt's avatar
Loren Merritt committed
378 379 380 381

                int delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc );
                pix[-1*xstride] = clip_uint8( p0 + delta );    /* p0' */
                pix[ 0*xstride] = clip_uint8( q0 - delta );    /* q0' */
Laurent Aimar's avatar
Laurent Aimar committed
382
            }
Loren Merritt's avatar
Loren Merritt committed
383
            pix += ystride;
Laurent Aimar's avatar
Laurent Aimar committed
384 385 386
        }
    }
}
Loren Merritt's avatar
Loren Merritt committed
387 388 389 390 391 392 393 394
static void deblock_v_chroma_c( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 )
{   
    deblock_chroma_c( pix, stride, 1, alpha, beta, tc0 );
}
static void deblock_h_chroma_c( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 )
{   
    deblock_chroma_c( pix, 1, stride, alpha, beta, tc0 );
}
Laurent Aimar's avatar
Laurent Aimar committed
395

Loren Merritt's avatar
Loren Merritt committed
396
static inline void deblock_luma_intra_c( uint8_t *pix, int xstride, int ystride, int alpha, int beta )
Laurent Aimar's avatar
Laurent Aimar committed
397
{
Loren Merritt's avatar
Loren Merritt committed
398 399 400 401 402 403 404 405 406
    int d;
    for( d = 0; d < 16; d++ ) {
        const int p2 = pix[-3*xstride];
        const int p1 = pix[-2*xstride];
        const int p0 = pix[-1*xstride];
        const int q0 = pix[ 0*xstride];
        const int q1 = pix[ 1*xstride];
        const int q2 = pix[ 2*xstride];

Loren Merritt's avatar
Loren Merritt committed
407 408 409
        if( abs( p0 - q0 ) < alpha &&
            abs( p1 - p0 ) < beta &&
            abs( q1 - q0 ) < beta ) {
Loren Merritt's avatar
Loren Merritt committed
410

Loren Merritt's avatar
Loren Merritt committed
411 412
            if(abs( p0 - q0 ) < ((alpha >> 2) + 2) ){
                if( abs( p2 - p0 ) < beta)
Laurent Aimar's avatar
Laurent Aimar committed
413
                {
Loren Merritt's avatar
Loren Merritt committed
414 415 416 417 418 419 420 421
                    const int p3 = pix[-4*xstride];
                    /* p0', p1', p2' */
                    pix[-1*xstride] = ( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3;
                    pix[-2*xstride] = ( p2 + p1 + p0 + q0 + 2 ) >> 2;
                    pix[-3*xstride] = ( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3;
                } else {
                    /* p0' */
                    pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2;
Laurent Aimar's avatar
Laurent Aimar committed
422
                }
Loren Merritt's avatar
Loren Merritt committed
423
                if( abs( q2 - q0 ) < beta)
Laurent Aimar's avatar
Laurent Aimar committed
424
                {
Loren Merritt's avatar
Loren Merritt committed
425 426 427 428 429 430 431 432
                    const int q3 = pix[3*xstride];
                    /* q0', q1', q2' */
                    pix[0*xstride] = ( p1 + 2*p0 + 2*q0 + 2*q1 + q2 + 4 ) >> 3;
                    pix[1*xstride] = ( p0 + q0 + q1 + q2 + 2 ) >> 2;
                    pix[2*xstride] = ( 2*q3 + 3*q2 + q1 + q0 + p0 + 4 ) >> 3;
                } else {
                    /* q0' */
                    pix[0*xstride] = ( 2*q1 + q0 + p1 + 2 ) >> 2;
Laurent Aimar's avatar
Laurent Aimar committed
433
                }
Loren Merritt's avatar
Loren Merritt committed
434 435 436 437
            }else{
                /* p0', q0' */
                pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2;
                pix[ 0*xstride] = ( 2*q1 + q0 + p1 + 2 ) >> 2;
Laurent Aimar's avatar
Laurent Aimar committed
438 439
            }
        }
Loren Merritt's avatar
Loren Merritt committed
440
        pix += ystride;
Laurent Aimar's avatar
Laurent Aimar committed
441 442
    }
}
Loren Merritt's avatar
Loren Merritt committed
443 444 445 446 447 448 449 450
static void deblock_v_luma_intra_c( uint8_t *pix, int stride, int alpha, int beta )
{   
    deblock_luma_intra_c( pix, stride, 1, alpha, beta );
}
static void deblock_h_luma_intra_c( uint8_t *pix, int stride, int alpha, int beta )
{   
    deblock_luma_intra_c( pix, 1, stride, alpha, beta );
}
Laurent Aimar's avatar
Laurent Aimar committed
451

Loren Merritt's avatar
Loren Merritt committed
452 453 454 455 456 457 458 459 460
static inline void deblock_chroma_intra_c( uint8_t *pix, int xstride, int ystride, int alpha, int beta )
{   
    int d; 
    for( d = 0; d < 8; d++ ) {
        const int p1 = pix[-2*xstride];
        const int p0 = pix[-1*xstride];
        const int q0 = pix[ 0*xstride];
        const int q1 = pix[ 1*xstride];

Loren Merritt's avatar
Loren Merritt committed
461 462 463
        if( abs( p0 - q0 ) < alpha &&
            abs( p1 - p0 ) < beta &&
            abs( q1 - q0 ) < beta ) {
Loren Merritt's avatar
Loren Merritt committed
464 465 466

            pix[-1*xstride] = (2*p1 + p0 + q1 + 2) >> 2;   /* p0' */
            pix[ 0*xstride] = (2*q1 + q0 + p1 + 2) >> 2;   /* q0' */
Laurent Aimar's avatar
Laurent Aimar committed
467 468
        }

Loren Merritt's avatar
Loren Merritt committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
        pix += ystride;
    }
}
static void deblock_v_chroma_intra_c( uint8_t *pix, int stride, int alpha, int beta )
{   
    deblock_chroma_intra_c( pix, stride, 1, alpha, beta );
}
static void deblock_h_chroma_intra_c( uint8_t *pix, int stride, int alpha, int beta )
{   
    deblock_chroma_intra_c( pix, 1, stride, alpha, beta );
}

static inline void deblock_edge( x264_t *h, uint8_t *pix, int i_stride, int bS[4], int i_qp, int b_chroma,
                                 x264_deblock_inter_t pf_inter, x264_deblock_intra_t pf_intra )
{
    int i;
    const int index_a = x264_clip3( i_qp + h->sh.i_alpha_c0_offset, 0, 51 );
    const int alpha = i_alpha_table[index_a];
    const int beta  = i_beta_table[x264_clip3( i_qp + h->sh.i_beta_offset, 0, 51 )];

    if( bS[0] < 4 ) {
        int8_t tc[4]; 
        for(i=0; i<4; i++)
            tc[i] = (bS[i] ? i_tc0_table[index_a][bS[i] - 1] : -1) + b_chroma;
        pf_inter( pix, i_stride, alpha, beta, tc );
    } else {
        pf_intra( pix, i_stride, alpha, beta );
Laurent Aimar's avatar
Laurent Aimar committed
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    }
}

void x264_frame_deblocking_filter( x264_t *h, int i_slice_type )
{
    const int s8x8 = 2 * h->mb.i_mb_stride;
    const int s4x4 = 4 * h->mb.i_mb_stride;

    int mb_y, mb_x;

    for( mb_y = 0, mb_x = 0; mb_y < h->sps->i_mb_height; )
    {
        const int mb_xy  = mb_y * h->mb.i_mb_stride + mb_x;
        const int mb_8x8 = 2 * s8x8 * mb_y + 2 * mb_x;
        const int mb_4x4 = 4 * s4x4 * mb_y + 4 * mb_x;
511
        const int b_8x8_transform = h->mb.mb_transform_size[mb_xy];
Loren Merritt's avatar
Loren Merritt committed
512 513
        const int i_edge_end = (h->mb.type[mb_xy] == P_SKIP) ? 1 : 4;
        int i_edge, i_dir;
514 515 516 517 518 519 520 521 522 523 524

        /* cavlc + 8x8 transform stores nnz per 16 coeffs for the purpose of
         * entropy coding, but per 64 coeffs for the purpose of deblocking */
        if( !h->param.b_cabac && b_8x8_transform )
        {
            uint32_t *nnz = (uint32_t*)h->mb.non_zero_count[mb_xy];
            if( nnz[0] ) nnz[0] = 0x01010101;
            if( nnz[1] ) nnz[1] = 0x01010101;
            if( nnz[2] ) nnz[2] = 0x01010101;
            if( nnz[3] ) nnz[3] = 0x01010101;
        }
Laurent Aimar's avatar
Laurent Aimar committed
525 526 527 528 529

        /* i_dir == 0 -> vertical edge
         * i_dir == 1 -> horizontal edge */
        for( i_dir = 0; i_dir < 2; i_dir++ )
        {
Loren Merritt's avatar
Loren Merritt committed
530
            int i_start = (i_dir ? mb_y : mb_x) ? 0 : 1;
Laurent Aimar's avatar
Laurent Aimar committed
531 532
            int i_qp, i_qpn;

Loren Merritt's avatar
Loren Merritt committed
533
            for( i_edge = i_start; i_edge < i_edge_end; i_edge++ )
Laurent Aimar's avatar
Laurent Aimar committed
534
            {
Loren Merritt's avatar
Loren Merritt committed
535
                int mbn_xy, mbn_8x8, mbn_4x4;
Laurent Aimar's avatar
Laurent Aimar committed
536 537
                int bS[4];  /* filtering strength */

Loren Merritt's avatar
Loren Merritt committed
538 539 540 541 542 543 544
                if( b_8x8_transform && (i_edge&1) )
                    continue;

                mbn_xy  = i_edge > 0 ? mb_xy  : ( i_dir == 0 ? mb_xy  - 1 : mb_xy - h->mb.i_mb_stride );
                mbn_8x8 = i_edge > 0 ? mb_8x8 : ( i_dir == 0 ? mb_8x8 - 2 : mb_8x8 - 2 * s8x8 );
                mbn_4x4 = i_edge > 0 ? mb_4x4 : ( i_dir == 0 ? mb_4x4 - 4 : mb_4x4 - 4 * s4x4 );

Laurent Aimar's avatar
Laurent Aimar committed
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
                /* *** Get bS for each 4px for the current edge *** */
                if( IS_INTRA( h->mb.type[mb_xy] ) || IS_INTRA( h->mb.type[mbn_xy] ) )
                {
                    bS[0] = bS[1] = bS[2] = bS[3] = ( i_edge == 0 ? 4 : 3 );
                }
                else
                {
                    int i;
                    for( i = 0; i < 4; i++ )
                    {
                        int x  = i_dir == 0 ? i_edge : i;
                        int y  = i_dir == 0 ? i      : i_edge;
                        int xn = (x - (i_dir == 0 ? 1 : 0 ))&0x03;
                        int yn = (y - (i_dir == 0 ? 0 : 1 ))&0x03;

                        if( h->mb.non_zero_count[mb_xy][block_idx_xy[x][y]] != 0 ||
                            h->mb.non_zero_count[mbn_xy][block_idx_xy[xn][yn]] != 0 )
                        {
                            bS[i] = 2;
                        }
565
                        else
Laurent Aimar's avatar
Laurent Aimar committed
566
                        {
567 568 569 570 571 572 573 574 575 576 577 578 579 580
                            /* FIXME: A given frame may occupy more than one position in
                             * the reference list. So we should compare the frame numbers,
                             * not the indices in the ref list.
                             * No harm yet, as we don't generate that case.*/

                            int i8p= mb_8x8+(x/2)+(y/2)*s8x8;
                            int i8q= mbn_8x8+(xn/2)+(yn/2)*s8x8;
                            int i4p= mb_4x4+x+y*s4x4;
                            int i4q= mbn_4x4+xn+yn*s4x4;
                            int l;

                            bS[i] = 0;

                            for( l = 0; l < 1 + (i_slice_type == SLICE_TYPE_B); l++ )
Laurent Aimar's avatar
Laurent Aimar committed
581
                            {
582 583 584 585 586 587 588
                                if( h->mb.ref[l][i8p] != h->mb.ref[l][i8q] ||
                                    abs( h->mb.mv[l][i4p][0] - h->mb.mv[l][i4q][0] ) >= 4 ||
                                    abs( h->mb.mv[l][i4p][1] - h->mb.mv[l][i4q][1] ) >= 4 )
                                {
                                    bS[i] = 1;
                                    break;
                                }
Laurent Aimar's avatar
Laurent Aimar committed
589 590 591 592 593 594 595 596 597 598 599 600 601
                            }
                        }
                    }
                }

                /* *** filter *** */
                /* Y plane */
                i_qp = h->mb.qp[mb_xy];
                i_qpn= h->mb.qp[mbn_xy];

                if( i_dir == 0 )
                {
                    /* vertical edge */
Loren Merritt's avatar
Loren Merritt committed
602 603 604
                    deblock_edge( h, &h->fdec->plane[0][16*mb_y * h->fdec->i_stride[0] + 16*mb_x + 4*i_edge],
                                  h->fdec->i_stride[0], bS, (i_qp+i_qpn+1) >> 1, 0,
                                  h->loopf.deblock_h_luma, h->loopf.deblock_h_luma_intra );
605
                    if( !(i_edge & 1) )
Laurent Aimar's avatar
Laurent Aimar committed
606 607 608 609
                    {
                        /* U/V planes */
                        int i_qpc = ( i_chroma_qp_table[x264_clip3( i_qp + h->pps->i_chroma_qp_index_offset, 0, 51 )] +
                                      i_chroma_qp_table[x264_clip3( i_qpn + h->pps->i_chroma_qp_index_offset, 0, 51 )] + 1 ) >> 1;
Loren Merritt's avatar
Loren Merritt committed
610 611 612 613 614 615
                        deblock_edge( h, &h->fdec->plane[1][8*(mb_y*h->fdec->i_stride[1]+mb_x)+2*i_edge],
                                      h->fdec->i_stride[1], bS, i_qpc, 1,
                                      h->loopf.deblock_h_chroma, h->loopf.deblock_h_chroma_intra );
                        deblock_edge( h, &h->fdec->plane[2][8*(mb_y*h->fdec->i_stride[2]+mb_x)+2*i_edge],
                                      h->fdec->i_stride[2], bS, i_qpc, 1,
                                      h->loopf.deblock_h_chroma, h->loopf.deblock_h_chroma_intra );
Laurent Aimar's avatar
Laurent Aimar committed
616 617 618 619 620
                    }
                }
                else
                {
                    /* horizontal edge */
Loren Merritt's avatar
Loren Merritt committed
621 622 623
                    deblock_edge( h, &h->fdec->plane[0][(16*mb_y + 4*i_edge) * h->fdec->i_stride[0] + 16*mb_x],
                                  h->fdec->i_stride[0], bS, (i_qp+i_qpn+1) >> 1, 0,
                                  h->loopf.deblock_v_luma, h->loopf.deblock_v_luma_intra );
Laurent Aimar's avatar
Laurent Aimar committed
624
                    /* U/V planes */
625
                    if( !(i_edge & 1) )
Laurent Aimar's avatar
Laurent Aimar committed
626 627 628
                    {
                        int i_qpc = ( i_chroma_qp_table[x264_clip3( i_qp + h->pps->i_chroma_qp_index_offset, 0, 51 )] +
                                      i_chroma_qp_table[x264_clip3( i_qpn + h->pps->i_chroma_qp_index_offset, 0, 51 )] + 1 ) >> 1;
Loren Merritt's avatar
Loren Merritt committed
629 630 631 632 633 634
                        deblock_edge( h, &h->fdec->plane[1][8*(mb_y*h->fdec->i_stride[1]+mb_x)+2*i_edge*h->fdec->i_stride[1]],
                                      h->fdec->i_stride[1], bS, i_qpc, 1,
                                      h->loopf.deblock_v_chroma, h->loopf.deblock_v_chroma_intra );
                        deblock_edge( h, &h->fdec->plane[2][8*(mb_y*h->fdec->i_stride[2]+mb_x)+2*i_edge*h->fdec->i_stride[2]],
                                      h->fdec->i_stride[2], bS, i_qpc, 1,
                                      h->loopf.deblock_v_chroma, h->loopf.deblock_v_chroma_intra );
Laurent Aimar's avatar
Laurent Aimar committed
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
                    }
                }
            }
        }

        /* newt mb */
        mb_x++;
        if( mb_x >= h->sps->i_mb_width )
        {
            mb_x = 0;
            mb_y++;
        }
    }
}

650
#ifdef HAVE_MMXEXT
Loren Merritt's avatar
Loren Merritt committed
651 652 653 654
void x264_deblock_v_chroma_mmxext( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_mmxext( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_chroma_intra_mmxext( uint8_t *pix, int stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_mmxext( uint8_t *pix, int stride, int alpha, int beta );
655
#endif
Loren Merritt's avatar
Loren Merritt committed
656 657 658 659

#ifdef ARCH_X86_64
void x264_deblock_v_luma_sse2( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_sse2( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 );
660
#elif defined( HAVE_MMXEXT )
Loren Merritt's avatar
Loren Merritt committed
661 662 663 664 665 666 667 668 669
void x264_deblock_h_luma_mmxext( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v8_luma_mmxext( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 );

void x264_deblock_v_luma_mmxext( uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0 )
{
    x264_deblock_v8_luma_mmxext( pix,   stride, alpha, beta, tc0   );
    x264_deblock_v8_luma_mmxext( pix+8, stride, alpha, beta, tc0+2 );
}
#endif
Laurent Aimar's avatar
Laurent Aimar committed
670

Loren Merritt's avatar
Loren Merritt committed
671 672 673 674 675 676 677 678 679 680 681
void x264_deblock_init( int cpu, x264_deblock_function_t *pf )
{
    pf->deblock_v_luma = deblock_v_luma_c;
    pf->deblock_h_luma = deblock_h_luma_c;
    pf->deblock_v_chroma = deblock_v_chroma_c;
    pf->deblock_h_chroma = deblock_h_chroma_c;
    pf->deblock_v_luma_intra = deblock_v_luma_intra_c;
    pf->deblock_h_luma_intra = deblock_h_luma_intra_c;
    pf->deblock_v_chroma_intra = deblock_v_chroma_intra_c;
    pf->deblock_h_chroma_intra = deblock_h_chroma_intra_c;

682
#ifdef HAVE_MMXEXT
Loren Merritt's avatar
Loren Merritt committed
683 684 685 686 687 688
    if( cpu&X264_CPU_MMXEXT )
    {
        pf->deblock_v_chroma = x264_deblock_v_chroma_mmxext;
        pf->deblock_h_chroma = x264_deblock_h_chroma_mmxext;
        pf->deblock_v_chroma_intra = x264_deblock_v_chroma_intra_mmxext;
        pf->deblock_h_chroma_intra = x264_deblock_h_chroma_intra_mmxext;
Laurent Aimar's avatar
Laurent Aimar committed
689

Loren Merritt's avatar
Loren Merritt committed
690 691 692 693 694 695 696 697 698 699 700
#ifdef ARCH_X86_64
        if( cpu&X264_CPU_SSE2 )
        {
            pf->deblock_v_luma = x264_deblock_v_luma_sse2;
            pf->deblock_h_luma = x264_deblock_h_luma_sse2;
        }
#else
        pf->deblock_v_luma = x264_deblock_v_luma_mmxext;
        pf->deblock_h_luma = x264_deblock_h_luma_mmxext;
#endif
    }
701
#endif
Loren Merritt's avatar
Loren Merritt committed
702
}
Laurent Aimar's avatar
Laurent Aimar committed
703