HLS协议及TS封装

HLS协议及TS封装

一、HLS协议

HLS协议由苹果公司提出并推广,来自维基百科的定义。

HTTP Live Streaming(缩写是HLS)是一个由苹果公司提出的基于HTTP流媒体网络传输协议。是苹果公司QuickTime
X
iPhone软件系统的一部分。它的工作原理是把整个流分成一个个小的基于HTTP的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。在开始一个流媒体会话时,客户端会下载一个包含元数据的extended
M3U (m3u8)playlist
文件,用于寻找可用的媒体流。
HLS只请求基本的HTTP报文,与实时传输协议(RTP)不同,HLS可以穿过任何允许HTTP数据通过的防火墙或者代理服务器。它也很容易使用内容分发网络来传输媒体流。
苹果公司把HLS协议作为一个互联网草案(逐步提交),在第一阶段中已作为一个非正式的标准提交到IETF。但是,即使苹果偶尔地提交一些小的更新,IETF却没有关于制定此标准的有关进一步的动作。[1]

1.1.协议简介

Apple推出的直播协议,是通过视频流切片成文件片段来直播的。客户端首先会请求一个m3u8文件,里面会有不同码率的流,或者直接是ts文件列表,通过给出的ts文件地址去依次播放。在直播的时候,客户端会不断请求m3u8文件,检查ts列表是否有新的ts切片。

HLS协议规定:

  • 视频的封装格式是TS。
  • 视频的编码格式为H264,音频编码格式为MP3、AAC或者AC-3。
  • 除了TS视频文件本身,还定义了用来控制播放的m3u8文件(文本文件)。

获取音视频进行HLS打包,H264+AAC的流媒体切片,提供给WEB服务器进行HLS流媒体发布,切片后:一个M3U8文件 和 多个.ts文件,M3U8是一种可扩展的播放列表文件格式。它是一个包含UTF-8编码文字的m3u播放列表。m3u是包含媒体文件URL的一个事实上的播放列表标准,编码还是h264。这种格式被用来作为HTTP Live 媒体流索引文件的格式。M3u8是一种视频列表格式,里面有真正的视频链接,在其中可以再嵌套一层m3u8。
实现HLS直播:

  1. 采集视频源和音频源数据
  2. 对原始数据进行H264编码和AAC编码
  3. 视频和音频数据封装为MPEG-TS包
  4. HLS分段生成策略及m3u8索引文件
  5. HTTP传输协议

1.2.m3u8文件协议

m3u8文件结构:

#EXTM3U                         //m3u文件头,必须放在第一行
#EXT-X-VERSION:3                  
#EXT-X-MEDIA-SEQUENCE:2         //第一个TS分片的序列号  
#EXT-X-TARGETDURATION:5         //每个分片TS的最大的时长  
#EXT-X-ALLOW-CACHE:             //是否允许cache  
#EXT-X-ENDLIST                  //m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流
#EXT-X-PLAYLIST-TYPE:VOD/Live   //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成)
#EXTINF:                        //extra info,分片TS的信息,如时长,带宽等

一级文件:index.m3u8

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1064000
1000kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=564000
500kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=282000
250kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2128000
2000kbps.m3u8

二级文件:2000kbps.m3u8

#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:5
2000kbps-0002.ts
#EXTINF:4.089
2000kbps-0003.ts
#EXTINF:4.989
2000kbps-0004.ts
...

#EXTINF:4.979
2000kbps-0100.ts
#ZEN-TOTAL-DURATION:491.66667
#ZEN-AVERAGE-BANDWIDTH:
#ZEN-MAXIMUM-BANDWIDTH:
#EXT-X-ENDLIST 

1.3.服务端与客户端逻辑

