视频编码中,帧内预测需要获取相邻块的参考像素才能获得重建,在AVS3参考软件平台HPM中,这个过程是如何实现的呢?

HPM中的map_scu

1、什么是SCU?

SCU是Smallest CU的缩写。HPM中,最大CU是128x128,最小是4x4。

CU编码的信息,无论CU大小都以SCU为基本单位进行存储。这样只需知道CU的(x, y)坐标,就可以计算相邻左边、上边、左上角等块的位置,获取他们的编码信息为当前编码块所用。

#define MAX_CU_LOG2                        7
#define MIN_CU_LOG2                        2
#define MAX_CU_SIZE                       (1 << MAX_CU_LOG2)
#define MIN_CU_SIZE                       (1 << MIN_CU_LOG2)

2、什么是map_scu?

HPM为每个scu都定义了一个map_scu用于存储CU编码的重要信息,map_scu是一个unsigned int 32数组,将CU的编码模式,QP,Skip mode Flag,luma cbf等信息紧凑的存储在一个变量中,这样可以更高效利用存储,减少内存访问及Cache Miss,具体定义如下。其中第31位存储了CU是否编完的信息。图1为map_scu一个32bit数据所存放的编码信息示意图。

图1、map_scu编码信息存放示意图
/****************************************************************************** macros for CU map- [ 0: 6] : slice number (0 ~ 128)- [ 7:14] : reserved- [15:15] : 1 -> intra CU, 0 -> inter CU- [16:22] : QP- [23:23] : skip mode flag- [24:24] : luma cbf- [25:25] : ibc flag- [26:30] : reserved- [31:31] : 0 -> no encoded/decoded CU, 1 -> encoded/decoded CU*****************************************************************************/

Intra预测过程

(1) 调用com_get_avail_intra,判断左边、上边和左上相邻块是否存在。

u16 com_get_avail_intra(int x_scu, int y_scu, int pic_width_in_scu, int scup, u32 * map_scu)
{u16 avail = 0;if (x_scu > 0 && MCU_GET_CODED_FLAG(map_scu[scup - 1])){SET_AVAIL(avail, AVAIL_LE);}if (y_scu > 0){if (MCU_GET_CODED_FLAG(map_scu[scup - pic_width_in_scu])){SET_AVAIL(avail, AVAIL_UP);}if (x_scu > 0 && MCU_GET_CODED_FLAG(map_scu[scup - pic_width_in_scu - 1])){SET_AVAIL(avail, AVAIL_UP_LE);}}return avail;
}

(2) 调用com_get_nbr获取Intra预测参考像素:从重建图像中获取上边行、左边列,左上角的重建像素值,作为当前帧内预测参考像素。如下图所示:

图2、Intra预测参考像素获取过程示意图
void com_get_nbr(int x, int y, int width, int height, pel *src, int s_src, u16 avail_cu, pel nb[N_C][N_REF][MAX_CU_SIZE * 3], int scup, u32 * map_scu, int pic_width_in_scu, int pic_height_in_scu, int bit_depth, int ch_type)
{int  i;int  width_in_scu  = (ch_type == Y_C) ? (width >> MIN_CU_LOG2)  : (width >> (MIN_CU_LOG2 - 1));int  height_in_scu = (ch_type == Y_C) ? (height >> MIN_CU_LOG2) : (height >> (MIN_CU_LOG2 - 1));int  unit_size = (ch_type == Y_C) ? MIN_CU_SIZE : (MIN_CU_SIZE >> 1);int  x_scu = PEL2SCU(ch_type == Y_C ? x : x << 1);int  y_scu = PEL2SCU(ch_type == Y_C ? y : y << 1);pel *const src_bak = src;pel *left = nb[ch_type][0] + STNUM;pel *up   = nb[ch_type][1] + STNUM;int pad_le = height;  //number of padding pixel in the left columnint pad_up = width;   //number of padding pixel in the upper rowint pad_le_in_scu = height_in_scu;int pad_up_in_scu = width_in_scu;*首先,设置左边参考列和上边参考行的值 = 1 << (bit_depth - 1)com_mset_16b(left - STNUM, 1 << (bit_depth - 1), height + pad_le + STNUM);com_mset_16b(up   - STNUM, 1 << (bit_depth - 1), width  + pad_up + STNUM);if(IS_AVAIL(avail_cu, AVAIL_UP)){com_mcpy(up, src - s_src, width * sizeof(pel));  *从重建图像中拷贝上边行的参考像素for(i = 0; i < pad_up_in_scu; i++)  *以SCU为单位继续往右看获取右上行参考像素{if(x_scu + width_in_scu + i < pic_width_in_scu && MCU_GET_CODED_FLAG(map_scu[scup - pic_width_in_scu + width_in_scu + i])){  *右上行的像素在图像内部,且已经重建,则拷贝右上的参考像素com_mcpy(up + width + i * unit_size, src - s_src + width + i * unit_size, unit_size * sizeof(pel));}else{  *当前右上SCU没有重建像素,则将当前位置左边像素值复制到右边com_mset_16b(up + width + i * unit_size, up[width + i * unit_size - 1], unit_size);}}}if(IS_AVAIL(avail_cu, AVAIL_LE)){src--;for(i = 0; i < height; ++i)  *拷贝左边列重建像素值到left[]{left[i] = *src;src += s_src;}for(i = 0; i < pad_le_in_scu; i++) *以SCU为单位继续往下看获取左下列参考像素{if(y_scu + height_in_scu + i < pic_height_in_scu && MCU_GET_CODED_FLAG(map_scu[scup - 1 + (height_in_scu + i) *pic_width_in_scu])){int j;for(j = 0; j < unit_size; ++j){left[height + i * unit_size + j] = *src;src += s_src;}}else{com_mset_16b(left + height + i * unit_size, left[height + i * unit_size - 1], unit_size);src += (s_src * unit_size);}}}if (IS_AVAIL(avail_cu, AVAIL_UP_LE))  *拷贝左上角重建像素值{up[-1] = left[-1] = src_bak[-s_src - 1];}else if (IS_AVAIL(avail_cu, AVAIL_UP)){up[-1] = left[-1] = up[0];}else if (IS_AVAIL(avail_cu, AVAIL_LE)){up[-1] = left[-1] = left[0];}up[-2] = left[0];left[-2] = up[0];up[-3] = left[1];left[-3] = up[1];
#if IIPif (STNUM > 3){up[-4] = left[2];left[-4] = up[2];up[-5] = left[3];left[-5] = up[3];}
#endif
}

