欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > SVT-AV1源码分析build_intra_predictors函数

SVT-AV1源码分析build_intra_predictors函数

2025/3/11 11:59:34 来源:https://blog.csdn.net/fantasy_ARM9/article/details/146166978  浏览:    关键词:SVT-AV1源码分析build_intra_predictors函数

build_intra_predictors函数作用

build_intra_predictors 函数视频编码技术中特别是帧内预测过程起着关键作用以下主要作用详细解释

一 处理调色板模式

在某些视频编码场景使用调色模式图像进行编码在这种情况系build_intra_predictors 函数直接根据调色映射预测器无需进行复杂帧内预测计算

二 构建预测参考

使用调色板模式时函数的主要任务构建当前进行帧内预测所需参考像素这包括当前周边是否存在可用进行判断如果周边不可用函数下一级函数进行padding构建预测所需要reference

三 考虑多种因素进行预测

在构建预测build_intra_predictors 函数考虑多种因素包括

邻居像素可用性检测左下邻居像素是否存在确定预测可以利用参考信息

预测模式 根据制定预测模式(如角度预测模式等)选择合适算法生成预测

角度偏移角度预测模式角度偏移量影响预测方向方式

滤波模式确定是否使用滤波以及使用何种滤波模式提高预测准确性

变换尺寸根据当前变换尺寸调整预测大小形状

四 生产预测块

结合上述考虑因素函数最终生成当前预测块这个预测用于后续编码过程残差计算熵编码实现高效视频压缩

五 参数说明

MacroBlockD *xd:指向宏块解码结构体的指针,包含当前宏块的解码信息。

top_neigh_arrayleft_neigh_array 分别存储上方左侧邻居像素数据用于构建预测参考

dstdst_stride 指向预测块存储位置指针步长用于输出生成的预测块

PredictionMode mode 指定当前预测模式决定预测块生成方式

angle_delta 角度偏移量影响角度预测方向方式

FilterIntraMode filter_intra_mode 滤波模式用于提高预测准确性

TxSize tx_szie 当前变换尺寸影响预测大小形状

disable_edge_filter是否禁用边缘滤波标志用于控制是否预测边缘进行滤波处理

n_top_px, n_topright_px, n_left_px, n_bottomleft_px 分别表示上方右上方左侧左下方邻居像素数据用于确定参考像素有效范围

plane 当前处理图像通道,用于区分亮度色度不同通道

六 源码分析

