打包TS流

做这一个事物很久了,从上年十三月份开始的,快5个月了。。。时期因为做事一直断断续续,直到方今才有了些进展,也就到此截止吧。

先说下小编做的是何等吧,总的来说,就是把H264视频流与AAC音频流封装成TS格式。要马到成功如此个效率首先要解析H264和AAC,得到录像帧和音频帧以及一些根本音信,比如帧率、采样率什么的为随后的打包做工作。分析到每一帧数据后,再添加PES头,封装成PES数据,在那些进程要留意打PTS、DTS,以及PES类型的设定,一般的话,录制PTS与DTS都要打,而音频只须求打PTS。最终一步就是将PES数据封装成TS了,这一步的坑比较多。做完这么些,最难个人感觉就是音视频同步了,于今还相比较疑忌,摄像播出来总是有通病。

一、解析h264

H264是以0x00 00 01或0x00 00 00
01看作分割NALU单元分割符的,整个H264也是以NALU作为主导单元的,NALU的协会如图一所示:

 图1

NALU包涵头和负载RBSP,尾部的句法结构如图二所示:

·图2

那1个字节便蕴藏了方方面面尾部的音信,约等于删除分割符后的头三个字节。nal_unit_type指明的NALU的门类,不多说了,贴图吧。。。

图3

NALU的负载RBSP在读取有效数据从前率先要做去除竞争码的操作,境遇0x00 00
03将字节0x03去掉即可。

·0x00 00 00  —–> 0x00 00 03 00

·0x00 00 01  —–> 0x00 00 03 01

·0x00 00 02  —–> 0x00 00 03 02

·0x00 00 03  —–> 0x00 00 03 03

负载的类型由前文nal_unit_type钦点,当值大于等于1,小于等于5的时候指明该负载是片数量(slice),去除竞争码后的载重采纳的是台中编码。在看片数据句法结构的时候能够留意到每种字段后边都有局地标记表达,如ue(v)se(v),给张图看的比较清楚

图4

自个儿贴的是片头句法的一局部,在合成TS的时候若是判断片类型就足以了,相当于说,只要将图4的slice_type剖析出即可,要想完全的解出片依然有点难度的,然而判断片的体系并简单。

回去前边的马赛编码,那是一种变长编码,括号里面带v的均是指编码的尺寸不稳定。

