音视频流媒体开发-目录
iOS知识点-目录
Android-目录
Flutter-目录
数据结构与算法-目录
uni-pp-目录
1 ts⽂件分层
ts ⽂件为传输流⽂件,视频编码主要格式为 H264/MPEG4,⾳频为 AAC/MP3。
ts ⽂件分为三层:
ts 层:Transport Stream,是在 pes 层的基础上加⼊数据流的识别和传输必须的信息。
pes 层: Packet Elemental Stream,是在⾳视频数据上加了时间戳等对数据帧的说明信息。
es 层:Elementary Stream,即⾳视频数据。
1.1 ts 层:Transport Stream
ts 包⼤⼩固定为 188 字节,ts 层分为三个部分:ts header、adaptation field、payload。ts header固定 4 个字节;adaptation field 可能存在也可能不存在,主要作⽤是给不⾜ 188 字节的数据做填充;
payload 是 pes 数据。
1.1.1 ts header
ts 层的内容是通过 PID 值来标识的,主要内容包括:PAT 表、PMT 表、⾳频流、视频流。解析 ts 流要先找到 PAT 表,只要找到 PAT 就可以找到 PMT,然后就可以找到⾳视频流了。PAT 表的和 PMT 表需要定期插⼊ ts 流,因为⽤户随时可能加⼊ ts 流,这个间隔⽐较⼩,通常每隔⼏个视频帧就要加⼊ PAT和 PMT。PAT 和 PMT 表是必须的,还可以加⼊其它表如 SDT(业务描述表)等,不过 hls 流只要有PAT 和 PMT 就可以播放了。
- PAT 表:主要的作⽤就是指明了 PMT 表的 PID 值。
- PMT 表:主要的作⽤就是指明了⾳视频流的 PID 值。
- ⾳频流/视频流:承载⾳视频内容。
1.1.2 adaptation field
⾃适应区的⻓度要包含传输错误指示符标识的⼀个字节。pcr 是节⽬时钟参考,pcr、dts、pts 都是对同⼀个系统时钟的采样值,pcr 是递增的,因此可以将其设置为 dts 值,⾳频数据不需要 pcr。如果没有字段,ipad 是可以播放的,但 vlc ⽆法播放。打包 ts 流时 PAT 和 PMT 表是没有 adaptation field 的,不够的⻓度直接补 0xff 即可。视频流和⾳频流都需要加 adaptation field,通常加在⼀个帧的第⼀个 ts包和最后⼀个 ts 包⾥,中间的 ts 包不加。如下图所示:
PAT 格式如下图
PMT 格式如下图
1.2 pes 层:Packet Elemental Stream
pes 层是在每⼀个视频/⾳频帧上加⼊了时间戳等信息,pes 包内容很多,这⾥只留下最常⽤的。
pes 层格式如下图:
[图片上传失败...(image-ba33b1-1684154355563)]
image.png
pes 层内容如下图:
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内容才可以获取帧类型。
举例说明:
1 . I P B B B P
2 读取顺序: 1 2 3 4 5 6
3 dts 顺序: 1 2 3 4 5 6
4 pts 顺序: 1 5 3 2 4 6
点播视频 dts 算法:
dts = 初始值 + 90000 / video_frame_rate ,初始值可以随便指定,但是最好不要取 0,video_frame_rate 就是帧率,⽐如 23、30。
pts 和 dts 是 以 timestamp 为 单 位 的 , 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 应该直接⽤直播数据流中的时间,不应该按公式计算。
1.3 es 层:Elementary Stream
es 层指的就是⾳视频数据。这⾥只介绍 h.264 视频和 aac ⾳频。
1.3.1 h.264 视频
打包 h.264 数据时必须给视频数据加上⼀个 nalu(Network Abstraction Layer Unit),nalu 包括nalu header 和 nalu type,nalu header 固定为 0x00000001(帧开始)或 0x000001(帧中)。
h.264 的数据是由 slice 组成的,slice 的内容包括:视频、sps、pps 等。nalu type 决定了后⾯的h.264 数据内容。
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|F|NRI| TYPE |
+-+-+-+-+-+-+-+-+
- F:1bit,forbidden_zero_bit,h.264 规定必须取 0。
- NRI:2bits,nal_ref_idc,取值为 0~3,指示这个 nalu 的重要性,I 帧、sps、pps 通常取 3,P 帧
常取 2,B 帧通常取 0 - Type:5bits,取值如下表所示:
打包 es 层数据时 pes 头和 es 数据之间要加⼊⼀个 type=9 的 nalu,关键帧 slice 前必须要加⼊type=7 和 type=8 的 nalu,⽽且是紧邻的。如下图所示:
1.3.2 aac⾳频
打包aac⾳频必须加上⼀个adts(Audio Data Transport Stream)头,共7Byte,adts包括fixed_header和variable_header两部分,各28bit。
fixed_header
variable_header








网友评论