帧类型决策-slicetype_frame/slice/mb_cost()

slicetype_frame_cost

/*
将帧b以slice为单位计算其开销,统计其总开销
其中p0表示b的前向参考帧,p1表示b的后向参考帧
若p0 = p1 = b,则表示没有参考帧,即I帧
若p1 = b,则表示只有前向参考帧,即P帧

作为I帧,所有宏块的cost = intra cost
作为P帧,所有宏块的cost = min( intra cost, inter cost)
作为B帧,所有宏块的cost = inter cost

其中每一个帧都带有开销矩阵i_cost_est[b-p0][p1-b]
表示帧b以p0为前向参考,p1为后向参考时的帧cost
*/
static int slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a,
                                 x264_frame_t **frames, int p0, int p1, int b )
{
    int i_score = 0;	//作为帧cost进行返回
    int do_search[2];	//用来标记帧b是否已经在 前向参考帧/后向参考帧 上进行了运动搜索
    const x264_weight_t *w = x264_weight_none;
    x264_frame_t *fenc = frames[b];		//得到帧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?) 
	 * 检查是否已经评估了该帧,如果我们已经把该帧当作P帧计算,
	 * 那我们仍然需要将前面的帧当作B帧来计算

     * Also check that we already calculated the row SATDs for the current frame. 
	 * 同样检查我们是否对该帧进行了行SATD计算. */
    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) )
		//如果帧b已经计算了前向参考p0后向参考p1的cost,则直接得到开销
		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. 
		 * 如果可以前向参考,且mv = 0x7fff,则将他们置0
		 * 如果可以后向参考,且mv = 0x7fff,同样将他们置0. */
        do_search[0] = b != p0 && fenc->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF;
        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 )
            {
                x264_emms();
                x264_weights_analyse( h, fenc, frames[p0], 1 );
                w = fenc->weight[0];
            }
            fenc->lowres_mvs[0][b-p0-1][0][0] = 0;
        }
        if( do_search[1] ) fenc->lowres_mvs[1][p1-b-1][0][0] = 0;

        if( p1 != p0 )	//非I帧,则计算距离因子dist_scale_factor
            dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0);

        int output_buf_size = h->mb.i_mb_height + (NUM_INTS + PAD_SIZE) * h->param.i_lookahead_threads;
        int *output_inter[X264_LOOKAHEAD_THREAD_MAX+1];
        int *output_intra[X264_LOOKAHEAD_THREAD_MAX+1];
        output_inter[0] = h->scratch_buffer2;
        output_intra[0] = output_inter[0] + output_buf_size;

        {
            if( h->param.i_lookahead_threads > 1 )	//多个lookahead线程
            {
				/* 申请X264_LOOKAHEAD_THREAD_MAX个threadslice线程所需要的数据结构体
				 * 其实可以优化成动态内存申请i_lookahead_threads个. 
				 * 这个s[]里面存储着每个threadslice计算所需的数据及其输出 */
                x264_slicetype_slice_t s[X264_LOOKAHEAD_THREAD_MAX];

                for( int i = 0; i < h->param.i_lookahead_threads; i++ )	//针对各个lookahead线程
                {
                    x264_t *t = h->lookahead_thread[i];	//得到lookahead第i个线程的句柄

                    /* FIXME move this somewhere else */
					//将句柄h中的 运动估计方法/下采样运动估计质量/是否进行色度运动估计 的参数给第i个线程的句柄t
                    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;

					//初始化threadslice计算所需数据及输出 s[i]
                    s[i] = (x264_slicetype_slice_t){ t, a, frames, p0, p1, b, dist_scale_factor, do_search, w,
                        output_inter[i], output_intra[i] };

					//得到该threadslice计算的的起始行
                    t->i_threadslice_start = ((h->mb.i_mb_height *  i    + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads);
                    //得到该threadslice计算的结束行的下一行
					t->i_threadslice_end   = ((h->mb.i_mb_height * (i+1) + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads);

					//计算该threadslice所需计算的行高
                    int thread_height = t->i_threadslice_end - t->i_threadslice_start;

					/* 计算threadslice[i]计算的输出大小,即output_inter[i]和output_inter[i]的大小
					 * 每一行一个ROW_SATD输出,另外多申请4个空间用于存储额外数据:
					 * COST_EST COST_EST_AQ INTRA_MBS NUM_ROWS [ROW_SATD1 ... ROW_SATDn]*/
                    int thread_output_size = thread_height + NUM_INTS;

					//初始化两个输出缓冲,大小为threadslice行高+NUM_INTS
                    memset( output_inter[i], 0, thread_output_size * sizeof(int) );
                    memset( output_intra[i], 0, thread_output_size * sizeof(int) );

					//将行高赋值给两个输出缓冲的第4个位置
                    output_inter[i][NUM_ROWS] = output_intra[i][NUM_ROWS] = thread_height;

					//PADDING?
                    output_inter[i+1] = output_inter[i] + thread_output_size + PAD_SIZE;
                    output_intra[i+1] = output_intra[i] + thread_output_size + PAD_SIZE;

					//开启threadslice[i]进行计算,并将结果输出到output_inter[i]/output_intra[i]中
                    x264_threadpool_run( h->lookaheadpool, (void*)slicetype_slice_cost, &s[i] );
                }

				//等待各threadslice线程计算结束并退出
                for( int i = 0; i < h->param.i_lookahead_threads; i++ )
                    x264_threadpool_wait( h->lookaheadpool, &s[i] );
            }
            else	//单lookahead线程
            {
				//设置threadslice的起始行和结束行
                h->i_threadslice_start = 0;
                h->i_threadslice_end = h->mb.i_mb_height;

				//初始化两个输出缓冲,大小为threadslice行高+NUM_INTS
                memset( output_inter[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) );
                memset( output_intra[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) );

				//将行高赋值给两个输出缓冲的第4个位置
                output_inter[0][NUM_ROWS] = output_intra[0][NUM_ROWS] = h->mb.i_mb_height;

				//初始化threadslice计算所需数据及输出 s[i]
                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,将结果输出到output_inter[0]/output_intra[0]中
				slicetype_slice_cost( &s );
            }

            /* Sum up accumulators */
            if( b == p1 )	//若是I/P帧
                fenc->i_intra_mbs[b-p0] = 0;	//初始化IMB的个数为0	

            if( !fenc->b_intra_calculated )	//如果还没进行帧内计算
            {
				//初始化帧b的开销矩阵中[0][0]的cost为0
                fenc->i_cost_est[0][0] = 0;
                fenc->i_cost_est_aq[0][0] = 0;
            }

			//将帧b的cost矩阵对应置0
            fenc->i_cost_est[b-p0][p1-b] = 0;
            fenc->i_cost_est_aq[b-p0][p1-b] = 0;

			//取出inter和intra的row_satd向量
            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 )	//若是非B帧
                    fenc->i_intra_mbs[b-p0] += output_inter[i][INTRA_MBS];	//累计IMB的个数

                if( !fenc->b_intra_calculated )	//若还没有进行帧内预测计算
                {
					//累计intra的cost和aq_cost到开销矩阵i_cost_est[0][0]中
                    fenc->i_cost_est[0][0] += output_intra[i][COST_EST];
                    fenc->i_cost_est_aq[0][0] += output_intra[i][COST_EST_AQ];
                }

				//累计inter的cost和aq_cost到开销矩阵i_cost_est[b-p0][p1-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 )	//若使用了vbv
                {
                    int row_count = output_inter[i][NUM_ROWS];

					/* 将output_inter中计算得到的row_satd赋值给row_satd_inter
					 * 若还没进行帧内计算,则将output_intra中计算得到的row_satd赋值给row_satd_intra */
                    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_satd_intra指针
                    row_satd_inter += row_count;
                    row_satd_intra += row_count;
                }
            }

			//取出帧cost
            i_score = fenc->i_cost_est[b-p0][p1-b];

            if( b != p1 )	//若是B帧,则根据i_bframe_bias对帧cost进行调整
                i_score = (uint64_t)i_score * 100 / (120 + h->param.i_bframe_bias);
            else			//若I/P,则设置帧内预测计算标致
                fenc->b_intra_calculated = 1;	//标记已经进行了intra计算

			//将帧开销写回帧b的开销矩阵中对应的位置
            fenc->i_cost_est[b-p0][p1-b] = i_score;
            x264_emms();
        }
    }

    return i_score;	//返回帧cost
}

