H265码率解析

概述

H.265技术的应用

编码技术主要运用于视频播放设备、软件应用以及拍摄、录制视频的设备。人们最熟悉的莫过于PPS网络视频播放器。在PC屏客户端产品上面,PPS已经于2013年初推出了基于H.265标准的高清视频,并命名“臻高清”为自己的高清品牌。同时 PPS不断加大了在H.265技术应用方面的研究,把H.265推向手机客户端,且在性能上不断优化提升。

名词

  • CTU: 编码树单元
  • CU: 编码单元
  • PU: 以CU为根,对CU进行划分,一个预测单元PU包含一个亮度预测块PB和两个色度预测块PB.
  • TU: 以CU为根,变换单元TU是在CU的基础上划分的,跟PU没有关系,采用四叉树划分方式,具体划分有率失真代价决定,下图给出了某个CU划分成TU的结构。

H265-NALU-Type介绍

NAL_TRAIL_N = 0, NAL_TRAIL_R = 1, NAL_TSA_N = 2, NAL_TSA_R = 3, NAL_STSA_N = 4, NAL_STSA_R = 5, NAL_RADL_N = 6, NAL_RADL_R = 7, NAL_RASL_N = 8, NAL_RASL_R = 9, NAL_BLA_W_LP = 16, NAL_BLA_W_RADL = 17, NAL_BLA_N_LP = 18, NAL_IDR_W_RADL = 19, NAL_IDR_N_LP = 20, NAL_CRA_NUT = 21, NAL_VPS = 32, NAL_SPS = 33, NAL_PPS = 34, NAL_AUD = 35, NAL_EOS_NUT = 36, NAL_EOB_NUT = 37, NAL_FD_NUT = 38, NAL_SEI_PREFIX = 39, NAL_SEI_SUFFIX = 40,

H265码流格式

VPS:视频参数集,用于传输视频分级信息,有利于兼容标准在可分级视频编码或多视点视频的扩展。

NALU header定义:

NALU header(){Descriptor
forbidden_zero_bitf(1)
nalu unit typeu(6)
nuh_layer_idu(6)
nuh_temporal_id_plus1u(3)

H264的NALU type是首字节&0x1f,H265的NALU type是(首字节&0x7E)>>1;

NALU type定义:

/**
 * Table 7-3: NAL unit type codes
 */
enum HEVCNALUnitType {
    HEVC_NAL_TRAIL_N    = 0,
    HEVC_NAL_TRAIL_R    = 1,
    HEVC_NAL_TSA_N      = 2,
    HEVC_NAL_TSA_R      = 3,
    HEVC_NAL_STSA_N     = 4,
    HEVC_NAL_STSA_R     = 5,
    HEVC_NAL_RADL_N     = 6,
    HEVC_NAL_RADL_R     = 7,
    HEVC_NAL_RASL_N     = 8,
    HEVC_NAL_RASL_R     = 9,
    HEVC_NAL_VCL_N10    = 10,
    HEVC_NAL_VCL_R11    = 11,
    HEVC_NAL_VCL_N12    = 12,
    HEVC_NAL_VCL_R13    = 13,
    HEVC_NAL_VCL_N14    = 14,
    HEVC_NAL_VCL_R15    = 15,
    HEVC_NAL_BLA_W_LP   = 16,
    HEVC_NAL_BLA_W_RADL = 17,
    HEVC_NAL_BLA_N_LP   = 18,
    HEVC_NAL_IDR_W_RADL = 19,
    HEVC_NAL_IDR_N_LP   = 20,
    HEVC_NAL_CRA_NUT    = 21,
    HEVC_NAL_IRAP_VCL22 = 22,
    HEVC_NAL_IRAP_VCL23 = 23,
    HEVC_NAL_RSV_VCL24  = 24,
    HEVC_NAL_RSV_VCL25  = 25,
    HEVC_NAL_RSV_VCL26  = 26,
    HEVC_NAL_RSV_VCL27  = 27,
    HEVC_NAL_RSV_VCL28  = 28,
    HEVC_NAL_RSV_VCL29  = 29,
    HEVC_NAL_RSV_VCL30  = 30,
    HEVC_NAL_RSV_VCL31  = 31,
    HEVC_NAL_VPS        = 32,
    HEVC_NAL_SPS        = 33,
    HEVC_NAL_PPS        = 34,
    HEVC_NAL_AUD        = 35,
    HEVC_NAL_EOS_NUT    = 36,
    HEVC_NAL_EOB_NUT    = 37,
    HEVC_NAL_FD_NUT     = 38,
    HEVC_NAL_SEI_PREFIX = 39,
    HEVC_NAL_SEI_SUFFIX = 40,
};

丢帧

在性能不足,或者音画不同步时,需要进行丢帧,H264丢帧根据nal_ref_idc来判断,H265根据来NALU type判断。以下type是可以丢帧,且不花屏的:

HEVC_NAL_TRAIL_N、HEVC_NAL_TSA_N、HEVC_NAL_STSA_N、HEVC_NAL_RADL_N、HEVC_NAL_RASL_N。

H265码流分析

H265相比较于H264,除了包含SPS、PPS外,还多包含一个VPS;在NALU header上,H.264的HALU header是一个字节,而H.265则是两个字节。

以OX4001为例,头信息可以被解析成4个部分,其中:

  • forbidden_zero_bit = 0:占1个bit,与H.264相同,禁止位,用以检查传输过程中是否发生错误,0表示正常,1表示违反语法; nal_unit_type = 32:占6个bit,用来用以指定NALU类型 nuh_reserved_zero_6bits = 0:占6位,预留位,要求为0,用于未来扩展或3D视频编码
  • nuh_temporal_id_plus1 = 1:占3个bit,表示NAL所在的时间层ID 对比H.264的头信息,H.265移除了nal_ref_idc,此信息被合并到了nal_unit_type中:

H.265的NALU类型是在信息头的第一个字节的第2到7位,所以判断H.265NALU类型的方法是将NALU第一个字节与0x7E进行与操作并右移一位,即:

NALU类型 = (NALU头第一字节 & 0x7E) >> 1 与H.264类似,H.265码流也有两种封装格式,一种是用起始码作为分界的Annex B格式,另一种则是在NALU头添加NALU长度前缀的格式,称为HVCC。

H265码流分析帧类型

  • nal单元分割

寻找0x000001或者0x00000001, 规则如下:

  1. 每个NALU前面都有起始码0x000001, 3bits
  2. 如果NALU类型为vps, sps, pps, 或者解码顺序为第一个AU的第一个NALU, 起始码前面再加一个0x00
  3. 视频流的首个NALU的起始码前加入0x00 实际分析中,不必要整的这么复杂,只要找到0x000001或者0x00000001即可
  • 上图中的码流nal拆分为: 第一帧: 0000 0001 4001 0c01 ffff 0160 0000 0300 0003 0000 0300 0003 00ba 9702 40 第二帧: 00 0000 0142 0101 0160 0000 0300 0003 0000 0300 0003 00ba a00f 0804 47f9 65e4 91b6 1c5e 4924 fe79 fcf2 ffff ffcf e7f3 f3f9 d9 第三帧: 00 0000 0144 01c1 9095 8112 第四帧: 0000 0126 01af 1380 790b dc5c 557c 74...
  • NAL类型分析 类型枚举定义
  • enum NALUnitType {
        NAL_TRAIL_N    = 0,
        NAL_TRAIL_R    = 1,
        NAL_TSA_N      = 2,
        NAL_TSA_R      = 3,
        NAL_STSA_N     = 4,
        NAL_STSA_R     = 5,
        NAL_RADL_N     = 6,
        NAL_RADL_R     = 7,
        NAL_RASL_N     = 8,
        NAL_RASL_R     = 9,
        NAL_BLA_W_LP   = 16,
        NAL_BLA_W_RADL = 17,
        NAL_BLA_N_LP   = 18,
        NAL_IDR_W_RADL = 19,
        NAL_IDR_N_LP   = 20,
        NAL_CRA_NUT    = 21,
        NAL_VPS        = 32,
        NAL_SPS        = 33,
        NAL_PPS        = 34,
        NAL_AUD        = 35,
        NAL_EOS_NUT    = 36,
        NAL_EOB_NUT    = 37,
        NAL_FD_NUT     = 38,
        NAL_SEI_PREFIX = 39,
        NAL_SEI_SUFFIX = 40,
    };
    

类型判断方式为分隔符之后的第一个字节右移一位的值 第一帧:0x40 >> 1 , 得到0x20,十进制32,为NAL_VPS 第二帧:0x42 >> 1 , 得到0x21, 十进制33, 为NAL_SPS 第三帧:0x44 >> 1 , 得到0x22, 十进制34, 为NAL_PPS 第四帧:0x26 >> 1 , 得到0x13, 十进制19, 为NAL_IDR_W_RADL

H265码流结构

H265的视频流中也是存在多个GOP,每一个GOP里面包含多个视频编码帧。H265支持的视频编码帧类型有IDR帧、I帧、P帧、B帧,这些帧类型的含义和H264码流的帧类型的含义是一样,作用也是一样,比如IDR帧和I帧都是帧内压缩编码,IDR帧是即时解码刷新帧,也是关键帧;P帧是前向参考帧,B帧是双向参考帧。

参考链接:https://juejin.cn/post/7179225076879851579 

前言#

音视频开发需要你懂得音视频中一些基本概念,针对编解码而言,我们必须提前懂得编解码器的一些特性,码流的结构,码流中一些重要信息如sps,pps,vps,start code以及基本的工作原理,而大多同学都只是一知半解,所以导致代码中的部分内容虽可以简单理解却不知其意,所以,在这里总结出了当前主流的H.264,H.265编码相关的原理,以供学习.


1. 概览#

1.1. 为什么要编码#

众所周知,视频数据原始体积是巨大的,以720P 30fps的视频为例,一个像素大约3个字节,如下所得,每秒钟产生87MB,这样计算可得一分钟就将产生5.22GB。

数据量/每秒=1280*720*33*3/1024/1024=87MB

因此,像这样体积重大的视频是无法在网络中直接传输的.而视频编码技术也就因运而生.关于视频编码原理的技术可以参考本人其他文章,这里不做过多描述.

1.2. 编码技术#

经过很多年的开发迭代,已经有很多大牛实现了视频编码技术,其中最主流的有H.264编码,以及新一代的H.265编码,谷歌也开发了VP8,VP9编码技术.对移动端而言,苹果内部已经实现了如H.264,H.265编码,我们需要使用苹果提供的VideoToolbox框架来实现它.

1.3. 编码分类#

  • 软件编码(简称软编):使用CPU进行编码。

  • 硬件编码(简称硬编):不使用CPU进行编码,使用显卡GPU,专用的DSP、FPGA、ASIC芯片等硬件进行编码。

优缺点

  • 软编:实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。

  • 硬编:性能高,低码率下通常质量低于硬编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。

iOS系统中的硬编码

苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统一直有,被称为Video ToolBox的框架来处理硬件的编码和解码,终于在iOS 8.0后,苹果将该框架引入iOS系统。

1.4. 编码原理#

对视频执行编码操作后,原始视频数据会被压缩成三种不同类型的视频帧: I帧,P帧,B帧.

  • I帧:关键帧.完整编码的帧.可以理解成是一张完整画面,不依赖其他帧

  • P帧:参考前面的I帧或P帧,即通过前面的I帧与自己记录的不同的部分可以形成完整的画面.因此,单独的P帧无法形成画面.

  • B帧:参考前面的I帧或P帧以及后面的P帧

补充: I帧的压缩率是7(跟JPG差不多),P帧是20,B帧可以达到50. 但是iOS中一般不开启B帧,因为B帧的存在会导致时间戳同步较为复杂.

两种核心算法

  • 帧内压缩

当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一般采用有损压缩算法,由于帧内压缩是编码一个完整的图像,所以可以独立的解码、显示。帧内压缩一般达不到很高的压缩,跟编码jpeg差不多。

如下图:我们可以通过第 1、2、3、4、5 块的编码来推测和计算第 6 块的编码,因此就不需要对第 6 块进行编码了,从而压缩了第 6 块,节省了空间

帧内预测.png

  • 帧间压缩: P帧与B帧的压缩算法

相邻几帧的数据有很大的相关性,或者说前后两帧信息变化很小的特点。也即连续的视频其相邻帧之间具有冗余信息,根据这一特性,压缩相邻帧之间的冗余量就可以进一步提高压缩量,减小压缩比。帧间压缩也称为时间压缩(Temporal compression),它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的。帧差值(Frame differencing)算法是一种典型的时间压缩法,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。

如下图:可以看到前后两帧的差异其实是很小的,这时候用帧间压缩就很有意义。


帧间压缩11.jpg

有损压缩与无损压缩

  • 有损压缩: 解压缩后的数据与压缩前的数据不一致.在压缩的过程中要丢失一些人眼和人耳所不敏感的图像或音频信息,而且丢失的信息不可恢复

  • 无损压缩: 压缩前和解压缩后的数据完全一致.优化数据的排列等.

DTS和PTS

DTS和PTS的解释  

FFmpeg里有两种时间戳:DTS(Decoding Time Stamp)和PTS(Presentation Time Stamp)。顾名思义,前者是解码的时间,后者是显示的时间。要仔细理解这两个概念,需要先了解FFmpeg中的packet和frame的概念。  

FFmpeg中用AVPacket结构体来描述解码前或编码后的压缩包,用AVFrame结构体来描述解码后或编码前的信号帧。对于视频来说,AVFrame就是视频的一帧图像。这帧图像什么时候显示给用户,就取决于它的PTS。DTS是AVPacket里的一个成员,表示这个压缩包应该什么时候被解码。如果视频里各帧的编码是按输入顺序(也就是显示顺序)依次进行的,那么解码和显示时间应该是一致的。可事实上,在大多数编解码标准(如H.264或HEVC,当出现B帧的时候)中,编码顺序和输入顺序并不一致。于是才会需要PTS和DTS这两种不同的时间戳。

  • DTS:主要用于视频的解码,在解码阶段使用.

  • PTS:主要用于视频的同步和输出.在渲染的时候使用.在没有B frame的情况下.DTS和PTS的输出顺序是一样的。


1.dtspts

如上图:I帧的解码不依赖于任何的其它的帧.而P帧的解码则依赖于其前面的I帧或者P帧.B帧的解码则依赖于其前的最近的一个I帧或者P帧 及其后的最近的一个P帧.

2. 编码数据码流结构#

在我们的印象中,一张图片就是一张图像,视频就是很多张图片的集合.。但是因为我们要做音视频编程,就需要更加深入理解视频的本质.

2.1 刷新图像概念.#

在编码的码流中图像是个集合的概念,帧、顶场、底场都可以称为图像,一帧通常就是一幅完整的图像.

  • 逐行扫描:每次扫描得到的信号就是一副图像,也就是一帧. 逐行扫描适合于运动图像

  • 隔行扫描:扫描下来的一帧图像就被分为了两个部分,这每一部分就称为「场」,根据次序分为:「顶场」和「底场」.适合于非运动图像

逐行扫描与隔行扫描.png

帧与场.png

2.2. 重要参数#

  • 视频参数集VPS(Video Parameter Set)

    VPS主要用于传输视频分级信息,有利于兼容标准在可分级视频编码或多视点视频的扩展。

    (1)用于解释编码过的视频序列的整体结构,包括时域子层依赖关系等。HEVC高效率视频编码(High Efficiency Video Coding)中加入该结构的主要目的是兼容标准在系统的多子层方面的扩展,处理比如未来的可分级或者多视点视频使用原先的解码器进行解码但是其所需的信息可能会被解码器忽略的问题。

    (2)对于给定视频序列的某一个子层,无论其SPS相不相同,都共享一个VPS。其主要包含的信息有:多个子层或操作点共享的语法元素;档次和级别等会话关键信息;其他不属于SPS的操作点特定信息。

    (3)编码生成的码流中,第一个NAL(Network Abstract Layer)单元,携带的就是VPS信息

  • 序列参数集SPS(Sequence Parameter Set)

    包含一个CVS 编码视频序列(Coded Video Sequence)中所有编码图像的共享编码参数。

    (1)一段HEVC码流可能包含一个或者多个编码视频序列,每个视频序列由一个随机接入点开始,即IDR/BLA/CRA。序列参数集SPS包含该视频序列中所有slice需要的信息。

    (2)SPS的内容大致可以分为几个部分:1、自引ID;2、解码相关信息,如档次级别、分辨率、子层数等;3、某档次中的功能开关标识及该功能的参数;4、对结构和变换系数编码灵活性的限制信息;5、时域可分级信息;6、VUI。

  • 图像参数集PPS(Picture Parameter Set)

    包含一幅图像所用的公共参数,即一幅图像中所有片段SS(Slice Segment)引用同一个PPS。

    (1)PPS包含每一帧可能不同的设置信息,其内容同H.264中的大致类似,主要包括:1、自引信息;2、初始图像控制信息,如初始QP等;3、分块信息。

    (2)在解码开始的时候,所有的PPS全部是非活动状态,而且在解码的任意时刻,最多只能有一个PPS处于激活状态。当某部分码流引用了某个PPS的时候,这个PPS便被激活,称为活动PPS,一直到另一个PPS被激活。

    参数集包含了相应的编码图像的信息。SPS包含的是针对一连续编码视频序列的参数(标识符seq_parameter_set_id、帧数及POC的约束、参考帧数目、解码图像尺寸和帧场编码模式选择标识等等)。PPS对应的是一个序列中某一幅图像或者某几幅图像 ,其参数如标识符pic_parameter_set_id、可选的seq_parameter_set_id、熵编码模式选择标识、片组数目、初始量化参数和去方块滤波系数调整标识等等。

    通常,SPS 和PPS 在片的头信息和数据解码前传送至解码器。每个片的头信息对应一个

    pic_parameter_set_id,PPS被其激活后一直有效到下一个PPS被激活;类似的,每个PPS对应一个

    seq_parameter_set_id,SPS被其激活以后将一直有效到下一个SPS被激活。

    参数集机制将一些重要的、改变少的序列参数和图像参数与编码片分离,并在编码片之前传送

    至解码端,或者通过其他机制传输。

    扩展知识点:档次(Profile)、层(Tier)和级别(Level)

  • 档次: 主要规定编码器可采用哪些编码工具或算法。

  • 级别: 指根据解码端的负载和存储空间情况对关键参数(最大采样率、最大图像尺寸、分辨率、最小压缩比、最大比特率、解码缓冲区DPB大小等)加以限制。

考虑到应用可根据最大的码率和CPB大小来区分,因此有些级别定义了两个层Tier:主层和高层,主层用于大多数应用,而高层用于那些最严苛的应用。

2.3. 原始码流#

  • IDR

一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。

  • 结构

由一个接一个的 NALU 组成的,而它的功能分为两层,VCL(视频编码层)和 NAL(网络提取层).

H.264从层次来看分为两层:视频编码层(VCL, Video Coding Layer)和网络提取层(NAL,Network Abstraction Layer)。VCL输出的是原始数据比特流(SODB,String of data bits),表示H.264的语法元素编码完成后的实际的原始二进制码流。SODB通常不能保证字节对齐,故需要补齐为原始字节序列负荷(RBSP,Raw Byte Sequence Payload)。NAL层实际上就是最终输出的H.264码流,它是由一个个NALU组成的,每个NALU包括一组对应于视频编码数据的NAL头信息和一个原始字节序列负荷(RBSP,Raw Byte Sequence Payload)。以上名词之间的关系如下:

RBSP = SODB + RBSP trailing bits
NALU = NAL header(1 byte) + RBSP
H.264 = Start Code Prefix(3 bytes) + NALU + Start Code Prefix(3 bytes) + NALU +…

所以H.264码流的结构如下:

  • 组成

NALU (Nal Unit) = NALU头 + RBSP 在 VCL

数据传输或存储之前,这些编码的 VCL 数据,先被映射或封装进 NAL 单元(以下简称 NALU,Nal Unit) 中。每个 NALU 包括一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload)、一组 对应于视频编码的 NALU 头部信息。RBSP 的基本结构是:在原始编码数据的后面填加了结尾 比特。一个 bit“1”若干比特“0”,以便字节对齐。