(3) 调用com_get_mpm获取 mpm。

void com_get_mpm(int x_scu, int y_scu, u32 *map_scu, s8 *map_ipm, int scup, int pic_width_in_scu, u8 mpm[2])
{u8 ipm_l = IPD_DC, ipm_u = IPD_DC;int valid_l = 0, valid_u = 0;if(x_scu > 0 && MCU_GET_INTRA_FLAG(map_scu[scup - 1]) && MCU_GET_CODED_FLAG(map_scu[scup - 1])){ipm_l = map_ipm[scup - 1];valid_l = 1;}if(y_scu > 0 && MCU_GET_INTRA_FLAG(map_scu[scup - pic_width_in_scu]) && MCU_GET_CODED_FLAG(map_scu[scup - pic_width_in_scu])){ipm_u = map_ipm[scup - pic_width_in_scu];valid_u = 1;}mpm[0] = COM_MIN(ipm_l, ipm_u);mpm[1] = COM_MAX(ipm_l, ipm_u);if(mpm[0] == mpm[1]){mpm[0] = IPD_DC;mpm[1] = (mpm[1] == IPD_DC) ? IPD_BI : mpm[1];}
}

(4) 按照Intra预测公式,对各个预测方向生成预测平面。

Patch边界对Intra预测的影响

在HPM中,当下一个LCU在新的Patch当中时,会将map_cu数组中的信息清除。这样,在patch边界的LCU,他访问的相邻SCU在其他Patch中时,CODED_FLAG为uncoded,拿不到预测值。

com_mset_x64a(ctx->map.map_scu, 0, sizeof(u32)* ctx->info.f_scu);  // 将整幅图像的map_scu清零。

代码如下所示:

        ......编完一个LCU后,进行下一步处理:core->x_lcu++;
#if PATCHpatch_cur_index = patch->idx;if (core->x_lcu >= *(patch->width_in_lcu + patch->x_pat) + patch_cur_lcu_x){core->x_lcu = patch_cur_lcu_x;core->y_lcu++;if (core->y_lcu >= *(patch->height_in_lcu + patch->y_pat) + patch_cur_lcu_y){新的Patch开始了(a new patch starts)core->cnt_hmvp_cands = 0;......enc_eco_slice_end_flag(bs, 1);enc_sbac_finish(bs, 0);/*update and store map_scu*/en_copy_lcu_scu(map_scu_temp, ctx->map.map_scu, map_refi_temp, ctx->map.map_refi, map_mv_temp, ctx->map.map_mv, map_cu_mode_temp, ctx->map.map_cu_mode, ctx->patch, ctx->info.pic_width, ctx->info.pic_height);com_mset_x64a(ctx->map.map_scu, 0, sizeof(u32)* ctx->info.f_scu);   重置map_scu中的所有flagcom_mset_x64a(ctx->map.map_refi, -1, sizeof(s8)* ctx->info.f_scu * REFP_NUM);com_mset_x64a(ctx->map.map_mv, 0, sizeof(s16)* ctx->info.f_scu * REFP_NUM * MV_D);com_mset_x64a(ctx->map.map_cu_mode, 0, sizeof(u32) * ctx->info.f_scu);/*set patch head*/if( patch_cur_index + 1 < num_of_patch ){set_sh( ctx, shext, patch_sao_enable + (patch_cur_index + 1)*N_C );}/* initialize entropy coder */enc_sbac_init(bs);com_sbac_ctx_init(&(GET_SBAC_ENC(bs)->ctx));com_sbac_ctx_init(&(core->s_curr_best[ctx->info.log2_max_cuwh - 2][ctx->info.log2_max_cuwh - 2].ctx));......

