开启辅助访问
 找回密码
 立即注册

H264视频编码格式

1888cn 回答数0 浏览数837
图片帧的像素块之间存在相似性,因此视频帧图像可以进行图像压缩;H264采用了16*16的分块大⼩对视频帧图像进行相似比较和压缩编码。
H264使用帧内压缩和帧间压缩的方式提高编码压缩率。H264采用了独特的I帧、P帧和B帧策略来实现连续帧之间的压缩。

  • I帧经过适度地压缩,作为随机访问的参考点,可以当成图象。I帧可以看成是一台图像经过压缩后的产物。自身可以通过视频解压算法解压成一张单独的完整的图片。
  • P帧通过利用与序列前面的编码帧的冗余信息来压缩传输数据量的编码图像,也叫预测帧。需要参考其前面的一台I帧或者P帧来生成一张完整的图片。
  • B帧既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的冗余信息来压缩传输数据量的编码图像, 也叫双向预测帧。则要参考其前一台I或者P帧及其后面的一台P帧来生成一张完整的图片。
H264除了实现了对视频的压缩处理之外,为了省事网络传输,提供了对应的视频编码和分片策略;类似于网络数据封装成IP帧,在H264中将其称为组(GOP, group of pictures)、片(slice)、宏块(Macroblock)。这些一起组成了H264的码流分层结构;H264将其组织成为序列(GOP)、图片(pictrue)、片(Slice)、宏块(Macroblock)、子块(subblock)五个层次。

H264将视频分为连续的帧进行传输,在连续的帧之间使用I帧、P帧和B帧。同时对于帧内而⾔,将图像分为片、宏块和子块进行传输;通过这个过程实现对视频文件的压缩包装。
一台序列的第一台图像叫做IDR图像(立即刷新图像),IDR图像都是I帧图像。I帧和IDR帧都使用帧内预测。I帧不用参考任何帧,但是之后的P帧和B帧是有可能参考这个I帧之前的帧的。IDR就不允许这样,其核⼼作用是为了解码的重同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一台新的序列。这样,如果前一台序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。
SPS:序列参数集。SPS中保存了一组编码视频序列(Coded video sequence)的全局参数。
PPS:图像参数集。对应的是一台序列中某一幅图像或者某几幅图像的参数。
H264原始码流(裸流)是由一台接一台NALU组成,它的功能分为两层,VCL(视频编码层)和NAL(网络提取层)

  • VCL层,视频数据编码层(Video Coding Layer),包括核⼼压缩引擎和块,宏块和片的语法级别定义,设计⽬标是尽可能地独立于网络进行高效的编码。
  • NAL层,视频数据网络抽象层(Network Abstraction Layer),负责将VCL产生的比特字符串适配到各种各样的网络和多元环境中,覆盖了所有片级以上的语法级别。
一台原始的H264 NALU单元通常由[StartCode] [NALU Header] [NALU Payload]三部分组成,其中Start Code用于标示这是一台NALU单元的开始,必须是 "00 00 00 01"或"00 00 01",除此之外基本相当于一台NAL header + RBSP。3字节的0x000001只有一种场合下使用,就是一台完整的帧被编为多个slice(片)的时候,包含这些slice的NALU使用3字节起始码。其余场合都是4字节0x00000001的。
H264有两种封装

  • 一种是annexb模式,传统模式,有startcode,SPS和PPS是在ES中。
  • 一种是mp4模式,一般mp4、mkv都是mp4模式,没有startcode,SPS和PPS以及其它信息被封装在container中,每一台frame前面4个字节是这个frame的⻓度。很多解码器只⽀持annexb这种模式,因此需要将mp4做转换。在ffmpeg中用h264_mp4toannexb_filter可以做转换。
通过提高GOP值来提高图像质量是有限度的,在遇到场景切换的情况时,H264编码器会自动强制插⼊一台I帧,此时实际的GOP值被缩短了。另一方面,在一台GOP中,P、B帧是由I帧预测得到的,当I帧的图像质量比较差时,会影响到一台GOP中后续P、B帧的图像质量,直到下一台GOP开始才有可能得以恢复,所以GOP值也不宜设置过大。
由于P、B帧的复杂度大于I帧,所以过多的P、B帧会影响编码效率,使编码效率降低。另外,过⻓的GOP还会影响seek操作的响应速度,由于P、B帧是由前面的I或P帧预测得到的,所以seek操作需要直接定位,解码某一台P或B帧时,需要先解码得到本GOP内的I帧及之前的N个预测帧才可以。GOP值越⻓,需要解码的预测帧就越多,seek响应的时间也越⻓。
P帧特点:

  • P帧是I帧后面相隔1~2帧的编码帧;
  • P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);
  • 解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
  • P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧;
  • P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧;
  • 由于P帧是参考帧,它可能造成解码错误的扩散;
  • 由于是差值传送,P帧的压缩比较高。
  • B帧特点:

    • B帧是由前面的I或P帧和后面的P帧来进行预测的;
    • B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
    • B帧是双向预测编码帧;
    • B帧压缩比最高,因为它只反映两参考帧间运动主体的变化情况,预测比较准确;
    • B帧不是参考帧,不会造成解码错误的扩散。



  • H264分析代码