2.3.1. H.264码流#

一个原始的H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成

NALU组成.jpeg

  • StartCode : Start Code 用于标示这是一个NALU 单元的开始,必须是”00 00 00 01” 或”00 00 01”(Annex B码流格式才必须是”00 00 00 01” 或”00 00 01”)

  • NALU Header

    下表为 NAL Header Type

NAL Header Type.png

例如,下面幅图分别代表IDR与非IDR帧具体的码流信息:

 2.IDR

在一个NALU中,第一个字节(即NALU header)用以表示其包含数据的类型及其他信息。我们假定一个头信息字节为0x67作为例子:

十六进制二进制
0x670 11 00111

如表所示,头字节可以被解析成3个部分,其中:

1>. forbidden_zero_bit = 0:占1个bit,禁止位,用以检查传输过程中是否发生错误,0表示正常,1表示违反语法;

2>. nal_ref_idc = 3:占2个bit,用来表示当前NAL单元的优先级。非0值表示参考字段/帧/图片数据,其他不那么重要的数据则为0。对于非0值,值越大表示NALU重要性越高

3>. nal_unit_type = 7:最后5位用以指定NALU类型,NALU类型定义如上表

从表中我们可以获知,NALU类型1-5为视频帧,其余则为非视频帧。在解码过程中,我们只需要取出NALU头字节的后5位,即将NALU头字节和0x1F进行与计算即可得知NALU类型,即:

NALU类型 = NALU头字节 & 0x1F

注意: 可以将start code理解为不同nalu的分隔符,header是某种类型的key,payload是该key的value.

2.3.2.码流格式#

H.264标准中指定了视频如何编码成独立的包,但如何存储和传输这些包却未作规范,虽然标准中包含了一个Annex附件,里面描述了一种可能的格式Annex B,但这并不是一个必须要求的格式。

为了针对不同的存储传输需求,出现了两种打包方法。一种即Annex B格式,另一种称为AVCC格式。

  • Annex B

从上文可知,一个NALU中的数据并未包含他的大小(长度)信息,因此我们并不能简单的将一个个NALU连接起来生成一个流,因为数据流的接收端并不知道一个NALU从哪里结束,另一个NALU从哪里开始。

Annex B格式用起始码(Start Code)来解决这个问题,它在每个NALU的开始处添加三字节或四字节的起始码0x000001或0x00000001。通过定位起始码,解码器就可以很容易的识别NALU的边界。

当然,用起始码定位NALU边界存在一个问题,即NALU中可能存在与起始码相同的数据。为了防止这个问题,在构建NALU时,需要将数据中的0x000000,0x000001,0x000002,0x000003中插入防竞争字节(Emulation Prevention Bytes)0x03,使其变为:

