AVI视频播放——STM32F769I 图像处理能力评测之四
硬件平台:STM32F769IDISCOVERY软件开发平台:Keil 5.1工具:SD卡,容量8G,Class10(10MB/S)AVI文件分析:AVI是音频和视频交错的文件,就是可以将视频和音频交织在一起进行同步播放。AVI视频的编码器非常多,如MPEG4、XVID、H.264和MJPEG等等。我这里使用的AVI文件的编码器是MJPEG,这样每一个视频帧文件都是一张JPEG图片,正好可以利用硬件解码器进行解码。AVI文件的音频编码器也有很多种格式,比如:MP3、AC3、PCM、AAC等等。这里我使用的是无编码的PCM数据格式,这样可以直接将读到的数据送往音频处理模块,而无须经过复杂的转换,节省时间,使视频播放更加流畅。AVI文件是基于RIFF文件结构,最常见的有两种数据单位,一种是chunk块,一种是LIST列表。整个RIFF文件的结构如下所示:RIFF字段+数据大小+AVI字段----LIST字段+数据大小+hdrl字段--------avih字段+数据大小+内容--------LIST字段+数据大小+strl字段------------strh字段+数据大小+内容------------strf字段+数据大小+内容------------strd字段+数据大小+内容(可选)--------LIST字段+数据大小+strl字段------------strh字段+数据大小+内容------------strf字段+数据大小+内容------------strd字段+数据大小+内容(可选)----LIST字段+数据大小+INFO字段+视频编码器相关信息----JUNK字段+数据大小+无用的数据----LIST字段+数据大小+movi字段+音频、视频数据----idx1字段+数据大小+ 每帧音频、视频数据大小和在文件中的偏移地址(可选)由上图可以看到,一个AVI RIFF文件由以下组成:RIFF文件头、hdrl列表(AVI文件的数据格式)、INFO列表、movi列表(AVI的视音频序列数据),可选索引块。我们这次解码用的AVI文件,视频采用MJPEG编码,音频采用PCM编码,现在着重分析这种类型的文件。RIFF头:在文件开始的前12个字节,如下图所示:
前4个字节为RIFF,代表这是一个RIFF结构体的文件。中间四个字节为RIFF结构数据大小,注意不包括前面8个字节(加上前面8个字节等于AVI文件大小),后面4个字节代表这是一个AVI文件。hdrl列表:嵌套了一系列块和子列表,一个avih块,一个或多个strl子列表。文件偏移地址0x0c--0x0f:LIST字符。文件偏移地址0x10--0x13:hdrl列表数据大小(不包括前面8个字节)。文件偏移地址0x14--0x17:hdrl字符。avih块:记录AVI文件的全局信息,是hdrl列表的子块。文件偏移起始地址:0x18。数据结构如下所示:文件偏移地址0x18--0x1B:avih字符。文件偏移地址0x1c--0x1f:avih字块大小不包括前面8个字节)。文件偏移地址0x20--0x23:显示每帧所需要的时间(单位us)文件偏移地址0x24--0x27:最大数据传输率。文件偏移地址0x28--0x2B:数据填充的粒度。文件偏移地址0x2C--0x2F:AVI文件的全局标记,比如是否含有索引块等。文件偏移地址0x30--0x33:视频帧总数。文件偏移地址0x34--0x37:为交互格式指定初始帧数(非交互格式应该指定为0)文件偏移地址0x38--0x3b:本文件包含的流的个数文件偏移地址0x3C--0x3F:建议读取本文件的缓存大小文件偏移地址0x40--0x43:视频图像的宽(以像素为单位)文件偏移地址0x44--0x47:视频图像的高(以像素为单位)文件偏移地址0x48--0x57:保留strl列表:中至少包含一个strh块和一个strf块。文件中有多少个流,就对应有多少个strl 列表。对于正常的AVI文件应该包含视频流和音频流文件,但是有的AVI文件却只有一个流文件,要么是视频流,要么是音频流。两种流列表出现的先后顺序不是固定的,第一个可以是视频流,也可以是音频流,但是两种流数据的结构是相同的。文件偏移地址0x58--0x5b:LIST字符。文件偏移地址0x5c--0x5f:strl列表数据大小(不包括前面8个字节)。文件偏移地址0x60--0x63:strl字符。strh块:用于描述流的头信息,是strl列表的子块。数据结构如下图所示:无论是音频流还是视频流,播放时长 = dwLength /dwRate / dwScale。选择最大值为AVI视频文件播放的总时长。
strf块:该块用于描述流的具体信息,是strl列表的子块。对于视频流,用于描述位图信息,对于采用MJPEG编码的视频,这段信息不重要。对于音频流,描述音频的相关信息,包括声道数,以及采样率等等。对于音频流,数据结构如下所示:
INFO列表:描述编码该AVI文件的程序信息,里面包含一个ISFT块。对我们来说,这段信息不重要。JUNK块:主要用于内部数据的对齐,都是些无用的信息,可以直接跳过。movi列表:存放音频、视频数据块,音频、视频数据块在该列表中交错方式存放着。音频数据块的结构为:01wb+音频数据块的大小+音频数据。视频数据块的结构:00db(00dc)+ 视频数据块的大小+视频数据。其中01wb—代表音频数据,00db--未压缩的视频数据,00dc--压缩的视频数据。idx1索引块:描述音视频数据的索引块信息,该内容是可选的。数据结构为:idx1+索引块数据大小+索引块数据。索引块数据有两种格式,一种为视频数据索引:00dc+4字节描述是否为重要帧(重要帧:0x00000010,无关帧:0x00000000)+4字节偏移地址(相对于movi列表的偏移地址)+视频数据大小;一种为音频数据索引:01wb+4字节描述是否为重要帧(重要帧:0x00000010,无关帧:0x00000000)+4字节偏移地址(相对于movi列表的偏移地址)+音频数据大小。利用索引块可以方便的定位视频数据和音频数据,现在随便打开一个AVI文件,找到索引块位置如下图所示:
可以看到索引块的内容第一个位视频索引块信息,它在movi列表的偏移地址为4个字节。接下来找到movi列表,如下图所示:
由图上所知,movi列表开始的第一个数据块为视频数据,跟索引块刚好一一对应。视频数据开始的地址为:0x26f6,movi列表中movi字段的地址为:0x26f2,二者地址相减当好差4个字节,与视频索引块的偏移地址相对应。但这并不是真实数据的起始位置,需要在移动8个字节。最后总结下:真实数据的偏移地址 = movi字段的起始地址+视频索引块中偏移地址+8。对于音频索引块也是一样的。视频解码:对于我们来说,需要知道的AVI文件参数如下所示:1.AVI文件的大小。2.视频画面的宽度和高度。3.视频帧率和音频采样率4.视频帧总数及其每帧数据的偏移地址5.音频帧总数及其每帧数据的偏移地址6.音频的通道数7.文件播放总时长上面的几个参数可以从AVI文件中直接读取或者计算出来,有了以上的参数,我们就可以进行视频解码了。我这里使用SD卡(class10)存放AVI文件,为了让AVI视频播放更加流畅,我们要对SD卡的读数据进行测试,下面是测试结果:数据大小时间16K2ms32K4ms64K6ms128K10ms读取时间越短,那么AVI视频文件解码也就越快。视频解码流程大致如下:1.初始化系统时钟相关外设,配置系统时钟为200MHZ。2.初始SDRAM相关外设。3.初始化液晶屏相关外设。4.初始化SD卡相关外设,配置时钟为25MHZ,并安装FATFS文件系统。5.初始化音频相关外设。5.初始化JPEG硬件解码器相关外设。6.在SDRAM中开辟两个视频帧输入缓存器,每个大小为256KB,用于存放AVI文件的视频帧数据。开辟一个视频帧索引区,大小为512KB,结构为:视频帧数据偏移地址(4字节)+视频帧数据(4字节),用于存放所有的视频帧信息。开辟一个音频帧索引区大小为512KB,结构为:音频帧数据偏移地址(4字节),用于存放所有的音频帧信息。7.打开AVI文件,使能FATFS快速查找功能,获取解码的相关参数,并把索引块的信息分类填充到音频帧索引区和视频索引区,方便音频数据和视频数据的定位。8.开始解码前,将第一帧和第二帧视频数据分别填充到视频帧输入缓存器。同时将第一帧和第二帧视频数据分别填充到音频输入缓存器。9.开始解码,将视频帧输入缓存器1的内容传送到JPEG硬件解码器,等待解码完成。在等待的过程中,判断视频帧输入缓存器是否为空,如果是空的话,马上填充下一帧视频数据到视频帧输入缓存器。将音频帧输入缓存器1的内容传送到音频解码器,等待解码完成。在等待的过程中,判断视频帧输入缓存器是否为空,如果是空的话,马上填充下一帧视频数据到音频帧输入缓存器。10.音频和视频解码同步进行,视频解码完成后,显示图像。11.等待视频帧间隔时间到达,进行下一帧数据处理。如此循环往复,就可以播放AVI视频了。具体程序编写,可以参照我的程序。下面是解码720X480的视频,帧率12: