打包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的结构如图一所示:

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

这一个字节便包含了整个头部的信息,也就是去除分割符后的头一个字节。 nal_unit_type 指明的NALU的类型,不多说了,贴图吧。。。

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) ,给张图看的比较清楚

我贴的是片头句法的一部分,在合成TS的时候只要判断片类型就可以了,也就是说,只要将图4的 slice_type 分析出即可,要想完整的解出片还是有点难度的,不过判断片的类型并不难。

回到前面的哥伦布编码,这是一种变长编码,括号里面带 v 的均是指编码的长度不固定。

或根据哥伦布编码动态确定,或由前文指定,符号 ue(v) 与 se(v) 说明解码的长度可根据哥伦布编码的规则动态指定,而 u(v) 这里的解码长度得由上文指定,有几个字段都是如此,如何由上文确定长度的资料不太好找,只找到一个英文的网站,它说明了几个字段(http://m.blog.csdn.net/article/details?id=40302581)

解码哥伦布编码的字段可以选用网上的库,看起来还行,但因为是在研究学习这个东西,

我选择了自己实现这个算法,也不是特别复杂。首先说下无符号的哥伦布编码,按网上的定义,哥伦布的编码方式有0阶、1阶、2阶...每种好像都不一样,也没有都去研究,因为H264用到的只是0阶的哥伦布编码,弄懂这个就够用了。

1.1 无符号0阶指数哥伦布编码 (u e)

按照算法的描述,应先将数据以二进制方式排列,接着连续读取M个0比特位,碰到1比特位结束读取,这时解码的数据长度就已经确定了,为2*M+1个比特,包含前面已经读取的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 与帧类型的对应关系

我在解码的时候只关心了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

PES的整结构没有完整的贴上来,只贴到PTS、DTS这部分句法,其实在打包TS的时候,这部分已经够用了,其他的可以不去关心。接下来说明一下几个重要的字段。

·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

2位标志,若为‘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 包格式

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 自适应区格式

· adaptation_field_length

这个字节指明了自适应区的长度,不包含此字节

· PCR_flag

如果此位被置为1,按照句法格式,接下来存在PCR值,这个值按照特定的公式转化成了 program_reference_base 和 program_clock_reference_extensio n 两个字段的值

PCR是音视频同步的关键参数,它决定播放器什么时候播放一帧音频或视频,它本质上是一个类似于时间戳的东西,它可以用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.3 PAT 表

PAT表指明了PMT表的PID,每个PMT表又可以指出音视频包的PID值,从这里可以看出一个PMT表就代表一个音视频流,或者说一个节目,当有多种PMT表时,说明在这个TS流中存在多种音视频流,多个节目,从而实现了节目复用的效果,实际上PAT表是可以索引多种PMT表的,但我在打流的时候只上了一种PMT,没关系,东西在精不在多,把一种研究透了,其他的也就是复制粘贴的效果。

图10贴的是PAT表负载的section部分,简单的划分下PAT表四个区域,第一个是头四个字节,第二是自适应区,不过这个自适应区没内容,因此标志自适应长度的那个字节为0,第三个就是这个section部分,在里面指明了PMT表的PID值,第四个是填充区域,严格来说,它和section共同组成了ts包负载的部分,一般填充区域的比特位都置为1。

·table_id

PAT表此值为0

· section_syntax_indicator

此位置为1

· reserved

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

· section_length

这12位指出了从该字段之后到CRC_32(包含它)为止的字节数

· CRC_32

4字节的循环校验码,它根据section区域动态计算得出

3.4 PMT 表

PMT表的作用是定位音视频包的PID值,以方便播放器找到并解码,接下来说下几个重要的字段。

· table_id

此处的值固定为0x02

· PCR_PID

这个字段指明了PCR值所在TS包的PID

· program_info_length

指定了接下来描述子 decriptor() 的大小,没什么需要描述的就置为0吧

·s tream_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片就对应一个NALU,NALU加上PES头打上PTS或DTS后得到一个PES包,我们现在要做的就是将这个包含视频数据的PES包分割成一个又一个的TS包,也就是打包一帧视频。

PES包数据在打包TS时,均作为TS包的负载部分。装载PES的第一个TS包,前面说过, payload_unit_start_indicator 字段要为1,这标志着一帧PES数据的开始。一般打包视频帧的时候也会打上PCR的值,不是每帧都要打,不过对于I帧最好还是打上。还有一点要注意的是,在从NALU到PES的时候,在每帧数据前都要加上 0x00 00 00 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包,这样做可能有些浪费数据量,因为一个AAC单元相比一帧视频要小得多,在打包成TS时,为了保持每个TS包都是188字节,在装载PES数据的最后一个TS包时往往要加上填充字节,填充字节是加在自适应区的,由于一个AAC单元所装载的数据量很小,所以相比于视频帧来说,AAC单元的数量多,那么最后打成的TS包就含有较多无用的填充字节,浪费传输的带宽,我看FFMPEG在打音频帧的时候是10多个AAC单元被同时包成一个PES包的,我不知道它这样打的规则,所以也没有用,而且一个AAC单元对应一个PES包的做法实现起来比较简单并且播放器也能正常解码,所以就采用了这种打法。

打音频帧比视频帧简单多了,除了开头包的 payload_unit_start_indicator 要为1,以及 coutinuity_counter 值连续变化之外,没有别的要求,不过还是要提醒一点的是 coutinuity_counter 值是接着上一次打包音频数据的 coutinuity_counter 来的。

3.7 音视频同步

这个问题我也在探究中,所以我这里不做说明,只贴出几个参考的链接,这些链接中包含了PTS与DTS的打法,但是没有PCR的打法,我目前就是视频帧PES包的PTS直接就作为TS包的PCR值了。

[TS流打包总结]

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

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

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

四、 后记

这次学习打TS流的过程我很满意,虽然花费的时间比较长,但这也算得上我第一次探究学习的经历吧,以前要学一样东西,资料总是齐备的,看几眼就能知道个大概,因为是在学校,有教材与老师领着,但这仅限于教材上的东西,在进入社会工作后,很多知识与技能都是没有完备的教程的,即使有,可能也不一定能找得到。学习这些资料缺失的知识是一次探究学习的过程,因为资料稀缺,为了了解其中一个知识面,不得不借助搜索工具大量查阅,在翻阅了几十个网站终于得到一句话甚至是一个字的线索时,那时不得不说,我是惊喜和满足的,到最后我能打成一段可以播放的TS流时,我觉得这五个月再长也值了。


什么是TS流?
作为一名数字电视前端研发工程师,我的日常工作中与TS流紧密相连,它就像电视信号的乐谱,是FPGA解码的核心舞台。TS流,全称Transport Stream,是一种业界标准的数据包结构,它巧妙地封装了MPEG-2或H.264编码后的音视频数据。每个TS包大小固定,为188或204字节,且包头始终保持着4字节的规律性。TS流的独...

ts流是什么意思啊?
TS流通常指的是MPEG-2转输流(MPEG-2 Transport Stream),是数字信号传输中常用的流式协议。其将压缩好的音视频等信息划分成小的数据包,通过网络传输,具有的优点是可靠性高,可快速切换多路数据流,在数字电视、广播、IPTV和网络直播等领域得到广泛应用。通过使用TS流,可以将压缩好的音视频数据等格式...

MPEG-2 TS流结构详细浅析
TS流由固定大小的包组成,每个包包含头部和有效负载,头部包含同步信息,确保在传输误差下仍能恢复。TS包结构允许在信道质量较差时,接收机通过检测后续包的同步信息进行恢复,而PS流的可变长度包在失同步时可能导致信息丢失。

MPEG-2 TS流结构详细浅析
TS流的核心是其头部结构,每个包由固定长度的头部和有效负载组成,负载即PES数据。头部包含了关键的固定和自适应字段,比如sync_byte、transport_error_indicator等,其中,transport_scrambling_control和adaptation_field_control决定着包的扩展形式。continuity_counter确保数据的连续性,自适应字段长度可变,根据...

ts流与rtsp流的区别是什么?
在传输方式上,TS流通常是通过流媒体服务器进行传输的,而RTSP流则可以通过TCP或RTP等协议进行传输。此外,RTSP流在传输过程中,通常需要使用2-3个通道,包括命令通道和数据通道,以实现更好的控制和数据传输效果。最后,在格式方面,TS流通常封装的是MP4、TS等格式的多媒体数据,而RTSP流则通常传输的是...

在音视频中请问什么是ts流 ,es流,ps流
数字信号实际传送的是数据流,一般数据流包括以下三种:ES流:也叫基本码流,包含视频、音频或数据的连续码流。TS流:也叫传输流,是由固定长度为188字节的包组成,含有独立时基的一个或多个节目,适用于误码较多的环境。TS流(TransportStream)即在MPEG-2系统中,由视频,音频的ES流和辅助数据复接生成...

什么是TS码流
TS即是"Transport Stream"的缩写。它是分包发送的,每一个包长为188字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。他的包的结构为,包头为4个字节,负载为184个字节。制定TS流标准的机构就规定了一些数据结构来定义。比如: PSI(Program Specific Information)表,所以解析起来...

打包TS流
TS流每个包的大小都介于188-204字节之间,一般就是188字节,每个PES包基本都大于188字节,所以在把PES封装成TS时,需要将PES分割成多个TS包,每个包都有唯一的ID标识它的类型,音视频PES打包成TS包的ID由TS中的PMT表指定,PMT表被单独打成一个TS包,它也有ID标识,这个标识由PAT表指定,与PMT类似,PAT也被打成独立的...

TS视频标准
在定义TS视频流标准时,相关机构采用了特定的数据结构,例如 PSI(Program Specific Information)表。解析过程通常涉及以下几个步骤:首先,接收包含PAT(Program Association Table)数据的包,然后在该包中定位到PMT(Program Map Table)的标识符。接着,获取包含PMT信息的数据包,从其中识别出指定的数据...

HLS协议及TS封装
pat是第一个包,解析时在ts包列表中寻找pid为0x0的包,即pat包。pat中包含pmt包的pid,pmt中存储的是流包的pid,如指定音频包pid是0x102,视频包pid是0x101。后面的0x102和0x101的包就是pes包。解析并合并pes包就能解码播放。2.2. TS文件 ts文件分为三次:ts层(Transport Stream)、pes层(...

潞西市15990975626: rs232数据打包伪装成成TS流的188字节的包格式,急需大神指教啊,最好是有代码 -
检钞克林: (复合)而成的单一数据流(用于播放或编辑系统,如...TS流是基于Packet的位流格式,每个包是188个字节(或...2. PAT表的定义(代码+分析) 3. PAT表的结构(代码 CSDN 上的

潞西市15990975626: 在音视频中请问什么是ts流 ,es流,ps流 -
检钞克林: 数字信号实际传送的是数据流,一般数据流包括以下三种: ES流:也叫基本码流,包含视频、音频或数据的连续码流. TS流:也叫传输流,是由固定长度为188字节的包组成,含有独立时基的一个或多个节目,适用于误码较多的环境. TS流...

潞西市15990975626: 无线广播是否也用TS流封装? -
检钞克林: 1. 应该是没有区别的,只是传输信道不一样.就像DVB-T、DVB-S、DVB-C这三种传输方式一样,只是传输信道不一样,TS流的结构都是一样的,都是符合mpeg-2标准的.2. 既然TS流的结构没有变化,那么转为IP传输以后,相应的加上IP的包头,应该就可以作为IPTV

潞西市15990975626: ASI和TS流有什么区别 -
检钞克林: TS流是信源码流,最高码率为44.209 Mbit/s,它是经过信源编码后的压缩码流,为了使欲传输的信源信息在传输速率一定的条件下更快更多地传输,还要把数据进行压缩,也就是通过信源编码去掉信息中多余的部分,从而提高通信的有效性,信...

潞西市15990975626: 什么是TS码流 -
检钞克林: DVD节目中的MPEG2格式,TS的全称则是Transport Stream.MPEG-TS主要应用于实时传送的节目,比如实时广播的电视节目. TS即是"Transport Stream"的缩写.它是分包发送的,每一个包长为188字节...

潞西市15990975626: 什么是DVB - S? -
检钞克林: Digital Video Broadcasting - SatelliteDVB-S(ETS 300 421)为数字卫星广播系统标准.卫星传输具有覆盖面广、节目容量大等特点.数据流的调制采用四相相移键控调制(QPSK)方式,工作频率为 11/12GHz.在使用MPEG-2MP@ML格式时...

潞西市15990975626: 如何将一张图片转换为可播放的TS流 -
检钞克林: 网上可以下载到该软件的共享试用版本,开始下了个汉化版,有些问题,很多格式的文件不能正常导入,后下载使用英文版v4.0.4.112可以使用.1. 首先打开已安装的电影魔方,并导入要转换的图片(怎么导入?可以将文件拖到左侧区域或者点...

潞西市15990975626: 什么是FEC -
检钞克林: 细心的朋友会注意到,在卫视节目的参数中,有个FEC,也叫前向纠错(Forward Error Correction).一些人会奇怪的问:FEC是什么?有什么用?既然数字机无需输入该参数,那么FEC有什么用? 其实,在卫视接收的参数中,FEC是个非常...

潞西市15990975626: 请问有没有人能详细的给我讲一下TS包,PES包和ES包的关系 ?详解TS包的头部payload - start - unit - indictator -
检钞克林: 1. ES你可以理解为一段音频或者视频的数据,ES流可能会很大,所以要拆分成PES包,PES包的长度是有限制的,64KB.所以并不是一个ES对应一个PES.关于PES拆分成TS,你的理解是正确的,同一个PES的TS的PID是相同的 2. PAT是节目关联表,你可以理解为PAT定义了PMT的位置(也就是PMT的PID),然后就可以根据PMT找到各个节目了,也就是你可以找到各个节目的PID了

潞西市15990975626: 怎么从视频中提取音频 -
检钞克林: 要看视频是什么封装格式,不同封装格式,音视频的打包不同 举3个例子 TS流:可以通过PMT表里面获取音频PID,然后在流里面提取该PID的包,出来就是音频数据 MP4:从stbl里面获取音频的packet索引,然后根据这个索引在mdat里面提取所有音频数据 MKV:从Segment info里面获取音频track位置,从音频track获取音频数据信息,然后从数据段去取音频数据 具体的还是需要仔细研读各个封装格式的数据结构.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网