FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法

作者:网络    软件教程库   2020-05-22

fu-a分包方式,以及从rtp包里面得到h.264数据和aac数据的方法


rfc3984是h.264的baseline码流在rtp方式下传输的规范,这里只讨论fu-a分包方式,以及从rtp包里面得到h.264数据和aac数据的方法。

h.264的nal层处理

h264以nalu(nalunit)为单位来支持编码数据在基于分组交换技术网络中传输。

nalu定义了可用于基于分组和基于比特流系统的基本格式,同时给出头信息,从而提供了视频编码和外部事件的接口。


h264编码过程中的三种不同的数据形式:
sodb 数据比特串-->最原始的编码数据,即vcl数据;
rbsp 原始字节序列载荷-->在sodb的后面填加了结尾比特(rbsp trailing bits 一个bit1)若干比特0,以便字节对齐;
ebsp 扩展字节序列载荷--在rbsp基础上填加了仿校验字节(0x03)它的原因是: 在nalu加到annexb上时,需要添加每组nalu之前的开始码startcodeprefix,如果该nalu对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示ox000001(是一帧的一部分)。另外,为了使nalu主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉。也称为脱壳操作。

编码处理过程:

1.将vcl层输出的sodb封装成nal_unit,nalu是一个通用封装格式,可以适用于有序字节流方式和ip包交换方式。

2.针对不同的传送网络(电路交换|包交换),将nal_unit封装成针对不同网络的封装格式(比如把nalu封装成rtp包)。

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

处理过程一,vcl数据封装成nalu

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


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 /* equal to 0x03 */

} else

rbsp_byte[ numbytesinrbsp++ ]

}

}

3.防字节竞争处理后的rbsp再加一个字节的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封装成nal_unit.
------------------------------------------------

处理过程二,nalu的rtp打包

一、nalu打包成rtp的方式有三种:

1.单一nal单元模式
即一个rtp包仅由一个完整的nalu组成.这种情况下rtp nal头类型字段和原始的h.264的
nalu头类型字段是一样的.

2.组合封包模式
即可能是由多个nal单元组成一个rtp包.分别有4种组合方式: stap-a, stap-b, mtap16, mtap24.
那么这里的类型值分别是24, 25, 26以及27.

3.分片封包模式
用于把一个nalu单元封装成多个rtp包.存在两种类型fu-a和fu-b.类型值分别是28和29.

还记得前面nal_unit_type的定义吧,0~23是给h264用的,24~31未使用,在rtp打包时,如果一个nalu放在一个rtp包里,可以使用nalu的nal_unit_type,但是当需要把多个nalu打包成一个rtp包,或者需要把一个nalu打包成多个rtp包时,就定义新的type来标识。

typepacket typename
---------------------------------------------------------
0undefined-
1-23 nal unit single nal unit packet perh.264
24 stap-a single-timeaggregation packet
25 stap-b single-timeaggregation packet
26 mtap16 multi-time aggregationpacket
27 mtap24 multi-time aggregationpacket
28 fu-a fragmentationunit
29 fu-b fragmentationunit
30-31undefined

二、三种打包方式的具体格式

1 .单一 nal 单元模式

对于 nalu 的长度小于 mtu 大小的包, 一般采用单一 nal 单元模式.
对于一个原始的h.264 nalu 单元常由 [start code] [nalu header] [nalu payload] 三部分组成, 其中 start code 用于标示这是一个

nalu 单元的开始, 必须是 "00 00 00 01" 或 "00 00 01", nalu 头仅一个字节, 其后都是 nalu 单元内容.
打包时去除 "00 00 01" 或 "00 00 00 01" 的开始码, 把其他数据封包的 rtp 包即可.

0123
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 01 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|f|nri| type||
+-+-+-+-+-+-+-+-+|
||
|bytes 2..n of a single nalunit|
||
|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|:...optional rtp padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


如有一个 h.264 的 nalu 是这样的:

[00 00 00 01 67 42 a0 1e 23 56 0e 2f... ]

