FU-A拆包方式小议

来源:互联网 发布:金山软件2017业绩 编辑:程序博客网 时间:2024/05/07 16:30

RFC3984是H.264的baseline码流在RTP方式下传输的规范,这里只讨论FU-A分包方式。

1、单个NAL包单元

一个封装单个NAL单元包到RTPNAL单元流的RTP序号必须符合NAL单元的解码顺序。单个NAL单元包的结构显示在图1

: NAL单元的第一字节和RTP荷载头第一个字节重合。

0                            1                            2                            3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|F|NRI|  type |                                                                                                    |

+-+-+-+-+-+-+                                                                                                  |

|                                                                                                                       |

|               Bytes 2..n of a Single NAL unit                                                         |

|                                                                                                                        |

|                                                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

|                                                                 :...OPTIONAL RTP padding     |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 

      1.  单个NAL单元包的RTP荷载格式。


 

2、FU-A的分片格式

   

如图2示,FU-ARTP荷载格式。FU-A1字节的分片单元指示,1字节的分片单元头,和分片单元荷载组成。

0                            1                            2                            3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| FU indicator|  FU header  |                                                                               |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-++-++-++-++-++-++-++-++-++-+|

|                                                                                                                         |

|                         FU payload                                                                              |

|                                                                                                                         |

|                                                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|                                                                        :...OPTIONAL RTP padding     |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

       2.  FU-ARTP荷载格式

FU indicator有以下格式:

      +---------------+

      |0|1|2|3|4|5|6|7|

      +-+-+-+-+-+-+-+-+

      |F|NRI|  Type   |

      +---------------+

   FU指示字节的类型域,28表示FU-A。。NRI域的值必须根据分片NAL单元的NRI域的值设置。

 

   FU header的格式如下:

      +---------------+

      |0|1|2|3|4|5|6|7|

      +-+-+-+-+-+-+-+-+

      |S|E|R|  Type   |

      +---------------+

   S: 1 bit

   当设置成1,开始位指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0

   E: 1 bit

   当设置成1, 结束位指示分片NAL单元的结束,即荷载的最后字节也是分片NAL单元的最后一个字节。当跟随的FU荷载不是分片NAL单元的最后分片,结束位设置为0

   R: 1 bit

   保留位必须设置为0,接收者必须忽略该位。

   Type: 5 bits

   NAL单元荷载类型定义见下表

1.  单元类型以及荷载结构总结

      Type   Packet      Type name                       

      ---------------------------------------------------------

      0      undefined                                    -

      1-23   NAL unit    Single NAL unit packet per H.264  

      24     STAP-A     Single-time aggregation packet    

      25     STAP-B     Single-time aggregation packet    

      26     MTAP16    Multi-time aggregation packet     

      27     MTAP24    Multi-time aggregation packet     

      28     FU-A      Fragmentation unit                

      29     FU-B      Fragmentation unit                 

      30-31  undefined                                    -

3、拆包和解包


拆包:当编码器在编码时需要将原有一个NAL按照FU-A进行分片,原有的NAL的单元头与分片后的FU-A的单元头有如下关系:

原始的NAL头的前三位为FU indicator的前三位,原始的NAL头的后五位为FU header的后五位,FU indicatorFU header的剩余位数根据实际情况决定。

 

解包:当接收端收到FU-A的分片数据,需要将所有的分片包组合还原成原始的NAl包时,FU-A的单元头与还原后的NAL的关系如下:

还原后的NAL头的八位是由FU indicator的前三位加FU header的后五位组成,即:

nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)

4、代码实现