服务端逻辑:

  • 1、将媒体源切片成 Media Segment, 应该优先从可以高效解码的时间点来进行切片(如: I-frame).
  • 2、为每一个 Media Segment 生成 URI.
  • 3、Server 需要支持 “gzip” 方式压缩文本内容.
  • 4、创建一个 Media Playlist 索引文件, EXT-X-VERSION 不要高于他需要的版本, 来提供更好的兼容性.
  • 5、Server 不能随便修改 Media Playlist, 除了 Append 文本到文件末尾, 按顺序移除 Media Segment URIs, 增长 EXT-X-MEDIA-SEQUENCE 和 EXT-X-DISCONTINUITY-SEQUENCE, 添加 EXT-X-ENDLIST 到文件尾.
  • 6、在最后添加 EXT-X-ENDLIST tag, 来减少 Client reload Playlist 的次数.
  • 7、注意点播与直播服务器不同的地方是, 直播的 m3u8 文件会不断更新, 而点播的 m3u8 文件是不会变的, 只需要客户端在开始时请求一次即可.

客户端逻辑:

  • 1、客户端通过 URI 获取 Playlist. 如果是 Master Playlist, 客户端可以选择一个 Variant Stream 来播放.
  • 2、客户端检查 EXT-X-VERSION 版本是否满足.
  • 3、客户端应该忽略不可识别的 tags, 忽略不可识别的属性键值对.
  • 4、加载 Media Playlist file.
  • 5、 播放 Media Playlist file.
  • 6、重加载 Media Playlist file.
  • 7、决定下一次要加载的 Media Segment.

优点:

  • 客户端支持简单, 只需要支持 HTTP 请求即可, HTTP 协议无状态, 只需要按顺序下载媒体片段即可.
  • 使用 HTTP 协议网络兼容性好, HTTP 数据包也可以方便地通过防火墙或者代理服务器, CDN 支持良好.
  • Apple 的全系列产品支持, 由于 HLS 是苹果提出的, 所以在 Apple 的全系列产品包括 iphone, ipad, safari 都不需要安装任何插件就可以原生支持播放 HLS, 现在, Android 也加入了对 HLS 的支持.
  • 自带多码率自适应, Apple 在提出 HLS 时, 就已经考虑了码流自适应的问题.

缺点:

  • 相比 RTMP 这类长连接协议, 延时较高, 难以用到互动直播场景.
  • 对于点播服务来说, 由于 TS 切片通常较小, 海量碎片在文件分发, 一致性缓存, 存储等方面都有较大挑战.

1.4.应用

HLS目前广泛应用于点播和直播领域。
如果是直播,客户端会不停的去请求这个m3u8文件,当这个列表有新的ts文件,客户端会请求新的ts文件追加到本地播放序列。
在HTML5页面上使用HLS非常简单

<video src="index.m3u8" controls></video>
或
<video controls>
    <source src="index.m3u8"></source>
</video>

二、TS封包

2.1概念

ts流最早应用于数字电视领域,其格式非常复杂包含的配置信息表多达十几个,视频格式主要是mpeg2。苹果公司发明的http live stream流媒体是基于ts文件的,不过他大大简化了传统的ts流,只需要2个最基本的配置表PAT和PMT,再加上音视频内容就可以了,hls流媒体视频编码的主要格式为h264/mpeg4,音频为aac/mp3。

关于ts的封包,ts的封装格式要比flv更复杂,主要的数据单元是ts包,每个包有pid,一个包固定大小普通没有crc的为188,主要分为三类ts包,pat,pmt,pes,pat就是第一个包,当解析的时候会在ts包列表里找pid为0x0的包,就是pat包,pat大概作用就是入口的意思,pat里面有pmt包的pid,pmt里面存储的是流的包的pid,比如指定音频包pid是0x102,视频包pid是0x101,后面的0x102和0x101的包就是pes包了,将pes包解析并合并出原始流,就能解码播放了。具体封包格式 详解参考一参考二

ES(Elementary Stream)流是基本码流,包含音频、视频、数据的连续码流。直接从编码器出来的数据流,可以是编码过的视频数据流(H.264,MJPEG等),音频数据流(AAC),或其他编码数据流的统称。ES流经过PES打包器之后,被转换成PES包。

PES(Packet Elementary Stream 分组的ES)ES形成的分组称为PES分组,是用来传递ES的一种数据结构。PES流是ES流经过PES打包器处理后形成的数据流,在这个过程中完成了将ES流分组、打包、加入包头信息等操作(对ES流的第一次打包)。PES流的基本单位是PES包。PES包由包头和payload组成。