0x000000 = 0x0000 03 00

0x000001 = 0x0000 03 01

0x000002 = 0x0000 03 02

0x000003 = 0x0000 03 03

解码器在检测到0x000003时,将0x03抛弃,恢复原始数据。

由于Annex B格式每个NALU都包含起始码,所以解码器可以从视频流随机点开始进行解码,常用于实时的流格式。在这种格式中通常会周期性的重复SPS和PPS,并且经常时在每一个关键帧之前。

  • AVCC

另一个存储H.264流的方式是AVCC格式,在这种格式中,每一个NALU包都加上了一个指定其长度(NALU包大小)的前缀(in big endian format大端格式),这种格式的包非常容易解析,但是这种格式去掉了Annex B格式中的字节对齐特性,而且前缀可以是1、2或4字节,这让AVCC格式变得更复杂了,指定前缀字节数(1、2或4字节)的值保存在一个头部对象中(流开始的部分),这个头通常称为'extradata'或者'sequence header',SPS和PPS数据也需要保存在extradata中。

你会发现SPS和PPS被存储在了非NALU包中(out of band带外),即独立于基本流数据。这些数据的存储和传输是文件容器的任务,超出了本文的范畴。注意:虽然AVCC格式不使用起始码,防竞争字节还是有的。

H.264 extradata语法如下:

