自我认知中的RTP(2)

本文深入介绍了H264编码格式,包括SODB、RBSP、EBSP和NALheader等组成部分。重点解析了NAL单元头的nal_ref_idc和nal_unit_type字段,以及如何通过这些字段区分I帧、P帧和B帧。此外,还讨论了一帧数据可能包含的多个NALU和NALU在RTP中的打包方式,对于理解H264在网络传输中的处理具有指导意义。
摘要由CSDN通过智能技术生成

RTP头介绍完后,可以介绍下负载,本文以H264为例,进行介绍。


前言

RTP头介绍完后,可以介绍下负载,本文以H264为例,进行介绍。
编码和H.264编码概述

一、H264是什么?

        作为一款视频压缩编码,h264强调更高的压缩率和可靠的传播性(相同码率下压缩率高且图像质量高、同时具有网络亲和性)。压缩 算法的细节暂时不学习,主要还是了解包的封装格式,slice格式也暂时不涉及。。

        经过一些列的压缩好,形成了I帧,P帧,B帧。

  • I帧:关键帧,采用帧内压缩技术。
  • P帧:向前参考帧,在压缩时,只参考前面已经处理的帧。采用帧音压缩技术。
  • B帧:双向参考帧,在压缩时,它即参考前而的帧,又参考它后面的帧。采用帧间压缩技术。
             此外还有一个GOP概念,两个I帧之间是一个图像序列,在一个图像序列中只有一个I帧。
    在这里插入图片描述

二、H264的编码格式

H264功能划分为2层:
VCL(Video Coding Layer),视频编码层,H264编码/压缩的核心,主要负责将视频数据编码/压缩,再切分。
NAL(Network Abstraction Layer),网络抽象层,这里的网络指的是计算机网络而不是神经网络,负责将VCL的数据组织打包。
下面这张图很传神:
在这里插入图片描述

1.SODB

String Of Data Bits 数据比特串-->最原始的编码数据

2.RBSP

Raw Byte Sequence Payload: 原始字节序列载荷,是在原始编码数据后面添加了结尾比特,一个bit“1”和若干个比特“0”,用于字节对齐。

3EBSP

Encapsulated Byte Sequence Payload扩展字节序列载荷(这几个名字翻译的真别扭),RBSP插入防竞争字节0x03。
原因是这样的,最终一个编码报文,前面会有0x000001或者0x00000001,用于标记是一个报文开始。但是,编码数据是多种多样的,有可能数据里面会和这个起始一样,因此,就说明在连续两个0x00后面插入一个0x03。解码时将0x03去掉。

总结:编码数据字节对齐后,然后将连续的两个0x00中间插上0x03,加上一字节的nal头,在最前面加上起始码0x00000001.

载荷说完后,然后看头:

4.NAL header

NALU头用来标识后面的RBSP是什么类型的数据。长度只有一字节,短小精悍起作用。

| forbidden_zero_bit | nal_ref_idc | nal_unit_type |
`--------------------+-------------+---------------`
|        1 bit       |    2 bit    |    5 bit      |
F: 1 个比特.
  	forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.
NRI: 2 个比特.
  	nal_ref_idc.00 ~ 11, 似乎指示这个 NALU 的重要性,00的NALU解码器可以丢弃它而不影响图像的回放,03,取值越大,表示当前NAL越重要,需要优先受到保护。如果当前NAL是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的单位时,本句法元素必需大于0。
Type: 5 个比特.
  	nal_unit_type. 这个 NALU 单元的类型. 简述如下:
	0    没有定义
	1     一个非IDR图像的编码条带 (bp帧)   
	2     编码条带数据分割块A 
	3     编码条带数据分割块B     
	4     编码条带数据分割块C   
	5     IDR图像的编码条带 (i帧)    
	6     辅助增强信息 (SEI) 
	7     序列参数集 (sps帧)
	8     图像参数集 
	9     访问单元分隔符 
	10     序列结尾 
	11     流结尾 
	12     填充数据 
	13     序列参数集扩展    
	14...18     保留      
	19     未分割的辅助编码图像的编码条带    
	20...23     保留      
	24    STAP-A   单一时间的组合包
	25    STAP-B   单一时间的组合包
	26    MTAP16   多个时间的组合包
	27    MTAP24   多个时间的组合包
	28    FU-A     分片的单元
	29    FU-B     分片的单元
	30-31 没有定义

一帧压缩数据有几个NALU
        一个视频帧输出的结果可以打包成一个NALU,也可能有多个NALU,含有多个NALU叫多个slice(multiple slices)。Slice(分片),h264编码可以将一幅图片分割成若干个Slice,Slice承载固定数目的宏块。将一幅图片分割成若干Slice的目的是,为限制误码的扩散和传输。如果H264的一个帧被分片编码,则每个slice最后将产生一个NALU。
        如果NALU对应的Slice为一帧的开始,则用4字节表示,即0x00000001,代表一个帧头的起始码前缀;否则用3字节表示,0x000001,就是一个完整的帧被编为多个slice的时候,第二个slice及以后的Slice的nalu使用3字节起始码。

总结:4字节头只出现在SPS、PPS和7.4.1.2.3规定的Access Unit的首个nalu。其余情况都是3字节头。

h264仅用1-23,24以后的用在RTP H264负载类型头中,这就意味着仅仅在h264这一层类型1-23,如果将其打包进RTP中是,在RTP头后的第一字节虽然和H264的nal header 长得一样,但是还是要根据具体情况进行类型的分配。因为RTP牵扯到了网络传输,在网络传输对数据长度有限制,因此有时需要对一个nalu进行拆包,拆包后的rtp负载类型可能就是28,FU-A

[start code]–[NALU]–[start code]–[NALU]…

1.区分帧类型。

在实际的H264数据帧中,往往帧前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧。
例如上面00000001后有67,68以及65,41

其中0x67的二进制码为:
0110 0111
4-8为00111,转为十进制7,对应序列参数集SPS

其中0x68的二进制码为:
0110 1000
4-8为01000,转为十进制8,对应图像参数集PPS

其中0x65的二进制码为:
0110 0101
4-8为00101,转为十进制5,对应IDR图像中的片(I帧)

要判断B帧和P帧,则需要到slice层去判断用到“熵编码”。
一个frame是可以分割成多个Slice来编码的,而一个Slice编码之后被打包进一个NAL单元,不过NAL单元除了容纳Slice编码的码流外,还可以容纳其他数据,比如序列参数集SPS。

(NALU类型  & 0001  1111= 5   

if(pData[i] == 0 && pData[i+1] == 0 &&
    pData[i+2] == 0 && pData[i+3] == 1 &&
    (pData[i+4] & 0x1F) == 5)
    {
        cout<<"IS I_FRAME"<<endl;
    }
else if(..........)
{

}

在这里插入图片描述
h264编码格式就看完了,下一个就是NALU 打包到RTP中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值