这是一个序列参数集 nal 单元. [00 00 00 01] 是四个字节的开始码,67 是 nalu 头, 42 开始的数据是 nalu 内容.

封装成 rtp 包将如下:

[ rtp header ] [ 67 42 a0 1e 23 56 0e 2f]

即只要去掉 4 个字节的开始码就可以了.


2 组合封包模式

其次, 当 nalu 的长度特别小时, 可以把几个 nalu 单元封在一个 rtp 包中.


0123
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 01 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|rtp header|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|stap-a nal hdr| nalu 1size | nalu 1hdr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|nalu 1 data|
::
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|| nalu 2size| nalu 2 hdr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|nalu 2 data|
::
|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|:...optional rtp padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


3 fragmentationunits (fus).

而当 nalu 的长度超过 mtu 时, 就必须对 nalu 单元进行分片封包. 也称为 fragmentation units (fus).

0123
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 01 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fu indicator | fuheader||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|
||
|fu payload|
||
|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|:...optional rtp padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

figure 14. rtppayload format for fu-a

fu indicator有以下格式:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|f|nri| type |
+---------------+
fu指示字节的类型域type=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

1、单个nal包单元

12字节的rtp头后面的就是音视频数据,比较简单。一个封装单个nal单元包到rtp的nal单元流的rtp序号必须符合nal单元的解码顺序。

2、fu-a的分片格式
数据比较大的h264视频包,被rtp分片发送。12字节的rtp头后面跟随的就是fu-a分片:
fu indicator有以下格式:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|f|nri| type |
+---------------+
fu指示字节的类型域type=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. 单元类型以及荷载结构总结
typepacket typename
---------------------------------------------------------
0undefined-
1-23 nalunit single nal unit packet per h.264
24stap-a single-time aggregation packet
25stap-b single-time aggregation packet
26mtap16 multi-time aggregation packet
27mtap24 multi-time aggregation packet
28 fu-afragmentation unit
29fu-b fragmentationunit
30-31undefined-

3、拆包和解包

拆包:当编码器在编码时需要将原有一个nal按照fu-a进行分片,原有的nal的单元头与分片后的fu-a的单元头有如下关系:
原始的nal头的前三位为fu indicator的前三位,原始的nal头的后五位为fu header的后五位,fuindicator与fu header的剩余位数根据实际情况决定。

解包:当接收端收到fu-a的分片数据,需要将所有的分片包组合还原成原始的nal包时,fu-a的单元头与还原后的nal的关系如下:
还原后的nal头的八位是由fu indicator的前三位加fu header的后五位组成,即:
nal_unit_type = (fu_indicator 0xe0) | (fu_header 0x1f)

4、代码实现

从rtp包里面得到h264视频数据的方法:


//功能:解码rtph.264视频
//参数:1.rtp包缓冲地址2.rtp包数据大小3.h264输出地址4.输出数据大小
//返回:true:表示一帧结束false:fu-a分片未结束或帧未结束
#definertp_headlen12
boolunpackrtph264(void * bufin,intlen,void** pbufout,int * poutlen)
{
* poutlen = 0 ;
if(len rtp_headlen)
{
returnfalse;
}

unsignedchar* src = (unsignedchar* )bufin+ rtp_headlen;
unsignedcharhead1= * src;//获取第一个字节
unsignedcharhead2= * (src + 1 );//获取第二个字节
unsignedcharnal= head1 0x1f;//获取fuindicator的类型域,
unsignedcharflag= head2 0xe0 ;//获取fuheader的前三位,判断当前是分包的开始、中间或结束
unsignedcharnal_fua= (head1 0xe0 ) | (head2 0x1f);//fu_anal
boolbfinishframe= false;
if(nal == 0x1c )//判断nal的类型为0x1c=28,说明是fu-a分片
{//fu-a
if(flag== 0x80 )//开始
{
* pbufout= src - 3 ;
* ((int* )( * pbufout)) = 0x01000000 ;//zyf:大模式会有问题
* ((char* )( * pbufout) + 4 ) = nal_fua;
* poutlen= len- rtp_headlen+ 3 ;
}
elseif(flag == 0x40 )//结束
{
* pbufout= src + 2 ;
* poutlen= len- rtp_headlen- 2 ;
}
else//中间
{
* pbufout= src + 2 ;
* poutlen= len- rtp_headlen- 2 ;
}
}
else//单包数据
{
* pbufout= src - 4 ;
* ((int* )( * pbufout)) = 0x01000000 ;//zyf:大模式会有问题
* poutlen= len- rtp_headlen+ 4 ;
}

unsignedchar* buftmp =(unsignedchar* )bufin;
if(buftmp[ 1 ] 0x80 )
{
bfinishframe= true;//rtpmark
}
else
{
bfinishframe= false;
}
returnbfinishframe;
}


