视频解码卡解码之后的数据解码是什么?是否是一帧一帧的图片数据解码呢?

本文涉及视频编解码最基础概念从工程应用角度出发,帮助理解和编写源码本文并不涉及深层次原理和算法。错误难免逐渐完善。

本文为作者原创转载请注明出處:

音视频领域早期采用模拟化技术,目前已发展为数字化技术数字化的主要好处有:可靠性高、能够消除传输及存储损耗,便于計算机处理及网络传输等数字化后,音视频处理就进入了计算机技术领域音视频处理本质上就是对计算机数据解码的处理。

图像信息經采集后生成的原始视频数据解码数据解码量非常大,对于某些采集后直接本地播放的应用场合不需要考虑压缩技术。但现实中更多嘚应用场合涉及视频的传输与存储,传输网络与存储设备无法容忍原始视频数据解码的巨大数据解码量必须将原始视频数据解码经过編码压缩后,再进行传输与存储

本文仅关注视频,不关注音频

引自参考资料[1]第1.5节

在所有的实际节目素材中,存茬着两种类型的信号分量:即异常的、不可预见的信号分量和可以预见的信号分量异常分量称为,它是信号中的真正信息其余部分稱为冗余,因为它不是必需的信息冗余可以是空间性的,如在图像的大片区域中邻近像素几乎具有相同的数值。冗余也可以是时间性嘚例如连续图像之间的相似部分。在所有的压缩系统编码器中都是将熵与冗余相分离只有熵被编码和传输,而在解码器中再从编码器嘚发送的信号中计算出冗余

帧内编码是空间域编码,利用图像空间性冗余度进行图像压缩处理的是一幅独立的图像,不会跨樾多幅图像空间域编码依赖于一幅图像中相邻像素间的相似性和图案区的主要空间域频率。

JPEG标准用于静止图像(即图片)只使用了空间域壓缩,只使用帧内编码

帧间编码是时间域编码,是利用一组连续图像间的时间性冗余度进行图像压缩如果某帧图像可被解码器使用,那么解码器只须利用两帧图像的差异即可得到下一帧图像比如运动平缓的几帧图像的相似性大,差异性小而运动剧烈的几幅圖像则相似性小,差异性大当得到一帧完整的图像信息后,可以利用与后一帧图像的差异值推算得到后一帧图像这样就实现了数据解碼量的压缩。时间域编码依赖于连续图像帧间的相似性尽可能利用已接收处理的图像信息来“预测”生成当前图像。

MPEG标准用于运动图像(即视频)会使用空间域编码和时间域编码,因此是帧内编码和帧间编码结合使用

一组连续图像记录了目标的运动。运动矢量用於衡量两帧图像间目标的运动程度运动矢量由水平位移量和垂直位移量二者构成。

目标的运动降低了图像间的相似性增加了差异数据解码量。而运动补偿则通过运行矢量来降低图像间的差异数据解码量

下图为运动补偿的示意图。当某一目标运动时其位置会變化但形状颜色等基本不变。编码器则可利用运动矢量减低图像差值解码器根据图像差值中的运动适量移动目标到合适的位置即可。假設图中是理想情况目标除移动位置外其他任何属性无任何变化,则两幅图像间的差值仅包含运动矢量这一数据解码量显然运动补偿可鉯显著减少图像差值数据解码量。

连续的三幅图像中目标块有垂直位置上的移动,背景块无位置移动我们考虑如何取得当前幀图像(画面N):
画面N中,目标向上移动后露出背景块。
画面N-1中因为背景块被目标块遮挡住了,因此没有背景块相关信息
画面N+1中,完整包含背景块的数据解码因此画面N可以从画面N-1中取得背景块。
如何可以得到画面N呢解码器可以先解码得到画面N-1和画面N+1,通过画面N-1中的目標块数据解码结合运动矢量即可得到画面N中的目标块数据解码通过画面N+1中的背景块数据解码则可得到画面N中的背景块数据解码。三幅画媔的解码顺序为:N-1, N+1, N三幅画面的显示顺序为:N-1, N, N+1。画面N通过其前一幅画面N-1和后一幅画面N+1推算(预测predicted)得到,因此这种方式称为双向预测(或前面預测、双向参考)

I帧:I帧(Intra-coded picture, 帧内编码帧,常称为关键帧)包含一幅完整的图像信息属于帧内编码图像,不含运动矢量在解码时不需要参考其他帧图像。因此在I帧图像处可以切换频道而不会导致图像丢失或无法解码。I帧图像用于阻止误差的累积和扩散在闭合式GOP中,每个GOP的第一个帧一定是I帧且当前GOP的数据解码不会参考前后GOP的数据解码。

IDR帧:IDR帧(Instantaneous Decoding Refresh picture, 即时解码刷新帧)是一种特殊的I帧当解码器解码到IDR帧时,会将DPB(Decoded Picture Buffer指前后向参考帧列表)清空,将已解码的数据解码全部输出或抛弃然后开始一次全新的解码序列。IDR帧之后的图像不会参考IDR帧之前嘚图像

B帧:B帧(Bi-directionally predicted picture, 双向预测编码图像帧)是帧间编码帧,利用之前和(或)之后的I帧或P帧进行双向预测编码B帧不可以作为参考帧。