TS(Transport Stream)流,也叫传输流。是在pes层上加入了数据流识别和传输的必要信息。是由固定长度的188字节的包组成。含有独立是一个或者多个program,一个program又可以包含多个视频,音频和文字信息的ES流。每个ES流会有不同的PID标示。为了分析这些ES流,TS有些固定的PID来间隔发送Program和ES信息表格:PAT表和PMT表。

2.2.TS文件

ts文件分为三次:ts层(Transport Stream)、pes层(Packet Elemental Stream)、es层(Elementary Stream)。es层就是音视频数据,pes层是在音视频数据上加了时间戳等数据帧的说明信息,ts层是在pes层上加入了数据流识别和传输的必要信息。

TS流:                      
  +-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |  TS   |  =  |  Packet 1 |  Packet 2 |  Packet 3 |    ...    | Packet n-1|  Packet n |
  +-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  
一个Packet:             4bytes             184bytes         
  +-+-+-+-+-+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |  Packet | =  | Packet header |       Packet data       |
  +-+-+-+-+-+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.1.ts层

ts包(Packet)大小固定为188字节,ts层分为三个部分:ts header、adaptation field、payload。ts header固定4个字节;adaptation field可能存在也可能不存在,主要作用是给不足188字节的数据做填充;payload是pes数据。

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |  adaptation field |          payload(pes)       |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.1.1.ts header

大小 说明
sync_byte 8bit 同步字节,固定为0x47
transport_error_indicator 1bit 传输错误指示符,表明在ts头的adapt域后由一个无用字节,通常都为0,这个字节算在adapt域长度内
payload_unit_start_indicator 1bit 负载单元起始标示符,一个完整的数据包开始时标记为1
transport_priority 1bit 传输优先级,0为低优先级,1为高优先级,通常取0
pid 13bit pid值
transport_scrambling_control 2bit 传输加扰控制,00表示未加密
adaptation_field_control 2bit 是否包含自适应区,‘00’保留;‘01’为无自适应域,仅含有效负载;‘10’为仅含自适应域,无有效负载;‘11’为同时带有自适应域和有效负载。
continuity_counter 4bit 递增计数器,从0-f,起始值不一定取0,但必须是连续的

      ts层的内容是通过PID值来标识的,主要内容包括:PAT表、PMT表、音频流、视频流。解析ts流要先找到PAT表,只要找到PAT就可以找到PMT,然后就可以找到音视频流了。PAT表的PID值固定为0。PAT表和PMT表需要定期插入ts流,因为用户随时可能加入ts流,这个间隔比较小,通常每隔几个视频帧就要加入PAT和PMT。PAT和PMT表是必须的,还可以加入其它表如SDT(业务描述表)等,不过hls流只要有PAT和PMT就可以播放了。

  • PAT表:他主要的作用就是指明了PMT表的PID值。
  • PMT表:他主要的作用就是指明了音视频流的PID值。
  • 音频流/视频流:承载音视频内容。

2.2.1.2.adaptation field

大小 说明
adaptation_field_length 1Byte 自适应域长度,后面的字节数
flag 1Byte 取0x50表示包含PCR或0x40表示不包含PCR
pcr 5Byte Program Clock Reference,节目时钟参考,用于恢复出与编码端一致的系统时序时钟STC(System Time Clock)。
stuffing_bytes xByte 填充字节,取值0xff

      自适应区的长度要包含传输错误指示符标识的一个字节。pcr是节目时钟参考,pcr、dts、pts都是对同一个系统时钟的采样值,pcr是递增的,因此可以将其设置为dts值,音频数据不需要pcr。如果没有字段,ipad是可以播放的,但vlc无法播放。打包ts流时PAT和PMT表是没有adaptation field的,不够的长度直接补0xff即可。视频流和音频流都需要加adaptation field,通常加在一个帧的第一个ts包和最后一个ts包里,中间的ts包不加。

PAT/PMT类型包(Packet)
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |    PAT/PMT    |   Stuffing Bytss  |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

视频/音频类型包(Packet),一帧视频/音频数据被拆分成N个Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |   adaptation field    |      payload(pes 1)     |-->第1个Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |              payload(pes 2)                     |-->第2个Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |                   ...                           |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |             payload(pes n-1)                    |-->第n-1个Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | ts header |   adaptation field    |      payload(pes n)     |-->第n个Packet
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.1.3.PAT(Program Associate Table)格式 节目关联表