从rtp包里面得到aac音频数据的方法:


//功能:解rtpaac音频包,声道和采样频率必须知道。
//参数:1.rtp包缓冲地址2.rtp包数据大小3.h264输出地址4.输出数据大小
//返回:true:表示一帧结束false:帧未结束一般aac音频包比较小,没有分片。
boolunpackrtpaac(void*bufin,intrecvlen,void**pbufout,int*poutlen)
{
unsignedchar*bufrecv=(unsignedchar*)bufin;
//charstrfilename[20];

unsignedcharadts[]={0xff,0xf1,0x00,0x00,0x00,0x00,0xfc};
intaudiosamprate=32000;//音频采样率
intaudiochannel=2;//音频声道1或2
intaudiobit=16;//16位固定
switch(audiosamprate)
{
case16000:
adts[2]=0x60;
break;
case32000:
adts[2]=0x54;
break;
case44100:
adts[2]=0x50;
break;
case48000:
adts[2]=0x4c;
break;
case96000:
adts[2]=0x40;
break;
default:
break;
}
adts[3]=(audiochannel==2)0x80:0x40;

intlen=recvlen-16+7;
len=5;//8bit*2-11=5(headersize11bit)
len|=0x1f;//5bit1
adts[4]=len8;
adts[5]=len0xff;
*pbufout=(char*)bufin+16-7;
memcpy(*pbufout,adts,sizeof(adts));
*poutlen=recvlen-16+7;

unsignedchar*buftmp=(unsignedchar*)bufin;
boolbfinishframe=false;
if(buftmp[1]0x80)
{
//debugtrace::d("marker");
bfinishframe=true;
}
else
{
bfinishframe=false;
}
returntrue;
}

fu-a分包方式,以及从rtp包里面得到h.264数据和aac数据的方法

原文地址:http://www.cnblogs.com/lidabo/p/4481376.html

这篇内容就是由软件教程库 小编为各位整理 原文链接:https://www.itjcku.com/9999/1091574.html

阅读全部内容


Tags:分包方式以及里面

返回首页



推荐内容

java面试题之ssh

1、写出你熟悉的开源框架以及各自的作用(项目中为什么使用ssh) 答:框架:hibernate,spring,strut ...

JDBC连接数据库的过程

以连接mysql为例: (1)加载mysql数据库连接的驱动程序。到mysql官网下载该驱动程序jar包,然后把包复制到 ...

ORACLEno1存储过程插入更新表数据