void CVAUClientSource::AnalyzeHeader(unsigned char * src, int len){       unsigned char head1 = *src;//获取第一个字节       unsigned char head2 = *(src+1);//获取第二个字节       unsigned char type = head1 & 0x1f;//获取FU indicator的类型域,       if (type==0x1c)//判断NAL的类型为0x1c=28,说明是FU-A分片       {//fu-a              unsigned char flag = head2 & 0xe0;//获取FU header的前三位,判断当前是分包的开始、中间或结束              if (flag==0x80)              {//开始                     /*进行处理*/              }              else (flag==0x40)              {//结束                     /*进行处理*/              }        else{//中间   /*进行处理*/}       }       else       {//单包数据              /*进行处理*/       }       return;}


注意事项:


,1,关于时间戳,需要注意的是h264的采样率为90000HZ,因此时间戳的单位为1(秒)/90000,因此如果当前视频帧率为25fps,那时间戳间隔或者说增量应该为3600,如果帧率为30fps,则增量为3000,以此类推。

  • 2,关于h264拆包,按照FU-A方式说明:
    1)第一个FU-A包的FU indicator:F应该为当前NALU头的F,而NRI应该为当前NALU头的NRI,Type则等于28,表明它是FU-A包。FU header生成方法:S = 1,E = 0,R = 0,Type则等于NALU头中的Type。
    2)后续的N个FU-A包的FU indicator和第一个是完全一样的,如果不是最后一个包,则FU header应该为:S = 0,E = 0,R = 0,Type等于NALU头中的Type。
    3)最后一个FU-A包FU header应该为:S = 0,E = 1,R = 0,Type等于NALU头中的Type。

    因此总结就是:同一个NALU分包厚的FU indicator头是完全一致的,FU header只有S以及E位有区别,分别标记开始和结束,它们的RTP分包的序列号应该是依次递增的,并且它们的时间戳必须一致,而负载数据为NALU包去掉1个字节的NALU头后对剩余数据的拆分,这点很关键,你可以认为NALU头被拆分成了FU indicator和FU header,所以不再需要1字节的NALU头了。
  • ,3,关于SPS以及PPS,配置帧的传输我采用了先发SPS,再发送PPS,并使用同样的时间戳,或者按照正常时间戳增量再或者组包发送的形式处理貌似都可以,看播放器怎么解码了,另外提一下,如果我们使用vlc进行播放的话,可以在sdp文件中设置SPS以及PPS,这样就可以不用发送它们了。
  • ,4,使用VLC播放时,sdp文件中的分包模式选项:packetization-mode=1,否则有问题。另外sdp里面设置的编码type必须和rtp包中的一致。

  • 关于时间戳,需要注意的是h264的采样率为90000HZ,因此时间戳的单位为1(秒)/90000,因此如果当前视频帧率为25fps,那时间戳间隔或者说增量应该为3600,如果帧率为30fps,则增量为3000,以此类推。
  • 关于h264拆包,按照FU-A方式说明:
    1)第一个FU-A包的FU indicator:F应该为当前NALU头的F,而NRI应该为当前NALU头的NRI,Type则等于28,表明它是FU-A包。FU header生成方法:S = 1,E = 0,R = 0,Type则等于NALU头中的Type。
    2)后续的N个FU-A包的FU indicator和第一个是完全一样的,如果不是最后一个包,则FU header应该为:S = 0,E = 0,R = 0,Type等于NALU头中的Type。
    3)最后一个FU-A包FU header应该为:S = 0,E = 1,R = 0,Type等于NALU头中的Type。

    因此总结就是:同一个NALU分包厚的FU indicator头是完全一致的,FU header只有S以及E位有区别,分别标记开始和结束,它们的RTP分包的序列号应该是依次递增的,并且它们的时间戳必须一致,而负载数据为NALU包去掉1个字节的NALU头后对剩余数据的拆分,这点很关键,你可以认为NALU头被拆分成了FU indicator和FU header,所以不再需要1字节的NALU头了。
  • 关于SPS以及PPS,配置帧的传输我采用了先发SPS,再发送PPS,并使用同样的时间戳,或者按照正常时间戳增量再或者组包发送的形式处理貌似都可以,看播放器怎么解码了,另外提一下,如果我们使用vlc进行播放的话,可以在sdp文件中设置SPS以及PPS,这样就可以不用发送它们了。
  • 使用VLC播放时,sdp文件中的分包模式选项:packetization-mode=1,否则有问题。另外sdp里面设置的编码type必须和rtp包中的一致。
  • 0 0
    原创粉丝点击