slicetype_slice_cost

/*
	将slice以mb为单位计算cost
	将结果输出到s->output_inter/s->output_intra中
*/
static void slicetype_slice_cost( x264_slicetype_slice_t *s )
{
	//取出传入的句柄
    x264_t *h = s->h;

    /* Lowres lookahead goes backwards because the MVs are used as predictors in the main encode.
     * This considerably improves MV prediction overall. 
	 * 进行低分辨率lookahead回溯,由于MV将会被用在主编码预测中,所以回溯可以明显的提示mv的预测精度 */

    /* The edge mbs seem to reduce the predictive quality of the
     * whole frame's score, but are needed for a spatial distribution. 
	 * 边缘宏块会降低整帧score(即cost)的预测质量,但是他们需要用于空间分布? */

	/* do_edges表示是否计算边界
	 * 若	使用宏块树 || 使用vbv || 行<=2 || 列<=2	,则使用计算边界宏块
	 * 否则不计算边界宏块 */
    int do_edges = h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size || h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2;

	//计算slice的起始行和结束行
    int start_y = X264_MIN( h->i_threadslice_end - 1, h->mb.i_mb_height - 2 + do_edges );
    int end_y = X264_MAX( h->i_threadslice_start, 1 - do_edges );

	//计算slice的起始列和结束列
    int start_x = h->mb.i_mb_width - 2 + do_edges;
    int end_x = 1 - do_edges;

    for( h->mb.i_mb_y = start_y; h->mb.i_mb_y >= end_y; h->mb.i_mb_y-- )	//遍历每一行
        for( h->mb.i_mb_x = start_x; h->mb.i_mb_x >= end_x; h->mb.i_mb_x-- )//遍历每一列
			//对每一个宏块进行cost计算
            slicetype_mb_cost( h, s->a, s->frames, s->p0, s->p1, s->b, s->dist_scale_factor,
                               s->do_search, s->w, s->output_inter, s->output_intra );
}

