x264 - x264_ratecontrol_end





// 编码一帧后, 保存码率控制状态信息
/* After encoding one frame, save stats and update ratecontrol state */
int x264_ratecontrol_end( x264_t *h, int bits, int *filler )
{
    x264_ratecontrol_t *rc = h->rc;
    //     宏块类型相关计数
    //     int i_mb_count[19];
    const int *mbs = h->stat.frame.i_mb_count;

    x264_emms();

    // 统计宏块相关信息
    h->stat.frame.i_mb_count_skip = mbs[P_SKIP] + mbs[B_SKIP];
    h->stat.frame.i_mb_count_i = mbs[I_16x16] + mbs[I_8x8] + mbs[I_4x4];
    h->stat.frame.i_mb_count_p = mbs[P_L0] + mbs[P_8x8];
   
    for( int i = B_DIRECT; i < B_8x8; i++ )
        h->stat.frame.i_mb_count_p += mbs[i];
   
    // 计算当前重构帧的qp信息
    h->fdec->f_qp_avg_rc = rc->qpa_rc /= h->mb.i_mb_count;
    h->fdec->f_qp_avg_aq = (float)rc->qpa_aq / h->mb.i_mb_count;
    h->fdec->f_crf_avg = h->param.rc.f_rf_constant + h->fdec->f_qp_avg_rc - rc->qp_novbv;

    // 输出统计信息到 stat 文件
    if( h->param.rc.b_stat_write )
    {
        char c_type = h->sh.i_type==SLICE_TYPE_I ? (h->fenc->i_poc==0 ? 'I' : 'i')
                    : h->sh.i_type==SLICE_TYPE_P ? 'P'
                    : h->fenc->b_kept_as_ref ? 'B' : 'b';
        int dir_frame = h->stat.frame.i_direct_score[1] - h->stat.frame.i_direct_score[0];
        int dir_avg = h->stat.i_direct_score[1] - h->stat.i_direct_score[0];
        char c_direct = h->mb.b_direct_auto_write ?
                        ( dir_frame>0 ? 's' : dir_frame<0 ? 't' :
                          dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' )
                        : '-';
        if( fprintf( rc->p_stat_file_out,
                 "in:%d out:%d type:%c dur:%"PRId64" cpbdur:%"PRId64" q:%.2f aq:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c ref:",
                 h->fenc->i_frame, h->i_frame,
                 c_type, h->fenc->i_duration,
                 h->fenc->i_cpb_duration,
                 rc->qpa_rc, h->fdec->f_qp_avg_aq,
                 h->stat.frame.i_tex_bits,
                 h->stat.frame.i_mv_bits,
                 h->stat.frame.i_misc_bits,
                 h->stat.frame.i_mb_count_i,
                 h->stat.frame.i_mb_count_p,
                 h->stat.frame.i_mb_count_skip,
                 c_direct) < 0 )
            goto fail;

        /* Only write information for reference reordering once. */
        int use_old_stats = h->param.rc.b_stat_read && rc->rce->refs > 1;
        for( int i = 0; i < (use_old_stats ? rc->rce->refs : h->i_ref[0]); i++ )
        {
            int refcount = use_old_stats         ? rc->rce->refcount[i]
                         : PARAM_INTERLACED      ? h->stat.frame.i_mb_count_ref[0][i*2]
                                                 + h->stat.frame.i_mb_count_ref[0][i*2+1]
                         :                         h->stat.frame.i_mb_count_ref[0][i];
            if( fprintf( rc->p_stat_file_out, "%d ", refcount ) < 0 )
                goto fail;
        }

        if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE && h->sh.weight[0][0].weightfn )
        {
            if( fprintf( rc->p_stat_file_out, "w:%d,%d,%d",
                         h->sh.weight[0][0].i_denom, h->sh.weight[0][0].i_scale, h->sh.weight[0][0].i_offset ) < 0 )
                goto fail;
            if( h->sh.weight[0][1].weightfn || h->sh.weight[0][2].weightfn )
            {
                if( fprintf( rc->p_stat_file_out, ",%d,%d,%d,%d,%d ",
                             h->sh.weight[0][1].i_denom, h->sh.weight[0][1].i_scale, h->sh.weight[0][1].i_offset,
                             h->sh.weight[0][2].i_scale, h->sh.weight[0][2].i_offset ) < 0 )
                    goto fail;
            }
            else if( fprintf( rc->p_stat_file_out, " " ) < 0 )
                goto fail;
        }

        if( fprintf( rc->p_stat_file_out, ";\n") < 0 )
            goto fail;

        /* Don't re-write the data in multi-pass mode. */
        if( h->param.rc.b_mb_tree && h->fenc->b_kept_as_ref && !h->param.rc.b_stat_read )
        {
            uint8_t i_type = h->sh.i_type;
            /* Values are stored as big-endian FIX8.8 */
            for( int i = 0; i < h->mb.i_mb_count; i++ )
                rc->mbtree.qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 );
            if( fwrite( &i_type, 1, 1, rc->p_mbtree_stat_file_out ) < 1 )
                goto fail;
            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 )
                goto fail;
        }
    }

    // 如果自适应码率控制
    if( rc->b_abr )
    {
        // 计算复杂度之和
        if( h->sh.i_type != SLICE_TYPE_B )
            rc->cplxr_sum += bits * qp2qscale( rc->qpa_rc ) / rc->last_rceq;
        else
        {
            // B 帧 复杂度之和
            /* Depends on the fact that B-frame's QP is an offset from the following P-frame's.
             * Not perfectly accurate with B-refs, but good enough. */
            rc->cplxr_sum += bits * qp2qscale( rc->qpa_rc ) / (rc->last_rceq * fabs( h->param.rc.f_pb_factor ));
        }
        rc->cplxr_sum *= rc->cbr_decay;
        rc->wanted_bits_window += h->fenc->f_duration * rc->bitrate;
        rc->wanted_bits_window *= rc->cbr_decay;
    }

    if( rc->b_2pass )  // 两阶段,计算预计的bits之和,见qscale2bits
        rc->expected_bits_sum += qscale2bits( rc->rce, qp2qscale( rc->rce->new_qp ) );

    // 如果 宏块qp可变
    if( h->mb.b_variable_qp )
    {
        if( h->sh.i_type == SLICE_TYPE_B )
        {
            // 增加B帧bits数
            rc->bframe_bits += bits;
            if( h->fenc->b_last_minigop_bframe )
            {
                // 见 update_predictor
                update_predictor( rc->pred_b_from_p, qp2qscale( rc->qpa_rc ),
                                  h->fref[1][h->i_ref[1]-1]->i_satd, rc->bframe_bits / rc->bframes );
                rc->bframe_bits = 0;
            }
        }
    }

    // 更新VBV, 控制下溢,上溢
    *filler = update_vbv( h, bits );
    rc->filler_bits_sum += *filler * 8;

    if( h->sps->vui.b_nal_hrd_parameters_present )
    {
        if( h->fenc->i_frame == 0 )
        {
            // access unit initialises the HRD
            h->fenc->hrd_timing.cpb_initial_arrival_time = 0;
            rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay;
            rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset;
            h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (double)rc->initial_cpb_removal_delay / 90000;
        }
        else
        {
            h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (double)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) *
                                                   h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;

            double cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - (double)rc->initial_cpb_removal_delay / 90000;
            if( h->fenc->b_keyframe )
            {
                 rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time;
                 rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay;
                 rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset;
            }
            else
                 cpb_earliest_arrival_time -= (double)rc->initial_cpb_removal_delay_offset / 90000;

            if( h->sps->vui.hrd.b_cbr_hrd )
                h->fenc->hrd_timing.cpb_initial_arrival_time = rc->previous_cpb_final_arrival_time;
            else
                h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( rc->previous_cpb_final_arrival_time, cpb_earliest_arrival_time );
        }
        int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0;
        // Equation C-6
        h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time = h->fenc->hrd_timing.cpb_initial_arrival_time +
                                                     (double)(bits + filler_bits) / h->sps->vui.hrd.i_bit_rate_unscaled;

        h->fenc->hrd_timing.dpb_output_time = (double)h->fenc->i_dpb_output_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale +
                                              h->fenc->hrd_timing.cpb_removal_time;
    }

    return 0;
