码流识别与传输

H.264基本语法简介

    H.264相对以往的视频压缩编码标准来说,在语法结构上有很大的改变,体现在下面两个方面:

    1、取消帧级语法单元

     H.264语法中没有frame_header之类的语法单元,帧信息全部放在slice_header、SPS和PPS中。由于一帧图像可以对应多个slice,因此解码器无法通过解析类似frame_header的语法来识别码流的一帧数据

    2、引入PPS、SPS等参数集概念

     将一个视频序列(从IDR帧开始到下一个IDR帧之前的数据成为一个视频序列)全部图像的共同特征提取出来,放在SPS语法单元中

     将各个图像的典型特征抽取出来,放在PPS语法弹雨中

     只有视频序列之间才能切换SPS,即只有IDR帧的第一个Slice可以切换到SPS

     只有图像之间才能切换PPS,只有每帧图像的第一个slice才能切换PPS

    从宏观上来说,一个典型的H.264码流结构包括SPS、PPS、IDR帧(包含一个或多个I-Slice)、P帧(包含一个或多个P-slice)、B帧(包含一个或多个B-slice)。除了上述信息外,H.264还定义了SEI语法结构(除非编码器和解码器进行特定的语法协商,否则一般不进行解析)。

Nalu简介

    Nalu是H264的最高抽象层,H264的所有语法结构最终都被封装成nalu,码流中nalu单元必须定义合适的分隔符。比如采用前缀码为"00 00 01"作为nalu 的分隔符,可以通过搜索前缀码"00 00 01"来识别一个nalu

    Nalu有自己的语法结构,但是仅占用一个字节,即nalu单元除了紧跟前缀码"00 00 01"的第一个字节外,其他都是H264的有效载荷。

    Nalu_type是nalu最重要的语法元素,它表征nalu内封装的H.264语法机构的类型。

    Nalu_type可以按照下列方式解析;

    Nalu_type = first_byte_in_nal & 0x1F

    这里用first_byte_in_nal表示nalu第一个字节

    Nalu_type和H.264语法结构之间的对应关系如下

    

IDR帧的识别方法

    解码器只能从IDR帧开始才能正常解码,所以播放器为了挖成快进、快退、解码通道转换功能时需要识别IDR帧。H.264可以通过识别nalu_type来识别IDR帧。例如,可以从码流中搜素并提取连续存放的若干个nalu_type等于05的nalu,来获得一个完整的IDR帧(上面nalu_type对应H.264语法结构中有)。一个IDR帧可以划分成多个 nalu

    SPS和PPS的搜索方法和IDR帧相同,但每个SPS和PPS进对应一个nalu

帧边界识别方法

    帧边界识别简介

    H2.64将构成一帧图像的所有nalu集合称为一个AU,帧边界识别实际上就是识别AU。因为H.264取消帧语法,所以无法简单的从码流中获取AU。解码器只有在解码的过程中,通过某些语法元素的组合才能判断一帧图像是否结束。因此解码器必须在完成一帧新图像的第一个slice_header语法解码之后,才能知道前一帧图像已经结束。

    AU识别步骤如下:

  1. 对码流实施去03处理
  2. 解析nalu语法
  3. 解析slice_header语法
  4. 判断前后两个nalu以及对应的slice_header中的若干个语法元素,看是否发生变化。如果发生变化,则说明这两个nalu属于不同的帧,否则说明这两个nalu属于同一帧。

     

    显然,解码之前的AU识别消耗许多CPU资源,因此不推荐AU方式解码

编码器和解码器配合实现帧边界识别

    为了提供一种简单的AU识别方案,H.264规定一种类型为09的nalu,即编码器在每次完成一个AU编码后,在码流中插入一个类型为09的nalu,在这个前提下,解码器只需要从码流中搜索类型为09的nalu即可获得一个AU。(这个得需要编码器方面的配合,解码的话需要特定环境)

高效的帧边界识别方法

    主要思路是利用一帧图像的slice_header中的语法元素first_mb_in_slice一般等于0这个特征。这种搞笑的帧边界识别方法主要是对配置的一段现行连续的缓冲区中的码流就行搜索,获得帧边界后就返回帧边界的位置信息,不进行任何拷贝操作。

解码视频通道切换

    一般来说在视频点播或者通道切换时,进搜索IDR帧是不够的。H.264规定在传输IDR帧之前,需要先把SPS和PPS送给解码器。因此,最严谨的做法是从视频码流的起始位置开始搜索,获得全部的SPS和PPS依次送给解码器,直至搜索到一个IDR帧。

    在实际的应用场景中,编码器一般连续传递SPS、PPS和IDR帧,即严格在传递IDR之前,传递SPS和PPS参数。Hi3507编码器即遵循这一标准,因此可以在每个IDR的第一个nalu之前找到四个尺寸较小的nalu,它们几位当前视频序列解码所需要的全部参数,其中第一个nalu为SPS。因此,对于Hi3507码流,只要找到SPS,并从起始位置开始送给解码器解码,那么一定可以得到完整的图像。

流媒体网络传输的方式

    基于MPEG-4的方案在网络传输时通常采用以下两种方案

  1. 用尺寸小于网络层MTU的定长数据段来切分线性的原始码流
  2. 直接传输增加私有格式头的一整帧数据,网络层对数据进行切分,而应用层则忽略网络拥堵而丢弃的包

H.264提出比MPEG-4更优秀的网络传输抗误码解决方案。H.264包含VCL和NAL。

IP网络的类型可以分为一下三种:

  1. 不可控IP网络(如Internet网)
  2. 可控IP网络(如广域网)
  3. 无线IP网络(如3G网络)

这三种IP网络有不同的MTU、比特出错概率和TCP使用标记。两个IP节点指点MTU是动态变化的,通常假定有线IP网络的MTU为1.5KB,无线IP网络MTU的范围为100byte到500byte。

在以UDP发包时建议以nalu作为基本单元,这样便于在应用层进行标记。推荐使用RTP进行组包传输,一个RTP分组里放一个nalu,将nalu(包括同步头)放入RTP的载荷中,并设置RTP的头信息。由于包传输的路径不同,接收端需要重新对slice分组进行排序,RTP包含的次序信息可以用来解决这一问题。

    不要随意丢弃尺寸大于MTU的UDP分组,可直接发送,有网络驱动层进行拆包和组包,对应用层不会产生影响。即使网络出现UDP丢包,丢失也是一个完整的包。

解码器前的丢包策略

    播放器在下面情况下需要进行丢包处理

  1. 计算机CPU负荷过重或者网络抖动等原因引起播放器前端码流缓冲区即将溢出
  2. 应用层检测到当前网络丢包现象严重
  3. 播放器调度需要进行丢包处理

目前通用的主动丢包处理方法

  1. 尽可能将收到的所有码流信息送至解码器,不要轻易丢弃已经收到的码流信息
  2. 如果播放器在上述几种情况下需要主动丢包,则播放器应从当前帧开始丢弃,一直丢弃到下一个IDR 帧。

学习资料来自海思H264编码库PDF文件。

原文地址:https://www.cnblogs.com/kui0621/p/4448140.html