首页 > 其他分享 >H264/H265的两种格式Annex B、AVCC(H264)/HVCC(H265)

H264/H265的两种格式Annex B、AVCC(H264)/HVCC(H265)

时间:2024-03-26 09:02:35浏览次数:30  
标签:extra Annex H264 H265 sps ++ pps buffer data

        H.264 (AVC) 和 H.265 (HEVC) 是两种常见的视频编码标准,它们都有不同的封装格式,即Annex B 和 AVCC(H264)/HVCC(H265) 封装格式。

1、Annex B 封装格式

        Annex B 是 H264/H265中适合流式传输的一种封装格式,在这种封装格式下,视频码流被分割成称为 NALU的小单元,每个 NALU 都以特定的起始码(start code)开头。Annex B 封装格式的特点包括:

  • 起始码:起始码指示了每个 NALU 的开始,是 3 或 4 个字节的特定模式(0x00 00 01/0x00 00 00 01),用于标识 NALU 的开始位置。
  •  容易进行流分割:由于起始码的存在,可以轻松地对码流进行分割和重新组合。

        视频编码参数vps(H265)、sps(H264/H265)、pps(H264/H265)均以Annex B即用起始码分隔NALU的方式包含在视频流中,H264/H265裸流文件就是以Annex B的方式进行存储的。
        Annex B格式如下:

| 起始码 | vps(H265) | 起始码 | sps(H264/H265) | 起始码 | pps(H264/H265) | 起始码 | NALU(H264/H265) | ... | 起始码 | vps(H265) | 起始码 | sps(H264/H265) | 起始码 | pps(H264/H265) | 起始码 | NALU(H264/H265) | ... |

        Annex B中视频编码参数vps、sps、pps和视频码流混合到一起,并且每个GOP的开始都会包含,所以可以从任意位置切入进去,只要找到vps(H265)、sps(H264/H265)、pps(H264/H265)即可开始视频解码。因此Annex B更适合流式传输场景。使用Annex B的封装格式有:TS、PS等。

2、AVCC/HVCC 封装格式

2.1、AVCC

        AVCC是H264的第二种封装格式,主要应用在视频存储中,AVCC不使用起始码分隔NALU,而是在NALU前面加上一个前缀,前缀使用大端模式,一般为4个字节表示当前NALU的长度。sps、pps也不会和视频码流混合到一起,而是把sps、pps按照一定的格式保存下来,通常称为extradata或者sequence header,并且在文件头部包含extradata/sequence header,视频码流就不会再包含sps、pps了。
        格式如下:

| extradata/sequence header | 前缀 | NALU | 前缀 | NALU | ... |

        由于sps、pps不会在每个GOP前重复出现,也因此节约了存储空间,更适合存储,解码的时候先从extradata/sequence header中解析出sps、pps,然后读取NALU解码出视频帧。使用AVCC的封装格式有:MP4、FLV等。
        AVCC的extradata/sequence header定义如下:

        NALULengthSizeMinusOne表示前缀的字节数,一般为4;number of SPS NALUs usually表示sps的数量,之后2个字节表示sps长度,然后接sps NALU data,如果number of SPS不等于1,后面继续接sps长度、sps NALU,以此类推,pps也同理。

        AVCC的extradata/sequence header封装代码为:

void Muxer::H264WriteExtra(unsigned char *extra_data, int &extra_data_size)
{

    unsigned char *extra_data_start = extra_data;
    extra_data[0] = 0x01;
    extra_data[1] = sps_buf_[0][1];
    extra_data[2] = sps_buf_[0][2];
    extra_data[3] = sps_buf_[0][3];
    extra_data += 4;
    *extra_data++ = 0xff;
    // sps
    *extra_data++ = 0xe0 | (sps_number_ & 0x1f); // sps 个数
    for (int i = 0; i < sps_number_; i++) {
        // 两个字节表示sps
        extra_data[0] = (sps_len_[i]) >> 8;
        extra_data[1] = sps_len_[i];
        extra_data += 2;
        memcpy(extra_data, sps_buf_[i], sps_len_[i]);
        extra_data += sps_len_[i];
    }

    // pps

    *extra_data++ = pps_number_; // 1个sps
    for (int i = 0; i < pps_number_; i++) {
        extra_data[0] = (pps_len_[i]) >> 8;
        extra_data[1] = pps_len_[i];
        extra_data += 2;
        memcpy(extra_data, pps_buf_[i], pps_len_[i]);
        extra_data += pps_len_[i];
    }

    extra_data_size = extra_data - extra_data_start;
}

        sps_number_为sps总个数、sps_len_[]存储了每个sps NALU的长度、sps_buf_[]保存了每个sps NALU data,pps同理。