bitsline by byteremark

8versionalways0x01
8avc profilesps[0][1]

8avc compatibilitysps[0][2]

8avc levelsps[0][3]

6reservedall bits on

2NALULengthSizeMinusOne

3reservedall bits on

5number of SPS NALUs usually1

16SPS size

Nvariable SPS NALU data

8number of PPS NALUs usually1

16PPS size

Nvariable PPS NALU data

我们注意一下这个值 NALULengthSizeMinusOne,通过将这个值加 1 ,我们就得出了后续每个 NALU 前面前缀(也就是表示长度的整数)的字节数

例如,这个 NALULengthSizeMinusOne 是 3,那么每个 NALU 前面前缀的长度就是 4 个字节。我们在读取后续数据时,可以先读 4 个字节,然后把这四个字节转成整数,就是这个 NALU 的长度了,注意,这个长度并不包含起始的4个字节,是单纯 NALU 的长度。

这里还需要注意的一点是,虽然AVCC格式不使用起始码,但防竞争字节还是有的。

AVCC格式的一个优点在于解码器配置参数在一开始就配置好了,系统可以很容易的识别NALU的边界,不需要额外的起始码,减少了资源的浪费,同时可以在播放时调到视频的中间位置。这种格式通常被用于可以被随机访问的多媒体数据,如存储在硬盘的文件。

2.3.3. H.265码流#

HEVC全称High Efficiency Video Coding(高效率视频编码,又称H.265),是比H.264更优秀的一种视频压缩标准。HEVC在低码率视频压缩上,提升视频质量、减少容量即节省带宽方面都有突出表现。

H.265标准围绕H.264编码标准,保留原有的某些技术,同时对一些技术进行改进,编码结构大致上和H.264的架构类似。这里着重讲一下两者编码格式的区别。

同H.264一样,H.265也是以NALU的形式组织起来。而在NALU header上,H.264的HALU header是一个字节,而H.265则是两个字节。我们同样假定一个头信息为0x4001作为例子:

十六进制二进制
0x40010 100000 000000 001

如表所示,头信息可以被解析成4个部分,其中:

  • forbidden_zero_bit = 0:占1个bit,与H.264相同,禁止位,用以检查传输过程中是否发生错误,0表示正常,1表示违反语法;

  • nal_unit_type = 32:占6个bit,用来用以指定NALU类型

  • nuh_reserved_zero_6bits = 0:占6位,预留位,要求为0,用于未来扩展或3D视频编码

  • nuh_temporal_id_plus1 = 1:占3个bit,表示NAL所在的时间层ID

对比H.264的头信息,H.265移除了nal_ref_idc,此信息被合并到了nal_unit_type中,H.265NALU类型规定如下:

nal_unit_typeNALU类型备注
0NAL_UNIT_CODE_SLICE_TRAIL_N非关键帧
1NAL_UNIT_CODED_SLICE_TRAIL_R

2NAL_UNIT_CODED_SLICE_TSA_N

3NAL_UINT_CODED_SLICE_TSA_R

4NAL_UINT_CODED_SLICE_STSA_N

5NAL_UINT_CODED_SLICE_STSA_R

6NAL_UNIT_CODED_SLICE_RADL_N

7NAL_UNIT_CODED_SLICE_RADL_R

8NAL_UNIT_CODED_SLICE_RASL_N

9NAL_UNIT_CODE_SLICE_RASL_R

10 ~ 15NAL_UNIT_RESERVED_X保留
16NAL_UNIT_CODED_SLICE_BLA_W_LP关键帧
17NAL_UNIT_CODE_SLICE_BLA_W_RADL

18NAL_UNIT_CODE_SLICE_BLA_N_LP

19NAL_UNIT_CODE_SLICE_IDR_W_RADL