GOP(Group Of Pictures, 图像组)是一组連续的图像由一个I帧和多个B/P帧组成,是编解码器存取的基本单位GOP结构常用的两个参数M和N,M指定GOP中首个P帧和I帧之间的距离N指定一个GOP的夶小。例如M=1N=15,GOP结构为:IPBBPBBPBBPBBPBGOP有两种:闭合式GOP和开放式GOP:
闭合式GOP:闭合式GOP只需要参考本GOP内的图像即可不需参考前后GOP的数据解码。这种模式决萣了闭合式GOP的显示顺序总是以I帧开始以P帧结束
开放式GOP :开放式GOP中的B帧解码时可能要用到其前一个GOP或后一个GOP的某些帧。码流里面包含B帧的時候才会出现开放式GOP
开放式GOP和闭合式GOP中I帧、P帧、B帧的依赖关系如下图所示:

音频中DTS和PTS是相同的。视频中由于B帧需要双向预测B帧依赖於其前和其后的帧,因此含B帧的视频解码顺序与显示顺序不同即DTS与PTS不同。当然不含B帧的视频,其DTS和PTS是相同的下图以一个开放式GOP示意圖为例,说明视频流的解码顺序和显示顺序
采集顺序指图像传感器采集原始信号得到图像帧的顺序
编码顺序指编码器编码后图像帧的顺序。存储到磁盘的本地视频文件中图像帧的顺序与编码顺序相同
传输顺序指编码后的流在网络中传输过程中图像帧的顺序。
解码顺序指解码器解码图像帧的顺序
显示顺序指图像帧在显示器上显示的顺序。

采集顺序与显示顺序相同编码顺序、传输顺序和解码顺序相同。 圖中“B[1]”帧依赖于“I[0]”帧和“P[3]”帧因此“P[3]”帧必须比“B[1]”帧先解码。这就导致了解码顺序和显示顺序的不一致后显示的帧需要先解码。

大家还是尽量下载附件查看帖孓里面好多格式都乱了……我再慢慢改吧。

移植libmad之前必须先调通SD卡硬件驱动学会使用znFAT的基本读数据解码功能(参考znFAT实例之“08文件定位读取数据解码”)。

Libmad原来是在Linux下面使用的我们需要做一些修改:

while (0) 这一句注释掉(如上图)

对于libmad文件的修改比较简单,也并非移植的重点夶家可以直接使用我们修改过的libmad文件。经过修改后的libmad文件如图:

         关于MP3格式的资料很多但很少有拿具体文件来分析的。我们这里结合手上嘚资料使用具体文件来分析分析。这里只进行简单介绍MP3内容主要分为三个部分:

为了方便研究MP3格式,我将一个SD卡格式化并放入一个MP3攵件,然后通过WinHex进行查看:

最开头十个字节为ID3标签头其结构如下:(来自pdf文档《mp3文件格式》)

。而后面的数据解码从0x开始中间经过0x400=1024(10),说明這个标签部分应该是有1024个字节所以说:那个计数应该没有包含标签头这十个字节。为了验证我们的猜想再拿一个文件来试试看。

计算嘚到246.但是数据解码一部分为0之后又从0x开始的距开头0x256个字节。验证了我们的猜想

关于ID3V2标签我们就介绍到这里。如需更深入了解可自巳看看《mp3文件格式》

中间的核心数据解码就是一个一个帧。每个MP3帧(frame)都有一个帧头(frameheader)长度为4Byte(后文用B代表字节Byte,b代表位bit)帧头后面可能有兩个字节的CRC校验位(这两个字节是否存在决定于frameheader第16b。0-无CRC校验位1-有crc校验位),接着就是frame实体数据解码了帧的格式如下:

解析这些数据解碼我们可以看到一些最基本的信息。我们这个帧是没有CRC校验的所以接着的数据解码就直接是所谓的MAIN_DATA。这个MAIN_DATA到底有多大我们可以通过上媔的参数计算得到。

1 无论帧的长度为多长每帧的播放时约为26ms

我们的版本是MPEG1所以我们计算如下:

这个部分的数据解码比较复杂,经过了一些压缩我们已经不能看到具体的意义了。只能基本看到数据解码被“FF FB 92 00”分为一堆一堆的每堆被“LAME3.90(alpha)”分为两块,LAME3.90后面的数据解码是一堆标記信息。具体内容已经被加密得面目全非不必深究。下面来看看libmad部分

Libmad解码mp3的具体过程中有些地方涉及到的知识还是比较深涩的。有兴趣的可以自己研究研究我们来介绍一些简单的概念。

mad_frame  记录MPEG帧解码后PCM数据解码的数据解码结构其中的mad_header用来记录帧的基本信息,比如MPEG层数、声道模式、流比特率、采样比特率声道模式包括单声道、双声道、联合立体混音道以及一般立体声。

我们可以再stream.h中找到mad_stream的定义:(在基于zn-X开发板的例子中已经加上比较详细的注释)

这里就不详细列出,大家可以到工程中查看libmad解码的流程是:

一、利用LIBMAD实现功能

为了方便验证解码是否正确,我们决定将解码得到的信息存入一个文件中然后利用cooledit进行查看。

要实现这个功能我们必须要从SD卡中读取出相应的數据解码这里我们采用南哥的znFAT

这就是解码的第一步,读入数据解码:

起始read_num和ReadStart都为0。至于remaining的值就是解码之后剩下不足一帧的数据解码嘚长度。我们将其放入InputBuffer(输入缓冲区)头然后再从SD卡中读取数据解码填满InputBuffer进行解码。

这之后我们将InputBuffer移交给Stream结构体。读入数据解码的第┅步就完成啦!

实现解码的是mad_frame_decode这一句如果返回值非零,表示出现错误对错误进行一些处理。

这个部分的代码就这么一句

每一帧解码絀来的PCM数据解码有左右声道各1152个。

程序运行完成后SD卡中会多出一个pcm.txt文档。我们打开CoolEdit

就可以听到解码出来的歌曲啦!


我要回帖

更多关于 数据解码 的文章

 

随机推荐