大小 说明
table_id 8bit PAT表固定为0x00
section_syntax_indicator 1bit 固定为二进制1
zero 1bit 固定为二进制0
reserved 2bit 固定为二进制11(3)
section_length 12bit 后面数据的长度
transport_stream_id 16bit 传输流ID,固定为0x0001
reserved 2bit 固定为二进制11(3)
version_number 5bit 版本号,固定为二进制00000,如果PAT有变化则版本号加1
current_next_indicator 1bit 固定为二进制1,表示这个PAT表可以用,如果为0则要等待下一个PAT表
section_number 8bit 固定为0x00
last_section_number 8bit 固定为0x00
开始循环
program_number 16bit 节目号为0x0000时表示这是NIT,节目号为0x0001时,表示这是PMT
reserved 3bit 固定为二进制111(7)
PID 13bit 节目号对应内容的PID值
结束循环
CRC32 32bit 前面数据的CRC32校验码

2.2.1.4.PMT(Program Map Table)格式 节目映射表

大小 说明
table_id 8bit PMT表取值随意,0x02
section_syntax_indicator 1bit 固定为二进制1
zero 1bit 固定为二进制0
reserved 2bit 固定为二进制11(3)
section_length 12bit 后面数据的长度
program_number 16bit 频道号码,表示当前的PMT关联到的频道,取值0x0001
reserved 2bit 固定为二进制11(3)
version_number 5bit 版本号,固定为00000,如果PAT有变化则版本号加1
current_next_indicator 1bit 固定为二进制1
section_number 8bit 固定为0x00
last_section_number 8bit 固定为0x00
reserved 3bit 固定为二进制111(7)
PCR_PID 13bit PCR(节目参考时钟)所在TS分组的PID,指定为视频PID
reserved 4bit 固定为二进制1111(15)
program_info_length 12bit 节目描述信息,指定为0x000表示没有
开始循环
stream_type 8bit 流类型,标志是Video还是Audio还是其他数据,h.264编码对应0x1b,aac编码对应0x0f,mp3编码对应0x03
reserved 3bit 固定为二进制111(7)
elementary_PID 13bit 与stream_type对应的PID
reserved 4bit 固定为二进制1111(15)
ES_info_length 12bit 描述信息,指定为0x000表示没有
结束循环
CRC32 32bit 前面数据的CRC32校验码

2.2.2.pes层

pes层(ts层中payload)是在每一个视频/音频帧上加入了时间戳等信息,pes包内容很多,我们只留下最常用的。

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | pes header|  optional pes header    |      pes payload      |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      6Byte         3~259Byte                  max 65526Byte
大小 说明
pes start code 3Byte 开始码,固定为0x000001
stream id 1Byte 音频取值(0xc0-0xdf),通常为0xc0 视频取值(0xe0-0xef),通常为0xe0
pes packet length 2Byte 后面pes数据的长度,0表示长度不限制,只有视频数据长度会超过0xffff
flag 1Byte 通常取值0x80,表示数据不加密、无优先级、备份的数据
flag 1Byte 取值0x80表示只含有pts,取值0xc0表示含有pts和dts
pes data length 1Byte 后面数据的长度,取值5或10
pts 5Byte 33bit值
dts 5Byte 33bit值

      pts是显示时间戳、dts是解码时间戳,视频数据两种时间戳都需要,音频数据的pts和dts相同,所以只需要pts。有pts和dts两种时间戳是B帧引起的,I帧和P帧的pts等于dts。如果一个视频没有B帧,则pts永远和dts相同。从文件中顺序读取视频帧,取出的帧顺序和dts顺序相同。dts算法比较简单,初始值 + 增量即可,pts计算比较复杂,需要在dts的基础上加偏移量。
      音频的pes中只有pts(同dts),视频的I、P帧两种时间戳都要有,视频B帧只要pts(同dts)。打包pts和dts就需要知道视频帧类型,但是通过容器格式我们是无法判断帧类型的,必须解析h.264内容才可以获取帧类型。