2.2、HVCC

        HVCC是H265的第二种封装格式,除了extradata/sequence header定义,其他和H264的AVCC格式都是一样的。
        HVCC的extradata/sequence header定义如下:

        numOfArrays表示数组的个数,一般为0x03,表示包含VPS、SPS、PPS,数组每个元素的数据格式如下:

        NAL unit type用以区分VPS、SPS、PPS。

        HVCC的extradata/sequence header的封装代码如下:

void Muxer::H265WriteExtra(unsigned char *extra_data, int &extra_data_size)
{
    int i = 0;
    unsigned char *buffer = extra_data;
    buffer[i++] = 0x01;

    // general_profile_idc 8bit
    buffer[i++] = 0x00;
    // general_profile_compatibility_flags 32 bit
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;

    // 48 bit NUll nothing deal in rtmp
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;

    // general_level_idc
    buffer[i++] = 0x00;

    // 48 bit NUll nothing deal in rtmp
    buffer[i++] = 0xf0;
    buffer[i++] = 0x00;
    buffer[i++] = 0xfc;
    buffer[i++] = 0xfc;
    buffer[i++] = 0xf8;
    buffer[i++] = 0xf8;

    // bit(16) avgFrameRate;
    buffer[i++] = 0x00;
    buffer[i++] = 0x00;

    /* bit(2) constantFrameRate; */
    /* bit(3) numTemporalLayers; */
    /* bit(1) temporalIdNested; */
    buffer[i++] = 0x03;

    /* unsigned int(8) numOfArrays; 03 */
    buffer[i++] = 3;

    // printf("HEVCDecoderConfigurationRecord data = %s\n", buffer);
    buffer[i++] = 0xa0; // vps 32
    buffer[i++] = (vps_number_ >> 8) & 0xff;
    buffer[i++] = vps_number_ & 0xff;
    for (int j = 0; j < vps_number_; j++) {
        buffer[i++] = (vps_len_[j] >> 8) & 0xff;
        buffer[i++] = (vps_len_[j]) & 0xff;
        memcpy(&buffer[i], vps_buf_[j], vps_len_[j]);
        i += vps_len_[j];
    }

    // sps
    buffer[i++] = 0xa1; // sps 33
    buffer[i++] = (sps_number_ >> 8) & 0xff;
    buffer[i++] = sps_number_ & 0xff;
    for (int j = 0; j < sps_number_; j++) {
        buffer[i++] = (sps_len_[j] >> 8) & 0xff;
        buffer[i++] = sps_len_[j] & 0xff;
        memcpy(&buffer[i], sps_buf_[j], sps_len_[j]);
        i += sps_len_[j];
    }

    // pps
    buffer[i++] = 0xa2; // pps 34
    buffer[i++] = (pps_number_ >> 8) & 0xff;
    buffer[i++] = pps_number_ & 0xff;
    for (int j = 0; j < pps_number_; j++) {
        buffer[i++] = (pps_len_[j] >> 8) & 0xff;
        buffer[i++] = pps_len_[j] & 0xff;
        memcpy(&buffer[i], pps_buf_[j], pps_len_[j]);
        i += pps_len_[j];
    }
    extra_data_size = i;
    return;
}

3、项目地址:

        完整代码:https://github.com/BreakingY/FFmpeg-Media-Codec-Pipeline里面的MediaMuxer/MediaMuxer.cpp,是用ffmpeg实现的MP4封装C++类。关于FFmpeg-Media-Codec-Pipeline:用ffmpeg实现音视频(H264/H265/AAC)封装、解封装、编解码pipeline,支持NVIDIA硬编解码。

