AVI 文件解析

结合avi视频文件头十六进制码分析AVI格式

 

这段时间要搞视频合成方面的东西,因此打算先弄明白avi视频的格式,介绍这方面内容的东西google一下一大堆,可是很悲剧,现在的人基本上都喜欢copy,内容基本来源于同一篇,对我没什么实质性的帮助。本来是希望通过看看一些avi合成的源码来分析avi的结构的,可是windows下的程序基本是调用directshow完成的,格式方法都封装好了。

  百思不得其解之余,还只自己分析吧。

  开始之前,先看看avi的文件格式图:

 

下面我们将结合一以下数据进行分析(该数据截取于是某个视频文件的文件头

[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0123456789012345]

000000000: 52 49 46 46 DC 6C 57 09 41 56 49 20 4C 49 53 54 |RIFF.lW.AVI LIST|

000000016: CC 41 00 00 68 64 72 6C 61 76 69 68 38 00 00 00 |.A..hdrlavih8...|e

000000032: 50 C3 00 00 00 B0 04 00 00 00 00 00 10 00 00 00 |P...............| c

000000048: A8 02 00 00 00 00 00 00 01 00 00 00 00 84 03 00 |................|

000000064: 40 01 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 |@...............|

000000080: 00 00 00 00 00 00 00 00 4C 49 53 54 74 40 00 00 |........LISTt@..|

000000096: 73 74 72 6C 73 74 72 68 38 00 00 00 76 69 64 73 |strlstrh8...vids|

000000112: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

000000128: 64 00 00 00 D0 07 00 00 00 00 00 00 A8 02 00 00 |d...............|

000000144: 00 84 03 00 10 27 00 00 00 00 00 00 00 00 00 00 |.....'..........|

000000160: 40 01 F0 00 73 74 72 66 28 00 00 00 28 00 00 00 |@...strf(...(...|

000000176: 40 01 00 00 F0 00 00 00 01 00 18 00 00 00 00 00 |@...............|

000000192: 00 84 03 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

000000208: 00 00 00 00 69 6E 64 78 F8 3F 00 00 04 00 00 00 |....indx.?......|

000000224: 01 00 00 00 30 30 64 62 00 00 00 00 00 00 00 00 |....00db........|

000000240: 00 00 00 00 0C 44 00 00 00 00 00 00 00 40 00 00 |.....D.......@..|

.

.

000017408: 4C 49 53 54 38 F9 56 09 6D 6F 76 69 69 78 30 30 |LIST8.V.moviix00|

000017424: F8 3F 00 00 02 00 00 01 A8 02 00 00 30 30 64 62  |.?..........00db|

"avih"子块:

typedefstruct_avimainheader{
  FOURCC fcc;//必须为‘avih’
  DWORD cb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)structsize
  DWORD dwMicroSecPerFrame;//视频帧间隔时间(以毫秒为单位)
  DWORD dwMaxBytesPerSec;//这个AVI文件的最大数据率
  DWORD dwPaddingGranularity;//数据填充的粒度
  DWORD dwFlags;//AVI文件的全局标记,比如是否含有索引块等
  DWORD dwTotalFrames;//总帧数
  DWORD dwInitialFrames;//为交互格式指定初始帧数(非交互格式应该指定为0)
  DWORD dwStreams;//本文件包含的流的个数
  DWORD dwSuggestedBufferSize;//建议读取本文件的缓存大小(应能容纳最大的块)
  DWORD dwWidth;//视频图像的宽(以像素为单位)
  DWORD dwHeight;//视频图像的高(以像素为单位)
  DWORD dwReserved[4];//保留

}AVIMAINHEADER;

          [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0123456789012345]
000000000: 52 49 46 46 DC 6C 57 09 41 56 49 20 4C 49 53 54 |RIFF.lW.AVI LIST|RIFF fileSize fileType LIST
000000016: CC 41 00 00 68 64 72 6C 61 76 69 68 38 00 00 00   |.A..hdrlavih8...|listSize listType avih  结构大小
000000032: 50 C3 00 00 00 B0 04 00 00 00 00 00 10 00 00 00 |P...............| 帧间时间  最大数据率 填充粒度 全局标记
000000048: A8 02 00 00 00 00 00 00 01 00 00 00 00 84 03 00 |................| 总帧数  交互帧数 流个数 建议缓存
000000064: 40 01 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 |@...............|width height  保留
000000080: 00 00 00 00 00 00 00 00

 

"strh"子块:

typedefstruct_avistreamheader{
  FOURCC fcc;//必须为‘strh’
  DWORD cb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
  FOURCC fccType;//流的类型:‘auds’(音频流)、‘vids’(视频流)、
  //‘mids’(MIDI流)、‘txts’(文字流)
  FOURCC fccHandler;//指定流的处理者,对于音视频来说就是解码器
  DWORD dwFlags;//标记:是否允许这个流输出?调色板是否变化?
  WORD wPriority;//流的优先级(当有多个相同类型的流时优先级最高的为默认流)
  WORD wLanguage;
  DWORD dwInitialFrames;//为交互格式指定初始帧数
  DWORD dwScale;//这个流使用的时间尺度
  DWORD dwRate;
  DWORD dwStart;//流的开始时间
  DWORD dwLength;//流的长度(单位与dwScale和dwRate的定义有关)
  DWORD dwSuggestedBufferSize;//读取这个流数据建议使用的缓存大小
  DWORD dwQuality;//流数据的质量指标(0~10,000)
  DWORD dwSampleSize;//Sample的大小
  struct{
      shortint left;
      shortint top;
      shortint right;
      shortint bottom;
  }rcFrame;//指定这个流(视频流或文字流)在视频主窗口中的显示位置
  //视频主窗口由AVIMAINHEADER结构中的dwWidth和dwHeight决定
}AVISTREAMHEADER;

4C 49 53 54 74 40 00 00 |........LISTt@..| LIST listSize

000000096: 73 74 72 6C  73 74 72 68 38 00 00 00 76 69 64 73 |strlstrh8...vidsstrl strh   结构大小  流类型(vids) 000000112: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|  流的处理者dwFlags  wPriority wLanguage 交互帧数 000000128: 64 00 00 00 D0 07 00 00 00 00 00 00 A8 02 00 00 |d...............| 000000144: 00 84 03 00 10 27 00 00 00 00 00 00 00 00 00 00 |.....'..........| 000000160: 40 01 F0 00

 

"strf"子块:

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;

     73 74 72 66 28 00 00 00 28 00 00 00 |@...strf(...(...|  strf

000000176: 40 01 00 00 F0 00 00 00 01 00 18 00 00 00 00 00 |@...............|

000000192: 00 84 03 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

000000208: 00 00 00 00

 

Index子块:

typedefstruct_avioldindex{

  FOURCCfcc;//必须为‘idx1’
  DWORDcb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
  struct_avioldindex_entry{
       DWORDdwChunkId;//表征本数据块的四字符码
       DWORDdwFlags;//说明本数据块是不是关键帧、是不是‘rec’列表等信息
       DWORDdwOffset;//本数据块在文件中的偏移量
       DWORDdwSize;//本数据块的大小
  }aIndex[];//这是一个数组!为每个媒体数据块都定义一个索引信息
}AVIOLDINDEX;

                       69 6E 64 78 F8 3F 00 00 04 00 00 00 |....indx.?......|  indx

000000224: 01 00 00 00 30 30 64 62 00 00 00 00 00 00 00 00 |....00db........|

000000240: 00 00 00 00 0C 44 00 00 00 00 00 00 00 40 00 00 |.....D.......@..|  

 

 

000017408: 4C 49 53 54 38 F9 56 09 6D 6F 76 69 69 78 30 30 |LIST8.V.moviix00|LISTlistSize listType indexBlock ( ix00 )

000017424: F8 3F 00 00 02 00 00 01 A8 02 00 00 30 30 64 62 |.?..........00db| .... 00db ( uncompressed video frame )

 

avi的index段

假如要将avi文件分成头、中、尾的话,RRFT开始到movi段之间应该算是头,movi算是中间,index就算是尾部了。index其实就是movi中的内容的索引,作用是在拖动视频进度条时,能让解码器迅速定位到要找的视频帧。索引以“idx1”开头,后面跟着的是整个索引的大小,其基本结构是:


--> struct  AVI_index_entry{
     unsigned  char  dwChunkId[ 4 ]; // 表征本数据块的四字符码
     DWORD dwFlags; // 说明本数据块是不是关键帧、是不是‘rec’列表等信息
     DWORD dwOffset; // 本数据块在文件中的偏移量
     DWORD dwSize; // 本数据块的大小
};

大家看一个实例:

idx1”就是索引的头

30 5b 00 00是索引的大小

大家看看实例的第二行,它们对应avi文件中的每一帧或者没一段音频:

30 30 64 63(“00dc”)是数据结构中的dwChunkId,当该段数据时音频时取(“01wb")

10 00 00 00 是dwFlags,关键帧取值为10 00 00 00,否则取值为00 00 00 00

04 00 00 00 是dwOffset;//本数据块在文件中的偏移量
BF 0E 00 00 是dwSize,对应帧的大小

  在最初合成avi视频的时候,我是没有添加index段的,视频一样可以播放。可是当你要拖动视频时,视频不会立刻跳到你所要的位置,而是加快播放速度,直到到达目标位置。

  目前遇到一个问题:当我将索引加进去avi以后,播放器需要有一个缓冲的过程,有点像用迅雷下载电影,可是没等电影下完,改过后缀就去播放的状况。问题解决以后再来补充吧

 

AVI的音频视频交叉规律

经过对avi视频的详细分析,发现音频视频的交叉有如下规律:

15 vedio

1段          audio

15vedio

1段          audio

16 vedio

1段          audio

15vedio

1段   audio

15vedio

1段   audio

16 vedio

1 audio

      也就是基本上是每15vedio就有一段的audio,可是每经过两个15段的vedio循环,就要有16段的vedio才能有一段audio

      另外还有一个规律就是,每一段audio大小都是一定的4096字节。

      这是某个特定文件的交叉规律,个人认为音视频交叉的频率跟帧率和音频频率有关,只要是按一定的比率来交叉就行,例如上面按每30帧视频放一段音频,然后音频的长度变为8192应该可以,有空再试试。

mpeg4视频中,I帧、p帧、B帧的判定

mpeg4的每一帧开头是固定的:00 00 01 b6,那么我们如何判断当前帧属于什么帧呢?在接下来的2bit,将会告诉我们答案。注意:是2bit,不是byte,下面是各类型帧与2bit的对应关系:

  00: I Frame
  01: P Frame
  10: B Frame 

为了更好地说明,我们举几个例子,以下是16进制显示的视频编码:

  00 00 01 b6 10 34 78 97 09 87 06 57 87 ……                             I帧

  00 00 01 b6 50 78 34 20 cc 66 b3 89 ……                                  P帧

  00 00 01 b6 96 88 99 06 54 34 78 90 98 ……                              B帧

下面我们来分析一下为什么他们分别是I、P、B帧

  0x10 = 0001 0000

  0x50 = 0101 0000

  0x96 = 1001 0100 

大家看红色的2bit,再对照开头说的帧与2bit的对应关系,是不是符合了呢?

下面给出一段c++代码供大家参考:

switch(buf[i] & (BYTE)0xc0)
{
case 0x00:
    //I Frame
    break;
case 0x40:
    //P Frame
    break;
case 0x80:
    //B Frame
    break;
default:
    break;
}

AVI的音频视频帧的开头

  Avi中视频音频交叉存放,每一帧视频都有一个视频帧头:30 30 64 63(这时二进制编码,字符是00dc),然后接着就是四个字节的帧长度,例如00 00 10 00,再往下就是帧的内容。

  Avi的音频也有一个音频头:30 31 77 6201wb),接着就是音频的长度,例如00 10 00 00,就是4096字节,接着就是音频的内容了。

 

g711格式

G711格式是纯粹的音频内容,没有头尾等任何附加的内容,拿过来可以直接用。

猜你喜欢

转载自blog.csdn.net/kemengli/article/details/48436289
今日推荐