您的位置:首页 > 其它

AVI转YUV的详细过程以及注意事项

2011-11-12 15:08 246 查看


先放上这张图片,是让大家有一个直观的感受,avi就像一个容器,只要按照这个框架依次读取数据,就能很好的解析出数据来。鉴于本人习惯,我喜欢看图说话,所以接来下会放上很多avi格式的二进制图片,以便更好详细说明读取过程的信息。



                                                 (图1)

如图(1)所示,这是avi的二进制图,AVI文件利用AVI RIFF格式(RIFF(Resource Interchange FileFormat,资源互换文件格式)是微软公司定义的一种用于管理windows环境中多媒体数据的文件格式,)

构造RIFF文件的基本单元叫做数据块(Chunk),每个数据块包含3个部分,
  1、4字节的数据块标记(或者叫做数据块的ID)
  2、数据块的大小
  3、数据

整个RIFF文件可以看成一个数据块,其数据块ID为RIFF,称为RIFF块。一个RIFF文件中只允许存在一个RIFF块。RIFF块中包含一系列的子块,其中有一种字块的ID为"LIST",称为LIST,LIST块中可以再包含一系列的子块,但除了LIST块外的其他所有的子块都不能再包含子块。
  RIFF和LIST块分别比普通的数据块多一个被称为形式类型(Form Type)和列表类型(List Type)的数据域,其组成如下:
  1、4字节的数据块标记(Chunk ID)
  2、数据块的大小
  3、4字节的形式类型或者列表类型
  4、数据

以上说了这么多,可能有些新手还是不太了解,举例说明之:


图(2)
此处蓝线部分为整个avi大小。注

此处蓝线部分为整个avi大小。注

意:文件是从右往左读取,故而是(08 99 2B B6)=144255926字节~而我打开文件实际字节是144,255,934,这是因为前面的"RIFF"和本身这四个表示大小的数据字节没有算进去,故144255926+8=144 255 934。

紧接着后面四个字节表示AVI说明这是一个AVI格式的视频。

所有的AVI文件必须包含两个LIST块。这些块定义流格式和stream数据。AVI文件也可能包含一个索引块,此块定义文件中的数据块位置。包含上述组件的AVI文件的格式为:
RIFF ('AVI '
     LIST ('hdrl'
          )
     LIST ('movi'
            .
          )
     ['idx1'<AVI Index>]
     )



(3)

紧接着是就是一个LIST块:后面四个字节表示这个LISI的大小E0 0F 02 00===135 136字节怎么验证我说的对不对了。。。呵呵呵。。。看图说话.见图(4)这是下一个LIST块。他所在的字节处20FF0H=135152,由于是在该行的第四字节出,还需往后移动4字节:135156

,刚刚表示第一个LIST大小的四字节所在位置是:20字节处,故20+135 136(第一个LIST块大小)=135 156(第二个LIST块处得字节数)



(4)

接下来再回到图(3)

正如我们所说LIST"hdrl" 和LIST "movi"块用子块来表示其数据。接下来先介绍hdrl块

 LIST ('hdrl'
             'avih'(<Main AVI Header>)
             LIST ('strl'
                   'strh'(<Streamheader>)
                   'strf'(<Streamformat>)
                   'strd'(additional headerdata)
                       .
             )



(5)

列表的结构为:‘LIST’: listSize listType:listData,所以我们看到在LIST后面是大小,接着是本列表的具体类型hdrl,

再来看块的结构:ckID ckSize ckData ——ckID是一个表示块类型的四字符码;ckSize占用4字节,记录了整个块的大小;ckData为实际的块数据

所以,ckID在这里指的是avih,接着就是大小38 00 00 00=56字节,其实打开任何avi格式,你都可以发现此处都是38 00 00 00,因为。。。格式固定。。。如下:

typedefstruct {
    DWORD dwMicroSecPerFrame; //定义视频帧之间的时间间隔,这个值确定文件的总体时速。
DWORD  dwMaxBytesPerSec;   //定义文件的大致数据率,这个值确定要显示由此Main Header及流的Header chunks所含其他参数定义的AVI系列,系统必
须达到的传输速率(每秒字节数)

    DWORD dwReserved1;      //保留字
DWORD  dwFlags;             //包含文件中的任何标志字。(如有无”idx1”块,为确定数据的显示次序所要用到的索引,AVI文件是否Interlaced,是否含版权
                         信息等)
    DWORD dwTotalFrames;      //文件中含的数据帧个数。
    DWORD dwInitialFrames;       //对interlaced文件,确定在文件中在AVI系列初始帧之前所含的数据帧的个数。
    DWORD dwStreams;      //文件中所含流的个数,如既有视频又有音频的文件含两个流。
    DWORD dwSuggestedBufferSize; //定义读文件所建议的Buff大小,大于最大的Chunk的大小。
    DWORD dwWidth;            //定义AVI文件就像素而言的宽与高
    DWORD dwHeight;              //
    DWORD dwScale;            //与dwRate一起定义文件所要用到的通用时间刻度,dwRate/dwSale为每秒的采样时间刻度。
   DWORD  dwRate;             //
    DWORD dwStart;            //定义AVI文件的起始时间。通常设为0
    DWORD dwLength;              //定义AVI文件的长度。
}MainAVIHeader;

dwFlags

