【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.264 RTSP 绝对时间戳

    是否可以从安讯士摄像机通过 RTSP 发送的 H 264 流中读取绝对时间戳 有必要知道相机何时拍摄该帧 谢谢 安德里亚 正如拉尔夫已经说过的 RTP 时间戳与随机时钟相关 它们仅用于计算两个帧 或一般的 RTP 数据包 之间的差异 为了将
  • H264 NAL 单元前缀

    我需要对 H264 NAL 单位分隔符前缀进行一些澄清 00 00 00 01 and 00 00 01 我正在使用 Intel Media SDK 生成 H264 并将其打包到 RTP 中 问题是到目前为止我只是在寻找00 00 00 0
  • 为什么从 avi 容器解码帧并将其编码为 h264/mp​​4 不起作用?

    我开始使用 ffmpeg 我想将 avi 文件转换为 mp4 h264 文件 我读过很多帖子 包括this 但我找不到任何好的示例如何将帧保存到 mp4 文件 下面的代码是简化的代码 它从 avi 文件中解码帧并将其编码为 H264 mp
  • 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
  • FFmpeg 无需解码视频即可获取运动向量

    我想访问 h264 视频流的运动向量而不解码视频 我知道这显示了视频和运动矢量 ffplay i myvideo avi flags2 export mvs vf codecview mv pf bf bb 如何避免解码整个视频以节省 CP
  • H264视频起始码的使用

    我对 H264 视频的起始代码 0x00 0x00 0x00 0x01 的使用有一般性问题 我不清楚这个起始代码的用法 因为在与 H264 视频相关的 RTP RFC 中没有参考 但我确实在网上看到了很多参考资料 特别是在 stackove
  • FFmpeg 从 UYVY422 转换为 YUV420P

    我有 UYVY422 格式的原始视频 我想将其转换为 YUV420p 我正在执行该命令 ffmpeg y r 25 0 f rawvideo s 1920x1080 pix fmt uyvy422 i input avi pix fmt y
  • 如何设置 VTCompressionSession 的 MaxH264SliceBytes 属性

    iOS VTCompressionSession有一个属性是kVTCompressionPropertyKey MaxH264SliceBytes 但是 我无法设置kVTCompressionPropertyKey MaxH264Slice
  • 使用 Android 低级 api 解码 H264 流

    我在 android 中使用 MediaCodec 低级 Api 来解码从 IP 摄像机接收到的 h264 原始流 来自 IP 摄像机的原始流 通过 TCP IP 连接接收 要解码流 我的代码是 Override protected voi
  • android mediacodec:实时解码h264 nals

    我正在尝试使用 android 低级媒体 api 实时解码 h264 nals 每个 nal 包含一个完整的帧 所以我希望在用我的 nal 提供输入并调用之后dequeueOutputBuffer它会 立即 当然有一点延迟 显示我的框架 但
  • 如何在iOS上通过硬件解码来解码H.264帧?

    我已经使用 ffmpeg 来解码从 ip cam 收到的每一帧 简短的代码如下所示 void decodeFrame unsigned char frameData frameSize int frameSize AVFrame frame
  • Android MediaCodec 似乎可以缓冲 H264 帧

    我正在手动读取 RTP H264 流并将 H264 帧传递给 Android MediaCodec 我使用 markerBit 作为框架的边框 MediaCodec 与 OpenGL 纹理 SurfaceTexture 绑定 一般来说 一切
  • H.264 over RTP - 识别 SPS 和 PPS 帧

    我有来自 IP 摄像机的原始 H 264 流 封装在 RTP 帧中 我想将原始 H 264 数据放入文件中 以便我可以将其转换为ffmpeg 因此 当我想将数据写入原始 H 264 文件时 我发现它必须如下所示 00 00 01 SPS 0
  • H264 中的 Elementary Stream 是什么意思

    我读了 Elementary Stream 的内容维基百科 http en wikipedia org wiki Elementary stream 我正在使用的工具 Live555 需要 H 264 视频基本流文件 因此 当从视频应用程序
  • 视频流基础设施

    我们想建立一个实时视频聊天网站 并正在寻找基本的架构建议和 或针对要使用的特定框架的推荐 以下是该网站的基本功能 大多数流媒体将由一个人通过网络摄像头等进行现场直播 通常由 1 10 人观看 但最多可能有 100 多名观众 音频和视频不必是
  • 使用 libavcodec 的 mpegts 容器中的原始 H264 帧

    我非常感谢对以下问题的帮助 我有一个带摄像头的小工具 可以生成 H264 压缩视频帧 这些帧将发送到我的应用程序 这些帧不在容器中 只是原始数据 我想用ffmpeg和libav函数创建一个视频文件 方便以后使用 如果我解码帧 然后对其进行编
  • Html5 视频和 Flash 方法

    研究 HTML5 视频标签 并研究哪些浏览器支持哪些视频文件类型 我最初的想法是事情变得比仅仅使用 Flash 更困难 我想知道是否有人已经找到一些骨架代码 与视频的开发方法相结合 来执行以下操作 如果闪光灯可用 请使用它 如果没有 请尝试
  • 将 H264 视频转换为原始 YUV 格式

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

    第一次来这里所以要温柔 我已经在给定的 H 264 字节流上工作了几个星期 一般注意事项 字节流不是来自文件 它是从外部源实时提供给我的 字节流使用 Android 的媒体编解码器进行编码 当将流写入扩展名为 H264的文件时 VLC能够正
  • 在 MediaFoundation 硬件 MFT 中设置更大的 GOP 大小

    我正在尝试直播通过桌面复制 API 捕获的桌面 H264 编码工作正常 除了桌面复制 API 仅在屏幕发生变化时才传送帧 但视频编码器希望以恒定的帧速率传送帧 因此 当没有触发屏幕更改时 我被迫保存之前的样本 以恒定的速率向编码器提供数据

随机推荐

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

    可能存在的问题 类路径错误 请确保你的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的标准进行解析和实现 欢迎观看 纸上得来终觉浅 绝知此事要躬行 只有自己按照标准文档