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

2023-11-16

《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视频编解码技术详解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • H.265/HEVC编码结构

    H 265 HEVC编码结构 为了增强各种应用下操作的灵活性以及数据损失的鲁棒性 H 265 HEVC在编解码的设计上添加了多种新的语法结构 相较于以往的视频编码标准 如H 264 AVC 这种新的语法架构使得H 265 HEVC在压缩效率
  • 除 ffmpeg x264 之外的 H264 编码器

    我正在开发的 iPhone 应用程序会在特定的用户定义的时间间隔内连续捕获图像 我正在寻找一种将这些图像组合成 H264 编码视频的方法 我在 Google 上做了一些研究 看起来我必须在 iPhone 上使用 ffmpeg mencode
  • OpenCV:FFMPEG:编解码器不支持标签 0x34363268/'h264'

    像在 Mac OS 10 13 6 上一样安装 opencv 后 conda install c conda forge ffmpeg conda install c conda forge opencv 并使用fourcc cv2 Vid
  • 如何用 SPS 和 PPS 数据填充 AVCodecContext 的“extradata”字段?

    问题是这样的 当解码 H264 流时ffmpeg 我可以获得SPS和PPS的原始数据 但我不知道如何将它们填充到extradata现场AVCodecContext 没有extradata 我无法正确解码帧 每次我打电话avcodec dec
  • 封装一个OpenH264 编解码H264视频文件的类

    下面是一个更新后的代码 增加了 H 264 编码的支持 在这个示例中 我使用了 OpenH264 的 ISVCEncoder 接口进行编码 请确保在项目中正确链接 OpenH264 库 并根据你的项目需要调整代码 include
  • 通过 ICodecAPI 为 H.264 IMFSinkWriter 编码器设置属性

    我试图通过检索 ICodecAPI 接口来调整通过 ActivateObject 创建的 H 264 编码器的属性 虽然我没有收到错误 但我的设置没有被考虑在内 代码在 Windows 10 下运行 我复制用于创建 IMFSinkWrite
  • 如何设置 VTCompressionSession 的 MaxH264SliceBytes 属性

    iOS VTCompressionSession有一个属性是kVTCompressionPropertyKey MaxH264SliceBytes 但是 我无法设置kVTCompressionPropertyKey MaxH264Slice
  • 将 mkv 转换为 h264 FFmpeg

    EDIT 这个问题已经变得非常流行 并且是搜索 convert mkv to h264 ffmpeg 的最佳结果之一 因此我认为对于任何偶然发现这个问题的人来说 添加这一点是适当的 而不是使用 ffmpeg i input mkv c v
  • 如何在iOS上通过硬件解码来解码H.264帧?

    我已经使用 ffmpeg 来解码从 ip cam 收到的每一帧 简短的代码如下所示 void decodeFrame unsigned char frameData frameSize int frameSize AVFrame frame
  • iOS 上通过 RTMP 的 H264 视频流

    经过一番挖掘 我发现了一个库 可以在写入 mp4 文件时从该文件中提取 NAL 单元 我正在尝试使用 RTMP 将此信息打包为 flvlibavformat and libavcodec 我使用以下方法设置视频流 void setupVid
  • 从 RTP 流中解码 h264 帧

    我正在使用 live555 和 ffmpeg 库从服务器获取和解码 RTP H264 流 视频流由 ffmpeg 编码 使用 Baseline 配置文件和 x264 param default preset m params veryfas
  • 如何用FFMPEG正确将H264封装成FLV?

    首先 标题中的 适当 指的是这个相关问题 https stackoverflow com questions 44952940 ffmpeg how to wrap h264 stream into flv container 其中的答案并
  • 使用 ffmpeg 将视频从 .264 转换为 .265 (HEVC)

    我看到关于这个主题的一些问题 但我仍然收到错误 我想要做的就是将库中的视频转换为 HEVC 以便它们占用更少的空间 我试过这个 ffmpeg i input mp4 c v libx265 output mp4 ffmpeg 似乎需要很长时
  • 如何在没有 MediaExtractor 的情况下使用 MediaCodec 进行 H264

    我需要在没有 MediaExtractor 的情况下使用 MediaCodec 并且我正在使用 FileInputStream 读取文件 目前它不起作用 它在屏幕上显示绿色的乱码图像 这是整个源代码 FileInputStream in n
  • 检测到损坏的 ffmpeg 默认设置

    我在使用 X264 Fourcc 编解码器的 VideoWrite 时遇到 ffmpeg 错误 我已经安装了所有依赖项 如何纠正此问题 我一直在使用的示例代码如下 VideoWriter oVideoWriter path mp4 CV F
  • 将 AVAssetWriter 与原始 NAL 单元结合使用

    我在 iOS 文档中注意到AVAssetWriterInput你可以通过nil为了outputSettings字典来指定输入数据不应重新编码 用于对附加到输出的媒体进行编码的设置 传递 nil 来指定不应重新编码附加的样本 我想利用此功能来
  • 有没有简单的方法来提取附件 b 格式的 h264 原始流?

    当我使用命令行使用 ffmpeg 提取视频流时 ffmpeg i 一些文件 vcodec copy an f rawvideo h264 什么 out h264 对于 Adob e Media Encoder 生成的某些媒体文件 只有 m4
  • 如何减少 MediaCodec 视频/avc 解码中的延迟

    我执行了一些简单的计时电影播放器 java https github com google grafika blob master src com android grafika MoviePlayer java in the Grafik
  • 如何减少 MediaCodec H264 编码器延迟

    我正在尝试使用 Android6 0 的 MediaCodec 将 h264 实时低延迟编码为流 编码器大约有 6 帧延迟 我想知道如何减少 代码来自屏幕记录 cpp https android googlesource com platf
  • 将 H264 视频转换为原始 YUV 格式

    是否可以使用 ffmpeg 从 H264 编码视频创建原始 YUV 视频 我想用 matlab 打开视频并逐帧访问 Luma Cb 和 Cr 分量 是的 您可以 您只需指定像素格式即可 要获取格式的完整列表 ffmpeg pix fmts