举例说明:
    ------------------------------>
    I     P     B     B     B     P
    1     2     3     4     5     6   读取顺序
    1     2     3     4     5     6   dts顺序
    1     5     3     2     4     6   pts顺序
    
点播视频dts算法:
dts = 初始值 + 90000 / video_frame_rate,初始值可以随便指定,但是最好不要取0,video_frame_rate就是帧率,比如23、30。
pts和dts是以timescale为单位的,1s = 90000 time scale , 一帧就应该是90000/video_frame_rate 个timescale。
用一帧的timescale除以采样频率就可以转换为一帧的播放时长

点播音频dts算法:
dts = 初始值 + (90000 * audio_samples_per_frame) / audio_sample_rate,audio_samples_per_frame这个值与编解码相关,aac取值1024,mp3取值1158,audio_sample_rate是采样率,比如24000、41000。AAC一帧解码出来是每声道1024个sample,也就是说一帧的时长为1024/sample_rate秒。所以每一帧时间戳依次0,1024/sample_rate,...,1024*n/sample_rate秒。

直播视频的dts和pts应该直接用直播数据流中的时间,不应该按公式计算。

2.2.3.es层

es层(pes payload)指的就是音视频数据。

video:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | start code(4 byte)| nalu header(1 byte) |      h264 data(x byte)        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

audio:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | adts header(7 byte) |      aac data(x byte)       |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2.3.1.h.264视频

      打包h.264数据我们必须给视频数据加上一个nalu(Network Abstraction Layer unit),nalu包括start code和nalu header,start code固定为0x00000001(帧开始)或0x000001(帧中)。h.264的数据是由slice组成的,slice的内容包括:视频、sps、pps等。nalu type决定了后面的h.264数据内容。

nalu header:
   0 1 2 3 4 5 6 7
  +-+-+-+-+-+-+-+-+
  |F|NRI|   Type  |          
  +-+-+-+-+-+-+-+-+
 
  F:   占1bit,forbidden_zero_bit,h.264规定必须取0,禁止位,当网络发现NAL单元有比特错误时可设置该比特为1,以便接收方纠错或丢掉该单元。
  NRI: 占2bit,nal_ref_idc,取值0~3,指示这个nalu的重要性,I帧、sps、pps通常取3,P帧通常取2,B帧通常取0,nal重要性指示,标志该NAL单元的重要性,值越大,越重要,解码器在解码处理不过来的时候,可以丢掉重要性为0的NALU。
  Type:占5bit, nal_unit_type:0=未使用 1=非IDR图像片,IDR指关键帧
                             2=片分区A 3=片分区B
                             4=片分区C 5=IDR图像片,即关键帧
                             6=补充增强信息单元(SEI) 7=SPS序列参数集
                             8=PPS图像参数集 9=分解符
                             10=序列结束 11=码流结束
                             12=填充
                             13~23=保留 24~31=未使用
             
  打包es层数据时pes头和es数据之间要加入一个type=9的nalu,关键帧slice前必须要加入type=7和type=8的nalu,而且是紧邻                             
  
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | pes header| nalu(0x09)| 1byte |  nalu |     | nalu(0x67)|     | nalu(0x68)|     | nalu(0x65)|     |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             随意     其他   内容       SPS     内容     PPS       内容      I帧      内容
                             
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | pes header| nalu(0x09)| 1byte |  nalu |     | nalu(0x41)|     |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             随意     其他   内容       P帧     内容

2.2.3.1.aac音频

      打包aac音频必须加上一个adts(Audio Data Transport Stream)头,共7Byte,adts包括fixed_header和variable_header两部分,各28bit。
fixed_header

大小 说明
syncword 12bit 固定为0xfff
id 1bit 0表示MPEG-4,1表示MPEG-2
layer 2bit 固定为00
protection_absent 1bit 固定为1
profile 2bit 取值0~3,1表示aac
sampling_frequency_index 4bit 表示采样率,0: 96000 Hz,1: 88200 Hz,2: 64000 Hz,3:48000 Hz,4: 44100 Hz,5: 32000 Hz,6: 24000 Hz,7: 22050 Hz,8: 16000 Hz,9: 12000 Hz,10: 11025 Hz,11: 8000 Hz,12: 7350 Hz
private_bit 1bit 固定为0
channel_configuration 3bit 取值0~7,1: 1 channel: front-center,2: 2 channels: front-left, front-right,3: 3 channels: front-center, front-left, front-right,4: 4 channels: front-center, front-left, front-right, back-center
original_copy 1bit 固定为0
home 1bit 固定为0

