MPEG4码流格式分析

参考:

MPEG4码流简单分析:http://blog.youkuaiyun.com/axdc_qa_team/article/details/4042762

关于MPEG4 码流(mpeg4 raw data)的格式分析:http://blog.youkuaiyun.com/vblittleboy/article/details/6695973

mpeg4 码流格式:http://blog.youkuaiyun.com/wuzhong325/article/details/7195171


=====================================================================

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开头的函数:

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

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

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

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

MPEG4二进制码流

 by lydia



=====================================================================

MPEG4码流开头往往如下:

      

    00 00 01 B0 F5 00 00 01 B5 09 00 00 01 00 00 00
    01 20 08 86 84 00 3F 18 58 21 20 A3 1F 00 00 01
    B2 58 76 69 44 30 30 36 32 00 00 01 B6

 

其格式为:

 

     MP4V type b0 size 5     //vosh
     MP4V type b5 size 5     //vo
     MP4V type 0 size 4    
     MP4V type 20 size 16    //vol
         ParseVol: timeBits 15 timeTicks 24000 frameDuration 1001
     MP4V type b6 size 5606   //vop

其宏定义为:

  #define MP4AV_MPEG4_VOL_START 0x20
  #define MP4AV_MPEG4_VOSH_START 0xB0
  #define MP4AV_MPEG4_VO_START 0xB5
  #define MP4AV_MPEG4_VOP_START 0xB6
  #define MP4AV_MPEG4_USER_DATA_START 0xB2

 

    使用格式工厂,看到如下

    根据标准,定义如下(http://bbs.lmtw.com/dispbbs.asp?boardID=20&ID=124481&star=2&page=15

    00 00 01 B0是视频对象序列开始标志(VISOBJSEQ_START_CODE),其后的数据只有一位F4,表示此视频对象编码序列编码的Profile与Level类型是XVID_PROFILE_AS_L4, Profile类型数值定义于xvid.h。

 

 

    00 00 01 B5是视频对象开始标志(VISOBJ_START_CODE),其后只有一位16进制数据09,从这一位数据可以获得视频对象版本号、视频类型和视频信号类型信息,详细介绍见图5-11。

 

 

    00 00 01 00是视频对象开始标志 (VIDOBJ_START_CODE),00 00 01 20是视频对象层开始标志(VIDOBJLAY_START_CODE),其后的11位16进制数据比较重要,解码所需要的VOP纵横比、视频对象形状和图像分辨率等数据都是从这11位数据获得的,详细介绍见图5-11,图中未标记用途的数据表示未使用。

 

 

    00 00 01 B2是用户数据开始标志(USERDATA_START_CODE),十六进制用户数据共有8位。

 

 

    00 00 01 B6是VOP开始标志(VOP_START_CODE),每个VOP编码数据都以VOP标识头开始,VOP标识头比较简单,如果用16进制数据表示其数值为00 00 01 B6。解码的时候,以00 00 01 B6来判定是不是一个VOP的开始,并从VOP标识头后的数据读取编码类型,量化值等参数后完成一帧VOP的解码。

    然后利用ffmpeg转码为mp4文件。

 

附:

    xvid yuv->m4v

    xvid_encraw.exe -i foreman_cif.yuv -w 352 -h 288
 -framerate 15 -csp i420 -o foreman_cif.m4v

    ffmpeg m4v->mp4

    ffmpeg -s cif -vcodec mpeg4 -i foreman_cif.m4v foreman_cif.mp4


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值