PS vs TS

MPEG program stream(mpg)

是一个面向于可靠存储媒介的一个封装格式
Program stream coding layer allows only one program of one or more elementary streams to be packaged into a single stream
ES是直接从编码器出来的数据流,可以是编码过的视频数据流,音频数据流,或其他编码数据流的统称。ES流经过PES打包器之后,被转换成PES包。PES包由包头和payload组成, PTS/DTS是打在PES包里面的,这两个parameters是解决视音频同步显示,防止解码器输入缓存上溢或下溢的关键
封装 - 图1

MPEG transport stream

是一个面向于一个可能丢失部分数据的传输格式
Can have multiple streams

MPEG-PS/TS

ES

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

  1. ES是只包含一种内容的数据流,如只含视频或只含音频等,打包之后的PES也是只含一种性质的ES,如只含视频ESPES,只含音频ESPES等。每个ES都由若干个存取单元(AU)组成,每个视频AU或音频AU都是由头部和编码数据两部分组成,1AU相当于编码的1幅视频图像或1个音频帧,也可以说,每个AU实际上是编码数据流的显示单元,即相当于解码的1幅视频图像或1个音频帧的取样。

PES

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

PTS、DTS

PTS—PresentationTime Stamp(显示时间标记)表示显示单元出现在系统目标解码器(H.264、MJPEG等)的时间。
DTS—Decoding Time Stamp(解码时间标记)表示将存取单元全部字节从解码缓存器移走的时间。
PTS/DTS是打在PES包的包头里面的,这两个参数是解决音视频同步显示,防止解码器输入缓存上溢或下溢的关键。每一个I(关键帧)、P(预测帧)、B(双向预测 帧)帧的包头都有一个PTS和DTS,但PTS与DTS对于B帧不一样,无需标出B帧的DTS,对于I帧和P帧,显示前一定要存储于视频解码器的重新排序缓存器中,经过延迟(重新排序)后再显示,所以一定要分别标明PTS和DTS。

PS

PS—Program Stream(节目流)PS流由PS包组成,而一个PS包又由若干个PES包组成(到这里,ES经过了两层的封装)。PS包的包头中包含了同步信息与时钟恢复信息。一个PS包最多可包含具有同一时钟基准的16个视频PES包和32个音频PES包。

TS

  1. TS--Transport Stream(传输流)由定长的TS包组成(188字节),而TS包是对PES包的一个重新封装(到这里,ES也经过了两层的封装)。PES包的包头信息依然存在于TS包中。
  2. TS流与PS流的区别在于TS流的包结构是固定长度的,而PS流的包结构是可变长度的。PS包由于长度是变化的,一旦丢失某一PS包的同步信息,接收机就会进入失步状态,从而导致严重的信息丢失事件。而TS码流由于采用了固定长度的包结构,当传输误码破坏了某一TS包的同步信息时,接收机可在固定的位置检测它后面包中的同步信息,从而恢复同步,避免了信息丢失。因此在信道环境较为恶劣、传输误码较高时一般采用TS码流,而在信环境较好、传输误码较低时一般采用PS码流。

TS单一码流、混合码流

单一性:TS流的基本组成单位是长度为188字节的TS包。
混合性: TS流由多种数据组合而成,一个TS包中的数据可以是视频数据,音频数据,填充数据,PSI/SI表格数据等(唯一的PID对应)。

H264

ES流封装格式

  • AVCC -> Mp4

  • AnnexB -> TS

每个I帧之前都有一个SPS PPS, SPS有数据可以计算PTS, 264原始流中的SPS, PPS并不包含时间戳信息,时间戳信息是根据他的帧率来计算得来的
一个frame 会跨越多个NALU, 通过对NALU中每个字节做0x08 & 运算可以判定一个frame(slice)的结束点,
H.264 码流中每个帧的开头的3~4个字节是H.264 的start_code(起始码),0x00000001或0x000001。3字节的0x000001只有一种场合下使用,就是一个完整的帧被编为多个slice(片)的时候,从第二个slice开始,包含这些slice的NALU 使用3字节起始码。也就是说,如果NALU对应的slice为一帧的开始就用0x00000001,否则就用0x000001。
封装 - 图2