fail:
    x264_log( h, X264_LOG_ERROR, "ratecontrol_end: stats file could not be written to\n" );
    return -1;
}

typedef struct x264_left_table_t
{
    uint8_t intra[4];
    uint8_t nnz[4];
    uint8_t nnz_chroma[4];
    uint8_t mv[4];
    uint8_t ref[4];
} x264_left_table_t;

/* Current frame stats */
typedef struct
{
    /* MV bits (MV+Ref+Block Type) */
    int i_mv_bits;
    /* Texture bits (DCT coefs) */
    int i_tex_bits;
    /* ? */
    int i_misc_bits;
    /* MB type counts */
    int i_mb_count[19];
    int i_mb_count_i;
    int i_mb_count_p;
    int i_mb_count_skip;
    int i_mb_count_8x8dct[2];
    int i_mb_count_ref[2][X264_REF_MAX*2];
    int i_mb_partition[17];
    int i_mb_cbp[6];
    int i_mb_pred_mode[4][13];
    int i_mb_field[3];
    /* Adaptive direct mv pred */
    int i_direct_score[2];
    /* Metrics */
    int64_t i_ssd[3];
    double f_ssim;
    int i_ssim_cnt;
} x264_frame_stat_t;

/* Texture bitrate is not quite inversely proportional to qscale,
 * probably due the the changing number of SKIP blocks.
 * MV bits level off at about qp<=12, because the lambda used
 * for motion estimation is constant there. */