或基于布里斯托编码动态明确,或由前文指定,符号ue(v)se(v)证实解码的尺寸可依照麦德林编码的条条框框动态指定,而u(v)此处的解码长度得由上文钦点,有多少个字段都以如此,怎样由上文确定长度的资料不太好找,只找到3个英文的网站,它讲明了多少个字段(http://m.blog.csdn.net/article/details?id=40302581)

解码毕尔巴鄂编码的字段可以采取网上的库,看起来尚可,但因为是在探讨学习那个事物,

自家选用了投机完成那个算法,也不是特地复杂。首先说下无符号的匹兹堡编码,按网上的概念,武汉的编码方式有0阶、1阶、2阶…每一种恍若都差别等,也从未都去研商,因为H264用到的只是0阶的匹兹堡编码,弄懂这几个就丰富了。

1.1无符号0阶指数长沙编码(ue)**

依照算法的叙述,应先将数据以二进制格局排列,接着延续读取M个0比特位,蒙受1比特位停止读取,这时解码的多寡长度就早已显然了,为2*M+3个比特,包罗前面早已读取的M个0比特。再将最终的M位比特转化成十进制数值W,即可拿到解码结果为W-1,到此截止,两次完整的无符号解码就到位了。

·无符号弗罗茨瓦夫编码测试例子:

                                                  (解码后)

0x4C  0x85  0x31  0xC4  0x09 =====> 1  2  3  4  5  6  7  8

1.2有号子0阶指数罗利编码(se)

有记号的弗罗茨瓦夫编码建立在无符号的底子上,依照无符号的解码步骤拿到十进制数n后,再实施以下的动作即可。

·获取n被2除后的商w(注意那几个商是去除了小数的整数部分)

·n不可以被2整除,w加1为解码结果

·n能够被2整除,w的相反数即为解码结果

                                                (解码后)

0x4C  0x85  0x31  0xC4  0x09 =====>1  -1  2  -2  3  -3  4  -4

1.3帧类型

前方在解析片数据的时候有关系过片的门类,实际上那里指明的是片所装载的视频帧的项目,按定义分为I,P,B,SP,SI,图5付出slice_type与帧类型的呼应关系

图5

自个儿在解码的时候只关怀了I,P,B帧,其它的二种帧的意思感觉和I,P帧类似,所以没做过多的探讨。I,P,B帧的差距在于编码格局的异样,I帧数据不借助于其他的帧数据,可独立解码,而P帧使用前向预测编码,它的解码依靠前面解码的I帧和P帧,B帧用了双向预测编码,解码B帧图像,须要同时参考前后的帧数据。它们压缩数量的能力也逐一增进,一般的话,B帧相比较多的互联网摄像流同等比特量所传输的录制质量会更高,不过相应的,播放器的解码压力也更大。由于P、B帧的解码要求参考其余帧,所以在解码的时候或然会生出误码扩散的图景,但由于播放器在遭逢I帧的时候会甩掉此前解码的摄像数据,再以当前的I帧作为以往P、B帧的参考帧,由此这一举措及时的拦截了错误的扩散,说到那里,小编得额外提下HLS协议,那一个协议在创设切片的时候总是以I帧开首,不仅是为了在播报视频的时候立即刷出图像,作者想更加多的是因为H264那种编码格式的界定而只可以以I帧初步,因为唯有I帧是足以独立解码的,假如开始的是其它须求参考的帧,他们的解码毫无意义。

二、打包PES

PES是对裸流的一层封装,H264和AAC就是三种裸流,他们就像是还没装订的书,随意的被堆放在角落里,PES的包装就是将混乱的纸打上页码装成书的进度。那里的页码指的就是PTS与DTS,突显时间戳息争码时间戳,这些小时足以指示播放器何时呈现一帧图像或然音频,一般的话摄像帧PTS、DTS都急需打,尤其是在有B帧的气象下,因为B帧须要参考前后两帧,所以它要等到前后帧都被解码出后才能解此B帧,因而B帧的来得时间息争码时间是不均等的,而音频帧没有那种景况,解一帧放一帧即可,它是不需求DTS的。PES头的句法结构如图6

 图6(1)

  图6(2)

PES的整结构没有完全的贴上来,只贴到PTS、DTS那有个别句法,其实在打包TS的时候,那有的已经丰裕了,其他的可以不去关怀。接下来说Bellamy下多少个紧要的字段。

·packet_start_code_prefix

那3个字节是PES的起首码,将PES包一一隔开,先导是一定的0x00 0x00 0x01

·stream_id

指明PES负载的门类,摄像为0xE0,音频为0xC0

·PES_packe_length

阐明在此字段末了三个字节之后PES分组的字节数。‘0’值声明PES分组的长短既没有表达也没有界定,那种情状唯有在PES分组的实惠载荷是传递流分组中的摄像原始流时才同意。

·PTS_DTS_flag

4位标志,若为‘10’,则PES分组首部有PTS字段;若为‘11’,则PES分组首部有PTS和DTS字段;若为’00’则PTS和DTS都不在PES分组首部出现;‘01’值被明令禁止。

·PES_header_data_length

声明在此字段最终三个字节还剩下的PES底部分组数据量,一般只怕指的是PTS与DTS部分编码的长度。

PES分组中相比较根本的字段就地点这么些的,对于PTS与DTS的编解码,依照PTS_DTS_flag以及相应的句法提示去做即可。

三、合成TS

TS流每一种包的高低都在于188-204字节之间,一般就是188字节,逐个PES包为主都不止188字节,所以在把PES封装成TS时,需求将PES分割成多个TS包,各种包都有唯一的ID标识它的连串,音摄像PES打包成TS包的ID由TS中的PMT表钦定,PMT表被单独打成二个TS包,它也有ID标识,这几个标识由PAT表钦赐,与PMT类似,PAT也被打成单身的包,它的ID是定点的0,所以,不管是解码还是编码TS流,都应从PAT表入手。

3.1 TS包格式

  图7

TS包由头与负载组成,底部占两个字节,假设还有自适应区,那么自适应区的长短由第拾个字节钦赐。这里先简要的分析下TS头的前七个字节。

·sync_byte

那里是一路字节,固定为0x47

·transport_error_indicator

以此比特位作者从没用到过,一贯都以0

·payload_unit_start_indicator

此比特位为1,标志着PES包负载的启幕,不仅如此,若是是PAT、PMT包,那里也被置为1

·transport_priority

小编暂没用到,暗中认同是0

·PID

种种包连串的标识

·transport_scrambling_control

本人暂未利用

·adaptation_field_control

此字段标识是不是有自适应区

00:是保留值。

01:负载中唯有有效载荷。

10:负载中唯有自适应字段。

11:先有自适应字段,再有有效载荷。

一旦带有自适应区,那么头八个字节后就是自适应区的码流结构,最终才是TS包的载荷部分

·continuity_counter

其一字段的值从00 – 15屡屡连续变化

3.2自适应区格式

 图8

·adaptation_field_length

以此字节指明了自适应区的尺寸,不分包此字节

·PCR_flag

若是此位被置为1,依据句法格式,接下去存在PCHighlander值,那么些值根据一定的公式转化成了program_reference_baseprogram_clock_reference_extension五个字段的值

PC本田CR-V是音摄像同步的要紧参数,它控制播放器曾几何时播放一帧音频或视频,它实质上是2个像样于岁月戳的东西,它能够用PES包的PTS或DTS来赋值,假使那么些值是timestamp,那么就有

program_clock_reference_base=  timestamp       (mod)  2^33

program_clock_reference_extension  = (300 * timestamp)  (mod)
 300

PCR  =program_clock_reference_base* 300
 +program_clock_reference_extension

3.3PAT表

 图9

PAT表指明了PMT表的PID,每种PMT表又有什么不可提议音视频包的PID值,从那边可以看看三个PMT表就代表三个音录像流,或然说2个节目,当有各样PMT表时,表达在那几个TS流中存在多样音录制流,八个剧目,从而达成了节目复用的效率,实际上PAT表是能够索引三种PMT表的,但自己在打流的时候只上了一种PMT,没涉及,东西在精不在多,把一种讨论透了,其余的约等于复制粘贴的法力。

图10贴的是PAT表负载的section部分,不难的细分下PAT表多个区域,首个是头五个字节,第壹是自适应区,但是那么些自适应区没内容,由此标志自适应长度的不得了字节为0,第多少个就是其一section部分,在其中指明了PMT表的PID值,第7个是填充区域,严谨来说,它和section共同组成了ts包负载的一些,一般填充区域的比特位都置为1。

·table_id

PAT表此值为0

·section_syntax_indicator

此职责为1

·reserved

像这种标志比特位都以置为1的

·section_length

那11位指出了从该字段之后到C酷威C_32(包括它)甘休的字节数

·CRC_32

4字节的循环校验码,它依据section区域动态总括得出

3.4 PMT表

图10(1)

 图10(2)

PMT表的功效是稳定音录像包的PID值,以福利播放器找到并解码,接下去说下多少个重大的字段。

·table_id

那边的值固定为0x02

·PCR_PID

以此字段指明了PCEnclave值所在TS包的PID

·program_info_length

点名了接下去描述子decriptor()的大大小小,没什么要求描述的就置为0吗

·stream_type

流类型,如下图所示

H264的摄像,流类型为0x1b,AAC音频一般为0x0f,随后的PID值就是对应的TS包标识了

·ES_info_length

表明ES流的附加新闻,可有可无,若是没有增大新闻,这些字段值为0

·CRC_32

与PAT的校验码类似

3.5打包H264视频帧

诚如的话,二个负载为I、P、B片的PES包可用作一帧,或然说的不太标准,一帧录制从概念上就是连环画的完好的一页,而一片啊大概就只是一页的部分画面了,但小编打包的时候是依照I、B、P片为单位的,为了好了然也叫一帧吧。

梳理下从H264到TS的经过,首先H264的单元叫NALU,二个I、B、P片就相应2个NALU,NALU加上PES头打上PTS或DTS后得到二个PES包,咱们前几天要做的就是将以此带有视频数据的PES包分割成二个又三个的TS包,也等于包装一帧录像。

PES包数据在打包TS时,均作为TS包的负载部分。装载PES的首先个TS包,后面说过,payload_unit_start_indicator字段要为1,那注解着一帧PES数据的上马。一般打包摄像帧的时候也会打上PC兰德酷路泽的值,不是每帧都要打,不过对于I帧最好或然打上。还有少数要专注的是,在从NALU到PES的时候,在每帧数据前都要丰硕0x000000
01 09
xx
那多少个字节,然后再打PES头,xx的值好像可以随心所欲选定,如此打出的流苹果之类的播放器才能支撑。

最后再说下I帧,在打包I帧的时候比打包其余两帧有越来越多必要小心的标题,首先,在I帧的面前最好能打上PAT与PMT表,如此一来,在任意一段的TS流中,只要包括了I帧,那么有很大几率得以被解码播放,那也是TS流的一个特色。H264除开包含I、B、P的NALU外,还有二种含有视频新闻的NALU,SPS与PPS,分别是种类参数集与图像参数集,他们对此解码I、B、P片有主要职能,没了那三种NALU播放器是解码不出摄像的,所以为了有限协助视频能健康解码,在打包TS流时,那三种NALU被置于了I帧数据的面前,它们是与I帧数据一起被封装成PES包再分割成TS的,那与此外帧二个NALU对应二个PES包有所不相同。

在分割摄像的七个PES包时,TS头的continuity_counter值要保全再三再四,从0-15往往变化。它随着上一回打包录制帧时最后这个TS包的coutinuity_counter值延续变化。

3.6打包AAC音频帧

AAC的格式相比简单,它的单元以0xFFF做为初阶码,大家打包的就是两个以0xFFF开端的AAC单元。作者的做法是多少个AAC单元对应二个PES包,再划分成七个个TS包,那样做恐怕有点浪费数据量,因为3个AAC单元比较一帧录制要小得多,在卷入成TS时,为了保持逐个TS包都是188字节,在装载PES数据的末梢1个TS包时往往要丰富填充字节,填充字节是加在自适应区的,由于一个AAC单元所装载的数据量很小,所以对待于录像帧来说,AAC单元的数量多,那么最终打成的TS包就带有较多没用的填充字节,浪费传输的带宽,作者看FFMPEG在打音频帧的时候是10多少个AAC单元被同时包成3个PES包的,作者不知道它那样打的平整,所以也从不用,而且3个AAC单元对应3个PES包的做法完成起来相比较不难并且播放器也能日常解码,所以就动用了那种打法。

打音频帧比视频帧不难多了,除了开始包的payload_unit_start_indicator要为1,以及coutinuity_counter值一而再变化之外,没有其余须要,可是如故要晋升一点的是coutinuity_counter值是跟着上一次打包音频数据的coutinuity_counter来的。

3.7音视频同步

本条标题本身也在研商中,所以本身这边不做阐明,只贴出多少个参考的链接,这一个链接中富含了PTS与DTS的打法,但是并未PCLX570的打法,我目前就是视频帧PES包的PTS直接就当作TS包的PC卡宴值了。

[TS流打包总括]

http://blog.csdn.net/yuan1125/article/details/51540918

[ffmpeg转码MPEG2-TS的音录制同步机制分析]

http://blog.chinaunix.net/uid-26000296-id-3483782.html

四、后记

本次学习打TS流的经过本人很乐意,固然费用的岁月比较长,但这也算得上自作者首先次探讨学习的经验呢,之前要学一样东西,资料总是齐备的,看几眼就能精晓个大约,因为是在全校,有教材与导师领着,但那仅限于教材上的事物,在进入社会行事后,很多学问与技术都以从未有过完备的科目标,即便有,大概也不必然能找得到。学习那一个材料缺失的文化是五回商讨学习的进度,因为材质稀缺,为了驾驭其中1个知识面,不得不倚重搜索工具大量翻看,在翻阅了几11个网站到底取得一句话甚至是二个字的端倪时,那时不得不说,小编是惊喜和满意的,到终极小编能打成一段能够播放的TS流时,小编认为那八个月再长也值了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注