zoukankan      html  css  js  c++  java
  • annexb格式

    总的来说H264的码流的打包方式有两种,一种为annex-b byte stream format的格式,这个是绝大部分编码器的默认输出格式,就是每个帧的开头的3~4个字节是H264的start_code,0x00000001或者0x000001。
    另一种是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编码器的profile,level,PPS,SPS等信息才可以解码。
    时空互换(178316135)   10:17:08
    rtp传输的是annexb的h264码流

    转自http://blog.sina.com.cn/s/blog_442ae05d0100je8y.html

    字节流格式(Annex B)和RTP格式流浅析


    AnnexB格式:NALU数据+开始前缀(00000001或000001,此处注意为甚么是4bit或3bit,后面有描述);针对H.320电话会议

    RTP   格式:NALU数据+20个字节的类似的并不符合RTP协议的RTP头。针对IP网络的RTP打包方式

    H.264协议只规定了字节流格式,没有规定 RTP 格式。可能也是因为这个原因,JM 的 RTP 格式没有被用到任何场合场合中,成为了摆设。下图中的 RTP 格式是h.264乐园的firstime从 JM86 中分析出来的。实际包交换网络中必须按照 RFC3984 将 NALU 数据封装为 RTP 包,而不能使用 JM 的 RTP 格式。

    字节流格式(Annex <wbr><wbr>B)和RTP格式流浅析

    下面引自“QUESTIONMARK”的博客

    下面说明3字节起始码和4字节起始码

    以下和leading_zero_8bits、trailing_zero_8bits已无关系,忘掉。
       if( next_bits( 24 ) != 0x000001 )
            zero_byte                                      f(8)
        start_code_prefix_one_3bytes   f(24)
    根据B.1节,可以看到所谓的4字节起始码是(zero_byte + 3字节起始码)。那么看zero_byte的说明,就可以明白zero_byte什么时候出现,也就能明白什么时候出现4字节起始码:
    1. SPS、PPS nalu是4字节起始码;
    2. Access Unit的首个nalu是4字节起始码(参见7.4.1.2.3)。
    这里举个例子说明,用JM可以生成这样一段码流(不要使用JM8.6,它在这部分与标准不符),这个码流可以见本楼附件:
          SPS            (4字节头)
          PPS            (4字节头)
          SEI            (4字节头)
          I0(slice0)     (4字节头)
          I0(slice1)    (3字节头)
          P1(slice0)     (4字节头)
          P1(slice1)    (3字节头)
          P2(slice0)     (4字节头)
          P2(slice1)    (3字节头)
    I0(slice0)是序列第一帧(I帧)的第一个slice,是当前Access Unit的首个nalu,所以是4字节头。而I0(slice1)表示第一帧的第二个slice,所以是3字节头。P1(slice0) 、P1(slice1)同理。


    总结:
    1 附录 B字节流在一个byte_stream_nal_unit的前后可能出现若干个0x00,仅用作填充之用。这个不常见。
    2 4字节头只出现在SPS、PPS和7.4.1.2.3规定的Access Unit的首个nalu。其余情况都是3字节头

    一共有两种起始码:3字节的0x000001和4字节的0x00000001
    3字节的0x000001只有一种场合下使用,就是一个完整的帧被编为多个slice的时候,包含这些slice的nalu使用3字节起始码。其余场合都是4字节的。

    IDR(刷新帧)与I帧的一些知识点

    (2010-06-08 20:38:40)
    标签:

    杂谈

    分类: H.264

    IDR帧属于I帧,但是I帧不一定是IDR帧解码器收到IDR帧时,将驱动器参数块(DPB)清空。而I帧不会。(我自己理解为即把参考帧列表刷新从新更新,就是不再参考idr前面的帧)由此可见,在编码器端,每发一个IDR,就相应地发一个nal。当然在现在的编码中,为了取得更高的图像质量,在一个视频文件中有好多个IDR帧,这些IDR帧把视频文件分成了片,但是每片中第一个帧是IDR,而且仅此一个

    例如:存在这样一段视频:

    码流

    IDR

    B

    B

    P

    B

    B

    P

    ……

    帧号

    1

    2

    3

    4

    5

    6

    7

    ……

     

    对IDR帧的处理(与I帧的处理相同):(1) 进行帧内预测,决定所采用的帧内预测模式。(2) 像素值减去预测值,得到残差。(3) 对残差进行变换和量化。(4) 变长编码和算术编码。(5) 重构图像并滤波,得到的图像作为其它帧的参考帧。

    这里要提一下,当编码器处理完IDR帧遇到B帧时,编码期先把其放入缓存器中存放起来。直接对P进行编码。即编码器中编码的实际顺序是IDR P B B P B B…..即1423756……

     

    有用的来了

     

    IDR-instantaneous decoding refresh (IDR)picture; 
          A coded picture in which all slices are I or SI slices that causes the decoding process to mark all reference pictures as "unused for reference" immediately after decoding the IDR picture. After the decoding of an IDR picture all following coded pictures in decoding order can be decoded without inter prediction from any picture decoded prior to the IDR picture. The first picture of each coded video sequence is an IDR picture. 
        “也就是说,IDR的出现其实是相当于向解码器发出了一个清理reference buffer的信号吧,上面说前于这一帧的所有已编码帧不能为inter做参考帧了。” 

    还有:“因为264采用了多帧预测,就有可能在display orderI帧后的P会参考I帧前的帧,这样在random access时如果只找I帧,随后的帧的参考帧可能unavailableIDR就是这样一种特殊的I帧,把它定义为确保后面的P一定不参考其前面的帧,可以放心地random access 

    多参考帧情况下。

        举个例子:有如下帧序列:IPPPPIPPPP……(我们程序没有B帧,所以帧序列简单些,但道理是一样的)。按照3个参考帧编码。

        因为“按照3个参考帧编码”,所以参考帧队列长度为3

        遇到绿色的I时,并不清空参考帧队列,把这个I帧加入参考帧队列(当然I编码时不用参考帧。)。再检测到红色的P帧时,用到的就是PPI三帧做参考了。

        不怕自己罗嗦(好记性不如烂笔头),再强调一个:一个参考帧,就是参考当前帧的前面的那帧(因为没涉及到B帧,所以“前面的那帧”既是播放顺序的,也是编码顺序的)。多个参考帧是一个道理我以前一直误解为从前面的几帧中找到最合适的一个参考帧)

        最后,“但是收到IDR帧时,解码器另外需要做的工作就是:把所有的PPSSPS参数进行更新。由此可见,在编码器端,每发一个IDR,就相应地发一个 PPS&SPS_nal_unit”应该是对的吧。先这样认为:)

     

     

     

    分享 annex-b格式 annex-b格式 annex-b格式 annex-b格式 annex-b格式

    0

    annex-b格式

    阅读(24) 评论 (0) 收藏(0) 转载(0)   打印举报
    已投稿到:
    后一篇:字节流格式(Annex B)和RTP格式流浅析

    【转】SODB RBSP EBSP 的来龙去脉

    (2010-06-07 21:22:39)

    H.264起始码

    在网络传输h264数据时,一个UDP包就是一个NALU,解码器可以很方便的检测出NAL分界和解码。但是如果编码数据存储为一个文件,原来的解码器将无法从数据流中分别出每个NAL的起始位置和终止位置,为此h.264用起始码来解决这一问题。
     
    H.264编码时,在每个NAL前添加起始码 0x000001,解码器在码流中检测到起始码,当前NAL结束。为了防止NAL内部出现0x000001的数据,h.264又提出'防止竞争 emulation prevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。当解码器在NAL内部检测到0x000003的数据,就把0x03抛弃,恢复原始数据。
       0x000000  >>>>>>  0x00000300
       0x000001  >>>>>>  0x00000301
       0x000002  >>>>>>  0x00000302
       0x000003  >>>>>>  0x00000303

     
     附上h.264解码nalu中检测起始码的算法流程 
     for(;;)
     {
        if next 24 bits are 0x000001
        {
            startCodeFound = true
            break;
        }
        else
        {
            flush 8 bits 
        }
     }// for(;;)

     if(true == startCodeFound)
     {
         //startcode found
         // Flush the start code found
         flush 24 bits 
         //Now navigate up to next start code and put the in between stuff
         // in the nal structure.
         for(;;)
         {
             get next 24 bits & check if it equals to 0x000001
             if(false == (next 24 bits == 000001))
             {
                 // search for pattern 0x000000
                 check if next 24 bits are 0x000000
                 if(false == result)
                 {
                     // copy the byte into the buffer
                     copy one byte to the Nal unit             
                 }
                 else
                 {
                     break;
                 }
              }
              else
              {
                  break;
              }
           }//for(;;)
       }

      2. MPEG4起始码
            MPEG4的特色是VOP,没有NALU的概念,仍使用startcode对每帧进行分界。MPEG4的起始码是0x000001. 另外MPEG4中很多起始码也很有用,比如video_object_sequence_start_code 0x000001B0 表示一个视频对象序列的开始,VO_start_code 0x000001B6 表示一个VOP的开始. 0x000001B6之后的两位,是00表示 I frame, 01 表示 P frame, 10 表示 B frame. 

    SODB 数据比特串-->最原始的编码数据

    RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若干比特“0”,以便字节对齐。

    EBSP 扩展字节序列载荷-->在RBSP基础上填加了仿校验字节(0X03)它的原因是: 在NALU加到Annexb上时,需要填加每组NALU之前的开始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示ox000001.为了使NALU主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉。也称为脱壳操作。


    网上查询的区别:

    在对整帧图像的数据比特串(SODB)添加原始字节序列载荷(RBSP)结尾比特(RBSP trailing bits,添加一比特的“1”和若干比特“0”,以便字节对齐)后,再检查RBSP 中是否存在连续的三字节“00000000 00000000 000000xx”;若存在这种连续的三字节码,在第三字节前插入一字节的“0×03”,以免与起始码竞争,形成EBSP码流,这需要将近两倍的整帧图像 码流大小。为了减小存储器需求,在每个宏块编码结束后即检查该宏块SODB中的起始码竞争问题,并保留SODB最后两字节的零字节个数,以便与下一宏块的 SODB的开始字节形成连续的起始码竞争检测;对一帧图像的最后一个宏块,先添加结尾停止比特,再检测起始码竞争。


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/threewells_14/archive/2007/02/12/1508657.aspx

    typedef struct

    {

      int             byte_pos;           //!< current position in bitstream;

      int             bits_to_go;         //!< current bitcounter

      byte            byte_buf;           //!< current buffer for last written byte

      int             stored_byte_pos;    //!< storage for position in bitstream;

      int             stored_bits_to_go;  //!< storage for bitcounter

      byte            stored_byte_buf;    //!< storage for buffer of last written byte

      byte            byte_buf_skip;      //!< current buffer for last written byte

      int             byte_pos_skip;      //!< storage for position in bitstream;

      int             bits_to_go_skip;    //!< storage for bitcounter

      byte            *streamBuffer;      //!< actual buffer for written bytes

      int             write_flag;         //!< Bitstream contains data and needs to be written

    } Bitstream; 定义比特流结构

    static byte *NAL_Payload_buffer;

    void SODBtoRBSP(Bitstream *currStream)
    {
      currStream->byte_buf <<= 1;  //左移1bit
      currStream->byte_buf |= 1;   //在尾部填一个“1”占1bit
      currStream->bits_to_go--;
      currStream->byte_buf <<= currStream->bits_to_go;
      currStream->streamBuffer[currStream->byte_pos++] = currStream->byte_buf;
      currStream->bits_to_go = 8;
      currStream->byte_buf = 0;
    }

    int RBSPtoEBSP(byte *streamBuffer, int begin_bytepos, int end_bytepos, int min_num_bytes)
    {
     
      int i, j, count;

      for(i = begin_bytepos; i < end_bytepos; i++)
        NAL_Payload_buffer[i] = streamBuffer[i];

      count = 0;
      j = begin_bytepos;
      for(i = begin_bytepos; i < end_bytepos; i++)
      {
        if(count == ZEROBYTES_SHORTSTARTCODE && !(NAL_Payload_buffer[i] & 0xFC))
        {
          streamBuffer[j] = 0x03;
          j++;
          count = 0;  
        }
        streamBuffer[j] = NAL_Payload_buffer[i];
        if(NAL_Payload_buffer[i] == 0x00)     
          count++;
        else
          count = 0;
        j++;
      }
      while (j < begin_bytepos+min_num_bytes) {
        streamBuffer[j] = 0x00; // cabac stuffing word
        streamBuffer[j+1] = 0x00;
        streamBuffer[j+2] = 0x03;
        j += 3;
        stat->bit_use_stuffingBits[img->type]+=16;
      }
      return j;
    }

    在2010-6-9 15:33:33我又看到了别人博客上的一句话 更加深了我的理解 ,这里贴出来。感谢QuestionMark

    标准 7.4.1.1 如是说:
    This process can allow any SODB to be represented in a NAL unit while ensuring that
    – ……
    – no sequence of 8 zero-valued bits followed by a start code prefix, regardless of byte-alignment, is emulated within the NAL unit.
    这段的意思是在nal_unit层面,即nalu header+RBSP的结构中,不可能出现0x00 00 01这样的片段。这是通过SODB->RBSP->EBSP的过程中添加防冲突字节实现的。这里多说一句

    标准附录 B 如是说:
    any bytes equal to 0x00 that follow a NAL unit syntax structure and precede the four-byte sequence 0x00000001 (which is to be interpreted as a zero_byte followed by a start_code_prefix_one_3bytes) will be considered to be trailing_zero_8bits syntax elements that are part of the preceding byte stream NAL unit.
    这一段则在说明byte_stream_nal_unit层面。结合B.1,可以明白这段话的意思是一个nalu之后,下一个起始码0x00000001之前,可能会有若干0x00,就是所谓的trailing_zero_8bits。 此外B.1中还说明了在码流的最开始,还有可能有若干0x00,就是所谓的leading_zero_8bits。这些 leading_zero_8bits和trailing_zero_8bits可能与传输打包有关,但在实际中,我没有见过包含这种“多余”的0x00 的码流。



    //

    H264实时编码及NALU,RTP传输(ZZ)

    codec 2010-11-24 14:21:16 阅读27 评论0   字号: 订阅

    http://hi.baidu.com/interxuxing/blog/item/1fdf08615a8f3649eaf8f8a3.htmlrfc3984
    Standards Track [Page 2] RFC 3984 RTP Payload Format for H.264 Video February 2005 1.
    按照RFC3984协议实现H264视频流媒体
    nalu单元 包起始 0x 00 00 00 01
    H.264 NAL格式及分析器
    http://hi.baidu.com/zsw_davy/b ... c409cc7cd92ace.html
    http://hi.baidu.com/zsw_davy/blo ... 081312c8fc7acc.html
    ----------------------------------比特流信息----------------------------------------------
    ①NALU(Network Abstract Layer Unit):两标准中的比特流都是以NAL为单位,每个NAL单元包含一个RBSP,NALU的头信息定义了RBSP所属类型。类型一般包括序列参数集 (SPS)、图像参数集(PPS)、增强信息(SEI)、条带(Slice)等,其中,SPS和PPS属于参数集,两标准采用参数集机制是为了将一些主要 的序列、图像参数(解码图像尺寸、片组数、参考帧数、量化和滤波参数标记等)与其他参数分离,通过解码器先解码出来。此外,为了增强图像的清晰 度,AVS-M添加了图像头(Picture head)信息。读取NALU流程中,每个NALU前有一个起始码0x000001,为防止 内部0x000001序列竞争,H.264编码器在最后一字节前插入一个新的字节——0x03,所以解码器检测到该序列时,需将0x03删掉,而AVS- M只需识别出起始码0x000001。
    ②读取宏块类型(mb type)和宏块编码模板(cbp):编解码图像以宏块划分,一个宏块由一个16*16亮度块和相应的一个8*8cb和一个8*8cr色度块组成。
    (a) 两标准的帧内、帧间预测时宏块的划分是有区别的。H.264中,I_slice亮度块有Intra_4*4和Intra_16*16两种模式,色度块只有 8*8模式;P_slice宏块分为16*16、16*8、8*16、8*8、8*4、4*8、4*4共7种模式。而AVS-M中,I_slice亮度块 有I_4*4和I_Direct两模式,P_slice时宏块的划分和H.264中的划分一致。
    (b) 两标准的宏块cbp值计算也不相同。H.264中,Intra_16*16宏块的亮度(色度)cbp直接通过读mb type得到;非Intra_16*16宏块的亮度cbp=coded_block_pattern,色度 cbp=coded_block_pattern/16 。其中,亮度cbp最低4位有效,每位决定对应宏块的残差系数能不能为0;色度cbp为0时,对应残差系数为0,cbp为1时,DC残差系数不为0,AC 系数为0,cbp为2时,DC、AC残差系数都不为0。AVS-M中,当宏块类型不是P_skip时,直接从码流中得到cbp的索引值,并以此索引值查表 得到codenum值,再以codenum查表分别得到帧内/帧间cbp。此cbp为6位,每位代表宏块按8*8划分时能不能包含非零系数,当变换系数不 为0时,需进一步读cbp_4*4中每位值来判断一个8*8块中4个4*4块的系数能不能为0。
    ---------------------------------------------------------------------------------------------
    总的来说H264的码流的打包方式有两种,一种为annex-b byte stream format的格式,这个是绝大部分编码器的默认输出格式,就是每个帧的开头的3~4个字节是H264的start_code,0x00000001或者0x000001。
    另一种是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编码器的profile,level,PPS,SPS等信息才可以解码。
    ----------------------------------------------------------------------------
    AVC vs. H.264
    AVC and H.264 are synonymous. The standard is known by the full names "ISO/IEC 14496-10" and "ITU-T Recommendation H.264". In addition, a number of alternate names are used (or have been) in reference to this standard. These include:
    MPEG-4 part 10
    MPEG-4 AVC
    AVC
    MPEG-4 (in the broadcasting world MPEG4 part 2 is ignored)
    H.264
    JVT (Joint Video Team, nowadays rarely used referring to actual spec)
    H.26L (early drafts went by this name)
    All of the above (and those I've missed) include the Annex B byte-stream format. Unlike earlier MPEG1/2/4 and H.26x codecs, the H.264 specification proper does not define a full bit-stream syntax. It describes a number of NAL (Network Abstraction Layer) units, a sequence of which can be decoded into video frames. These NAL units have no boundary markers, and rely on some unspecified format to provide framing.
    Annex B of of the document specifies one such format, which wraps NAL units in a format resembling a traditional MPEG video elementary stream, thus making it suitable for use with containers like MPEG PS/TS unable to provide the required framing. Other formats, such as ISO base media based formats, are able to properly separate the NAL units and do not need the Annex B wrapping.
    The H.264 spec suffers from a deficiency. It defines several header-type NAL units (SPS and PPS) without specifying how to pack them into the single codec data field available in most containers. Fortunately, most containers seem to have adopted the packing used by the ISO format known as MP4.
    1. H.264起始码
       在网络传输h264数据时,一个UDP包就是一个NALU,解码器可以很方便的检测出NAL分界和解码。但是如果编码数据存储为一个文件,原来的解码器将无法从数据流中分别出每个NAL的起始位置和终止位置,为此h.264用起始码来解决这一问题。
       H.264编码时,在每个NAL前添加起始码 0x000001,解码器在码流中检测到起始码,当前NAL结束。为了防止NAL内部出现0x000001的数据,h.264又提出'防止竞争 emulation prevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。当解码器在NAL内部检测到 0x000003的数据,就把0x03抛弃,恢复原始数据。
    0x000000   >>>>>>   0x00000300
    0x000001   >>>>>>   0x00000301
    0x000002   >>>>>>   0x00000302
    0x000003   >>>>>>   0x00000303
    附上h.264解码nalu中检测起始码的算法流程  
    for(;;)
    {
    if next 24 bits are 0x000001
    {
           startCodeFound = true
           break;
    }
    else
    {
           flush 8 bits  
    }
    }// for(;;)
    if(true == startCodeFound)
    {
        //startcode found
        // Flush the start code found
        flush 24 bits  
        //Now navigate up to next start code and put the in between stuff
        // in the nal structure.
        for(;;)
        {
          get next 24 bits & check if it equals to 0x000001
          if(false == (next 24 bits == 000001))
          {
             // search for pattern 0x000000
             check if next 24 bits are 0x000000
             if(false == result)
             {
                    // copy the byte into the buffer
                    copy one byte to the Nal unit             
             }
             else
             {
                    break;
             }
          }
          else
          {
                 break;
          }
       }//for(;;)
    }
       2. MPEG4起始码
           MPEG4的特色是VOP,没有NALU的概念,仍使用startcode对每帧进行分界。MPEG4的起始码是0x000001. 另外MPEG4中很多起始码也很有用,比如video_object_sequence_start_code 0x000001B0 表示一个视频对象序列的开始,VO_start_code 0x000001B6 表示一个VOP的开始. 0x000001B6之后的两位,是00表示 I frame, 01 表示 P frame, 10 表示 B frame.
    1.引言
    H.264的主要目标:
    1.高的视频压缩比
    2.良好的网络亲和性
    解决方案:
    VCL   video coding layer    视频编码层
    NAL   network abstraction layer   网络提取层
    VCL:核心算法引擎,块,宏块及片的语法级别的定义
    NAL:片级以上的语法级别(如序列参数集和图像参数集),同时支持以下功能:独立片解码,起始码唯一保证,SEI以及流格式编码数据传送
    VCL设计目标:尽可能地独立于网络的情况下进行高效的编解码
    NAL设计目标:根据不同的网络把数据打包成相应的格式,将VCL产生的比特字符串适配到各种各样的网络和多元环境中。
    NALU头结构:NALU类型(5bit)、重要性指示位(2bit)、禁止位(1bit)。
    NALU类型:1~12由H.264使用,24~31由H.264以外的应用使用。
    重要性指示:标志该NAL单元用于重建时的重要性,值越大,越重要。
    禁止位:网络发现NAL单元有比特错误时可设置该比特为1,以便接收方丢掉该单元。
    2.NAL语法语义
    NAL层句法:
    在编码器输出的码流中,数据的基本单元是句法元素。
    句法表征句法元素的组织结构。
    语义阐述句法元素的具体含义。
    分组都有头部,解码器可以很方便的检测出NAL的分界,依次取出NAL进行解码。
    但为了节省码流,H.264没有另外在NAL的头部设立表示起始位置的句法元素。
    如果编码数据是存储在介质上的,由于NAL是依次紧密相连的,解码器就无法在数据流中分辨出每个NAL的起始位置和终止位置。
    解决方案:在每个NAL前添加起始码:0X000001
    在某些类型的介质上,为了寻址的方便,要求数据流在长度上对齐,或某个常数的整数倍。所以在起始码前添加若干字节的0来填充。
    检测NAL的开始:
    0X000001和0X000000
    我们必须考虑当NAL内部出现了0X000001和0X000000
    解决方案:
    H.264提出了“防止竞争”机制:
    0X000000——0X00000300
    0X000001——0X00000301
    0X000002——0X00000302
    0X000003——0X00000303
    为此,我们可以知道:
    在NAL单元中,下面的三字节序列不应在任何字节对齐的位置出现
    0X000000
    0X000001
    0X000002
    Forbidden_zero_bit =0;
    Nal_ref_idc:表示NAL的优先级。0~3,取值越大,表示当前NAL越重要,需要优先受到保护。如果当前NAL是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的单位时,本句法元素必需大于0。
    Nal_unit_type:当前NAL 单元的类型
    3.H.264的NAL层处理
    结构示意图:
    NAL以NALU(NAL unit)为单元来支持编码数据在基于分组交换技术网络中传输。
    它定义了符合传输层或存储介质要求的数据格式,同时给出头信息,从而提供了视频编码和外部世界的接口。
    NALU:定义了可用于基于分组和基于比特流系统的基本格式
    RTP封装:只针对基于NAL单元的本地NAL接口。
    三种不同的数据形式:
    SODB 数据比特串-->最原始的编码数据
    RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若干比特“0”,以便字节对齐
    EBSP  扩展字节序列载荷-->在RBSP基础上填加了仿校验字节(0X03)它的原因是: 在NALU加到Annexb上时,需要添加每组NALU之前 的开始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示 ox000001.为了使NALU主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉。 也称为脱壳操作
    处理过程:
    1.   将VCL层输出的SODB封装成nal_unit, Nal_unit是一个通用封装格式,可以适用于有序字节流方式和IP包交换方式。
    2.   针对不同的传送网络(电路交换|包交换),将nal_unit 封装成针对不同网络的封装格    式。
    第一步的具体过程:
    VCL层输出的比特流SODB(String Of Data Bits),到nal_unit之间,经过了以下三步处理:
    1.SODB字节对齐处理后封装成RBSP(Raw Byte Sequence Payload)。
    2. 为防止RBSP的字节流与有序字节流传送方式下的SCP(start_code_prefix_one_3bytes,0x000001)出现字节竞争情 形,循环检测RBSP前三个字节,在出现字节竞争时在第三字节前加入emulation_prevention_three_byte (0x03),具体方法:
    nal_unit( NumBytesInNALunit ) {
    forbidden_zero_bit
    nal_ref_idc
    nal_unit_type
    NumBytesInRBSP = 0
    for( i = 1; i < NumBytesInNALunit; i++ ) {
    if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {
    rbsp_byte[ NumBytesInRBSP++ ]
    rbsp_byte[ NumBytesInRBSP++ ]
    i += 2
    emulation_prevention_three_byte
    } else
    rbsp_byte[ NumBytesInRBSP++ ]
    }
    }
    3. 防字节竞争处理后的RBSP再加一个字节的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封装成nal_unit.
    第二步的具体过程:
    case1:有序字节流的封装
    byte_stream_nal_unit( NumBytesInNALunit ) {
    while( next_bits( 24 ) != 0x000001 )
    zero_byte
    if( more_data_in_byte_stream( ) ) {
    start_code_prefix_one_3bytes nal_unit( NumBytesInNALunit )
    }
    }
    类 似H.320和MPEG-2/H.222.0等传输系统,传输NAL作为有序连续字节或比特流,同时要依靠数据本身识别NAL单元边界。在这样的应用系统 中,H.264/AVC规范定义了字节流格式,每个NAL单元前面增加3个字节的前缀,即同步字节。在比特流应用中,每个图像需要增加一个附加字节作为边 界定位。还有一种可选特性,在字节流中增加附加数据,用做扩充发送数据量,能实现快速边界定位,恢复同步
    Case2:IP网络的RTP打包封装
    分组打包的规则
    (1)额外开销要少,使MTU尺寸在100~64k字节范围都可以;
    (2)不用对分组内的数据解码就可以判别该分组的重要性;
    (3)载荷规范应当保证不用解码就可识别由于其他的比特丢失而造成的分组不可解码;
    (4)支持将NALU分割成多个RTP分组;
        (5)支持将多个NALU汇集在一个RTP分组中。
    RTP的头标可以是NALU的头标,并可以实现以上的打包规则。
    一 个RTP分组里放入一个NALU,将NALU(包括同时作为载荷头标的NALU头)放入RTP的载荷中,设置RTP头标值。为了避免IP层对大分组的再一 次分割,片分组的大小一般都要小于MTU尺寸。由于包传送的路径不同,解码端要重新对片分组排序,RTP包含的次序信息可以用来解决这一问题。
    NALU分割
    对 于预先已经编码的内容,NALU可能大于MTU尺寸的限制。虽然IP层的分割可以使数据块小于64千字节,但无法在应用层实现保护,从而降低了非等重保护 方案的效果。由于UDP数据包小于64千字节,而且一个片的长度对某些应用场合来说太小,所以应用层打包是RTP打包方案的一部分。
    新的讨论方案(IETF)应当符合以下特征:
    (1)NALU的分块以按RTP次序号升序传输;
    (2)能够标记第一个和最后一个NALU分块;
    (3)可以检测丢失的分块。
    NALU合并
    一些NALU如SEI、参数集等非常小,将它们合并在一起有利于减少头标开销。已有两种集合分组:
    (1)单一时间集合分组(STAP),按时间戳进行组合;
    (2)多时间集合分组(MTAP),不同时间戳也可以组合。
    NAL规范视频数据的格式,主要是提供头部信息,以适合各种媒体的传输和存储。NAL支持各种网络,包括:
    1.任何使用RTP/IP协议的实时有线和无线Internet 服务
    2.作为MP4文件存储和多媒体信息文件服务
    3.MPEG-2系统
    4.其它网
    NAL规定一种通用的格式,既适合面向包传输,也适合流传送。实际上,包传输和流传输的方式是相同的,不同之处是传输前面增加了一个起始码前缀
    在类似Internet/RTP面向包传送协议系统中,包结构中包含包边界识别字节,在这种情况下,不需要同步字节。
    NAL单元分为VCL和非VCL两种
    VCL NAL单元包含视频图像采样信息,
    非VCL包含各种有关的附加信息,例如参数集(头部信息,应用到大量的VCL NAL单元)、提高性能的附加信息、定时信息等
    参数集:
    参数集是很少变化的信息,用于大量VCL NAL单元的解码,分为两种类型:
    1.序列参数集,作用于一串连续的视频图像,即视频序列。
    两个IDR图像之间为序列参数集。IDR和I帧的区别见下面。
    2.   图像参数集,作用于视频序列中的一个或多个个别的图像
    序列和图像参数集机制,减少了重复参数的传送,每个VCL NAL单元包含一个标识,指
    向有关的图像参数集,每个图像参数集包含一个标识,指向有关的序列参数集的内容
    因此,只用少数的指针信息,引用大量的参数,大大减少每个VCL NAL单元重复传送的信息。
    序列和图像参数集可以在发送VCL NAL单元以前发送,并且重复传送,大大提高纠错能力。序列和图像参数集可以在“带内”,也可以用更为可靠的其他“带外”通道传送。
  • 相关阅读:
    基本排序
    mysql安装
    函数和方法
    COOKIE 与 SESSION
    django---入门
    django模板继承
    2017-11-14
    Django---模板层(template)
    Dajngo---model基础
    Django--基础篇
  • 原文地址:https://www.cnblogs.com/soniclq/p/2482185.html
Copyright © 2011-2022 走看看