/*
* @Author: gongluck
* @Date: 2020-11-02 17:07:19
* @Last Modified by: gongluck
* @Last Modified time: 2021-08-02 22:13:40
*/

#pragma once

// Network Abstract Layer Unit
//网络抽象层单元
// Advanced Video Codec
//高阶视频编码解码器

#include <stdint.h>
#include <iostream>

// NAL ref idc codes
#define NAL_REF_IDC_PRIORITY_HIGHEST 3
#define NAL_REF_IDC_PRIORITY_HIGH 2
#define NAL_REF_IDC_PRIORITY_LOW 1
#define NAL_REF_IDC_PRIORITY_DISPOSABLE 0

// Table 7-1 NAL unit type codes
#define NAL_UNIT_TYPE_UNSPECIFIED 0                                                                         // Unspecified
#define NAL_UNIT_TYPE_CODED_SLICE_NON_IDR 1                                         // Coded slice of a non-IDR picture
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A 2 // Coded slice data partition A
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B 3 // Coded slice data partition B
#define NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C 4 // Coded slice data partition C
#define NAL_UNIT_TYPE_CODED_SLICE_IDR 5                                                         // Coded slice of an IDR picture
#define NAL_UNIT_TYPE_SEI 6                                                                                                         // Supplemental enhancement information (SEI)
#define NAL_UNIT_TYPE_SPS 7                                                                                                         // Sequence parameter set
#define NAL_UNIT_TYPE_PPS 8                                                                                                         // Picture parameter set
#define NAL_UNIT_TYPE_AUD 9                                                                                                         // Access unit delimiter
#define NAL_UNIT_TYPE_END_OF_SEQUENCE 10                                                 // End of sequence
#define NAL_UNIT_TYPE_END_OF_STREAM 11                                                         // End of stream
#define NAL_UNIT_TYPE_FILLER 12                                                                                         // Filler data
#define NAL_UNIT_TYPE_SPS_EXT 13                                                                                 // Sequence parameter set extension \
                                                                                                         // 14..18    // Reserved
#define NAL_UNIT_TYPE_CODED_SLICE_AUX 19                                                 // Coded slice of an auxiliary coded picture without partitioning \
                                                                                                         // 20..23    // Reserved
#define NAL_RTP_TYPE_STAP_A 24                                                                                         // STAP - A Single - time aggregation packet 5.7.1
#define NAL_RTP_TYPE_STAP_B 25                                                                                         // STAP - B Single - time aggregation packet 5.7.1
#define NAL_RTP_TYPE_MTAP16 26                                                                                         // MTAP16 Multi - time aggregation packet 5.7.2
#define NAL_RTP_TYPE_MTAP24 27                                                                                         // MTAP24 Multi - time aggregation packet 5.7.2
#define NAL_RTP_TYPE_FU_A 28                                                                                                 // FU - A Fragmentation unit 5.8
#define NAL_RTP_TYPE_FU_B 29                                                                                                 // FU - B Fragmentation unit 5.8 \
                                                                                                         // 29..31    // Unspecified

typedef struct __NALHEADER
{
        uint8_t nal_unit_type : 5;                        // NAL_UNIT_TYPE_XXX,NAL单元的类型
        uint8_t nal_ref_idc : 2;                                // NAL_REF_IDC_PRIORITY_XXX,标识重要性,3最高
        uint8_t forbidden_zero_bit : 1; //必须为0
} NALHEADER;

const char *nal_parse_idc(uint8_t idc);
const char *nal_parse_type(uint8_t type);

std::ostream &operator<<(std::ostream &os, const NALHEADER &nalheader);

int32_t findnalu(uint8_t *data, uint32_t start, uint32_t end, int8_t *nalstep);
[h264](https://github.com/gongluck/AnalysisAVP/blob/master/%E9%9F%B3%E8%A7%86%E9%A2%91%E5%AA%92%E4%BD%93%E6%A0%BC%E5%BC%8F.md#h264%E6%96%B0%E4%B8%80%E4%BB%A3%E8%A7%86%E9%A2%91%E5%8E%8B%E7%BC%A9%E7%BC%96%E7%A0%81%E6%A0%87%E5%87%86)

> 本文部分技术点出处,Linux C/C++服务器直播视频:[推荐免费订阅](FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体开发:https://ke.qq.com/course/3202131?flowToken=1041605)
使用道具 举报
|
当贝投影