H264解码之PES流解析

PES简介:

  • PES–Packetized Elementary Streams (分组的ES),ES形成的分组称为PES分组,是用来传递ES的一种数据结构。PES流是ES流经过PES打包器处理后形成的数据流,在这个过程中完成了将ES流分组、打包、加入包头信息等操作(对ES流的第一次打包)。PES流的基本单位是PES包。PES包由包头和payload组成。
  • PES流是对原始ES流进行的第一层封装,PES流的基本单位是PES包,由包头和payload组成,ES流即音视频裸流,是从编码器里面出来的原始视频音频流;ES流只包含一种内容,里面是视频或者音频;封装时不对其进行改变,只在前面添加头部,如私有头,解码时,将私有头剥掉,将原始ES码流送进解码器解码,这也是解码通用性,若是修改了,则其他解码器就没法解码了;PES和ES一样,都是单一原始码流,一般我遇到的是一帧数据放在一个PES包里面,但是一个PES包的最大长度为65535字节,因此一帧数据有可能被分为多个PES;其包头格式如下:
    图一
    下图更为清晰:
    图二

可以看出:

  • PES包由3部分组成:
    • 固定头
    • 可选头
    • 负载(即ES流)
      其中固定头共有24+8+16 = 48位(即6个字节)
  • 固定头由3部分组成:
    • packet_start_code_prefix
    • stream_id
      图三
    • PES Packet length
      通过PES Packet length我们可以知道从PES Packet length域之后还剩多少字节长度,由于PES Packet length共16位,最大可表示216 -1 个字节即65535个字节,由此我们可以推算出PES包的最大长度。
      故一帧可能会分为多个PES包。

字段含义