create or replace procedure sp_cust_main_data_yx(instrdate i ...

win使用telnet到ubuntu下vim显示中文为乱码的解决方法~

1.几个路径: ubuntu: /etc/default/locale 相当于 centos:/etc/sysconfi ...

mediawiki的安装与配置

apache的配置: 1. 开启php module 查看mods-enabled/php5.load 是否存在,不存在 ...

C#随机数

c#中有个random类可以非常方便的产生一个随机数,但是在使用中你会发现这个类并不是特别好用,偶尔会一直提供同一 ...

shell-入门

dos2unix start.sh 在windows系统下编写的shell脚本 在liunx下进行一次转译,否则会爆出 ...

团队开发——软件需求分析报告(HelloWorld团队)

一.项目名称超级迷宫二.设计背景随着生活节奏加快,游戏更新速度的加快,游戏大同小异缺少新颖度,同时为了满足多游戏的结合, ...

MSSQl事务的使用

注册了博客这么久没还好好写过文章呢?昨天看了我同学的博客,写的很好,每次用到以前的知识我就会去看看她写的博客,现在 ...

NSDictionary转化为NSData

之前自己写了nsdictionary转化为nsdata的一种方法如下 nsmutabledata *data = ...

nginx关键字

反向代理: proxy_pass: 负载均衡: upstream 负载均衡,有四种方式:     a/ 轮询 ...

Java设计模式之简单工厂模式

设计模式之简单工厂举例: l简单工厂模式概述 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例 l优点 ...

解题报告之POJ3686TheWindy's

解题报告 之 poj3686 the windy‘s description the windy‘s i ...

【ThinkingInJava】18、关于java中的闭包与回调

/** * 书本:《thinking in java》 * 功能:关于java中的闭包与回调,这里回调区别于c++,c+ ...

TreasureHunting (hdu3468二分匹配+bfs最短路径)

treasure hunting time limit: 4000/2000 ms (java/others)mem ...

【ThinkingInJava】19、控制框架的实现

/** * 书本:《thinking in java》 * 功能:控制框架的实现 * 文件:event.java * 时 ...

【ThinkingInJava】20、控制框架的使用(初始化系统使用)

/** * 书本:《thinking in java》 * 功能:控制框架的实现,1、控制框架的完整实现是由单个的类创建 ...

最小汉密尔顿回路问题状态压缩dp

给定n个顶点做成的图,要求从顶点0出发经过所有点一次然后回到0点的一条权#20540;之和最小的一条路的权#20540; ...

POJ1966.CableTVNetwork——无向图的点连通度

http://poj.org/problemid=1966 题目描述: 有线电视网络中,中继器的连接是双向的。如果网 ...

Oracle备忘录1

数据库管理员:安装升级oracle数据库建库,表空间,表,视图,索引。。。制定并实施备份和修复计划数据库权限管理,调优, ...

FileStream文件流

使用文件流拷贝一个较大的多媒体文件: public static void copyfile(string soucr ...

C语言BFS(5)___TT与魔法师(swustoj2464)

description tt生活在一个充满魔法的国度,为了便于管理,国王请魔法师在一些重要的城市之间造出 ...

进程类Process与多线程Thread

进程类(process)的基本操作: //通过进程类查询系统所有进程 process[] pr ...

Xml解析方式之Pull解析器的使用

xml有多种解析的方式,这篇文章只介绍用pull解析器来解析xml文件,接下来我会说明使用pull解析器来读取xml文件 ...

enum,EnumMap,EnumSet

enum基本使用 : package com.enumtest; enum shrubbery { gr ...

Hibernate乱码问题解决

乱码问题其实归根接地就是两端的字符集不统一。 解决思路也有两种: 1. 修改两端字符集统一。 2. 通过代码进行转 ...

eclipse集成struts2.3.20

需要强调的是,这里介绍的是在eclipse工具下集成struts2.3.20而不是myeclipse添加对struts2 ...

ubi文件系统制作,还是"-c"选项的问题

以下是分析记录: --------------------------------------------------- ...

如何把事情做到最好读书笔记1

开篇语: 每个人生来都具备足够的潜力,每个人都能做到别人#30524;中难以企及的事情。请永远保持初学之心,勇敢面对 ...

如何把事情做到最好读书笔记2

第二章 认清自己:你属于哪种类型的人 你必须足够了解你自己,下面有三种类型的人、 (1)浅尝辄止者 浅尝辄止者对一切 ...


本网站部分内容来自互联网,版权归原作者所有,文章内容仅代表原作者个人观点。如有侵权请联系我们删除 电子邮件 itjcku@foxmail.com