mpeg4 码流格式及判断关键帧

来源:互联网 发布:郑州淘宝运营 编辑:程序博客网 时间:2024/05/16 09:34
 

mpeg4 码流格式及判断关键帧

MPEG4码流视频关键帧头部16个字节,非关键帧8个字节(均包含四字节ID),说明如下:

关键帧:

字节

0

1

2

3

4

5

6

7

8

9

A

B

C

D

E

F

0

0

1

FB

XX

R

W&H

Date time

Length

含义

ID



图像大小

时间戳

帧长度

非关键帧

字节

0

1

2

3

4

5

6

7

0

0

1

FA

Length

含义

ID

帧长度

  • XX:保留。

  • RATE:帧率,低5位表示帧率,目前取值从130,高三位表示解交错,可选012其中0做解交错,2不做解交错。

  • WIDTHHEIGHT表示视频数据高度和宽度,一个字节最大256,所以存储的信息为真实高度和宽度的1/8

  • TIMESTAMP:帧时间戳:

struct DateTime

{

DWORDsecond :6; // 1-60

DWORDminute :6; // 1-60

DWORDhour :5; // 1-24

DWORDday :5; // 1-31

DWORDmonth :4; // 1-12

DWORDyear :6; // 2000-2063

};

非关键帧的时间戳是根据帧率和对关键帧的偏移计数计算出来的。

  • LENGTH:帧长度,低字节优先,不包括帧头长度(16字节或者8字节,这个需要注意)

  • H.264码流跟MPEG4的最大不同在于ID,关键帧ID000001FD,非关键帧ID000001FC


给一个例子:







测试解码器测试了很久,由于需要将H264和MPEG4的码流进行分析和判断,并逐帧输入解码器进行测试,如何正确的分析码流,并将Video送给我们的解码器做Decode的呢?耐着性子找了很多资料,主要也因为我本身对MPEG4和H264的码流的格式并不懂,自己在视频编码方面的积累也实在是太少了,所以也确实挺头疼的。后来就直接在网上找是否有对码流的各个部分意义的解释,开始搜索码流中的的StartCode。高兴的是,最终找到了一些有用的讯息,得以继续进行测试代码的撰写。

今天就把MPEG4码流的分析和它的I,P,B Frame的判定方法在这里简要记录一下吧,供日后的翻看和大家的参考。!

MPEG4码流分析:

0x00, 0x00, 0x01, 0xB0作为一个VOS的开始;

0x00, 0x00, 0x01, 0xB6作为一个VOP的开始,紧跟着VOP开始的,有一个2bit 的标志,用来表示这个Frame到底是一个 I Frame,P Frame,B Frame抑或是S Frame(GMS-VOP)

标志如下:

00: I Frame

01: P Frame

10: B Frame

11: S Frame

但是,有关这 2bit 是在0xB6的后面字节的高位还是低位,却没有很明确的描述。

于是又回头开始针对某个MPEG4编码好的文件开始分析,结果终于发现,判定方法如下:

1.可以写一个判定VOP,或者VOS开头的函数:

  1. static unsigned char *Find_VOP_Start(unsigned char *addrp, unsigned int FindSizes) 
  2.        while(pos < FindSizes) 
  3.        { 
  4.               if(addrp[pos] == 0x00) 
  5.                      if(addrp[pos + 1] == 0x00)   
  6.                             if(addrp[pos + 2] == 0x01)   
  7.                                    if(addrp[pos + 3] == 0xB0) 
  8.                                           break;//判断是否是VOS头; 
  9.                                    if(addrp[pos] == 0x00) 
  10.                                           if(addrp[pos + 1] == 0x00)   
  11.                                                  if(addrp[pos + 2] == 0x01)   
  12.                                                      if(addrp[pos + 3] == 0xB6) 
  13.                                                         break;//判断是否是VOP头 
  14. pos++; 
  15.        } 
  16.        if(pos< FindSizes - 4) 
  17.        {     
  18.               return addrp+pos+4; 
  19.        } 
  20.        else   
  21.               return NULL; 

2. 读一个MPEG4码流文件,然后利用刚才写的函数搜索StartCode:

  1. size_t nRead = fread(lpSrc, 1, lSize, fp); 
  2. fseek(fp, 0, SEEK_SET); 
  3. while (!feof(fp)) 
  4. unsigned char *p=Find_VOP_Start(lpSrc,lSize); 
  5. if (pos)    //pos为文件当前指针 
  6. length=pos-poslast+header;   //每帧长度为两个StartCode之间的字节数; 
  7. if (length<MAX_HEADERLEN)   
  8. //长度小于一定值,则不够一帧大小,表示在I frame前面的VOS,VO,VOL头 
  9. header=length; 
  10. else 
  11. header=0; 
  12. if (0==(nInput=fread(buffer,1,length,fp))) break//读取一帧大小数据, 
  13. //调用解码器接口,进行解码测试操作;…… 
  14. if (p==NULL) break
  15. //判定VOS是哪种profile 
  16. if (*(p-1)==0xB0) 
  17. if (*p==0xF5)  printf("VOS Header start,Advanced Simple Profile level 5!/n"); 
  18. else if (*p==0x1) printf("VOS Header start,Simple Profile level 1!/n"); 
  19. else if (*p==0x2)  printf("VOS Header start,Simple Profile level 2/n!"); 
  20.      …… 
  21. else  printf("VOS Header Start,Other profile@level/n!"); 
  22. if (*(p-1)==0xB6) 
  23. //判定是I,P,B ,S  Frame 
  24. if ((*p & 0xC0)==0x00)printf("VOP-I frame # %d, ", frames++); 
  25. else if ((*p & 0xC0)==0x40) printf("VOP-P frame # %d, ", frames++); 
  26. else if ((*p & 0xC0)==0x80) printf("VOP-B frame # %d, ", frames++); 
  27. else if ((*p & 0xC0)==0xC0) printf("VOP-S frame # %d, ", frames++); 
  28. else   printf("VOP-unknown type frame # %d, ",frames++); 
  29. //继续查找下一个VOS/VOP的StartCode 
  30. poslast=pos; 
  31. pos=pos+4;    

可以简单拿个图说明一下,下图中,第一个VOS的开头,第二个是一个I Frame:

MPEG4二进制码流

 

by lydia


本文地址:http://www.rosoo.net/a/201111/15315.html

0 0
原创粉丝点击