static inline double qscale2bits( ratecontrol_entry_t *rce, double qscale )
{
    if( qscale<0.1 )
        qscale = 0.1;
    return (rce->tex_bits + .1) * pow( rce->qscale / qscale, 1.1 )
           + rce->mv_bits * pow( X264_MAX(rce->qscale, 1) / X264_MAX(qscale, 1), 0.5 )
           + rce->misc_bits;
}

static void update_predictor( predictor_t *p, float q, float var, float bits )
{
    float range = 1.5;
    if( var < 10 )
        return;
    float old_coeff = p->coeff / p->count;
    float new_coeff = X264_MAX( bits*q / var, p->coeff_min );
    float new_coeff_clipped = x264_clip3f( new_coeff, old_coeff/range, old_coeff*range );
    float new_offset = bits*q - new_coeff_clipped * var;
    if( new_offset >= 0 )
        new_coeff = new_coeff_clipped;
    else
        new_offset = 0;
    p->count  *= p->decay;
    p->coeff  *= p->decay;
    p->offset *= p->decay;
    p->count  ++;
    p->coeff  += new_coeff;
    p->offset += new_offset;
}

// 编码一帧后更新VBV
// update VBV after encoding a frame
static int update_vbv( x264_t *h, int bits )
{
    int filler = 0;
    int bitrate = h->sps->vui.hrd.i_bit_rate_unscaled;
    x264_ratecontrol_t *rcc = h->rc;
    x264_ratecontrol_t *rct = h->thread[0]->rc;
    uint64_t buffer_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;

    // 更新帧类型预测器
    if( rcc->last_satd >= h->mb.i_mb_count )
        update_predictor( &rct->pred[h->sh.i_type], qp2qscale( rcc->qpa_rc ), rcc->last_satd, bits );

    if( !rcc->b_vbv )
        return filler;
       
    // 计算实际剩下的缓冲区大小
    rct->buffer_fill_final -= (uint64_t)bits * h->sps->vui.i_time_scale;

    if( rct->buffer_fill_final < 0 )
    {
        // VBV 缓冲区下溢
        double underflow = (double)rct->buffer_fill_final / h->sps->vui.i_time_scale;
        if( rcc->rate_factor_max_increment && rcc->qpm >= rcc->qp_novbv + rcc->rate_factor_max_increment )
            x264_log( h, X264_LOG_DEBUG, "VBV underflow due to CRF-max (frame %d, %.0f bits)\n", h->i_frame, underflow );
        else
            x264_log( h, X264_LOG_WARNING, "VBV underflow (frame %d, %.0f bits)\n", h->i_frame, underflow );
    }
    // 重新设置, 计算实际缓冲区大小
    rct->buffer_fill_final = X264_MAX( rct->buffer_fill_final, 0 );

    if( h->param.i_avcintra_class )
        rct->buffer_fill_final += buffer_size;
    else
        rct->buffer_fill_final += (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration;

    // 控制VBV上溢
    if( h->param.rc.b_filler && rct->buffer_fill_final > buffer_size )
    {
        int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8;
        filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale;
        bits = h->param.i_avcintra_class ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8;
        rct->buffer_fill_final -= (uint64_t)bits * h->sps->vui.i_time_scale;
    }
    else
        rct->buffer_fill_final = X264_MIN( rct->buffer_fill_final, buffer_size );

    return filler;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值