对应:
AVIF_HASINDEX:标明该AVI文件有"idx1"块   

  AVIF_MUSTUSEINDEX:标明必须根据索引表来指定数据顺序     

  AVIF_ISINTERLEAVED:标明该AVI文件是interleaved格式的   

  AVIF_WASCAPTUREFILE:标明该AVI文件是用捕捉实时视频专门分配的文件   

  AVIF_COPYRIGHTED:标明该AVI文件包含有版权信息   



                                        
(6)

主文件头后紧跟一个或几个"strl"块(每个数据流需要一个"strl" 块)。

每个"strl"块必须包含一个Stream头和Stream格式块。

Stream头由四个字符"strh"标记,Stream格式块由四个字符"strf"标记,此外"strl"块也可能包含一个流数据块,流数据块由四个字符”strd”来标识。

如图(6)LIST(列表)后面是表示大小,然后是strl,表示一条流,接着strh,表示stream头标识,接着是大小,一定是56字节,。。。格式固定嘛。。。

从vids开始后面表示的是数据,格式如下

Stream头的数据格式定义为:
typedefstruct {
FOURCC  fccType;     //若此流含的是video数据,此域值为"vids",若为audio数据,则为”auds”.
                                 //‘mids’(MIDI流)、‘txts’(文字流)

    FOURCC fccHandler;   //为四个字符,描述数据所用的压缩、解压缩算法。
    DWORD  dwFlags;       //包含流数据所用的任何标志字(如此流数据用到变化的调色板,只有在用户显式说明时才对此流数据进行render)
// 标记:是否允许这个流输出?调色板是否变化?

    DWORD  dwReserved1; //保留字// 流的优先级(当有多个相同类型的流时优先级最高的为默认流)
    DWORD  dwInitialFrames; //用于interlaced文件,定义在文件中在AVI系列初始帧之前所含的数据帧的个数。
    DWORD  dwScale;         //与dwRate一起定义回放速率。
    DWORD  dwRate;       //dwScale /dwRate = 每秒的采样数
    DWORD  dwStart;        //系列的起始时间
    DWORD  dwLength;      //系列的长度
    DWORD  dwSuggestedBufferSize;   //回放所需的Buff大小 // 读取这个流数据建议使用的缓存大小
    DWORD  dwQuality;    //数据质量标志字// 流数据的质量指标(0~ 10,000)
    DWORD  dwSampleSize;  //采样大小
}AVIStreamHeader;

依据我的经验,

FOURCC fccHandler;如果显示的是V210 就表示该视频未经过压缩,是一个未压缩的avi视频



在stream头(”strh”)块之后紧接着出现的是stream格式块("strf") ,它描述流中数据的格式。对视频流而言,这一块中的信息为一个BITMAPINFO结构(包含调色板信息),对音频流而言,这一块中的信息为一个WAVEFORMATEX或PCMWAVEFORMAT结构(WAVEFORMATEX结构为WAVEFORMAT结构的扩展版本)。

如果 strh子块是视频数据流,则 strf子块的内容是一个与windows设备无关位图的BIMAPINFO结构,如下:

typedef struct tagBITMAPINFO

{

 BITMAPINFOHEADER bmiHeader;

 RGBQUAD bmiColors[1]; //颜色表

}BITMAPINFO;

typedef struct tagBITMAPINFOHEADER

{

 DWORD biSize;

 LONG biWidth;

 LONG biHeight;

 WORD biPlanes;

 WORD biBitCount;

 DWORD biCompression;

 DWORD biSizeImage;

 LONG biXPelsPerMeter;

 LONG biYPelsPerMeter;

 DWORD biClrUsed;

 DWORD biClrImportant;

}BITMAPINFOHEADER;

如果 strh子块是音频数据流,则strf子块的内容是一个WAVEFORMAT结构,如下:

typedef struct

{

 WORD wFormatTag;

 WORD nChannels; //声道数

 DWORD nSamplesPerSec; //采样率

 DWORD nAvgBytesPerSec; //WAVE声音中每秒的数据量

 WORD nBlockAlign; //数据块的对齐标志

 WORD biSize; //此结构的大小

}WAVEFORMAT

//以上两幅图可以忽略。。。以免影响看文章的心情。。。

"strl"块也可能包含一个流数据块("strd"chunk),它一般在stream格式块("strf")之后,这一块的格式和内容由压缩或解压缩的驱动程序来定义。一般驱动程序利用这些信息来配置读写RIFF文件的应用程序,而不必解码它们。
接下来我们来看后面的



此处我也不太懂,,,望知道的留言解释,没有相关资料提到过这个indx块...不过貌似他很像索引。。。但是索引块是在最后啊,而且他后面的数据都是00000000000.。。。。。。通过他后面的四字节大小可以知道是00 00 FF F8=65528
我们就直接跨过65528字节大小到 下一处.



可以看到这是到了音频。。。你看到那个auds了吗?哈哈~~~其他都一样了~~
在此处强调一个细节:

AVI播放器将LIST "hdrl"块中的Stream头结构与LIST"movi"块中的stream数据通过利用"strl"块的次序联系起来.第一个"strl"块用于stream 0, 第二个用于stream 1,依次下去。例如,如果第一个"strl" 块描述wave audio数据,则wave audio数据在stream 0中。同样,如果第二个"strl" 块描述video数据,则此video数据在stream 1中。
所以你会看到第一个视频流中strl中:后面有一个标志是"00db",而这里是第二个strl,表示音频,固有一个"01wb"

接下来是就可以跳到数据部分了“movi”。。。好累啊~~改天写吧。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息