序列和图像参数集:减少了重复参数的传送,每个VCL NAL单元包含一个标识,指向有关的图像参数集,每个图像参数集包含一个标识,指向有关的序列参数集的内容因此,只用少数的指针信息,引用大量的参数,大大减少每个VCL NAL单元重复传送的信息。(所以丢失关键帧的时候,就无法通过这个引用拿到编码参数)
封装 - 图3
如果不采用DP(数据分割)机制,则一个片就是一个NALU,一个 NALU 也就是一个片。否则,一个片由三个 NALU 组成,即DPA、DPB和DPC,对应的nal_unit_type 值为 2、3和4。
由于一帧可能编码成多个片,解码时需要保证帧的完整性。例如IDR帧就可能分成多个IDR片,可以从码流中搜索并提取连续存放的若干个nalu_type 等于05 的nalu,即可获得一个完整的IDR 帧。这里实际上涉及到了帧边界识别问题,H.264 将构成一帧图像所有NALU的集合称为一个AU(Access Unit),帧边界识别实际上就是识别AU。因为H.264 取消帧级语法,所以无法简单地从码流中获取AU 。解码器只有在解码的过程中,通过某些语法元素的组合才能判断一帧图像是否结束。
Many SIP video phones configure their H.264 encoders to use multiple slice NALUs in a single frame, unlike Flash Player which generates one picture NALU per frame. Thus the traditional SIP video phones are capable of using low sized encoded payload without RFC 6184 which can be sent in a single RTP/UDP packet.

NALU解码过程

封装 - 图4

StartCode

通常为 0x00000001或者 0x000001取决于编码器, 对于AUD, 有没有对于播放器的播放基本上没影响,AUD实际上是一个特殊的NAL类型,也就是分隔符,这种也就是ANNEX-B格式

  • 0:未规定

  • 1:非IDR图像中不采用数据划分的片段

  • 2:非IDR图像中A类数据划分片段

  • 3:非IDR图像中B类数据划分片段

  • 4:非IDR图像中C类数据划分片段

  • 5:IDR图像的片段

  • 6:补充增强信息(SEI)

  • 7:序列参数集(SPS)

  • 8:图像参数集(PPS)

  • 9:分割符

  • 10:序列结束符

  • 11:流结束符

  • 12:填充数据

  • 13:序列参数集扩展

  • 14:带前缀的NAL单元

  • 15:子序列参数集

  • 16 – 18:保留

  • 19:不采用数据划分的辅助编码图像片段

  • 20:编码片段扩展

  • 21 – 23:保留

  • 24 – 31:未规定

  1. 0x67: SPS
  2. 0x68: PPS
  3. 0x65: IDR
  4. 0x61: non-IDR Slice
  5. 0x01: B Slice
  6. 0x06: SEI
  7. 0x09: AU Delimiter

AVPacket

AVPacket是解码前数据,AVframe是解码后数据
使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。

MP4

  1. No start codes.
  2. The elementary streams shall not include start codes. As stored, each NAL unit is
  3. preceded by a length field as specified in 5.2.3; this enables easy scanning of the samples NAL units.
  4. Systems that wish to deliver, from this file format, a stream using start codes will need to reformat the
  5. stream to insert those start codes.

AVCC

格式用作于MP4封装,在mdat中去掉了startcode还有sps pps(sps pps存储在moov中),通过chunk offset来决定一个chunk的起始地址,chunk中的sample对应于每一个视频帧(chunk中可能有多个sample)

sample的格式为:

  1. type Sample struct{
  2. Len Uint32 //长度 Big endian
  3. Date []byte //NAL数据(不带startcode)
  4. }

参考链接

  1. H.264格式分析