第一章 前言
第三章 有关 SPS 和 PPS 的一切
第四章 有关 Slice 的一切
第七章 帧间编码
第八章 残差的熵编码: CAVLC 和 CABAC
今天群里的小伙伴遇到了一个问题。这个问题是 iOS 的 videoToolbox 硬解视频的问题。对于包含 B 帧的视频来说,其视频帧的解码顺序和播放顺序有可能是不一致的,这就需要解码器在解码之后,要按照播放顺序对视频帧进行重新的排序。大部分的解码器都做了重排序,例如 Android 的 MediaCode (大部分厂家),又例如 FFmpeg 自带的那个软件解码器。唯独有一个比较特殊的,就是 iOS 的 videoToolbox。videoToolbox 不会为你重新排序,他只要解出来一帧就会给你吐出来。所以,对于 videoToolbox,必须由我们手动进行排序。
排序方案有很多种,比较简单的就是先缓存,然后再用时间戳进行排序。
如上图,我们可以准备一个链表,链表最长可以放 4 个元素,每解码一帧,我们就把解出来的这一帧放到链表里面去。然后从链表中找出来时间戳最小的一帧进行播放。然后再解码,再防入链表中。
以此类推,我们就可以对其进行重排序了。
但是这里有一个问题,我们这个链表最大长度要设置多长?太长了,我们就需要过多的内存来存放视频帧。但是如果太短了,我们就无法对其进行完全的排序。
其实在 SPS 和 PPS 中,是存在一个属性来告诉我们,在这个 GOP 中,最大的参考帧列表的长度的。所以,我们缓存队列的长度,依照这个长度就可以了。
在 PPS 中,有这样两个属性。
num_ref_idx_l0_default_active_minus1 表示的是参考帧队列 List0 的最大长度减去一。
num_ref_idx_l1_default_active_minus1 表示的是参考帧队列 List1 的最大长度减去一。
P 帧会使用 List0, B 帧会使用 List0 和 List1。所以这两个值里面的最大值,就是我们要缓存的帧的长度。