H264解析Demo10变换量化_1_CAVLC结果还原为系数矩阵
Posted 叮咚咕噜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H264解析Demo10变换量化_1_CAVLC结果还原为系数矩阵相关的知识,希望对你有一定的参考价值。
前面已经通过cavlc解析出了numCoeff、trailingOnes、trailingSigns(拖尾系数符号)、levels、totalZeros、runBefore等值,在反变换量化之前,需要根据这些值还原系数矩阵
一、定义
定义数据保存矩阵:int m_residual_matrix_luma[16][4][4];
定义还原函数:Restore_coeff_matrix
二、知识储备
一个宏块在进行CAVLC编码时是如何划分的:4 * 4模式是如何划分的呢?首先将16 * 16的宏块划分成4个8 * 8的,每个8 * 8的都是由cbp的一个bit表示的
基本编程思路:cavlc结果->还原为8 * 8的矩阵->4 * 4的矩阵->再填充矩阵数组
三、代码实现
1、重建8 * 8系数矩阵框架:
//<变换量化><1>根据cavlc结果还原系数矩阵
void CResidual::Restore_coeff_matrix()
{
UINT8 cbp_luma = m_macroblock_belongs->m_cbp_luma;
UINT8 cbp_chroma = m_macroblock_belongs->m_cbp_chroma;
//<变换量化><1>4*4宏块
if (m_macroblock_belongs->m_mb_type == I4MB)
{
for (int blk8Idx = 0; blk8Idx < 4; blk8Idx++)
{
if (cbp_luma & (1 << blk8Idx)) //<变换量化><1>判断是否有系数矩阵
{
restore_8x8_coeff_block_luma(m_coeff_matrix_luma, blk8Idx, LUMA); //<变换量化><1>处理8*8的块,将里面4个4*4的系数矩阵都解析出来
}
}
}
}
2、解析8 * 8矩阵
//<变换量化><1>重建8 * 8系数矩阵接口
void CResidual::restore_8x8_coeff_block_luma(int (*matrix)[4][4], int idx, int blockType)
{
int blkColumnIdxStart = 2 * (idx / 2), blkRowIdxStart = 2 * (idx % 2); //<变换量化><2>计算宏块索引序号,宏块的计数是针对于整体16 * 16的块而言的,第一行0-3,第二行4-7
for (int columnIdx = blkColumnIdxStart; columnIdx < blkColumnIdxStart + 2; columnIdx ++)
{
for (int rowIdx = blkRowIdxStart; rowIdx < blkRowIdxStart + 2; rowIdx++)
{
restore_4x4_coeff_block_luma(columnIdx, rowIdx, blockType);
}
}
}
3、解析4 * 4矩阵
void CResidual::restore_4x4_coeff_block_luma(int column_idx, int row_idx, int blockType)
{
int max_coeff_num = 0, start_idx = 0;
Coeff4x4Block *targetBlock = NULL;
switch (blockType)
{
case LUMA:
max_coeff_num = 16;
targetBlock = &luma_residual[column_idx][row_idx]; //<变换量化><2>前面cavlc解析出的结果
break;
case LUMA_INTRA16x16AC:
start_idx = 1; //<变换量化><2>设置为1是因为直流分量已经被单独解析了,所以这里需要从1开始
max_coeff_num = 15;
targetBlock = &luma_residual16x16_AC[column_idx][row_idx];
break;
default:
break;
}
int coeffBuf[16] = { 0 };
UINT8 numCoeff = targetBlock->numCoeff, coeffIdx = numCoeff;
UINT8 trailingOnes = targetBlock->trailingOnes, trailingLeft = trailingOnes;
UINT8 totalZeros = targetBlock->totalZeros;
// write trailing ones
//<变换量化><2>[10 0 2 3 0 0 5 3 0 1....]
//<变换量化><2>[10 2 3 5 3 1] 先写为这种,后面再补0
for (int i = numCoeff - trailingOnes, j = trailingOnes - 1; j >= 0; j--)
{
coeffBuf[i++] = targetBlock->trailingSign[j];
}
// write levels
//<变换量化><2>写非零非拖尾系数的值
for (int i = numCoeff - trailingOnes - 1; i >= 0; i--)
{
coeffBuf[i] = targetBlock->levels[numCoeff - trailingOnes - 1 - i];
}
// move levels with run_before
//<变换量化><2>[10 0 2 3 0 0 5 3 0 1....]
//<变换量化><2>[10 2 3 5 3 1 0 0 0 0] totalZeros=4 - runBefore=1
//<变换量化><2>[10 2 3 5 3 0 0 0 0 1] totalZeros=3 - runBefore=0
//<变换量化><2>[10 2 3 5 0 0 0 3 0 1] totalZeros=3 - runBefore=2
//<变换量化><2>[10 2 3 0 0 0 5 3 0 1]
for (int i = numCoeff - 1; i > 0; i--)
{
swap(coeffBuf[i], coeffBuf[i + totalZeros]);
totalZeros -= targetBlock->runBefore[i];
}
swap(coeffBuf[0], coeffBuf[totalZeros]); //<变换量化><2>如果totalZeros还不为0,需要交换最低频前面的0
insert_matrix(m_coeff_matrix_luma, coeffBuf, start_idx, max_coeff_num, column_idx, row_idx); //<变换量化><2>插入系数矩阵数组
// int blkIdx = position_to_block_index(row_idx, column_idx);
// coeff_invers_transform(m_coeff_matrix_luma[blkIdx], m_residual_matrix_luma[blkIdx]);
}
4、填充系数矩阵数组:
注意因为是Z字型扫描,所以我们定义了一个坐标数组
以上是关于H264解析Demo10变换量化_1_CAVLC结果还原为系数矩阵的主要内容,如果未能解决你的问题,请参考以下文章