【H.264/AVC视频编解码技术详解】八、 熵编码算法(2):H.264中的熵编码基本方法、指数哥伦布编码

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 《H.264/AVC视频编解码技术详解》视频教程已经在“CSDN学院”上线,视频中详述了H.264的背景、标准协议和实现,并通过一个实战工程的形式对H.

《H.264/AVC视频编解码技术详解》视频教程已经在“CSDN学院”上线,视频中详述了H.264的背景、标准协议和实现,并通过一个实战工程的形式对H.264的标准进行解析和实现,欢迎观看!

“纸上得来终觉浅,绝知此事要躬行”,只有自己按照标准文档以代码的形式操作一遍,才能对视频压缩编码标准的思想和方法有足够深刻的理解和体会!

链接地址:H.264/AVC视频编解码技术详解

GitHub代码地址:点击这里

本节视频免费

1. H.264中的熵编码基本方法

在成功从NAL Unit中获取到语法元素的码流之后,接下来就是对语法元素的码流进行解析。根据我们在前面的博文中所讲述的H.264编码框架图,经过预测、变换量化等步骤后得到的H.264语法元素将通过熵编码器压缩为符合标准的H.264码流。因此,为了还原各个语法元素,必须对码流使用熵编码的解码器进行解码。

在H.264的标准协议中,不同的语法元素指定了不同的熵编码方法。在协议文档中共指定了10种语法元素的描述符,这些描述符表达了码流解析为语法元素值的方法,其中包含了H.264标准所支持的所有熵编码方法:

语法元素描述符 编码方法
b(8) 8位二进制比特位串,用于描述rbsp_byte()
f(n) n位固定模式比特位串,从最左bit开始计算
u(n) 使用n位无符号整数表示,由n位bit换算得到
i(n) 使用n位有符号整数表示,由n位bit换算得到
ue(v) 使用无符号指数哥伦布编码
se(v) 使用有符号指数哥伦布编码
te(v) 使用截断指数哥伦布编码
me(v) 使用映射指数哥伦布编码
ce(v) 上下文自适应的变长编码
ae(v) 上下文自适应的二进制算术编码

2. 指数哥伦布编码

同上篇介绍的哈夫曼编码一样,指数哥伦布编码同样属于变长编码(VLC)的一种。指数哥伦布编码同哈夫曼编码最显著的一点不同在于,哈弗曼编码构建完成后必须在传递的信息中加入码字和码元值的对应关系,也就是编码的码表,而指数哥伦布编码则不需要。

(1). 指数哥伦布编码的分类

如上表指出,常用的指数哥伦布编码通常可以分为四类:

  • ue(v):无符号指数哥伦布编码;
  • se(v):有符号指数哥伦布编码;
  • me(v):映射指数哥伦布编码;
  • te(v):截断指数哥伦布编码;

其中无符号指数哥伦布编码ue(v)是其他编码方式的基础,其余几种方法基本可以由ue(v)推导得出。本文先从ue(v)来讲述指数哥伦布算法的原理,而后再看如何推导至其他编码方法。

(2). 无符号指数哥伦布编码ue(v)

ue(v)的码字可以分为三个部分:[prefix] 1 [surfix]。其中前缀码为n个bit长度的0,后缀码为表示实际数值的信息位,信息位的长度为前缀码中0的个数。指数哥伦布编码中前缀和后缀部分的长度根据码元数值来确定:

0阶指数哥伦布编码模板 适用码元值
1 0
0 1 x 1, 2
0 0 1 x x 3~6
0 0 0 1 x x x 7~14
0 0 0 0 1 x x x x 15~30
0 0 0 0 0 1 x x x x x 31~62
…… ……

在上标中编码模板的后缀部分,xx以二进制的形式表示解码后的数值。前缀0的长度以LeadingZeroBits表示,那么解码后数值为:codeNum = 2^LeadingZeroBits - 1 + (xxx)。(xxx)为二进制数值xxx的10进制表示。因此,指数哥伦布编码的码字与码元值的对应关系如下表:

指数哥伦布编码码字 码元数值
1 0
0 1 0 1
0 1 1 2
0 0 1 0 0 3
0 0 1 0 1 4
0 0 1 1 0 5
0 0 1 1 1 6
0 0 0 1 0 0 0 7
…… ……

例如,当使用指数哥伦布编码来表示数值codeNum = 10,那么其前缀0的长度为prefixLen = floor[log2(codeNum+1)] = 3,因此指数哥伦布码的前缀为 0 0 0。其后缀部分的二进制表示为codeNum+1-2^prefixLen = 11-8 = 3 = b(0 1 1),因此10的指数哥伦布编码码字为0 0 0 1 0 1 1。

又例如,当读取到指数哥伦布码0 0 0 0 1 0 1 0 1时,首先计算前缀0的个数,此处为4,然后越过中间的1,读取后面的0 1 0 1为后缀码。二进制0101表示为十进制为5,因此该指数哥伦布码解码后的数值为2^4-1+5 = 20。

无符号指数哥伦布编码是其余多种变形算法的基础,其余的比如有符号指数哥伦布编码、映射指数哥伦布编码、截断指数哥伦布编码都是由无符号指数哥伦布编码进一步处理得到的。

(3). 有符号指数哥伦布编码

有符号的指数哥伦布编码值是通过无符号的指数哥伦布编码的值通过换算得到的,其语法元素描述符为se(v)。每一个无符号指数哥伦布编码的数值通过固定的换算关系转换为有符号的值,其换算关系为:n = (-1)^(k+1) * Ceil(k/2)。下表表示了有符号和无符号指数哥伦布编码之间的换算关系:

codeNum syntax element value
0 0
1 1
2 -1
3 2
4 -2
5 3
6 -3
k (-1)^(k+1)*Ceil(k/2)