slicetype_mb_cost

/*
	对帧b的当前宏块计算其intra/inter_cost,intra/inter_aq_cost根据intra/inter_cost进行修正
	若intra_cost<inter_cost,则判定为IMB,累计IMB个数到output_inter[INTRA_MBS]中,且令inter_cost=intra_cost
	若当前宏块计入全帧的score中,则
		将intra/inter_cost累加进各自的output_intra/inter[COST_EST]中
		将intra/inter_aq_cost累加进各自的output_intra/inter[COST_AQ_EST]中
	将intra/inter_aq_cost累加进各自所在行的output_intra/inter[ROW_SATD]中
*/
static void slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,
                               x264_frame_t **frames, int p0, int p1, int b,
                               int dist_scale_factor, int do_search[2], const x264_weight_t *w,
                               int *output_inter, int *output_intra )
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,请允许我一一解释这些编译参数的含义。 1. --prefix=${PATH_INSTALL}/nginx 这个参数指定了 nginx 安装的路径。在这里,${PATH_INSTALL} 是一个变量,代表 nginx 安装的根目录。例如,如果 ${PATH_INSTALL} 被设置为 /usr/local,则 nginx 将会被安装到 /usr/local/nginx 目录下。 2. --user=nginx 这个参数指定了 nginx 进程运行的用户。在这里,nginx 进程将会以 nginx 用户的身份运行。 3. --group=nginx 这个参数指定了 nginx 进程运行的用户组。在这里,nginx 进程将会以 nginx 用户组的身份运行。 4. --with-http_ssl_module 这个参数启用了 nginx 的 SSL 功能,使得 nginx 能够处理 HTTPS 请求。 5. --with-http_realip_module 这个参数启用了 nginx 的真实 IP 功能,使得 nginx 能够获取客户端的真实 IP 地址。 6. --with-http_addition_module 这个参数启用了 nginx 的响应内容添加功能,使得 nginx 能够在 HTTP 响应中添加额外的内容。 7. --with-http_sub_module 这个参数启用了 nginx 的响应内容替换功能,使得 nginx 能够在 HTTP 响应中替换指定的内容。 8. --with-http_dav_module 这个参数启用了 nginx 的 WebDAV 功能,使得 nginx 能够处理 WebDAV 请求。 9. --with-http_flv_module 这个参数启用了 nginx 的 FLV 视频流功能,使得 nginx 能够处理 FLV 视频流请求。 10. --with-http_mp4_module 这个参数启用了 nginx 的 MP4 视频流功能,使得 nginx 能够处理 MP4 视频流请求。 11. --with-http_gunzip_module 这个参数启用了 nginx 的 Gzip 解压缩功能,使得 nginx 能够解压缩 Gzip 压缩的响应内容。 12. --with-http_gzip_static_module 这个参数启用了 nginx 的 Gzip 静态文件压缩功能,使得 nginx 能够对静态文件进行 Gzip 压缩。 13. --with-http_random_index_module 这个参数启用了 nginx 的随机索引功能,使得 nginx 能够在目录索引中随机显示文件。 14. --with-http_secure_link_module 这个参数启用了 nginx 的安全链接功能,使得 nginx 能够生成基于时间戳的安全链接。 15. --with-http_stub_status_module 这个参数启用了 nginx 的状态页面功能,使得 nginx 能够在浏览器中显示当前服务器的状态信息。 16. --with-http_auth_request_module 这个参数启用了 nginx 的认证请求功能,使得 nginx 能够向另一个服务器发送认证请求。 17. --with-threads 这个参数启用了 nginx 的线程池功能,使得 nginx 能够处理并发请求。 18. --with-stream 这个参数启用了 nginx 的流模块功能,使得 nginx 能够处理 TCP 和 UDP 流量。 19. --with-stream_ssl_module 这个参数启用了 nginx 的流 SSL 功能,使得 nginx 能够处理加密的 TCP 流量。 20. --with-http_slice_module 这个参数启用了 nginx 的分片功能,使得 nginx 能够将大文件分成多个小块进行传输。 21. --with-file-aio 这个参数启用了 nginx 的异步文件 I/O 功能,使得 nginx 能够异步读取文件。 22. --with-http_v2_module 这个参数启用了 nginx 的 HTTP/2 功能,使得 nginx 能够处理 HTTP/2 请求。 23. --with-pcre 这个参数启用了 PCRE 库,使得 nginx 能够使用正则表达式进行匹配操作。 24. --with-openssl=/www/server/nginx/src/openssl 这个参数指定了 OpenSSL 库的路径,使得 nginx 能够使用 OpenSSL 库进行加密操作。 25. --with-stream_ssl_preread_module 这个参数启用了 nginx 的流 SSL 预读功能,使得 nginx 能够在客户端发送 SSL 握手之前识别出 SSL 流量。 26. --with-http_image_filter_module 这个参数启用了 nginx 的图像处理功能,使得 nginx 能够处理图像文件。 27. --with-ipv6 这个参数启用了 IPv6 功能,使得 nginx 能够处理 IPv6 地址。 28. --with-ld-opt=-Wl,-E 这个参数指定了链接器的选项,使得 nginx 能够在运行时动态链接库。 29. --with-cc-opt=-Wno-error 这个参数指定了编译器的选项,禁止编译器将警告视为错误。 30. --with-ld-opt=-ljemalloc 这个参数指定了链接器的选项,使得 nginx 能够使用 jemalloc 内存分配器。 31. --add-module=/www/server/nginx/src/ngx_devel_kit 这个参数添加了一个模块,这个模块是 ngx_devel_kit,它提供了一些开发工具和库,使得开发 nginx 模块更加容易。 32. --add-module=/www/server/nginx/src/lua_nginx_module 这个参数添加了一个模块,这个模块是 lua_nginx_module,它使得 nginx 能够使用 Lua 脚本进行定制化操作。 33. --add-module=/www/server/nginx/src/ngx_cache_purge 这个参数添加了一个模块,这个模块是 ngx_cache_purge,它使得 nginx 能够手动清除缓存。 34. --add-module=/www/server/nginx/src/ngx_http_substitutions_filter_module-master 这个参数添加了一个模块,这个模块是 ngx_http_substitutions_filter_module-master,它使得 nginx 能够在 HTTP 响应中替换指定的内容。 以上就是这些编译参数的详细说明。希望对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值