标签:extra,Annex,H264,H265,sps,++,pps,buffer,data
From: https://blog.csdn.net/weixin_43147845/article/details/137011573

相关文章

  • FFmpeg-aac、h264封装flv及时间转换
    文章目录时间概念流程api核心代码时间概念dts:解码时间戳,表示压缩帧的解码时间pts:显示时间戳,表示将压缩帧解码后得到的原始帧的显示时间时间基:time_base,通常以ms为单位时间戳:timestamp,多少个时间基真实时间:time_base*timestamp如一个视频帧......
  • H265 NALU类型详细解析
    1.H265NALU类型解析F:禁止位,必须为0,表示有效;为1的话表示无效。Type:6-bitsNALType确定NAL的类型,其中VCLNAL和non-VCLNAL各有32类。0-31是vclnal单元;32-63,是非vclnal单元。VCL是指携带编码数据的数据流,而non-VCL则是控制数据流。vclnal单元的类型(0-31)如下表: no......
  • ubuntu c语言 opencv实现h265 编码
    在Ubuntu上使用C语言和OpenCV实现H.265编码,你可以遵循以下步骤:安装依赖:首先确保你的系统已经安装了Ubuntu最新版本,并更新所有包列表。安装FFmpeg,因为OpenCV使用FFmpeg来处理视频编码。可以使用以下命令安装:复制sudoaptupdatesudoaptinstallffmpeg安装OpenCV:OpenCV库本......
  • Macos arm64 ffmpeg h264 还原成yuv
    首先编译ffmpeg由于编译很多依赖尝试了三天果断放弃~使用brewbrewinstallffmpegbrewinfoffmpegcmakelist.txtcmake_minimum_required(VERSION3.20)project(ffmpeg_baseC)set(CMAKE_C_STANDARD11)set(FFMPEG_DIR/usr/local/Cellar/ffmpeg/6.1.1_3)include_......
  • 编码层判断帧类型H264
    由于靠起始码判断帧类型无法严谨区分I,P,B;所以需要到slice层去判断;以下是代码(转载)/*仅用于精准判断帧类型*//*----https://blog.csdn.net/zhuweigangzwg/article/details/44152239-----------*/#include<stdio.h>#include<stdlib.h>#include<string.h>//H264一帧数......
  • x264 yuv to h264 c99
    如何编译引入x264参考这里正式编码#include<stdint.h>#include<x264.h>#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<stdlib.h>#include<string.h>#defineCLEAR(x)(memset((&x),0,sizeof(x)))#def......
  • H264码流分析
    1.frame_num的检测frame_num被用作图片的标识符,应由比特流中的log2_max_frame_num_minus4+4位表示。frame_num的约束如下:变量PrevRefFrameNum的导出方式如下:如果当前图片是IDR图片,PrevRefFrameNum被设为0。否则(当前图片不是IDR图片),PrevRefFrameNum被设为:如果在8.2......
  • WebSocket-FLV H264/H265服务器基本实现
    场景HTTP-FLV:基于HTTP流式IO传输FLV,依赖浏览器支持播放FLV。但是由于同源的限制问题,浏览器只能播放六路视频,因此采用WebSocket-FLVWebSocket-FLV:基于WebSocket传输FLV,依赖浏览器支持播放FLV。WebSocket建立在HTTP之上,建立WebSocket连接前还要先建立HTTP连接。视频参数代码H264S......
  • 格式工厂MP4视频转格式(H265->H264)图文详解
    最近上传到网站上的视频播放时只有声音没有图像,但是在本地播放一切正常,检查后发现问题是有些浏览器不支持播放H265格式的视频。不能让访问网站的用户去换浏览器或者单独安装浏览器插件,最简单的解决办法还是自己转化视频格式重新上传。推荐一个老牌免费使用简单的视频格式转换软件—......
  • IEC60730-1 Annex-H
    IEC-60730安全标准法规由国际电工委员会(IEC)制定,该安全标准定义了家用电器嵌入式控制软件与硬件安全操作的测试与检测方法,以确保家电中受控设备的安全操作。IEC-60730将家用电器分为3类:A类–不用于确保设备的安全性。例如:照明控制、湿度控制等。B类–用于防止受控设备的......