音视频流媒体开发【六十九】- RTSP流媒体4-RTP之H264封包和解包

音视频流媒体开发-目录
iOS知识点-目录
Android-目录
Flutter-目录
数据结构与算法-目录
uni-pp-目录

1 H264打包RTP的⽅法

RTP的特点不仅仅⽀持承载在UDP上,这样利于低延迟⾳视频数据的传输,另外⼀个特点是它允许通过其它协议接收端和发送端协商⾳视频数据的封装和编解码格式,这样固定头的playload type字段就⽐较灵活。截⽌⽬前为⽌,RTP是我⻅过传输⾳视频数据类型最多的,具体参考:

https://en.wikipedia.org/wiki/RTP_payload_formats。

今天我以H264裸码流NALU为例,给⼤家讲述下如何进⾏H264的打包,这也是我上⾯⼏篇封装格式讲解的固定套路,其中H264打包的详细⽅法要参考RFC6184⽂档。

H.264 标 准 协 议 定 义 了 两 种 不 同 的 类 型 : ⼀ 种 是 VCL 即 Video Coding Layer , ⼀ 种 是 NAL 即Network Abstraction Layer。其中前者就是编码器吐出来的原始编码数据,没有考虑传输和存储问 题 。 后 ⾯ 这 种 就 是 为 了 展 现 H.264 的 ⽹ 络 亲 和 性 , 对 VCL 输 出 的 slice ⽚ 数 据 进 ⾏ 了 封 装 为NALUs(NAL Units),然后再封装为RTP包进⾏传输,这些都是H.264的基础,⻅后续⽂章。

NALU的基本格式是:NALU Header + NALU Data,其中NALU的头由⼀个字节组成如下所示:


参考⽂档:

https://tools.ietf.org/html/rfc3984 过时的
https://tools.ietf.org/html/rfc6184 最新的

我们看到1-11就是NALU的单个包类型,但是⼀个NALU的⼤⼩是不⼀样的,如果是⾮视频数据的SPS PPS才⼗⼏个字节,对于IDR帧,则有可能⼏⼗KB。

这样把NALU打包到RTP⽅式就很多,分为:

  • ⼀个RTP包承载⼀个NALU;
  • 多个NALU合并到⼀个RTP;
  • ⼀个⼤的NALU切分成多个RTP。

同时由于时间戳的问题,就有了24-29⼏种类型。

但是对于发送端组RTP包的⼀⽅来说,尽可能找简单的打包⽅式。对于接受端则需要适配各种发送端的打包⽅式,因为⽆法决定输⼊源的打包⽅式。这⾥先分享下我们的打包⽅式,⽐较简单(打包的时候不要搞太复杂的模式):

  1. 我们对于NALU的⻓度<=1400(rtp payload size)的则采⽤的是单⼀NALU打包到单⼀的RTP包中;
  2. 我们对于NALU的⻓度>1400的则采⽤了FU-A的⽅式进⾏了打包,这种就是把⼀个⼤的NALU进⾏了切分,最后接收⽅则进⾏了合并,把多个RTP包合并成⼀个完整的NALU即可;
  3. 为什么NALU的⻓度⼤于1400字节就要进⾏FU-A切⽚,是因为底层MTU⼤⼩值固定为1500,从传输效率讲,这⾥⽤1400作为切分条件。

同时我们发现现在视频监控领域摄像头通过RTP 传输码流的打包⽅式都是基本这种,这种打包⽅案简单容易实现,⼜满⾜需要。如下图所示:

① 28、29、30三个RTP分别传输的SPS、PPS、SEI这三种NALU,其中⼀个NALU分到⼀个RTP包,这是单⼀打包⽅式;
② 31、32三个RTP包分别传输了IDR帧的NALU单元,由于⽐较⼤,发送⽅采⽤了FU-A的打包⽅式;
③ 上图还显示了SPS、PPS、SEI的RTP包固定头,Seq初始值不为0,为随机值,并且⼀个RTP包就顺序+1,这跟上⾯分析的⼀致;
④ 上⾯SPS、PPS、SEI本身不涉及时间戳,但是这⾥头填充为和⾃⼰后⾯的第⼀个RTP保持⼀致,同样IDR的NALU切分的不同RTP包时间戳也是⼀样的;

那么到底将单⼀的NALU打包到RTP或者把⽐较⼤的NLAU打包到多个RTP即FU-A⽅式是怎么操作的呢?

1.1 打包⽅式之Single NAL Unit

就是⼀个RTP包打包⼀个单独的NALU⽅式,其实最好理解,就是在RTP固定头后⾯直接填充NLAU单元数据即可,即:

