一.实验原理
AVI文件格式是微软公司推出的,Windows操作系统上最常用的流媒体文件之一。AVI文件是一种最复杂的RIFF文件,现在常用的AVI文件有两种:AVI-1和AVI-2。在AVI-2文件中通常包含2个流,一个视频流和一个音频流(被称为标准AVI格式)。
一个AVI RIFF文件由3大部分组成:
- RIFF文件头
- hdrl列表
-avih子块
-strl子列表 - movi列表
文件有多少个流,hdrl列表中就有多少个strl子列表,strl子列表在hdrl中的次序就是流的序号。strl子列表由strh字块、strf字块、strd子块(可选)、strn子块(可选)构成。
movi列表中储存的则是流实际的数据,其中种类有:##db,##dc,##pc,##wb。其中“##”代表数据所属的流的序号。db代表未压缩的视频帧(DIB的简写),dc代表已压缩的视频帧(DIB compressed的简写);wb代表音频数据;pc代表调色板变化。
应注意的是,AVI RIFF文件格式只规定了文件的组成方式,即各种数据如何在文件中排列对等,对于文件中的数据并没有做任何编码格式的约束。即可理解为AVI格式只是个容器,其中可以放置多种编码格式的数据,可以是MPEG-4、h.264编码的,数据本身也可以未经压缩。
本次实验所用素材:对YUV文件,利用FFMPEG直接封装成的AVI文件。
利用VFW从AVI文件中提取RGB数据
VFW是微软公司为开发Windows平台下视频应用程序提供的软件工具包。我们利用VFW提供的应用程序编程接口(API)可以很方便地实现视频捕获、视频编辑、视频播放等功能。
- 句柄(Handle)
句柄是整个windows编程的基础。一个句柄是指使用的一个唯一的整数值,即一个四字节长的数值,来标志应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。应用程序通过句柄访问相应的对象信息。
以下为实验所用到的函数:(函数释义打*号需另外说明)
函数调用形式 | 函数形式 | 函数释义 |
---|---|---|
AVIFileOpen ( &avi_file, AVIFILE, OF_READ, NULL ) | STDAPI AVIFileOpen( PAVIFILE * ppfile, LPCTSTR szFile, UINT mode, CLSID pclsidHandler ); | 打开一个AVI文件并返回可处理它的接口。 |
AVIFileGetStream ( avi_file, &avi_stream, streamtypeVIDEO, 0 ) | STDAPI AVIFileGetStream( PAVIFILE pfile, PAVISTREAM * ppavi, DWORD fccType, LONG lParam ); | 函数返回与AVI文件所指定对的流接口的地址,这里第二个参数avi_stream为接下来处理流的句柄,类型为PAVISTREAM。 |
AVIStreamReadFormat ( avi_stream, 0, &bi, &lStreamSize) | STDAPI AVIStreamReadFormat( PAVISTREAM pavi, LONG lPos, LPVOID lpFormat, LONG * lpcbFormat ); | *这个函数通过指定的内存返回数据流的格式信息,比如对于视频流,这个buffer包含了一个BIMAPINFO结构,对于音频流,内存块包含了WAVEFORMATEX结构 |
AVIStreamInfo ( avi_stream, &str_info, sizeof(str_info) | STDAPI AVIStreamInfo( PAVISTREAM pavi, AVISTREAMINFO * psi, LONG lSize ); | 函数可以获取数据的一些信息,该函数返回一个AVISTREAMINFO结构,该结构包含了数据的类型压缩方法,建议的buffersize,回放的rate,以及一些description。 |
AVIStreamStart ( avi_stream ); | STDAPI_(LONG) AVIStreamStart( PAVISTREAM pavi ); | 函数用来获取第一祯包含的sample number。也可以通过AVIStreamInfo函数来获取这个信息,AVISTREAMINFO结构中包含了dwStart,可以通过AVIStreamStartTime宏来获取第一个sample。 |
AVIStreamLength ( avi_stream ); | STDAPI_(LONG) AVIStreamLength( PAVISTREAM pavi ); | 函数获取流的长度,同样可以通过AVIStreamInfo函数来获取长度 |
AVIStreamGetFrameOpen ( avi_stream, &bi_wanted ); | STDAPI_(PGETFRAME) AVIStreamGetFrameOpen( PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted ); | 函数用来获取未压缩的视频祯,这个函数创建了内存来获取未压缩的数据 |
AVIStreamGetFrame ( pgf, f+begin ); | STDAPI_(LPVOID) AVIStreamGetFrame( PGETFRAME pgf, LONG lPos ); | 函数用以压缩一个单独的视频祯,调用成功返回值为指向一帧数据的地址值,帧数据形式为打包好的DIB |