20NAL_UNIT_CODE_SLICE_IDR_N_LP

21NAL_UNIT_CODE_SLICE_CRA

22 ~ 31NAL_UNIT_RESERVED_X保留
32NAL_UNIT_VPSVPS(Video Paramater Set)
33NAL_UNIT_SPSSPS
34NAL_UNIT_PPSPPS
35NAL_UNIT_ACCESS_UNIT_DELIMITER

36NAL_UNIT_EOS

37NAL_UNIT_EOB

38NAL_UNIT_FILLER_DATA

39NAL_UNIT_SEIPrefix SEI
40NAL_UNIT_SEI_SUFFIXSuffix SEI
41 ~ 47NAL_UNIT_RESERVED_X保留
48 ~ 63NAL_UNIT_UNSPECIFIED_X未规定
64NAL_UNIT_INVALID


H.265的NALU类型是在信息头的第一个字节的第2到7位,所以判断H.265NALU类型的方法是将NALU第一个字节与0x7E进行与操作并右移一位,即:

NALU类型 = (NALU头第一字节 & 0x7E) >> 1

与H.264类似,H.265码流也有两种封装格式,一种是用起始码作为分界的Annex B格式,另一种则是在NALU头添加NALU长度前缀的格式,称为HVCC。在HVCC中,同样需要一个extradata来保存视频流的编解码参数,其格式定义如下:

bitsline by byteremark
8configurationVersionalways 0x01
2general_profile_space

1general_tier_flag

5general_profile_idc

32general_profile_compatibility_flags

48general_constraint_indicator_flags

8general_level_idc

4reserved‘1111’b
12min_spatial_segmentation_idc

6reserved‘111111’b
2parallelismType

6reserved‘111111’b
2chromaFormat

5reserved‘11111’b
3bitDepthLumaMinus8

5reserved‘11111’b
3bitDepthChromaMinus8

16avgFrameRate

2constantFrameRate

3numTemporalLayers

1tmporalIdNested

2lengthSizeMinusOne

8numOfArrays

Repeated of Array(VPS/SPS/PPS)

1| array_completeness

1| reserved| ‘0’b

6| NAL_unit_type

16| numNalus

16| nalUnitLength

N| NALU data

从上表可以看到,在H.265的extradata后半段是一段格式重复的数组数据,里面需要包含的除了与H.264相同的SPS、PPS外,还需多添加一个VPS。

VPS(Video Parament Set,视频参数集),在H.265中类型为32。VPS用于解释编码过的视频的整体结构,包括时域子层依赖关系等,主要目的在于兼容H.265标准在系统的多子层方面的扩展。

https://www.cnblogs.com/lcgbk/p/15005059.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/788568.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mirthConnect 常用示例和语法整理

mirthConnect 常用示例和语法整理 1、jolt json常用语法 https://please.blog.csdn.net/article/details/140137463 2、常用方法 2.1 WinningDateUtils 所有的时间工具在WinningDateUtils里面 获取当前时间:var nowStrWinningDateUtils.getStandardNowStr()获取…

JVM是如何创建一个对象的?

哈喽,大家好🎉,我是世杰。 本文我为大家介绍面试官经常考察的**「Java对象创建流程」** 照例在开头留一些面试考察内容~~ 面试连环call Java对象创建的流程是什么样?JVM执行new关键字时都有哪些操作?JVM在频繁创建对象时,如何…

The First项目报告:引领L2解决方案新纪元的模块化协议AltLayer

在区块链演进中,可扩展性与定制化成为开发者核心诉求。ZK Rollups与Optimistic Rollups虽显著提升以太坊等区块链性能,却面临访问性、定制难、中心化风险及流动性分散等挑战。AltLayer以Rollups-as-a-Service创新模式,赋予开发者直接管理roll…

爆破器材期刊

