x264 - x264_slicetype_frame_cost

来源:互联网 发布:淘宝金币不够用怎么办 编辑:程序博客网 时间:2024/06/10 03:03




static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a,
                                      x264_frame_t **frames, int p0, int p1, int b,
                                      int b_intra_penalty )
{
    int i_score = 0;
    int do_search[2];
    const x264_weight_t *w = x264_weight_none;
    // 索引b, 表示待编码的帧
    x264_frame_t *fenc = frames[b];

    /* Check whether we already evaluated this frame
     * If we have tried this frame as P, then we have also tried
     * the preceding frames as B. (is this still true?) */
    /* Also check that we already calculated the row SATDs for the current frame. */
    // fenc->i_cost_est[][]
    // 第一维表示前向参考距, 第二维表示后向参考距
    if( fenc->i_cost_est[b-p0][p1-b] >= 0 && (!h->param.rc.i_vbv_buffer_size || fenc->i_row_satds[b-p0][p1-b][0] != -1) )
        i_score = fenc->i_cost_est[b-p0][p1-b];
    else
    {
       
        int dist_scale_factor = 128;

        /* For each list, check to see whether we have lowres motion-searched this reference frame before. */
       
        // 不做I帧编码, 可能按P帧编码
        do_search[0] = b != p0 && fenc->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF;
        // 作B帧编码
        do_search[1] = b != p1 && fenc->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF;
        if( do_search[0] )
        {
            if( h->param.analyse.i_weighted_pred && b == p1 )
            {
                // b == p1 表示作为P帧来编码
                x264_emms();
                // 计算编码帧平面的权重,
                // fenc是待编码的帧,frames[p0]是前向参考帧
                x264_weights_analyse( h, fenc, frames[p0], 1 );
                // 获得待编码帧Y平面的权重
                w = fenc->weight[0];
            }
           
            // b != p0, 按P帧编码
            // b - p0 - 1 表示前向参考距
            fenc->lowres_mvs[0][b-p0-1][0][0] = 0;
        }
       
        // if do_search[1], 按B帧编码
        // p1 - b - 1 表示后向参考距
        if( do_search[1] ) fenc->lowres_mvs[1][p1-b-1][0][0] = 0;

        if( p1 != p0 ) // 待编帧不作为I帧来编码
            dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0);

        //  #define PAD_SIZE 32
        //  /* cost_est, cost_est_aq, intra_mbs, num rows */
        //  #define NUM_INTS 4
        //  #define COST_EST 0
        //  #define COST_EST_AQ 1
        //  #define INTRA_MBS 2
        //  #define NUM_ROWS 3
        //  #define ROW_SATD (NUM_INTS + (h->mb.i_mb_y - h->i_threadslice_start))

        int output_buf_size = h->mb.i_mb_height + (NUM_INTS + PAD_SIZE) * h->param.i_lookahead_threads;
        //  int *output_inter[17]
        //  int *output_intra[17]
        int *output_inter[X264_LOOKAHEAD_THREAD_MAX+1];
        int *output_intra[X264_LOOKAHEAD_THREAD_MAX+1];
       
        //  in macroblock.c
        //   int buf_lookahead_threads = (h->mb.i_mb_height + (4 + 32) * h->param.i_lookahead_threads) * sizeof(int) * 2;
        //   CHECKED_MALLOC( h->scratch_buffer2, buf_lookahead_threads );
        //  从上述malloc代码, 得知 h->scratch_buffer2 分配了2倍的一块内存
        //  一块赋予output_inter[0], 一块赋予output_intra[0]
        //  每一块将被分为4段,分别保存cost_est, cost_est_aq, intra_mbs, num_rows
        output_inter[0] = h->scratch_buffer2;
        output_intra[0] = output_inter[0] + output_buf_size;

#if HAVE_OPENCL
        if( h->param.b_opencl )
        {
            x264_opencl_lowres_init(h, fenc, a->i_lambda );
            if( do_search[0] )
            {
                x264_opencl_lowres_init( h, frames[p0], a->i_lambda );
                x264_opencl_motionsearch( h, frames, b, p0, 0, a->i_lambda, w );
            }
            if( do_search[1] )
            {
                x264_opencl_lowres_init( h, frames[p1], a->i_lambda );
                x264_opencl_motionsearch( h, frames, b, p1, 1, a->i_lambda, NULL );
            }
            if( b != p0 )
                x264_opencl_finalize_cost( h, a->i_lambda, frames, p0, p1, b, dist_scale_factor );
            x264_opencl_flush( h );

            i_score = fenc->i_cost_est[b-p0][p1-b];
        }
        else
#endif
        {
            if( h->param.i_lookahead_threads > 1 )
            {
                x264_slicetype_slice_t s[X264_LOOKAHEAD_THREAD_MAX];

                for( int i = 0; i < h->param.i_lookahead_threads; i++ )
                {
                    x264_t *t = h->lookahead_thread[i];

                    /* FIXME move this somewhere else */
                    t->mb.i_me_method = h->mb.i_me_method;
                    t->mb.i_subpel_refine = h->mb.i_subpel_refine;
                    t->mb.b_chroma_me = h->mb.b_chroma_me;

                    s[i] = (x264_slicetype_slice_t){ t, a, frames, p0, p1, b, dist_scale_factor, do_search, w,
                        output_inter[i], output_intra[i] };

                    t->i_threadslice_start = ((h->mb.i_mb_height *  i    + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads);
                    t->i_threadslice_end   = ((h->mb.i_mb_height * (i+1) + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads);

                    int thread_height = t->i_threadslice_end - t->i_threadslice_start;
                    int thread_output_size = thread_height + NUM_INTS;
                    // 初始化输出缓冲区
                    memset( output_inter[i], 0, thread_output_size * sizeof(int) );
                    memset( output_intra[i], 0, thread_output_size * sizeof(int) );
                    output_inter[i][NUM_ROWS] = output_intra[i][NUM_ROWS] = thread_height;

                    output_inter[i+1] = output_inter[i] + thread_output_size + PAD_SIZE;
                    output_intra[i+1] = output_intra[i] + thread_output_size + PAD_SIZE;

                    x264_threadpool_run( h->lookaheadpool, (void*)x264_slicetype_slice_cost, &s[i] );
                }
                for( int i = 0; i < h->param.i_lookahead_threads; i++ )
                    x264_threadpool_wait( h->lookaheadpool, &s[i] );
            }
            else
            {
                // 一行为一个slice
                // 因此 threadslice_start = 0, threadslice_end = i_mb.height
                h->i_threadslice_start = 0;
                h->i_threadslice_end = h->mb.i_mb_height;
               
                // 将output_inter[0], output_intra[0]的除padding外部分都初始为0
               
                memset( output_inter[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) );
                memset( output_intra[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) );
                // 将output_inter[0], output_intra[0]的NUM_ROWS段 赋值为 i_mb_height
                output_inter[0][NUM_ROWS] = output_intra[0][NUM_ROWS] = h->mb.i_mb_height;
                // 初始化s变量
                x264_slicetype_slice_t s = (x264_slicetype_slice_t){ h, a, frames, p0, p1, b, dist_scale_factor, do_search, w,
                    output_inter[0], output_intra[0] };
                // slice cost 计算, 见x264_slicetype_slice_cost
                x264_slicetype_slice_cost( &s );
            }

            /* Sum up accumulators */
            if( b == p1 )
                fenc->i_intra_mbs[b-p0] = 0;
            if( !fenc->b_intra_calculated )
            {
                // 初始化I帧代价估计
                fenc->i_cost_est[0][0] = 0;
                fenc->i_cost_est_aq[0][0] = 0;
            }
            // 初始化前向,后向距代价估计
            fenc->i_cost_est[b-p0][p1-b] = 0;
            fenc->i_cost_est_aq[b-p0][p1-b] = 0;

            // row_satd_inter 指向P帧/B帧的i_row_satds
            // row_satd_intra 指向I帧的i_row_satds
            int *row_satd_inter = fenc->i_row_satds[b-p0][p1-b];
            int *row_satd_intra = fenc->i_row_satds[0][0];
            for( int i = 0; i < h->param.i_lookahead_threads; i++ )
            {
                if( b == p1 )
                    fenc->i_intra_mbs[b-p0] += output_inter[i][INTRA_MBS];
                if( !fenc->b_intra_calculated )
                {
                    // 统计待编帧作为I帧编码的代价
                    fenc->i_cost_est[0][0] += output_intra[i][COST_EST];
                    fenc->i_cost_est_aq[0][0] += output_intra[i][COST_EST_AQ];
                }
               
                // 统计待编帧作为P/B帧编码的代价
                fenc->i_cost_est[b-p0][p1-b] += output_inter[i][COST_EST];
                fenc->i_cost_est_aq[b-p0][p1-b] += output_inter[i][COST_EST_AQ];

                if( h->param.rc.i_vbv_buffer_size )
                {
                    // 如果h->param.rc.i_vbv_buffer_size不为0,
                    // 则将satd row估计拷贝到待编码帧row_satd_inter /  row_satd_intra数组中

                    int row_count = output_inter[i][NUM_ROWS];
                    memcpy( row_satd_inter, output_inter[i] + NUM_INTS, row_count * sizeof(int) );
                    if( !fenc->b_intra_calculated )
                        memcpy( row_satd_intra, output_intra[i] + NUM_INTS, row_count * sizeof(int) );
                    row_satd_inter += row_count;
                    row_satd_intra += row_count;
                }
            }

            // 获得当前待编帧作为I/P/B帧编码的代价
            i_score = fenc->i_cost_est[b-p0][p1-b];
            // 如果是作B帧编, 调整i_score
            if( b != p1 )
                i_score = (uint64_t)i_score * 100 / (120 + h->param.i_bframe_bias);
            else
                fenc->b_intra_calculated = 1;
               
            // 将最终的i_score保存在待编帧的相应i_cost_est数组中

            fenc->i_cost_est[b-p0][p1-b] = i_score;
            x264_emms();
        }
    }

    if( b_intra_penalty )
    {
        // arbitrary penalty for I-blocks after B-frames
        int nmb = NUM_MBS;
        i_score += (uint64_t)i_score * fenc->i_intra_mbs[b-p0] / (nmb * 8);
    }
    return i_score;
}


0 0