Ticket #8768: rescale.diff

File rescale.diff, 12.4 KB (added by Mista_D, 6 years ago)

x264 mbtree rescale diff

  • encoder/ratecontrol.c

    From 14d4597dc855efbf008fb3db3ef3a300691075a7 Mon Sep 17 00:00:00 2001
    From: Jason Garrett-Glaser <jason@x264.com>
    Date: Fri, 8 Jun 2012 18:19:59 -0700
    Subject: [PATCH] Support changing resolutions between passes with
     macroblock-tree Implement a basic separable bilinear filter
     to rescale the quantizer offsets. Structure inspired by
     swscale, but floating-point instead of fixed-point. Not as
     optimized as it could be, but it's quite fast already.
    
    Example compression penalties on a 720p video game recording:
    First pass with 720p and second as 480p: ~-1.5% (vs. same res)
    First pass with 480p and second as 720p: ~-3% (vs. same res)
    ---
     encoder/ratecontrol.c |  191 ++++++++++++++++++++++++++++++++++++++++++------
     1 files changed, 167 insertions(+), 24 deletions(-)
    
    diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
    index f9c8591..78b44f7 100644
    a b struct x264_ratecontrol_t  
    136136    double lmin[3];             /* min qscale by frame type */
    137137    double lmax[3];
    138138    double lstep;               /* max change (multiply) in qscale per frame */
    139     uint16_t *qp_buffer[2];     /* Global buffers for converting MB-tree quantizer data. */
    140     int qpbuf_pos;              /* In order to handle pyramid reordering, QP buffer acts as a stack.
     139    struct
     140    {
     141        uint16_t *qp_buffer[2]; /* Global buffers for converting MB-tree quantizer data. */
     142        int qpbuf_pos;          /* In order to handle pyramid reordering, QP buffer acts as a stack.
    141143                                 * This value is the current position (0 or 1). */
     144        int src_mb_count;
     145
     146        /* For rescaling */
     147        int rescale_enabled;
     148        float *scale_buffer[2]; /* Intermediate buffers */
     149        int filtersize[2];      /* filter size (H/V) */
     150        float *coeffs[2];
     151        int *pos[2];
     152        int srcdim[2];          /* Source dimensions (W/H) */
     153    } mbtree;
    142154
    143155    /* MBRC stuff */
    144156    float frame_size_estimated; /* Access to this variable must be atomic: double is
    void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_off  
    392404    }
    393405}
    394406
     407static int x264_macroblock_tree_rescale_init( x264_t *h, x264_ratecontrol_t *rc )
     408{
     409    /* Use fractional QP array dimensions to compensate for edge padding */
     410    float srcdim[2] = {rc->mbtree.srcdim[0] / 16.f, rc->mbtree.srcdim[1] / 16.f};
     411    float dstdim[2] = {    h->param.i_width / 16.f,    h->param.i_height / 16.f};
     412    int srcdimi[2] = {ceil(srcdim[0]), ceil(srcdim[1])};
     413    int dstdimi[2] = {ceil(dstdim[0]), ceil(dstdim[1])};
     414    if( PARAM_INTERLACED )
     415    {
     416        srcdimi[1] = (srcdimi[1]+1)&~1;
     417        dstdimi[1] = (dstdimi[1]+1)&~1;
     418    }
     419   
     420    rc->mbtree.src_mb_count = srcdimi[0] * srcdimi[1];
     421
     422    CHECKED_MALLOC( rc->mbtree.qp_buffer[0], rc->mbtree.src_mb_count * sizeof(uint16_t) );
     423    if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read )
     424        CHECKED_MALLOC( rc->mbtree.qp_buffer[1], rc->mbtree.src_mb_count * sizeof(uint16_t) );
     425    rc->mbtree.qpbuf_pos = -1;
     426   
     427    /* No rescaling to do */
     428    if( srcdimi[0] == dstdimi[0] && srcdimi[1] == dstdimi[1] )
     429        return 0;
     430
     431    rc->mbtree.rescale_enabled = 1;
     432
     433    /* Allocate intermediate scaling buffers */
     434    CHECKED_MALLOC( rc->mbtree.scale_buffer[0], srcdimi[0] * srcdimi[1] * sizeof(float) );
     435    CHECKED_MALLOC( rc->mbtree.scale_buffer[1], dstdimi[0] * srcdimi[1] * sizeof(float) );
     436
     437    /* Allocate and calculate resize filter parameters and coefficients */
     438    for( int i = 0; i < 2; i++ )
     439    {
     440        if( srcdim[i] > dstdim[i] ) // downscale
     441            rc->mbtree.filtersize[i] = 1 + (2 * srcdimi[i] + dstdimi[i] - 1) / dstdimi[i];
     442        else                        // upscale
     443            rc->mbtree.filtersize[i] = 3;
     444
     445        CHECKED_MALLOC( rc->mbtree.coeffs[i], rc->mbtree.filtersize[i] * dstdimi[i] * sizeof(float) );
     446        CHECKED_MALLOC( rc->mbtree.pos[i], dstdimi[i] * sizeof(int) );
     447
     448        /* Initialize filter coefficients */
     449        float inc = srcdim[i] / dstdim[i];
     450        float dmul = inc > 1.f ? dstdim[i] / srcdim[i] : 1.f;
     451        float dstinsrc = 0.5f * inc - 0.5f;
     452        int filtersize = rc->mbtree.filtersize[i];
     453        for( int j = 0; j < dstdim[i]; j++ )
     454        {
     455            int pos = dstinsrc - (filtersize - 2.f) * 0.5f;
     456            float sum = 0.0;
     457            rc->mbtree.pos[i][j] = pos;
     458            for( int k = 0; k < filtersize; k++ )
     459            {
     460                float d = fabs( pos + k - dstinsrc ) * dmul;
     461                float coeff = X264_MAX( 1.f - d, 0 );
     462                rc->mbtree.coeffs[i][j * filtersize + k] = coeff;
     463                sum += coeff;
     464            }
     465            sum = 1.0f / sum;
     466            for( int k = 0; k < filtersize; k++ )
     467                rc->mbtree.coeffs[i][j * filtersize + k] *= sum;
     468            dstinsrc += inc;
     469        }
     470    }
     471
     472    /* Write back actual qp array dimensions */
     473    rc->mbtree.srcdim[0] = srcdimi[0];
     474    rc->mbtree.srcdim[1] = srcdimi[1];
     475    return 0;
     476fail:
     477    return -1;
     478}
     479
     480static void x264_macroblock_tree_rescale_destroy( x264_ratecontrol_t *rc )
     481{
     482    for( int i = 0; i < 2; i++ )
     483    {
     484        x264_free( rc->mbtree.scale_buffer[i] );
     485        x264_free( rc->mbtree.coeffs[i] );
     486        x264_free( rc->mbtree.pos[i] );
     487    }
     488}
     489
     490static ALWAYS_INLINE float tapfilter( float *src, int pos, int max, int stride, float *coeff, int filtersize )
     491{
     492    float sum = 0.f;
     493    for( int i = 0; i < filtersize; i++, pos++ )
     494        sum += src[x264_clip3( pos, 0, max-1 )*stride] * coeff[i];
     495    return sum;
     496}
     497
     498static void x264_macroblock_tree_rescale( x264_t *h, x264_ratecontrol_t *rc, float *dst )
     499{
     500    float *input, *output;
     501    int filtersize, stride, height;
     502
     503    /* H scale first */
     504    input = rc->mbtree.scale_buffer[0];
     505    output = rc->mbtree.scale_buffer[1];
     506    filtersize = rc->mbtree.filtersize[0];
     507    stride = rc->mbtree.srcdim[0];
     508    height = rc->mbtree.srcdim[1];
     509    for( int y = 0; y < height; y++, input += stride, output += h->mb.i_mb_width )
     510    {
     511        float *coeff = rc->mbtree.coeffs[0];
     512        for( int x = 0; x < h->mb.i_mb_width; x++, coeff+=filtersize )
     513            output[x] = tapfilter( input, rc->mbtree.pos[0][x], stride, 1, coeff, filtersize );
     514    }
     515
     516    /* V scale next */
     517    input = rc->mbtree.scale_buffer[1];
     518    output = dst;
     519    filtersize = rc->mbtree.filtersize[1];
     520    stride = h->mb.i_mb_width;
     521    height = rc->mbtree.srcdim[1];
     522    for( int x = 0; x < h->mb.i_mb_width; x++, input++, output++ )
     523    {
     524        float *coeff = rc->mbtree.coeffs[1];
     525        for( int y = 0; y < h->mb.i_mb_height; y++, coeff+=filtersize )
     526            output[y*stride] = tapfilter( input, rc->mbtree.pos[1][y], height, stride, coeff, filtersize );
     527    }
     528}
     529
    395530int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets )
    396531{
    397532    x264_ratecontrol_t *rc = h->rc;
    int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offs  
    400535    if( rc->entry[frame->i_frame].kept_as_ref )
    401536    {
    402537        uint8_t i_type;
    403         if( rc->qpbuf_pos < 0 )
     538        if( rc->mbtree.qpbuf_pos < 0 )
    404539        {
    405540            do
    406541            {
    407                 rc->qpbuf_pos++;
     542                rc->mbtree.qpbuf_pos++;
    408543
    409544                if( !fread( &i_type, 1, 1, rc->p_mbtree_stat_file_in ) )
    410545                    goto fail;
    411                 if( fread( rc->qp_buffer[rc->qpbuf_pos], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_in ) != h->mb.i_mb_count )
     546                if( fread( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos], sizeof(uint16_t), rc->mbtree.src_mb_count, rc->p_mbtree_stat_file_in ) != rc->mbtree.src_mb_count )
    412547                    goto fail;
    413548
    414                 if( i_type != i_type_actual && rc->qpbuf_pos == 1 )
     549                if( i_type != i_type_actual && rc->mbtree.qpbuf_pos == 1 )
    415550                {
    416551                    x264_log( h, X264_LOG_ERROR, "MB-tree frametype %d doesn't match actual frametype %d.\n", i_type, i_type_actual );
    417552                    return -1;
    int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offs  
    419554            } while( i_type != i_type_actual );
    420555        }
    421556
    422         for( int i = 0; i < h->mb.i_mb_count; i++ )
     557        float *dst = rc->mbtree.rescale_enabled ? rc->mbtree.scale_buffer[0] : frame->f_qp_offset;
     558        for( int i = 0; i < rc->mbtree.src_mb_count; i++ )
    423559        {
    424             frame->f_qp_offset[i] = ((float)(int16_t)endian_fix16( rc->qp_buffer[rc->qpbuf_pos][i] )) * (1/256.0);
    425             if( h->frames.b_have_lowres )
    426                 frame->i_inv_qscale_factor[i] = x264_exp2fix8(frame->f_qp_offset[i]);
     560            int16_t qp_fix8 = endian_fix16( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos][i] );
     561            dst[i] = qp_fix8 * (1.f/256.f);
    427562        }
    428         rc->qpbuf_pos--;
     563        if( rc->mbtree.rescale_enabled )
     564            x264_macroblock_tree_rescale( h, rc, frame->f_qp_offset );
     565        if( h->frames.b_have_lowres )
     566            for( int i = 0; i < h->mb.i_mb_count; i++ )
     567                frame->i_inv_qscale_factor[i] = x264_exp2fix8( frame->f_qp_offset[i] );
     568        rc->mbtree.qpbuf_pos--;
    429569    }
    430570    else
    431571        x264_stack_align( x264_adaptive_quant_frame, h, frame, quant_offsets );
    int x264_ratecontrol_new( x264_t *h )  
    762902                x264_log( h, X264_LOG_ERROR, "resolution specified in stats file not valid\n" );
    763903                return -1;
    764904            }
    765             else if( h->param.rc.b_mb_tree && (i != h->param.i_width || j != h->param.i_height)  )
     905            else if( h->param.rc.b_mb_tree )
    766906            {
    767                 x264_log( h, X264_LOG_ERROR, "MB-tree doesn't support different resolution than 1st pass (%dx%d vs %dx%d)\n",
    768                           h->param.i_width, h->param.i_height, i, j );
    769                 return -1;
     907                rc->mbtree.srcdim[0] = i;
     908                rc->mbtree.srcdim[1] = j;
    770909            }
    771910            res_factor = (float)h->param.i_width * h->param.i_height / (i*j);
    772911            /* Change in bits relative to resolution isn't quite linear on typical sources,
    parse_error:  
    10251164
    10261165    if( h->param.rc.b_mb_tree && (h->param.rc.b_stat_read || h->param.rc.b_stat_write) )
    10271166    {
    1028         CHECKED_MALLOC( rc->qp_buffer[0], h->mb.i_mb_count * sizeof(uint16_t) );
    1029         if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read )
    1030             CHECKED_MALLOC( rc->qp_buffer[1], h->mb.i_mb_count * sizeof(uint16_t) );
    1031         rc->qpbuf_pos = -1;
     1167        if( !h->param.rc.b_stat_read )
     1168        {
     1169            rc->mbtree.srcdim[0] = h->param.i_width;
     1170            rc->mbtree.srcdim[1] = h->param.i_height;
     1171        }
     1172        if( x264_macroblock_tree_rescale_init( h, rc ) < 0 )
     1173            return -1;
    10321174    }
    10331175
    10341176    for( int i = 0; i<h->param.i_threads; i++ )
    void x264_ratecontrol_delete( x264_t *h )  
    12161358    x264_free( rc->pred );
    12171359    x264_free( rc->pred_b_from_p );
    12181360    x264_free( rc->entry );
    1219     x264_free( rc->qp_buffer[0] );
    1220     x264_free( rc->qp_buffer[1] );
     1361    x264_free( rc->mbtree.qp_buffer[0] );
     1362    x264_free( rc->mbtree.qp_buffer[1] );
     1363    x264_macroblock_tree_rescale_destroy( rc );
    12211364    if( rc->zones )
    12221365    {
    12231366        x264_free( rc->zones[0].param );
    int x264_ratecontrol_end( x264_t *h, int bits, int *filler )  
    17081851            uint8_t i_type = h->sh.i_type;
    17091852            /* Values are stored as big-endian FIX8.8 */
    17101853            for( int i = 0; i < h->mb.i_mb_count; i++ )
    1711                 rc->qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 );
     1854                rc->mbtree.qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 );
    17121855            if( fwrite( &i_type, 1, 1, rc->p_mbtree_stat_file_out ) < 1 )
    17131856                goto fail;
    1714             if( fwrite( rc->qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count )
     1857            if( fwrite( rc->mbtree.qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count )
    17151858                goto fail;
    17161859        }
    17171860    }
    void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next )  
    25272670        COPY(short_term_cplxcount);
    25282671        COPY(bframes);
    25292672        COPY(prev_zone);
    2530         COPY(qpbuf_pos);
     2673        COPY(mbtree.qpbuf_pos);
    25312674        /* these vars can be updated by x264_ratecontrol_init_reconfigurable */
    25322675        COPY(bitrate);
    25332676        COPY(buffer_size);