《爆破器材》简介   《爆破器材》自1958年创刊以来,深受广大读者喜爱,是中国兵工学会主办的中央级技术刊物,在国内外公开发行,近几年已发行到10个国家和地区。《爆破器材》杂志被美国著名检索机构《化学文摘》(CA&a…

【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …

2018-2022 年份微博签到数据集

前阵子接到一个实验室老师的需求,采集五年前(2024-52019)过年前后的北京微博签到数据。 前两年采集的深圳签到数据是 2022 年是当年的尚可,这次虽然时间跨度只有两个月,但是由于时间太过久远,但是颇费了一…

JAVA从入门到精通之入门初阶(一)

1. 认识变量 一、 首先变量名要遵循如下命名规则: 1. 变量名只能由字母、数字和下划线组成 2. 变量名必须以字母或下划线开头 3. 变量名大小写敏感 4. 变量名不能使用关键字,如const、static等 5. 变量名应具有描述性,以便于代码的可读性…

秋招突击——7/9——复习{Java实现——LRU,Java实现——搜索插入位置}——新作{二分查找——搜索二维矩阵}

文章目录 引言复习Java实现——LRU缓存对照实现 Java实现——搜索插入位置java实现知识补充 新作搜索二维矩阵个人实现参考实现 总结 引言 以后都要向使用Java刷算法进行过滤了,所以今天主要是复习为主,复习两道之前做过的题目,然后做两道新…

基于Java Web的考编论坛网站的设计与实现+lw+源码+讲解+调试+视频演示

第3章 系统分析 用户的需求以及与本系统相似的在市场上存在的其它系统可以作为系统分析中参考的资料,分析人员可以根据这些信息确定出本系统具备的功能,分析出本系统具备的性能等内容。 3.1可行性分析 尽管系统是根据用户的要求进行制作,但…

Springboot项目实训--day2

今天学习的是idea和MySQL的连接,以及一些基本的增删改查的功能实现。 一、软件下载 昨天下载了idea,今天要是西安它们的连接,就需要再下载MySQL,我的MySQL是前面几个学期别人帮忙下载的,所以具体的操作步骤我也不清楚…

Java并发关键字

并发关键字 关键字: synchronized详解关键字: volatile详解关键字: final详解 # Synchronized可以作用在哪里? 对象锁方法锁类锁 # Synchronized本质上是通过什么保证线程安全的? 加锁和释放锁的原理 深入JVM看字节码,创建如下的代码: public cl…

基于Java的科大讯飞大模型API调用实现

写在前面:因为现在自己实习的公司新拓展的一个业务是结合AI的低代码平台,我负责后端的开发,之前一直都是直接使用gpt或者文心一言等ui界面来直接使用大模型,从来没有自己调接口过,所以本文记录一下自己第一次使用大模型…

vue子组件调用父组件方法

父组件 页面<popoverss ref"pop" :goodspop"goodspop"></popoverss>子组件components: {"popoverss": () > import(../comm/popover.vue)},方法goodspop(e){console.log(e"----")return 9999;},子组件 方法props:[go…

理解点对点协议:构建高效网络通信

在通信线路质量较差的年代&#xff0c;能够实现可靠传输的高级数据链路控制&#xff08;High-level Data Link Control, HDLC&#xff09;协议曾是比较流行的数据链路层协议。HDLC是一个较复杂的协议&#xff0c;实现了滑动窗口协议&#xff0c;并支持点对点和点对多点两种连接…

单对以太网:工业4.0时代的通信革命

单对以太网连接器概述 单对以太网&#xff08;Single Pair Ethernet&#xff0c;简称SPE&#xff09;是一种新兴的以太网技术&#xff0c;它通过一对双绞线实现数据传输&#xff0c;支持PoDL&#xff08;Power over Data Line&#xff09;技术&#xff0c;为终端设备提供电力供…

Python | Leetcode Python题解之第225题用队列实现栈

题目&#xff1a; 题解&#xff1a; class MyStack:def __init__(self):"""Initialize your data structure here."""self.queue collections.deque()def push(self, x: int) -> None:"""Push element x onto stack."&…

基于单片机的温湿度感应智能晾衣杆系统设计

&#xff3b;摘 要&#xff3d; 本设计拟开发一种湿度感应智能晾衣杆系统 &#xff0c; 此新型晾衣杆是以单片机为主控芯片 来控制的实时检测系统 &#xff0e; 该系统使用 DHT11 温湿度传感器来检测大气的温湿度 &#xff0c; 然后通过单 片机处理信息来控制 28BYJ &…

Python不使用元类的ORM实现

不使用元类的简单ORM实现 在 Python 中&#xff0c;ORM&#xff08;Object-Relational Mapping&#xff09;是一种将对象和数据库之间的映射关系进行转换的技术&#xff0c;使得通过面向对象的方式来操作数据库更加方便。通常&#xff0c;我们使用元类&#xff08;metaclass&a…

网络安全合规建设

网络安全合规建设 一、法律安全需求基本合规&#xff08;1&#xff09;《网络安全法》重要节点等级保护政策核心变化 二、安全需求 业务刚需&#xff08;1&#xff09;内忧&#xff08;2&#xff09;外患 三、解决方法&#xff08;1&#xff09;总安全战略目标图&#xff08;2&…

CTF-PWN-kernel-栈溢出(retuser rop pt_regs ret2dir)

文章目录 参考qwb2018 core检查逆向调试打包上传测试脚本retuserkernel ropinit_credcommit_creds( prepare_kernel_cred(0) )开启KPTI利用swapgs_restore_regs_and_return_to_usermode开启KPTI利用SIGSEGVrop设置CR3寄存器再按照没有KPTI返回 kernel rop ret2userpt_regs 构造…