下面依次介绍其每个字段的含义:

  • Packet start code prefix: 包头起始码,固定为0x00 00 01,占位24bit;
  • Stream id: (UI)PES包中的负载流类型,一般视频为0xe0,音频为0xc0,占位8bit;
  • PES packet length: (UI)PES包长度,包括此字节后的可选包头和负载的长度,占位16bit;
  • Optional PES Header,顺序依次为:
    • ’10’字段:占位2bit;
    • PES scrambling control:加密模式,占2bit;00未加密,01或10或11由用户定义;
    • PES priority:有效负载的优先级,占位1bit;值为1比值为0的负载优先级高;
    • Data alignment indicator:数据定位指示器,占位1bit;
    • Copyright:版权信息,1为有版权,0无版权,占位1bit;
    • Original or copy:原始或备份,1为原始,0为备份,占位1bit;
      后面是7个flags(一般我们关注的就是PTS DTS的标志位):
    • PTS_DTS_flags:PTS和DTS标志位,占位2bit;10表示首部有PTS字段,11表示有PTS和DTS字段,00表示都没有,01被禁止,不会出现此种情况;
    • ESCR_flag:ESCR标志,占位1bit;1表示首部有ESCR字段,0则无此字段
    • ES_rate_flag:ES_rate字段,占位1bit;1表示首部有此字段,0无此字段;
    • DSM_trick_mode_flag:占位1bit;1表示有8位的DSM_trick_mode_flag字段,0无此字段;
    • Additional_copy_info_flag:占位1bit;1表示首部有此字段,0表示无此字段;
    • PES_CRC_flag:占位1bit;置1表示PES分组有CRC字段,0无此字段;
    • PES_extension_flag:占位1bit;扩展标志位,置1表示有扩展字段,0无此字段;
    • PES header data length:(UI)PES首部中可选字段和填充字段的长度;占位8bit;可选字段的内容由上面7个flags来进行控制;
    • Optional fields:可选字段的描述信息区域,其内容由上面的7个flag来控制;
      • PTS/DTS字段:显示时间戳/解码时间戳,占位40bit,当PTS_DTS_flags == 1x时此字段存在;时间占用33个bit,PTS和DTS的内容是在这40bit中取33位,方式相同;
        PTS(presentation time stamp)显示时间戳和DTS(Decoding Time Stamp)解码时间戳,是用来音视频同步的,是打在PES包的包头里面的,PTS/DTS是相对SCR(系统参考)的时间戳,是以90000为单位的,PTS/DTS到ms的转换公式是PTS/90,系统时钟频率(H264采样频率?)为90Khz,所以转换到秒为PTS/90000,所以如果是以ms为单位的播放器,PTS/DTS是要使用公式ms=pts/90来转换才行的,而如果是以时钟频率为单位的话,则直接将PTS/DTS送进去解码即可;如果没有B帧,PTS和DTS的顺序应该是一致的,如果有B帧,则需要先解码P帧,才能解出来B帧,所以需要PTS和DTS来控制解码时间和显示时间;
        先找到original or copy后边得"7 flags",得出是否有pts/dts的标志,标志为高两位,所以
        标志= (“7 flags” & 0xc0 ) >> 6;
        标志第一位是PTS标识,第二位是DTS标识。
        标志:
        • 00,表示无PTS无DTS;

        • 01,错误,不能只有DTS没有PTS;

        • 10,有PTS;

        • 11,有PTS和DTS.
          接下来,跳过8字节的PES header data length;
          虽然由第二个图可以知道PTS有33位,但是它不是直接的33位数据,而是占了5个字节,PTS分别在这5字节中取。
          图四
          见过上边这个图的就应该比较清楚了,PTS的33位的各部分是如上图那样分布的,如果从左至右分别为PTS1,PTS2,PTS3。
          字节顺序依次:

          • start_code:起始码,占位4bit;若PTS_DTS_flags == ‘10’,则说明只有PTS,起始码为0010;若PTS_DTS_flags == ‘11’,则PTS和DTS都存在,PTS的起始码为0011,DTS的起始码为0001;(PTS的起始码后2个bit与flag相同)
          • PTS[32…30]:占位3bit;
          • marker_bit:占位1bit;
          • PTS[29…15]:占位15bit;
          • marker_bit:占位1bit;
          • PTS[14…0]:占位15bit;
          • marker_bit:占位1bit;
            那么:
            PTS = (PTS1 & 0x0e) << 29 + (PTS2 & 0xfffe) << 14 + (PTS3 & 0xfffe ) >> 1;
            DTS(如果有)紧接着后边读取5个字节的数据,也是这样求出来的
        • ESCR字段:此字段占位48bit,由33bit的ESCR_base字段和9bit的ESCR_extension字段组成,ESCR_flag == 1时此字段存在;数据依次顺序:

          • Reserved:保留字段,占位2bit;
          • ESCR_base[32…30]:占位3bit;
          • marker_bit:占位1bit;
          • ESCR_base[29…15]:占位15bit;
          • marker_bit:占位1bit;
          • ESCR_base[14…0]:占位15bit;
          • marker_bit:占位1bit;
          • ESCR_extension:(UI)占位9bit;周期数,取值范围0~299;循环一次,base+1;
          • marker_bit:占位1bit;
        • ES rate字段:目标解码器接收PES分组字节速率,禁止为0,占位24bit,ES_rate_flag == 1时此字段存在;数据顺序为:

          • marker_bit:占位1bit;
          • ES_rate:占位22bit;
          • marker_bit:占位1bit;
        • Trick mode control字段:表示哪种trick mode被应用于相应的视频流,占位8个bit,DSM_trick_mode_flag == 1时此字段存在;其中trick_mode_control占前3个bit,根据其值后面有5个bit的不同内容;
          如果trick_mode_control == ‘000’,依次字节顺序为:

          • field_id:占位2bit;
          • intra_slice_refresh :占位1bit;
          • frequency_truncation:占位2bit;
            如果trick_mode_control == ‘001’,依次字节顺序为:
          • rep_cntrl:占位5bit;
            如果trick_mode_control == ‘010’,依次字节顺序为:
          • field_id:占位2bit;
          • Reserved:占位3bit;
            如果trick_mode_control == ‘011’,依次字节顺序为:
          • field_id:占位2bit;
          • intra_slice_refresh:占位1bit;
          • frequency_truncation:占位2bit;
            如果trick_mode_control== ‘100’,依次字节顺序为:
          • rep_cntrl:占位5bit;
            其他情况,字节顺序为:
          • reserved :占位5bit;
        • Additional copy info字段:占8个bit,Additional_copy_info_flag == 1时此字段存在;数据顺序为:

          • marker_bit:占位1bit;
          • copy info字段:占位7bit;表示和版权相关的私有数据;
        • Previous PES CRC字段:占位16bit字段,包含CRC值,PES_CRC_flag == 1时此字段存在;

          扫描二维码关注公众号,回复: 10446931 查看本文章
        • PES extension字段:PES扩展字段,PES_extension_flag == 1时此字段存在;内容如下,字节顺序依次为:

          • PES_private_data_flag:占位1bit,置1表示有私有数据,0则无;

          • Pack_header_field_flag:占位1bit,置1表示有Pack_header_field字段,0则无;

          • Program_packet_sequence_counter_flag:占位1bit,置1表示有此字段,0则无;

          • P-STD_buffer_flag:占位1bit,置1表示有P-STD_buffer字段,0则无此字段;

          • Reserved字段:3个bit;

          • PES_extension_flag_2:占位1bit,置1表示有扩展字段,0则无此字段;

          • Optional field :PES扩展字段的可选字段内容顺序为:

            • PES_private_data字段:私有数据内容,占位128bit,PES_private_data_flag == 1时此字段存在;
            • Pack_header_field字段:Pack_header_field_flag == 1时此字段存在;字段组成顺序如下:
              • Pack_field_length字段:(UI)指定后面的field的长度,占位8bit;
              • pack_header_field():长度为Pack_field_length指定;
            • Program_packet_sequence_counter字段:计数器字段,16个bit;当flag字段Program_packet_sequence_counter_flag == 1时此字段存在;字节顺序依次为:
              • marker_bit:占位1bit;
              • packet_sequence_counter字段:(UI)占位7bit;
              • marker_bit:占位1bit;
              • MPEG1_MPEG2_identifier:占位1bit;置位1表示此PES包的负载来自MPEG1流,置位0表示此PES包的负载来自PS流;
              • original_stuff_length:(UI)占位6bit;表示PES头部填充字节长度;
            • P-STD_buffer字段:表示P-STD_buffer内容,占位16bit;P-STD_buffer_flag == '1’时此字段存在;字节顺序依次为:
              • ’01’字段:占位2bit;
              • P-STD_buffer_scale:占位1bit;表示用来解释后面P-STD_buffer_size字段的比例因子;如果之前的stream_id表示音频流,则此值应为0,若之前的stream_id表示视频流,则此值应为1,对于其他stream类型,此值可以0或1;
              • P-STD_buffer_size:占位13bit;无符号整数;大于或等于所有P-STD输入缓冲区大小BSn的最大值;若P-STD_buffer_scale == 0,则P-STD_buffer_size以128字节为单位;若P-STD_buffer_scale == 1,则P-STD_buffer_size以1024字节为单位;
            • PES_extension 2个字段:扩展字段的扩展字段;占用N*8个bit,PES_extension_flag_2 == '1’时此字段存在;字节顺序依次为:
              • marker_bit:占位1bit;
              • PES_extension_field_length:占位7bit,表示扩展区域的长度;
              • Reserved字段:占位8*PES_extension_field_length个bit;
    • Stuffing bytes:填充字段,固定为0xFF;不能超过32个字节;
  • PES_packet_data_byte:PES包负载中的数据,即ES原始流数据;
    PES包是TS和PS包封装的基础,TS和PS其实就是对PES包的再一次封装,下篇将讲解一下TS流
发布了135 篇原创文章 · 获赞 67 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/y601500359/article/details/97648359