// 定义一个静态函数,用于构建帧内预测器
static void build_intra_predictors(const MacroBlockD *xd,                // 当前宏块的解码信息uint8_t* top_neigh_array,             // 上方邻居像素数组uint8_t* left_neigh_array,            // 左侧邻居像素数组uint8_t *dst, int32_t dst_stride,     // 预测块的存储位置和步长
    PredictionMode mode,                  // 预测模式int32_t angle_delta,                  // 角度偏移量
    FilterIntraMode filter_intra_mode,    // 滤波模式
    TxSize tx_size,                       // 变换尺寸int32_t disable_edge_filter,          // 是否禁用边缘滤波int32_t n_top_px,                     // 上方邻居像素数量int32_t n_topright_px,                // 右上方邻居像素数量int32_t n_left_px,                    // 左侧邻居像素数量int32_t n_bottomleft_px,              // 左下方邻居像素数量int32_t plane)                        // 当前处理的图像平面
{int32_t i;//设置参考像素步长1int32_t ref_stride = 1;// 指向顶部和左侧邻居像素的指针const uint8_t *above_ref = top_neigh_array;//顶部const uint8_t *left_ref = left_neigh_array;//左侧// 声明并初始化用于存储左侧和上方参考像素的临时数组,对齐以优化性能DECLARE_ALIGNED(32, uint8_t, left_data[MAX_TX_SIZE * 2 + 48]);DECLARE_ALIGNED(32, uint8_t, above_data[MAX_TX_SIZE * 2 + 48]);// 将临时数组初始化为128(默认值)memset(left_data, 0x80, sizeof(left_data));memset(above_data, 0x80, sizeof(above_data));// 指向临时数组中间位置的指针,用于方便访问和操作参考像素uint8_t *const above_row = above_data + 32;uint8_t *const left_col = left_data + 32;// 获取当前变换块的宽度和高度(以像素为单位)const int32_t txwpx = tx_size_wide[tx_size];const int32_t txhpx = tx_size_high[tx_size];// 根据预测模式确定是否需要左侧、上方和左上角的像素作为参考int32_t need_left = extend_modes[mode] & NEED_LEFT;int32_t need_above = extend_modes[mode] & NEED_ABOVE;int32_t need_above_left = extend_modes[mode] & NEED_ABOVELEFT;// 初始化预测角度为0int32_t p_angle = 0;// 判断是否为方向性预测模式const int32_t is_dr_mode = av1_is_directional_mode(mode);// 判断是否启用滤波模式const int32_t use_filter_intra = filter_intra_mode != FILTER_INTRA_MODES;// 如果是方向性预测模式if (is_dr_mode) {// 计算实际预测角度,结合模式和角度偏移
        p_angle = mode_to_angle_map[mode] + angle_delta * ANGLE_STEP;// 根据角度调整需要的参考像素方向if (p_angle <= 90)
            need_above = 1, need_left = 0, need_above_left = 1;else if (p_angle < 180)
            need_above = 1, need_left = 1, need_above_left = 1;else
            need_above = 0, need_left = 1, need_above_left = 1;}// 如果启用滤波模式,强制需要所有方向的参考像素if (use_filter_intra) need_left = need_above = need_above_left = 1;// 断言确保邻居像素数量非负assert(n_top_px >= 0);assert(n_topright_px >= 0);assert(n_left_px >= 0);assert(n_bottomleft_px >= 0);// 处理特殊情况:无需参考像素if ((!need_above && n_left_px == 0) || (!need_left && n_top_px == 0)) {int32_t val;// 根据需要的参考方向选择默认值if (need_left)
            val = (n_top_px > 0) ? above_ref[0] : 129;else
            val = (n_left_px > 0) ? left_ref[0] : 127;// 使用默认值填充整个预测块for (i = 0; i < txhpx; ++i) {memset(dst, val, txwpx);
            dst += dst_stride;}return;}// 如果需要左侧参考像素if (need_left) {// 判断是否需要底部像素(用于某些预测模式)int32_t need_bottom = !!(extend_modes[mode] & NEED_BOTTOMLEFT);if (use_filter_intra) need_bottom = 0; // 如果启用滤波,不需要底部像素if (is_dr_mode) need_bottom = p_angle > 180; // 方向性模式下根据角度判断// 计算需要的左侧像素数量const int32_t num_left_pixels_needed = txhpx + (need_bottom ? txwpx : 0);
        i = 0;// 如果有左侧邻居像素if (n_left_px > 0) {// 填充左侧参考像素for (; i < n_left_px; i++) left_col[i] = left_ref[i * ref_stride];// 如果需要底部像素且有可用的底部左侧像素if (need_bottom && n_bottomleft_px > 0) {assert(i == txhpx); // 确保索引正确// 填充底部左侧像素for (; i < txhpx + n_bottomleft_px; i++)
                    left_col[i] = left_ref[i * ref_stride];}// 如果像素不足,用最后一个可用像素填充剩余部分if (i < num_left_pixels_needed)memset(&left_col[i], left_col[i - 1], num_left_pixels_needed - i);}else {// 如果没有左侧邻居像素,使用上方邻居像素或默认值填充if (n_top_px > 0)memset(left_col, above_ref[0], num_left_pixels_needed);elsememset(left_col, 129, num_left_pixels_needed);}}// 如果需要上方参考像素if (need_above) {// 判断是否需要右侧像素(用于某些预测模式)int32_t need_right = !!(extend_modes[mode] & NEED_ABOVERIGHT);if (use_filter_intra) need_right = 0; // 如果启用滤波,不需要右侧像素if (is_dr_mode) need_right = p_angle < 90; // 方向性模式下根据角度判断// 计算需要的上方像素数量const int32_t num_top_pixels_needed = txwpx + (need_right ? txhpx : 0);// 如果有上方邻居像素if (n_top_px > 0) {// 复制上方邻居像素到临时数组svt_memcpy(above_row, above_ref, n_top_px);
            i = n_top_px;// 如果需要右侧像素且有可用的右上方像素if (need_right && n_topright_px > 0) {assert(n_top_px == txwpx); // 确保索引正确// 复制右上方像素svt_memcpy(above_row + txwpx, above_ref + txwpx, n_topright_px);
                i += n_topright_px;}// 如果像素不足,用最后一个可用像素填充剩余部分if (i < num_top_pixels_needed)memset(&above_row[i], above_row[i - 1], num_top_pixels_needed - i);}else {// 如果没有上方邻居像素,使用左侧邻居像素或默认值填充if (n_left_px > 0)memset(above_row, left_ref[0], num_top_pixels_needed);elsememset(above_row, 127, num_top_pixels_needed);}}// 如果需要左上角像素if (need_above_left) {// 根据可用的邻居像素设置左上角像素if (n_top_px > 0 && n_left_px > 0)
            above_row[-1] = above_ref[-1];else if (n_top_px > 0)
            above_row[-1] = above_ref[0];else if (n_left_px > 0)
            above_row[-1] = left_ref[0];else
            above_row[-1] = 128;// 同步左上角像素到左侧列数组
        left_col[-1] = above_row[-1];}// 如果启用滤波模式if (use_filter_intra) {// 调用滤波函数生成预测块svt_av1_filter_intra_predictor(dst, dst_stride, tx_size, above_row, left_col,
                                       filter_intra_mode);return;}// 如果是方向性预测模式if (is_dr_mode) {// 初始化是否需要对上方和左侧像素进行上采样int32_t upsample_above = 0;int32_t upsample_left = 0;// 如果未禁用边缘滤波if (!disable_edge_filter) {// 根据角度判断是否需要右侧和底部像素const int32_t need_right = p_angle < 90;const int32_t need_bottom = p_angle > 180;// 获取滤波器类型const int32_t filt_type = get_filt_type(xd, plane);// 如果角度不是90或180度if (p_angle != 90 && p_angle != 180) {// 如果需要上方和左侧像素且块尺寸足够大,进行边缘和角落滤波const int32_t ab_le = need_above_left ? 1 : 0;if (need_above && need_left && (txwpx + txhpx >= 24))filter_intra_edge_corner(above_row, left_col);// 对上方像素进行滤波if (need_above && n_top_px > 0) {const int32_t strength = svt_aom_intra_edge_filter_strength(
                            txwpx, txhpx, p_angle - 90, filt_type);const int32_t n_px = n_top_px + ab_le + (need_right ? txhpx : 0);svt_av1_filter_intra_edge(above_row - ab_le, n_px, strength);}// 对左侧像素进行滤波if (need_left && n_left_px > 0) {const int32_t strength = svt_aom_intra_edge_filter_strength(
                            txhpx, txwpx, p_angle - 180, filt_type);const int32_t n_px = n_left_px + ab_le + (need_bottom ? txwpx : 0);svt_av1_filter_intra_edge(left_col - ab_le, n_px, strength);}}// 判断是否需要对上方像素进行上采样
            upsample_above = svt_aom_use_intra_edge_upsample(
                    txwpx, txhpx, p_angle - 90, filt_type);if (need_above && upsample_above) {const int32_t n_px = txwpx + (need_right ? txhpx : 0);svt_av1_upsample_intra_edge(above_row, n_px);}// 判断是否需要对左侧像素进行上采样
            upsample_left = svt_aom_use_intra_edge_upsample(
                    txhpx, txwpx, p_angle - 180, filt_type);if (need_left && upsample_left) {const int32_t n_px = txhpx + (need_bottom ? txwpx : 0);svt_av1_upsample_intra_edge(left_col, n_px);}}// 调用方向性预测函数生成预测块svt_aom_dr_predictor(dst, dst_stride, tx_size, above_row, left_col, upsample_above,
                         upsample_left, p_angle);return;}// 如果是直流预测模式if (mode == DC_PRED) {// 调用直流预测函数生成预测块
        svt_aom_dc_pred[n_left_px > 0][n_top_px > 0][tx_size](dst, dst_stride, above_row,
                                                      left_col);}// 其他预测模式else {// 调用相应的预测函数生成预测块
        svt_aom_eb_pred[mode][tx_size](dst, dst_stride, above_row, left_col);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词