(4). 截断指数哥伦布编码

截断指数哥伦布编码的语法元素描述符为te(v)。当语法元素以te(v)解码时,首先需要判断的是语法元素的取值范围,假定为[0, x], x≥1。根据x的取值情况,语法元素根据下面不同情况进行解析:

  • 若x>1,解析方法同ue(v)相同;
  • 若x=1,语法元素值等同于下一位bit值的取反。

(5). 映射指数哥伦布编码

映射指数哥伦布编码的描述符为me(v),适用于预测模式为Intra_4x4, Intra_8x8或Inter的宏块的coded_block_pattern的编码。me(v)的映射方式并无指定的换算公式,通常由查表的方式进行。下表为H.264 spec文档的表9-4的一部分:

三. 指数哥伦布编码同哈夫曼编码的比较

指数哥伦布编码同前文中提到的哈夫曼编码都遵循了同一规律,即针对不同的码元分配了bit位长度不同的码字,因此各自都属于变长编码的一种。然而二者仍然具有较大的差别,具体如:

  1. 哈夫曼编码在编码过程中考虑了信源各个符号的概率分布特性,根据符号的概率分布进行编码,因此对于不同的信源,即使是相同的符号的哈夫曼编码的结果也是不同的;指数哥伦布编码针对不同的信源采用的编码是统一的,因此无论是什么样的输入,输出的编码后的数据都是一致的。
  2. 由于哈夫曼编码是针对信源特性进行的编码,因此在存储或传输编码后的数据之前必须在前面保存一份码表供解码段重建原始信息使用;而指数哥伦布编码不需要存储任何额外信息就可以进行解码。
  3. 由于未考虑信源的实际特性,指数哥伦布编码的压缩比率通常比较低,对于有些信息甚至完全没有压缩效果,输出数据比原始数据更大,在这一点上哈夫曼编码作为“最优编码”在效率上更高;然而由于哈夫曼编码运算较指数哥伦布编码更为复杂,且必须保存码表信息增加了传输负荷,也对压缩比率造成了不利影响。

实际上,对于视频压缩这样的需求而言,类似于哈夫曼编码所提供的压缩比率的优势远远不够,而且像H.264等编码标准都不会指望靠这样的方式来提高压缩比率。因此在实际的视频编码方法中使用的是指数哥伦布编码,但是只作为少数的辅助语法元素的编码以及多数语法元素的二值化方法。真正贡献了高压缩比还需要后面详述的CAVLC和CABAC等。

四. 0阶无符号指数哥伦布编码的实现Demo

程序代码如下:

// ExpColum.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <assert.h>

typedef unsigned char UINT8;

static int get_bit_at_position(UINT8 *buf, UINT8 &bytePotion, UINT8 &bitPosition)
{
    UINT8 mask = 0, val = 0;

    mask = 1 << (7 - bitPosition);
    val = ((buf[bytePotion] & mask) != 0);
    if (++bitPosition > 7)
    {
        bytePotion++;
        bitPosition = 0;
    }

    return val;
}

static int get_uev_code_num(UINT8 *buf, UINT8 &bytePotion, UINT8 &bitPosition)
{
    assert(bitPosition < 8);
    UINT8 val = 0, prefixZeroCount = 0;
    int prefix = 0, surfix = 0;

    while (true)
    {
        val = get_bit_at_position(buf, bytePotion, bitPosition);
        if (val == 0)
        {
            prefixZeroCount++;
        }
        else
        {
            break;
        }
    }
    prefix = (1 << prefixZeroCount) - 1;
    for (size_t i = 0; i < prefixZeroCount; i++)
    {
        val = get_bit_at_position(buf, bytePotion, bitPosition);
        surfix += val * (1 << (prefixZeroCount - i - 1));
    }

    prefix += surfix;

    return prefix;
}

int _tmain(int argc, _TCHAR* argv[])
{
    UINT8 strArray[6] = { 0xA6, 0x42, 0x98, 0xE2, 0x04, 0x8A };
    UINT8 bytePosition = 0, bitPosition = 0;
    UINT8 dataLengthInBits = sizeof(strArray) * 8;

    int codeNum = 0;
    while ((bytePosition * 8 + bitPosition) < dataLengthInBits)
    {
        codeNum = get_uev_code_num(strArray, bytePosition, bitPosition);
        printf("ExpoColumb codeNum = %d\n", codeNum);
    }

    return 0;
}

该例程的详细解读请观看视频教程:H.264/AVC视频编解码技术详解

目录
相关文章
|
20天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
38 3
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-19
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-19
43 2
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16
24 1
|
20天前
|
机器学习/深度学习 人工智能 算法
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-15
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-15
43 1
|
20天前
|
存储 人工智能 算法
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-18
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-18
33 0
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-17
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-17
54 0
|
15天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
1天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
2天前
|
存储 算法 决策智能
基于免疫算法的TSP问题求解matlab仿真
旅行商问题(TSP)是一个经典的组合优化问题,目标是寻找经过每个城市恰好一次并返回起点的最短回路。本文介绍了一种基于免疫算法(IA)的解决方案,该算法模拟生物免疫系统的运作机制,通过克隆选择、变异和免疫记忆等步骤,有效解决了TSP问题。程序使用MATLAB 2022a版本运行,展示了良好的优化效果。
|
1天前
|
机器学习/深度学习 算法 芯片
基于GSP工具箱的NILM算法matlab仿真
基于GSP工具箱的NILM算法Matlab仿真,利用图信号处理技术解析家庭或建筑内各电器的独立功耗。GSPBox通过图的节点、边和权重矩阵表示电气系统,实现对未知数据的有效分类。系统使用MATLAB2022a版本,通过滤波或分解技术从全局能耗信号中提取子设备的功耗信息。