版权声明:本文为博主原创文章,未经博主允许请勿转载。

AVS3中Intra预测过程 - HPM代码分析相关推荐

  1. 关于《机器学习实战》中创建决策树的核心代码分析

       关于<机器学习实战>中创建决策树的核心代码分析                 SIAT  nyk          2017年10月21日星期六 一.源码内容 def create ...

  2. vin-slam中调用ceres库内部代码分析与性能优化

    vin-slam中调用ceres库内部代码分析与性能优化 1,vin-slam中后端参数优化调用流程代码 2,ceres内部的求解流程(未完待续) 首先,很抱歉前几次上传的关于一些图像算法代码不全,主 ...

  3. C语言 带参数宏定义中 # 和 ## 知识点总结、代码分析

    目录 一.宏定义中 "#"知识点 1.直接转换字符串,不展开. 2.转换出的结果一定是"字符串". 二.宏定义中 ## 知识点 1.应用场景 2."# ...

  4. OSEA中QRS波检测算法代码分析-未完待续

    最近一直在搞R波检测算法,对OSEA代码主要是对注释做一个翻译,增加注释,使代码更容易理解. 一.首先看QRSDE.H /*************************************** ...

  5. vs 2015 C 语言,VS2015中C/C++代码分析

    VS2015中C/C++代码分析 03/31/2015 8 分钟可看完 本文内容 [原文发表时间]:2015/2/24 1:00 PM 来自 Joe Morris & Jim Springfi ...

  6. TensorFlow-CIFAR10 CNN代码分析

    CIFAR 代码组织 代码分析 cifar10_trainpy cifar10py cifar10_evalpy Reference 根据TensorFlow 1.2.1,改了官方版本的报错. CIF ...

  7. 【高通SDM660平台 Android 10.0】(10) --- Camera Sensor lib 与 Kernel Camera Probe 代码分析

    [高通SDM660平台 Android 10.0]Camera Sensor lib 与 Kernel Camera Probe 代码分析 一.libmmcamera_imx258.so 代码分析 1 ...

  8. S3C6410开发板LED驱动代码分析及测试代码分析

    在本文中,我们对S3C6410开发板LED驱动代码的实现过程进行分析,然后通过一个实例对LED进行控制.在本文的资源中包含了设备驱动的源码和测试的源码. 一.设备驱动源码分析 设备驱动主要实现了模块的 ...

  9. HTK解码代码分析(二)

    HTK解码总体流程: 首先在HVite.C的main函数中调用相应库的函数. HVite_main() {解析HVite命令行:Initialise();net = ExpandWordNet(&am ...

最新文章

  1. 天池NLP中文预训练模型赛来了!
  2. opencv固定窗口在桌面的位置
  3. C#中成员初始化顺序
  4. ……OleContainer中嵌入WORD后,用什么办法显示滚动条???……
  5. 关于内核页表和进程页表的一个问题
  6. Android开发:利用Activity的Dialog风格完成弹出框设计
  7. 作者:杨青海(1965-),男,博士,中国标准化研究院高级工程师。
  8. java撕裂_屏幕撕裂与卡顿分析
  9. 关于iBatis中的错误提示(必须以 或 /结尾,有时并不是你的结尾没有以 /结束,而是这个标签里面有问题!!)(更重要的是sqlMap的修改手段!!!)
  10. 系统学习机器学习之特征工程(四)--分箱总结
  11. 基于马尔萨斯的人口模型的一个Logistic模型(MATLAB)
  12. 哈工大计算机系统大作业 程序人生-Hello’s P2P
  13. 算法三十四:最近点对
  14. Python中利用pygame做弹球游戏
  15. Photoshop设计精讲精练笔记(一)
  16. 装饰器python与python装饰器
  17. 服务器的型号规格,云服务器规格型号
  18. python交互方式是什么意思_python交互模式是什么
  19. Sublime 安装与中文配置
  20. Window系统 cd命令

热门文章

  1. 转帖--想唱不能唱的IT精英们
  2. 从原理到趋势,解剖风口上的区块链技术
  3. 第六届GPLT团体程序设计天梯赛
  4. 西北工业大学#面向对象编程实验#实验三
  5. 告别单调的主妇,这三件好物,让妈妈变身精致美厨娘丨Fancy辣妈系列
  6. 公式计算机实现,编译原理:实现容易数学公式排版
  7. hosts权限问题/trustedinstaller权限获取
  8. 市值仅剩三分之一,电商生态系统能否助力唯品会脱困?
  9. ios 快捷键~刪除文字、英文拼写
  10. Thinkphp 反序列化深入分析pop利用链