{ next_start_code() do
{ sequence_header(); do
{ group_of_pictures() ; //画面组 }while (nextbits()==GROUP_START_CODE) }while(nextbits()==SEQUENCE_HEADER_CODE) SEQUENCE_END_CODE }; 正是由于视频序列中存在很多开始码,或者称之为定位码、同步码。用来告诉解码器目前数据的区域信息,所以解码器才可以正确的处理各个数据区的数据,下面就是视频序列中的开始码的罗列: #define SEQ_END_CODE 0x000001b7 #define SEQ_START_CODE 0x000001b3 #define GOP_START_CODE 0x000001b8 #define PICTURE_START_CODE 0x00000100 #define SLICE_MIN_START_CODE 0x00000101 #define SLICE_MAX_START_CODE 0x000001af #define EXT_START_CODE 0x000001b5 #define USER_START_CODE 0x000001b2 这些开始码都是一些特殊的32bits的比特序列,在视频码流中不会出现的。他们的起着标志的作用,具体可以从名称上面看出来。 其中EXT_START_CODE和USER_START_CODE在每个层里面都会出现,用来标志扩展数据区和用户数据区,用来添加任意的数据,直到下一个开始码结束。 2.2画面组层(GOP) 在软件xmplay1.1中的定义 typedef struct GoP { BOOLEAN drop_flag; /* Flag indicating dropped frame. */ unsigned int tc_hours; /* Hour component of time code. */ unsigned int tc_minutes; /* Minute component of time code. */ unsigned int tc_seconds; /* Second component of time code. */ unsigned int tc_pictures; /* Picture counter of time code. */ BOOLEAN closed_gop; /* Indicates no pred. vectors to previous group of pictures. */ BOOLEAN broken_link; /* B frame unable to be decoded. */ char *ext_data; /* Extension data. */ char *user_data; /* User data. */ } GoP; 当然每个画面组层都是开始与标志码:GOP_START_CODE 该层次语法上的定义是 group_of_pictures
{ GOP_START_CODE Time_code; tc_hours,tc_minutes,tc_seconds,tc_pictures Closed_gop; Broken_link; Next_start_code; If(nextbits==extension_start_code)
{ Extension_start_code; While(nextbits()==”0000 0000 0000 0000 0000 0001”)
{ Group_extension_data; } next_start_code() } if(nextbits==user_data_start_code)
{ user_data_start_code while(nextbits()!=’0000 0000 0000 0000 0000 0001’)
{ user_data; } next_start_code() } do
{ picture() }while(nextbits==picture_start_code) } Mpeg流最终显示出来是一系列的画面,而画面组是mpeg流中可以独立编码的最小的单位,每个画面组由一个标题和一系列画面组成。GOP标题包含了时间和编辑的信息。 Mpeg画面组中必须至少有一个I帧画面,可以有数目可变的B帧和P帧画面,也可以没有P和B帧。画面组的第一幅编码画面是I画面,该画面之后跟随着任意数目的I或P画面,每对I、P画面之间可以插入任意数目的B画面。 画面组是画面的集合,每幅画面按照显示的顺序相邻。 画面组中的画面有两种排列顺序: 1.按比特流顺序 必须以I帧开头,后面可按任何的次序,跟上任意数目的I,P或B画面。 2.按显示顺序必须以I或B画面打头,且以I或P画面结束,最小的画面组由一个I画面组成。 从编码角度,可以精确的陈述的是,画面组以一个画面组标题开始,以最先出现的下一个画面组标题或者下一个序列标题或者序列结束码结束。 Mepg流中的标志码也就是开始码,对正确的分割和识别码流的成分起到了至关重要的作用。 2.3画面层(Pictures) 画面组层中的一幅幅画面就是画面层的数据了。包含了一幅画面的所有编码信息。一幅画面同样始于画面的标题。标题以画面开始码(PICTURE_START_CODE 0x00000100)打头。 解析画面单元的语法结构: picture()
{ picture_start_code temprol_reference /*时序编号,通常一组画面的编号都在1024以内,如果超过那么在1025幅画面出复位为0,重新计数。 */ picture_coding_type vbv_delay/*对于固定比特率的视频流,vbv_delay用与解码过程开始和随机存取之后,以保证在第一幅画面被显示之前,解码器 已经读到正确数目的比特数。*/ if((picture_coding_type==2) || picture_coding_type==3)
{ full_pel_foward_vector /*全象素前向矢量,给定前向矢量的精度,在P和B画面的标题中出现*/ forward_f_code } if(picture_coding_type==3)
{ full_pel_backward_vector back_f_code } while(nextbits()==’1’)
{ extra_bit_picture extra_information_picture } extra_bit_picture next_start_code if(nextbits()==extension_start_code)
{ extension_start_code while(nextbits()!=’0000 0000 0000 0000 0000 0001’)
{ picture_extension_data } next_start_code() } if(nextbits()==user_data_start_code)
{ user_data_start_code while(nextbits()!=’0000 0000 0000 0000 0000 0001’)
{ user_data } next_start_code() } do
{ slice() }while(nextbits()==slice_start_code) } 整个画面单元结构是这样的: typedef struct pict { unsigned int temp_ref; /* Temporal reference. */ unsigned int code_type; /* Frame type: P, B, I */ unsigned int vbv_delay; /* Buffer delay. */ BOOLEAN full_pel_forw_vector; /* Forw. vectors specified in full pixel values flag. */ unsigned int forw_r_size; /* Used for vector decoding. */ unsigned int forw_f; /* Used for vector decoding. */ BOOLEAN full_pel_back_vector; /* Back vectors specified in full pixel values flag. */ unsigned int back_r_size; /* Used in decoding. */ unsigned int back_f; /* Used in decoding. */ char *extra_info; /* Extra bit picture info. */ char *ext_data; /* Extension data. */ char *user_data; /* User data. */ } Pict; 可以看出整个pictures层的bit流结构中由标题和pictures数据组成。 标题中提供了必要的画面信息数据和运动矢量的信息。 2.4片层(Slice) 片是任意数目宏块组成的序列,其中宏块必须从画面的左上位置开始,按照光栅扫描的方向从左到右,从上到下排列。片中至少包涵一个宏块,片与片之间没有重叠,也没有间隙。 片层的解析语法: 首先给出识别出Slice层数据的头标slice_start_code 『 #define SLICE_MIN_START_CODE 0x00000101 #define SLICE_MAX_START_CODE 0x000001af 』 slice
{ slice_start_code /*从中可以计算出slice_vertical_position 片中第一个宏块,以宏块为单位的垂直位置*/ quantizer_scale /*设置量化步长尺寸。1-31*/ while(nextbits()==’1’)
{ extra_bit_slice ‘1’ extra_information_slice } extra_bit_scale ‘0’ do
{ macroblock() }while(nextbits()!=’0000 0000 0000 0000 0000 0000’) next_start_code() } typedef struct slice { unsigned int vert_pos; /* Vertical position of slice. */ unsigned int quant_scale; /* Quantization scale. */ char *extra_info; /* Extra bit slice info. */ } Slice; 每个片由一个开始码开始,开始后DC系数和矢量解码的预测值都被复位,片开始部位的位置的水平位置由片中第一个宏块的宏块地址决定。这些措施使得在一幅画面内任何一片都可以单独编码而不需要前一片的信息。当解码是出现错误,即可以从后继的片重新开始。 所以,当数据在无错的环境中,可以一幅画面就作为一片,但是如果是有错的环境,则每行宏块作为一片会更加合理。 表2 256×192画面内的片划分(每行宏块作为一个片,每个片的高度都是16pixels) 1开始 1结束 2开始 2结束 3开始 3结束 4开始 4结束 5开始 5结束 6开始 6结束 7开始 7结束 8开始 8结束 9开始 9结束 10开始 10结束 11开始 11结束 12开始 12结束 13开始 13结束 实际情况中片不宜太多,因为片标题,以及新片所需要尽心重新编码花费的开销很大。 片始于片标题,片标题又始于片开始码,片开始码是可以在一个范围中取得得,这个范围就是 #define SLICE_MIN_START_CODE 0x00000101 #define SLICE_MAX_START_CODE 0x000001af 片开始码得最后8为可以给出片得垂直位置,即以宏块为单位从画面顶部位置为1开始算起,片中第一个宏块的垂直位置。宏块有一个行号可以作为它得定位数据,这个行号的计算方法是:片垂直位置-1 宏块的垂直位置最大为175。片中第一个宏块的水平位置,可以由该宏块的地址偏移计算出来,所以不需要依赖画面内的任何其他的宏块的信息。 2.5宏块层(Macroblock) 宏块是包含16pixels*16lines的亮度分量部分,以及在空间位置上对应的两个8pixels*8lines的色度分量部分,一个宏块有4个亮度块和2个色度块。宏块可以指源图像或者重构图像的数据,或者是量化后的DCT系数。 宏块中块的顺序如下: 表1 宏块中块的排列 01 23 4 5 Y分量Cb分量Cr分量 宏块的数据分析语法描述: macroblock()
{ while(nextbits()==’0000 0001 111’)
{ macroblock_stuffing /*宏块填料,为了防止下溢出,由编码器填入的数据,有它固定的11位bit格式就 是’0000 0001 111’,当然 解决下溢出的方法还有很多,编码器可以在标题之前就加入填料位,或者可以减小quant_scale获得更多的编码系数等等*/ } while(nextbits()==’0000 0001 000’)
{ macroblock_escape /*固定模式的bit串,当macroblock_address与 previous_macroblock_address的差大于33时将用到该码。 使得后继的macroblock_increment所表示的值加33。 } macroblock_address_increment /* 用于表示macroblock_address和previous_macorblock_ address之间的差值。 最大值为33,当前两者差大于 33时用macroblock_escape补充。 Macroblock_address表示的是宏块在画面中的绝对位置,最左上角的宏块的 macroblock_address为0,previous_macroblock_address指示片中最后一个非跳空宏块的位置。*/
macroblock_type if(macroblock_motion_forward)
{ motion_horizontal_forward_code if((forward_f!=1) && (motion_horizontal_forward_code!=0)) motion_horizontal_forward_r motion_vertical_forward_code if((forward_f!=1) && (motion_vertical_forward_code!=0)) motion_vertical_forward_r } if(macroblock_motion_backward)
{ motion_horizontal_backward_code if((backward_f!=1) && (motion_horizontal_backward_code!=0)) motion_horizontal_backward_r motion_vertical_backward_code if((backward_f!=1) && (motion_vertical_backward_code!=0)) motion_vertical_backward_r } if(macroblock_pattern) coded_block_pattern /*可以得到宏块宏块的pattern_code[i](i=0:5),从而确定该宏块接收到的块的种类有哪些。*/ for(i=0;i<6;i++) block(i) if(picture_coding_type==4) end_of_marcoblock } 片被分为16pixels*16lines的象素宏块。每个宏块都有它的标题。包含了宏块的地址、类型、量化器标尺信息等等。标题之后是该宏块的6个块的数据。 在Xmplay代码中给出的macrblock的定义: typedef struct macroblock { int mb_address; /* Macroblock address. */ int past_mb_addr; /* Previous mblock address. */ int motion_h_forw_code; /* Forw. horiz. motion vector code. */ unsigned int motion_h_forw_r; /* Used in decoding vectors. */ int motion_v_forw_code; /* Forw. vert. motion vector code. */ unsigned int motion_v_forw_r; /* Used in decdoinge vectors. */ int motion_h_back_code; /* Back horiz. motion vector code. */ unsigned int motion_h_back_r; /* Used in decoding vectors. */ int motion_v_back_code; /* Back vert. motion vector code. */ unsigned int motion_v_back_r; /* Used in decoding vectors. */ unsigned int cbp; /* Coded block pattern. */ BOOLEAN mb_intra; /* Intracoded mblock flag. */ BOOLEAN bpict_past_forw; /* Past B frame forw. vector flag. */ BOOLEAN bpict_past_back; /* Past B frame back vector flag. */ int past_intra_addr; /* Addr of last intracoded mblock. */ int recon_right_for_prev; /* Past right forw. vector. */ int recon_down_for_prev; /* Past down forw. vector. */ int recon_right_back_prev; /* Past right back vector. */ int recon_down_back_prev; /* Past down back vector. */ } Macroblock; 2.6块层(Block) 块是一个正交的8pixels*8lines的亮度或者色度分量,块可以指源画面数据或者相应的编码数据元素。 8*8单位象素的源画面数据经过DCT变换后的成为了相应的DCT系数块。 块的具体结构为(xmplay源码中的结构定义): typedef struct block
{ short int dct_recon[8][8]; /* Reconstructed dct coeff matrix. */ short int dct_dc_y_past; /* Past lum. dc dct coefficient. */ short int dct_dc_cr_past; /* Past cr dc dct coefficient. */ short int dct_dc_cb_past; /* Past cb dc dct coefficient. */ } Block; 解析块的语法结构是: block(i)
{ if(pattern_code[i])
{ if(macroblock_intra)
{ if(i<4)
{ dct_dc_size_luminance if(dc_size_luminance!=0) dct_dc_differential } else
{ dct_dc_size_chrominance if(dc_size_chrominance!=0) dct_dc_differential } } else
{ dct_coeff_first } if(picture_coding_type!=4)
{ while(nextbits()!=’10’) dct_coeff_next end_of_block } } } 附录 文中部分代码中的数据类型与标准C中数据类型对应关系: typedef int INT32; typedef short INT16; typedef char INT8; #endif typedef unsigned int UINT32; typedef unsigned short UINT16; typedef unsigned char UINT8; xmplay-1.1这个播放器的源码,对帮助理解mpeg1结构很有帮助,同时这也是一个编码和解码器,以及数据分析器,在internet上面可以搜所到
下面是另一篇博文中的,和上面结合起来看比较好。(http://blog.sina.com.cn/s/blog_5f5ad6a90100dqzt.html)
MPEG文件格式附表
缩写 | 全名 | 长度 | 内容 | |
程序层 | SHC | Sequence Header Code | 32 | 程序层开始码 |
HS | Horizontal Size | 12 | 画面的横向像素 | |
VS | Vertical Size | 12 | 像素的纵向扫描条数 | |
PAR | Pel Aspect Ratio | 4 | 像素间的长宽比 | |
PR | Picture Rate | 4 | 画面显示的周期 | |
BR | Bit Rate | 18 | 限制产生的位元数量而将 位元速率分割成400bps | |
MB | Marker Bit | 1 | ||
VBS | VBV ( Video BuFrameering Verifer BuFrameer Size ) | 10 | 制编码发生量的虚拟 缓冲器大小的参数. VBV=16x1024xBS | |
CPF | Constrained Parameters Flag | 1 | 各参数在控制量内 | |
LIQM IQM | Load Intra Quantize Matrix Intra Quantize Matrix | 1 8x64 | 内部MB用量子化矩阵数据 存在的Intra MB用量子化矩阵 | |
LNIQM NIQM | Load Non Intra Quantize Matrix Non Intra Quantize Matrix | 1 8x64 | 非内部MB用量子化矩阵数据 存在非Intra MB用量子化矩阵 | |
ESC SED | Extension Start Code Sequence Extension Data | 32 8xn | 扩充数据的开始码 | |
UDSC UD | User Data Start Code User Data | 32 8xn | User Data的开始码 User Data | |
SEC | Sequence End Code | 32 | 程序终了码 | |
GOP层 | GSC | Group Start Code | 32 | GOP开始码 |
TC | Time Code | 25 | 时间码 | |
CG | Close GOP | 1 | GOP内画面可自其他的 GOP做独立拨放 | |
BL | Broken Link | 1 | 为前一GOP数据的编辑 而无法使用 | |
ESC GED | Extension Start Code Group Extension Data | 32 8xn | ||
UDSC UD | User Data Start Code User Data | 32 8xn | User Data | |
PSC | Picture Start Code | 32 | Picture层的开始码 | |
TR | Temporal Reference | 10 | 以Picture连续的序号做GOP 的栏重设之0124残馀值 | |
画面层 | PCT | Picture Coding Type | 3 | 表示Picture的型态 |
VD | VBV Dalay | 16 | 随机存取时 BuFrameer初始状态的记数 | |
FPEV | Full pel Forward Vector | 1 | 以整数或半像素单位 做动态向量的单位 | |
FRAME | Forward f Code | 3 | 顺向动态向量的描述范围 | |
C | ||||
FPBV | Full Pel Backward | 1 | 以整数或半像素单位 做动态向量的精度 | |
BFC | Vector | |||
Backward Code | 3 | 反向动态向量的技术范围 | ||
EBP | Extra Bit Picture | 1xn | 其他画面资讯 | |
EIP | Extra information Picture | 8xn | 将来 | |
EBP | Extra Bit Picture | 1 | 无EIP时以'0'表示 | |
ESC | Extra Start Code | 32 | 将来 | |
PED | Picture Extension Code | 8xn | User Data | |
UDSC | User Data Start Code | 32 | ||
UD | User Data | 8xn | ||
切面层 | SSC QS | Start Code Quantizer Scale | 32 5 | 切片开始时以该切片层做量子化 |
EBS EIS | Extra Bit Extra Information | 1xn 8xn | 表示其他切片层的资讯 | |
EBS | 16 | 无EIS时以0表示 | ||
巨集区块层 | MB STUFF | Macroblock Stuffing | 11 | 编码量不足时之Dummycode |
MB | Macroblock Escape | 11 | 相当33个MB Space | |
MBAI | Macroblock Address Increment | 1-11 | 前有Scape时MB数+1 自VLC画面的又端表示MB+1 | |
SSC | Start Code | 1-8 | MB编码模式的VLC | |
QS | Quantizer scale | 5 | 以MB以後的量子化步骤值 | |
MHF MHV | Motion Horzontal Forward Code Motion Forward Motion Vertical Forward Code Motion Vertical Backward | 1-11 1-6 1-11 1-6 | 以MB顺向的动态向量水平分量与前较量的微分以反方向表示的VLC做编码与顺向动态向量的垂直分量的MHB表现相同 | |
MHB MVB | Motion Horzontal Backward Code Motion Backward Motion Vertical Backward Motion | 1-11 1-6 1-14 1-6 | 以MB顺向的动态向量水平分量 与前较量的微分以反方向表示 的VLC做编码与反向动态向量的 垂直分量的MHB表现相同 | |
CPB | Coded Block Pattem | 3-9 | 表是否有MB内6个区块系数的 VLC | |
EOM | End of Mircoblock | 1 | 只有B Fram才有表MB终了 | |
区块层 | DDSL DDSC DDCD | DCT DC Size Luminance DCT DC Size Chrominance DCT DC Differential | 2-7 2-8 1-8 | 表示下一DCT DC微分的位元数 该区块的DC分量与 前区块的分量的微分 |
CDF | DCT Coefficient First | 2-28 | DC分量的VLC | |
DCN EOB | DCT Coefficient Next End of Block | 3-28 2 | 将DCT系数依DC分量顺序送出 以非0的细数与其前为0的系数 组合的VLC在该区块後的系数 全以0表示 |