x265对语法元素cu_qp_delta_abs的编码(后缀及符号位部分)
2018-03-18 21:06
411 查看
先看后缀部分。
根据标准,语法元素cu_qp_delta_abs的后缀值suffixVal = cu_qp_delta_abs − 5。void Entropy::codeDeltaQP(const CUData& cu, uint32_t absPartIdx)
{
int dqp = cu.m_qp[absPartIdx] - cu.getRefQP(absPartIdx);
int qpBdOffsetY = QP_BD_OFFSET;
dqp = (dqp + 78 + qpBdOffsetY + (qpBdOffsetY / 2)) % (52 + qpBdOffsetY) - 26 - (qpBdOffsetY / 2);
uint32_t absDQp = (uint32_t)((dqp > 0) ? dqp : (-dqp));//语法元素cu_qp_delta_abs的值
uint32_t TUValue = X265_MIN((int)absDQp, CU_DQP_TU_CMAX);//语法元素的前缀值
writeUnaryMaxSymbol(TUValue, &m_contextState[OFF_DELTA_QP_CTX], 1, CU_DQP_TU_CMAX);//使用截断一元码(TU)二元化方法将前缀转换为二元码,在对每一位比特进行常规编码。
if (absDQp >= CU_DQP_TU_CMAX)
writeEpExGolomb(absDQp - CU_DQP_TU_CMAX, CU_DQP_EG_k);////使用EGK二元化方法将后缀转换为二元码,在对每一位比特进行旁路编码。
if (absDQp > 0)
{
uint32_t sign = (dqp > 0 ? 0 : 1);
encodeBinEP(sign);////对符号进行旁路编码
}
}codeDeltaQP函数中判断当absDQp>=CU_DQP_TU_CMAX(5)时也就是存在后缀值时对其进行编码。
标准中确定使用零阶指数哥伦布编码对其进行二值化。该过程在writeEpGolomb函数中完成,传入的参数第一个就是后缀值,第二个参数值CU_DQP_EG_k(0)表示指数哥伦布编码的阶数。void Entropy::writeEpExGolomb(uint32_t symbol, uint32_t count)
{
uint32_t bins = 0;
int numBins = 0;
while (symbol >= (uint32_t)(1 << count))
{
bins = 2 * bins + 1;
numBins++;
symbol -= 1 << count;
count++;
}
bins = 2 * bins + 0;
numBins++;
bins = (bins << count) | symbol;
numBins += count;
X265_CHECK(numBins <= 32, "numBins too large\n");
encodeBinsEP(bins, numBins);
}函数中变量bins代表二值化后的二进制串,numBins就表示二进制串的长度。首先讲解下无符号数的零阶指数哥伦布编码的原理:分为前缀码和后缀码,计算M=log2(V+1),且向下取整,表示前缀码中‘1’的个数,最后加上‘0’得到前缀码,计算INFO=V+1-2的M次,它的二进制串就是后缀码。
简单点表示就是前缀码最后一个‘1’为分界线,前面有n个零,且满足 V-2的n-1次+...+2的0次<2的n次, 而V-2的n-1次+...+2的0次 得到的结果的二进制串就是后缀码。x265中也是利用这一点,while循环中就确定了前缀码中‘1’的个数,并且symbol已经被减去了2的幂次求和,输出分界‘1’,然后将bins左移count(n)位,填入symbol,完成二值化。
将二进制串bins和长度numBins传入encodeBinEP函数实现旁路编码。void Entropy::encodeBinsEP(uint32_t binValues, int numBins)
{
if (!m_bitIf)
{
m_fracBits += 32768 * numBins;
return;
}
while (numBins > 8)
{
numBins -= 8;
uint32_t pattern = binValues >> numBins;
m_low <<= 8;
m_low += m_range * pattern;
binValues -= pattern << numBins;
m_bitsLeft += 8;
if (m_bitsLeft >= 0)
writeOut();
}
m_low <<= numBins;
m_low += m_range * binValues;
m_bitsLeft += numBins;
if (m_bitsLeft >= 0)
writeOut();
}第一个if语句是通过估计的方法实现编码,这里就不管了。
函数中通过while循环逐个传入字节,应该是为了控制码流,这里不进行解释。先看旁路编码的流程图
![](//img-blog.csdn.net/20180318205256126?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L1hYX2JhaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
循环中以8位为一个单位进行算术编码,首先编码高8位,流程图中需要逐位完成的上半部分,函数中直接一步完成,也就是直接将L左移8位,然后L=L*R,两者的结果是相同的。调整完变量后,由writeOut函数根据L来输出码流。while循环后的部分步骤相同,只是numBins<8。
最后是对符号位的编码,非常简单,encodeBinEP(sign),对其进行旁路编码 void Entropy::encodeBinEP(uint32_t binValue)
{
if (!m_bitIf)
{
m_fracBits += 32768;
return;
}
m_low <<= 1;
if (binValue)
m_low += m_range;
m_bitsLeft++;
if (m_bitsLeft >= 0)
writeOut();
}与上述同样的步骤对其进行编码。
根据标准,语法元素cu_qp_delta_abs的后缀值suffixVal = cu_qp_delta_abs − 5。void Entropy::codeDeltaQP(const CUData& cu, uint32_t absPartIdx)
{
int dqp = cu.m_qp[absPartIdx] - cu.getRefQP(absPartIdx);
int qpBdOffsetY = QP_BD_OFFSET;
dqp = (dqp + 78 + qpBdOffsetY + (qpBdOffsetY / 2)) % (52 + qpBdOffsetY) - 26 - (qpBdOffsetY / 2);
uint32_t absDQp = (uint32_t)((dqp > 0) ? dqp : (-dqp));//语法元素cu_qp_delta_abs的值
uint32_t TUValue = X265_MIN((int)absDQp, CU_DQP_TU_CMAX);//语法元素的前缀值
writeUnaryMaxSymbol(TUValue, &m_contextState[OFF_DELTA_QP_CTX], 1, CU_DQP_TU_CMAX);//使用截断一元码(TU)二元化方法将前缀转换为二元码,在对每一位比特进行常规编码。
if (absDQp >= CU_DQP_TU_CMAX)
writeEpExGolomb(absDQp - CU_DQP_TU_CMAX, CU_DQP_EG_k);////使用EGK二元化方法将后缀转换为二元码,在对每一位比特进行旁路编码。
if (absDQp > 0)
{
uint32_t sign = (dqp > 0 ? 0 : 1);
encodeBinEP(sign);////对符号进行旁路编码
}
}codeDeltaQP函数中判断当absDQp>=CU_DQP_TU_CMAX(5)时也就是存在后缀值时对其进行编码。
标准中确定使用零阶指数哥伦布编码对其进行二值化。该过程在writeEpGolomb函数中完成,传入的参数第一个就是后缀值,第二个参数值CU_DQP_EG_k(0)表示指数哥伦布编码的阶数。void Entropy::writeEpExGolomb(uint32_t symbol, uint32_t count)
{
uint32_t bins = 0;
int numBins = 0;
while (symbol >= (uint32_t)(1 << count))
{
bins = 2 * bins + 1;
numBins++;
symbol -= 1 << count;
count++;
}
bins = 2 * bins + 0;
numBins++;
bins = (bins << count) | symbol;
numBins += count;
X265_CHECK(numBins <= 32, "numBins too large\n");
encodeBinsEP(bins, numBins);
}函数中变量bins代表二值化后的二进制串,numBins就表示二进制串的长度。首先讲解下无符号数的零阶指数哥伦布编码的原理:分为前缀码和后缀码,计算M=log2(V+1),且向下取整,表示前缀码中‘1’的个数,最后加上‘0’得到前缀码,计算INFO=V+1-2的M次,它的二进制串就是后缀码。
简单点表示就是前缀码最后一个‘1’为分界线,前面有n个零,且满足 V-2的n-1次+...+2的0次<2的n次, 而V-2的n-1次+...+2的0次 得到的结果的二进制串就是后缀码。x265中也是利用这一点,while循环中就确定了前缀码中‘1’的个数,并且symbol已经被减去了2的幂次求和,输出分界‘1’,然后将bins左移count(n)位,填入symbol,完成二值化。
将二进制串bins和长度numBins传入encodeBinEP函数实现旁路编码。void Entropy::encodeBinsEP(uint32_t binValues, int numBins)
{
if (!m_bitIf)
{
m_fracBits += 32768 * numBins;
return;
}
while (numBins > 8)
{
numBins -= 8;
uint32_t pattern = binValues >> numBins;
m_low <<= 8;
m_low += m_range * pattern;
binValues -= pattern << numBins;
m_bitsLeft += 8;
if (m_bitsLeft >= 0)
writeOut();
}
m_low <<= numBins;
m_low += m_range * binValues;
m_bitsLeft += numBins;
if (m_bitsLeft >= 0)
writeOut();
}第一个if语句是通过估计的方法实现编码,这里就不管了。
函数中通过while循环逐个传入字节,应该是为了控制码流,这里不进行解释。先看旁路编码的流程图
循环中以8位为一个单位进行算术编码,首先编码高8位,流程图中需要逐位完成的上半部分,函数中直接一步完成,也就是直接将L左移8位,然后L=L*R,两者的结果是相同的。调整完变量后,由writeOut函数根据L来输出码流。while循环后的部分步骤相同,只是numBins<8。
最后是对符号位的编码,非常简单,encodeBinEP(sign),对其进行旁路编码 void Entropy::encodeBinEP(uint32_t binValue)
{
if (!m_bitIf)
{
m_fracBits += 32768;
return;
}
m_low <<= 1;
if (binValue)
m_low += m_range;
m_bitsLeft++;
if (m_bitsLeft >= 0)
writeOut();
}与上述同样的步骤对其进行编码。
相关文章推荐
- x265对语法元素cu_qp_delta_abs的编码(前缀部分)
- QP编码标准-对AN_QL_Coding_Standard文档的总结(部分)
- x265对变换系数的编码(最后一个非零系数的位置编码部分)
- 英语构语法(前、后缀部分)
- homerHEVC代码阅读(40)——熵编码(4)对语法元素进行编码并更新上下文模型
- python-第一课-入门语法(1)-基础部分
- Linux下利用json-c从一个json数组中提取每一个元素中的部分字段组成一个新json数组
- C#部分语法总结
- linux3.0内核KDB调试:无法获取部分符号
- 有符号数在计算机内的编码
- DOCTYPE元素语法
- Delphi笔记(整理)-符号和基本语法
- PYTHON中的语法元素(续)--Python(8)
- @ 符号 在java中是什么语法 代表什么
- HTML 特殊符号编码对照表
- html dl dt dd标签元素语法结构与使用
- Python语法元素入门
- HTML5新语义元素_部分
- 816x部分编码参数分析
- 如何删除动态数组的指定元素 - 回复 "Splendour" 的部分问题