variable_header

大小 说明
copyright_identification_bit 1bit 固定为0
copyright_identification_start 1bit 固定为0
aac_frame_length 13bit 包括adts头在内的音频数据总长度
adts_buffer_fullness 11bit 固定为0x7ff
number_of_raw_data_blocks_in_frame 2bit 固定为00

2.2.4.ts打包流程图

    一个PAT包含整个TS流的信息,其中里面有一张表,比较重要的两个属性 program_number和program_map_PID,可能出现多对,
每一对program_number表示一个节目,而与该program_number对应的program_map_PID则表示该节目对应的流信息应该放在一个PMT表中,
而该PMT表的PID应该与这里的program_map_PID相等。
    一个PMT中描述了流的类型,其中0x0f表示AAC音频,而0x1b表示H264视频,除这两种之外还有其他流,例如字幕。
elementay_PID表示该流的数据应该存放在以该PID为表示的TS包中。

  +-+-+-+-+-+-+-+-+-+-+-+
  | PAT                 | 
  |                     |
  | program_number  5   |___
  | program_map_PID 10  |   |
  |                     |   |
  | program_number  6   |___|__  
  | program_map_PID 11  |   |  |
  |                     |   |  |  
  | program_number  7   |   |  |   
  | program_map_PID 12  |   |  |
  |                     |   |  |
  |         ...         |   |  |
  |                     |   |  |
  +-+-+-+-+-+-+-+-+-+-+-+   |  |
                            |  |
  +-+-+-+-+-+-+-+-+-+-+-+   |  |
  | PMT                 |   |  |
  | TS Header PID = 10  |<——   |
  |                     |      |
  | stream_type    0x0f |______|__________________0x0f表示AAC音频,下方AAC数据打包PID=20,   
  | elementary_PID 20   |      |
  | stream_type    0x1b |______|__________________0x1b表示H264视频,下方H264数据打包PID=22 
  | elementary_PID 22   |      |
  |                     |      |  
  +-+-+-+-+-+-+-+-+-+-+-+      |
                               |
  +-+-+-+-+-+-+-+-+-+-+-+      |
  | PMT                 |      | 
  | TS Header PID = 6   |<————— 
  |                     |
  | stream_type    0x0f |   
  | elementary_PID 23   |
  | stream_type    0x1b |
  | elementary_PID 24   |
  |                     |  
  +-+-+-+-+-+-+-+-+-+-+-+



裸ACC数据:
  +-+-+-+-+-+-+-+-+-+-+-+
  |         AAC         |          
  +-+-+-+-+-+-+-+-+-+-+-+
添加PES头的ACC数据:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | AAC PES |         AAC         |          
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
添加TS头将PES分割之后的TS包,假设正好分割成2个TS包,包大小固定188字节,不够用adaptation域填充一般填充0xFF:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |TS | AAC PES |  AAC 1  |TS | adaptation|    AAC 2    |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |- - - - Packet 1 - - - |- - - - - Packet 2 - - - - - |
  <假设 PID = 20 的TS包>            
  

裸H264数据,一帧:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |              H264             |          
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
添加PES头之后的H264数据,一帧表示一个PES包:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | H264 PES|           H264                |          
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
将一个PES包分割之后,分别添加TS头之后的TS包,这里假设分割成3个TS包,每个包固定大小188字节(包含TS包头在内),
最后一个包不够188字节使用adaptaion域填充0xFF:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |TS | H264 PES| H264 1|TS |  H264 2     |TS | adaptation|  H264 3 |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |- - - Packet 1 - - - |- - Packet 2 - - | - - - - Packet 3 - - - -|
  <假设 PID = 22 的TS包>
  
  
  


参考

苹果官方文档
HLS标准协议
维基百科
https://blog.csdn.net/yuan1125/article/details/51540918
https://blog.csdn.net/max_min_go/article/details/39463675

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

推荐阅读更多精彩内容