RTP Header + NALU Header + NALU Data; (不包括startcode)

为验证猜想,进⾏了抓包和写⽂件,我们发现写⽂件的SPS和抓包RTP包固定头后⾯的负载完全是⼀致的,写⽂件中的SPS:

抓包中的RTP固定头后⾯的SPS:

1.2 打包⽅式之FU-A

这种打包⽅式也不复杂,为了解释清楚,需要了解下⾯两个数据包头即FU indicator和Fu header。

FU indication

这⾥⾯的的F和NRI已经在NALU的Header解释清楚了,就是NALU头的前⾯三个bit位,后⾯的TYPE就是NALU的FU-A类型28,这样在RTP固定头后⾯第⼀字节的后⾯5bit提取出来就确认了该RTP包承载的不是⼀个完整的NALU,是其⼀部分。

那么问题来了,⼀个NALU切分成多个RTP包传输,那么到底从哪⼉开始哪⼉结束呢?可能有⼈说RTP包固定头不是有mark标记么,注意区分那个是以帧图像的结束标记,这⾥要确定是NALU结束的标记,其次NALU的类型呢?那么就需要RTP固定12字节后⾯的Fu Header来进⾏区分。

FU header

字段解释:
S: 1 bit 当设置成1,开始位指示分⽚NAL单元的开始。当跟随的FU荷载不是分⽚NAL单元荷载的开始,开始位设为0。
E: 1 bit 当设置成1, 结束位指示分⽚NAL单元的结束,即, 荷载的最后字节也是分⽚NAL单元的最后⼀个字节,当跟随的FU荷载不是分⽚NAL单元的最后分⽚,结束位设置为0。
也就是说⼀个NALU切⽚时,第⼀个切⽚的SE是10,然后中间的切⽚是00,最后⼀个切⽚时11。
R: 1 bit
保留位必须设置为0,接收者必须忽略该位。
Type: 5 bits
此处的Type就是NALU头中的Type,取1-23的那个值,表示 NAL单元荷载类型定义,

综上所述:
对于⽐较⼤的NLAU进⾏FU-A切⽚时,其中NALU的Header字段在RTP打包时划分为两个字节
1、NALU header的前3bit为RTP固定头后⾯第⼀个字节FU-indication的前3bit,后⾯5bit后⾯跟了FU-A打包这种类型28;
2、NALU header的后⾯5bit变成了RTP固定头第⼆字节的后⾯5bit,其中前3bit标识了分⽚的开始和结束。

为了验证这种打包⽅式,我们同样进⾏了写⽂件和抓包,对第⼀个IDR帧的NLAU采取的这种分⽚进⾏了研究。

第⼀个IDR帧的NALU第⼀个切⽚:

FU indication

⼗六机制:0x7C
⼆进制:0111 1100
FU header
⼗六进制:0x85
⼆进制:1000 0101
这⾥的SE是10,则说明该RTP包承载的NALU的第⼀个切⽚。

这样我们提取FU indication字节的前3bit位和Fu header字节后5bit位则为0110 0101即0x65这刚好符合IDR帧的NALU Header定义,后⾯的b8 00 00 03等⼆进制就是NALU的DATA字段。

第⼀个IDR帧的NALU第⼆个切⽚:

FU indication

⼗六机制:0x7C
⼆进制:0111 1100

FU header

⼗六进制:0x05
⼆进制:0000 0101

这⾥的SE是00,则说明该RTP包承载的NALU的中间切⽚。

按照同样⽅法提取,则NALU Header的⼆进制为0110 0101即0x65,同样说明是IDR帧类型,类似这种的中间切⽚有很多,从31-56RTP包都是中间切⽚,直到最后⼀个NALU的切⽚。

第⼀个IDR帧的NALU最后⼀个切⽚:

FU indication

⼗六机制:0x7C
⼆进制:0111 1100

FU header

⼗六进制:0x45
⼆进制:0100 0101

这⾥的SE是01,则说明该RTP包承载的NALU的最后⼀个切⽚。

当然通过抓包你还可以到IDR帧时⽐较⼤的,⽽后⾯的P帧就相对⽐较⼩,因为⼀个NALU切⽚4次就完了,同样能看到时间戳的变化值等信息。

我们可以看到发送端⼀般采⽤Single NAL Unit和FU-A打包⽅式就基本可以将H264数据发送到接收端了,对于AAC⾳频来说,直接将ADTS头部去掉以1024字节组成⼀帧直接塞到RTP即可,打包并不难。⾄于其他的封装格式如PS、TS或者H265,VPx等数据如何打包RTP,以后再给⼤家进⾏分享,完善这个传输系列。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容