X264代码跟踪之x264_ratecontrol_mb

来源:互联网 发布:java的保留字有哪些 编辑:程序博客网 时间:2024/05/21 17:15
int x264_ratecontrol_mb( x264_t *h, int bits )
{
    x264_ratecontrol_t *rc = h->rc;
    const int y = h->mb.i_mb_y;

    h->fdec->i_row_bits[y] += bits;
    rc->qpa_aq += h->mb.i_qp;

    if( h->mb.i_mb_x != h->mb.i_mb_width - 1 )
        return 0;

    x264_emms();
    rc->qpa_rc += rc->qpm * h->mb.i_mb_width;

    if( !rc->b_vbv )
        return 0;

    float qscale = qp2qscale( rc->qpm );
    h->fdec->f_row_qp[y] = rc->qpm;
    h->fdec->f_row_qscale[y] = qscale;

    update_predictor( rc->row_pred[0], qscale, h->fdec->i_row_satd[y], h->fdec->i_row_bits[y] );
    if( h->sh.i_type == SLICE_TYPE_P && rc->qpm < h->fref[0][0]->f_row_qp[y] )
        update_predictor( rc->row_pred[1], qscale, h->fdec->i_row_satds[0][0][y], h->fdec->i_row_bits[y] );

    /* update ratecontrol per-mbpair in MBAFF */
    if( SLICE_MBAFF && !(y&1) )
        return 0;

    /* FIXME: We don't currently support the case where there's a slice
     * boundary in between. */
    int can_reencode_row = h->sh.i_first_mb <= ((h->mb.i_mb_y - SLICE_MBAFF) * h->mb.i_mb_stride);

    /* tweak quality based on difference from predicted size */
    float prev_row_qp = h->fdec->f_row_qp[y];
    float qp_absolute_max = h->param.rc.i_qp_max;
    if( rc->rate_factor_max_increment )
        qp_absolute_max = X264_MIN( qp_absolute_max, rc->qp_novbv + rc->rate_factor_max_increment );
    float qp_max = X264_MIN( prev_row_qp + h->param.rc.i_qp_step, qp_absolute_max );
    float qp_min = X264_MAX( prev_row_qp - h->param.rc.i_qp_step, h->param.rc.i_qp_min );
    float step_size = 0.5f;
    float buffer_left_planned = rc->buffer_fill - rc->frame_size_planned;
    float slice_size_planned = h->param.b_sliced_threads ? rc->slice_size_planned : rc->frame_size_planned;
    float max_frame_error = X264_MAX( 0.05f, 1.0f / h->mb.i_mb_height );
    float size_of_other_slices = 0;
    if( h->param.b_sliced_threads )
    {
        float size_of_other_slices_planned = 0;
        for( int i = 0; i < h->param.i_threads; i++ )
            if( h != h->thread[i] )
            {
                size_of_other_slices += h->thread[i]->rc->frame_size_estimated;
                size_of_other_slices_planned += h->thread[i]->rc->slice_size_planned;
            }
        float weight = rc->slice_size_planned / rc->frame_size_planned;
        size_of_other_slices = (size_of_other_slices - size_of_other_slices_planned) * weight + size_of_other_slices_planned;
    }
    if( y < h->i_threadslice_end-1 )
    {
        /* B-frames shouldn't use lower QP than their reference frames. */
        if( h->sh.i_type == SLICE_TYPE_B )
        {
            qp_min = X264_MAX( qp_min, X264_MAX( h->fref[0][0]->f_row_qp[y+1], h->fref[1][0]->f_row_qp[y+1] ) );
            rc->qpm = X264_MAX( rc->qpm, qp_min );
        }

        /* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */
        float rc_tol = buffer_left_planned / h->param.i_threads * rc->rate_tolerance;
        float b1 = predict_row_size_sum( h, y, rc->qpm ) + size_of_other_slices;

        /* Don't increase the row QPs until a sufficent amount of the bits of the frame have been processed, in case a flat */
        /* area at the top of the frame was measured inaccurately. */
        if( row_bits_so_far( h, y ) < 0.05f * slice_size_planned )
            qp_max = qp_absolute_max = prev_row_qp;

        if( h->sh.i_type != SLICE_TYPE_I )
            rc_tol *= 0.5f;

        if( !rc->b_vbv_min_rate )
            qp_min = X264_MAX( qp_min, rc->qp_novbv );

        while( rc->qpm < qp_max
               && ((b1 > rc->frame_size_planned + rc_tol) ||
                   (rc->buffer_fill - b1 < buffer_left_planned * 0.5f) ||
                   (b1 > rc->frame_size_planned && rc->qpm < rc->qp_novbv)) )
        {
            rc->qpm += step_size;
            b1 = predict_row_size_sum( h, y, rc->qpm ) + size_of_other_slices;
        }

        while( rc->qpm > qp_min
               && (rc->qpm > h->fdec->f_row_qp[0] || rc->single_frame_vbv)
               && ((b1 < rc->frame_size_planned * 0.8f && rc->qpm <= prev_row_qp)
               || b1 < (rc->buffer_fill - rc->buffer_size + rc->buffer_rate) * 1.1f) )
        {
            rc->qpm -= step_size;
            b1 = predict_row_size_sum( h, y, rc->qpm ) + size_of_other_slices;
        }

        /* avoid VBV underflow or MinCR violation */
        while( (rc->qpm < qp_absolute_max)
               && ((rc->buffer_fill - b1 < rc->buffer_rate * max_frame_error) ||
                   (rc->frame_size_maximum - b1 < rc->frame_size_maximum * max_frame_error)))
        {
            rc->qpm += step_size;
            b1 = predict_row_size_sum( h, y, rc->qpm ) + size_of_other_slices;
        }

        h->rc->frame_size_estimated = b1 - size_of_other_slices;

        /* If the current row was large enough to cause a large QP jump, try re-encoding it. */
        if( rc->qpm > qp_max && prev_row_qp < qp_max && can_reencode_row )
        {
            /* Bump QP to halfway in between... close enough. */
            rc->qpm = x264_clip3f( (prev_row_qp + rc->qpm)*0.5f, prev_row_qp + 1.0f, qp_max );
            rc->qpa_rc = rc->qpa_rc_prev;
            rc->qpa_aq = rc->qpa_aq_prev;
            h->fdec->i_row_bits[y] = h->fdec->i_row_bits[y-SLICE_MBAFF] = 0;
            return -1;
        }
    }
    else
    {
        h->rc->frame_size_estimated = predict_row_size_sum( h, y, rc->qpm );

        /* Last-ditch attempt: if the last row of the frame underflowed the VBV,
         * try again. */
        if( (h->rc->frame_size_estimated + size_of_other_slices) > (rc->buffer_fill - rc->buffer_rate * max_frame_error) &&
             rc->qpm < qp_max && can_reencode_row )
        {
            rc->qpm = qp_max;
            rc->qpa_rc = rc->qpa_rc_prev;
            rc->qpa_aq = rc->qpa_aq_prev;
            h->fdec->i_row_bits[y] = h->fdec->i_row_bits[y-SLICE_MBAFF] = 0;
            return -1;
        }
    }

    rc->qpa_rc_prev = rc->qpa_rc;
    rc->qpa_aq_prev = rc->qpa_aq;

    return 0;
}
原创粉丝点击