随机推荐

  • 错误:找不到或无法加载主类

    可能存在的问题 类路径错误 请确保你的IDE或构建工具正确配置了项目的类路径 并且能够找到 com coll ApiApplication 类所在的位置 可以检查项目的配置文件 如pom xml 或类路径设置 确保类被正确地包含在项目中 编
  • 【转】Configuring VM Acceleration on Linux

    Configuring VM Acceleration on Linux Linux based systems support virtual machine acceleration through the KVM software p
  • texlive下载速度慢(完美解决)

    在使用latex之前 都需要下载texlive 这个过程十分煎熬 官网下载 Index of CTAN systems texlive Images bjtu edu cn 清华源 Index of CTAN systems texlive
  • nodejs koa

    第一步 如何写一个基于node的hello world 创建新的文件夹nodejsdemo 在cmd命令行中进入新建的文件夹nodejsdemo 运行 npm init y 生成package json文件 在cmd命令行中进入新建的文件夹
  • 验证性实验

    验证性实验 验证性实验 ipconfig 实作一 实作二 ping 实作一 实作二 tracert 实作一 ARP 实作一 实作二 实作三 DHCP 实作一 netstat 实作一 实作二 DNS 实作一 实作二 实作三 cache 实作一
  • 安装RapidDesign_v1.3.0.Cracked.DX10.3.Rio

    1 下载 https t00y com file tempdir A2NSZVRiXTRSZAZpVGBRLg4 V2IBNw47XTBQMFYzUGVXM1R BTZaNFZkUDRQaFczUmABMAIwDTg 2 解压 D rioc
  • Discuz!X模板代码解析--Header(头文件)

    Discuz X模板代码解析 Header 头文件 header html这个文件存储于common文件下 这个大家应该不陌生吧 我是每个DIV为小节来讲 头部的核心div我就不加if语句来讲解 因为代码太多了 我会在最下面给大家总结一下
  • 【数据分析入门】Seaborn[散点图、条形图、计数图、热力图、箱型图、小提琴图]

    这里写目录标题 一 数据 二 画布外观 2 1 Seaborn样式 2 2 上下文函数 2 3 调色板 三 使用 Seaborn 绘图 3 1 坐标轴栅格 3 2 各类图形 3 2 1 散点图 3 2 2 条形图 3 2 3 计数图 3 2
  • Java编写的公交查询系统 功能非常齐全 完整源码

    今天为大家分享一个java语言编写的教室管理系统 目前系统功能已经很全面 后续会进一步完善 整个系统界面漂亮 有完整得源码 希望大家可以喜欢 喜欢的帮忙点赞和关注 一起编程 一起进步 开发环境 开发语言为Java 开发环境Eclipse或者
  • Android机上跑linux(结果为Termux)

    文章目录 前言 Termux 前言 需求 我只想可以运行自己写的python程序 需要这个系统能有网络地址 能ssh 能连别人 也能别人连自己 能pip安装上合适的包 比如numpy 过程 ipad上搞ish 优点 垃圾IOS闭源生态 就它
  • 春秋云境:CVE-2022-22947

    春秋云境 CVE 2022 22947 文章合集 春秋云境系列靶场记录 合集 Spring Cloud Gateway spel 远程代码执行 CVE 2022 22947 漏洞介绍 Spring Cloud Gateway 远程代码执行漏
  • 永洪科技入选2023 商业智能应用案例TOP10

    8月13日 由DBC联合CIW CIS推出 经过两轮多维度评价 评议 评选 2023 商业智能应用案例TOP10 发布 永洪科技案例入选 电力行业数字化转型 数字化技术渗透至电力产业 发 输 变 配 用 各个环节 电力企业在复杂的产业环境中
  • 解决开发中Win Linux差别(持续更新)

    1 目录分隔符 Winxp Linux 解决办法 采用 File separator web目录 request getSession getServletContext getRealPath 数据库中图片目录用 serverInfo i
  • 【docker】将本地镜像push上传到dockerhub上,再从dockerhub上pull下来到本地,并运行的过程

    使用指示 完成本章操作 你需要有魔法 绿色 备注 红色或高亮 重点 要修改的地方 要注意的地方 注册dockerhub 登录官网 注册一个账号 需要用户名 邮箱 密码 前提是有魔法 不然邮箱会报错 然后在官网直接登录一下 在本地用命令行登录
  • ctfshow-菜狗杯-抽老婆

    任意文件读取 抽老婆 打开首先发现是一个图片下载 老婆们都很不错 感觉也没什么其他的东西 先F12看一下代码 发现有一处标注 感觉跟任意文件下载有关 一开始的错误思路 想着先扫一遍看看能不能发现啥 于是用dirsearch扫了一下 发现了
  • LAMP架构

    LAMP架构介绍 1 1LAMP平台概述 LAMP架构是目前成熟的企业网站应用模式之一 指的是协同工作的一整台系统和相关软件 能够提供动态web站点服务及其应用开发环境 LAMP是一个缩写词 具体包括Linux操作系统 Apache网站服务
  • 佳博 热敏打印机 ESCPOS 指令研究

    Test txt内容 参考打印到文档功能 初识打印机驱动 http www cnblogs com MrDing p 4078189 html 热敏打印头打印原理和C实现黑白位图的放大 https www jianshu com p c75
  • 一般报java.lang.NullPointerException的原因有以下几种

    一般报java lang NullPointerException的原因有以下几种 字符串变量未初始化 接口类型的对象没有用具体的类初始化 比如 List lt 会报错 List lt new ArrayList 则不会报错了 当一个对象的
  • 如何创建与框架无关的JavaScript插件

    本文旨在介绍个人在研读源码的时的一些浅薄理解 希望能对各位有一些帮助 本文将对所有可能遇到的知识点或细节进行注解或链接 跳转 以保证各位读者都能看懂 如果文中有说的不对的或者引导方向不正确的 欢迎各位批评指正 欢迎在评论区交流补充 感谢阅读
  • 【H.264/AVC视频编解码技术详解】八、 熵编码算法(2):H.264中的熵编码基本方法、指数哥伦布编码

    H 264 AVC视频编解码技术详解 视频教程已经在 CSDN学院 上线 视频中详述了H 264的背景 标准协议和实现 并通过一个实战工程的形式对H 264的标准进行解析和实现 欢迎观看 纸上得来终觉浅 绝知此事要躬行 只有自己按照标准文档