H264/H265 NALU的nalu_unit_type解析

一、概述

  在 H.264/H.265 编码中,视频数据被封装为一系列 NALU(Network Abstraction Layer Unit),每个 NALU 包含不同类型的数据(如 SPS/PPS 参数集、I 帧 / P 帧 / B 帧等)。

  

  NALU 的结构如下:
     [Start Code] [NAL Header] [NAL Payload]
    0x000001 2字节
    • 起始码:表示一个 NALU 的开始,有两种形式:
      • 0x000001(3 字节,用于 AVC/H.264)
      • 0x00000001(4 字节,用于 AVC/H.264 和 HEVC/H.265)
    • NAL 头部:紧跟起始码后的 1 字节,结构为:
    • +---------------+
    • |0|1|2|3|4|5|6|7|
    • +-+-+-+-+-+-+-+-+
    • |F|NRI| Type |
    • +---------------+
      • F(1bit):禁止位,通常为 0。
      • NRI(2bits):重要性指示,值越大越重要(如 I 帧相关 NALU 的 NRI 较高)。
      • Type(5bits):NALU 类型,决定了该 NALU 的用途。
      • H265常见类型
        0 TRAIL_N 非参考条带
        1 TRAIL_R 参考条带
        19 IDR_W_RADL 带参考数据的 IDR 帧
        20 IDR_N_LP 低延迟 IDR 帧
        32 VPS 视频参数集(H.265 特有)
        33 SPS 序列参数集
        34 PPS 图像参数集
        35 AUD 访问单元分隔符
      • H264常见类型
        1 NDR 非 IDR 帧的视频数据片段(如 P 帧、B 帧)
        5 IDR 即时解码刷新帧(I 帧),表示一个 GOP 的开始,解码器需重置状态
        6 SEI 补充增强信息(如时间码、用户数据)
        7 SPS 序列参数集,包含视频分辨率、帧率等基本参数
        8 PPS 图像参数集,包含熵编码模式、量化参数等编码参数
        9 AUD 访问单元分隔符,用于标记视频帧的边界
        12 EOS 序列结束符,表示视频流结束

二、解析nal_unit_type

  

#include <cstdint>
#include <vector>

class NaluTypeParser {
public:
    // 初始化码流数据(data: 码流指针,size: 数据大小,is_h265: 是否为H.265)
    NaluTypeParser(const uint8_t* data, size_t size, bool is_h265)
        : data_(data), size_(size), is_h265_(is_h265), pos_(0) {}

    // 解析下一个NALU的类型(返回类型值,-1表示无更多NALU)
    int parse_next_type() {
        // 查找NALU起始码
        size_t start_code_len = find_start_code();
        if (start_code_len == 0) return -1;

        // 跳过起始码,定位到NAL头部
        pos_ += start_code_len;
        if (pos_ >= size_) return -1;

        // 提取NALU类型值
        return is_h265_ ? parse_h265_type() : parse_h264_type();
    }

private:
    const uint8_t* data_;  // 码流数据指针
    size_t size_;          // 数据总大小
    bool is_h265_;         // 是否为H.265码流
    size_t pos_;           // 当前解析位置

    // 查找起始码(返回起始码长度:3或4字节,0表示未找到)
    size_t find_start_code() {
        while (pos_ + 4 <= size_) {
            // 检查4字节起始码 0x00000001
            if (data_[pos_] == 0 && data_[pos_+1] == 0 && 
                data_[pos_+2] == 0 && data_[pos_+3] == 1) {
                return 4;
            }
            // 检查3字节起始码 0x000001
            if (pos_ + 3 <= size_ && 
                data_[pos_] == 0 && data_[pos_+1] == 0 && 
                data_[pos_+2] == 1) {
                return 3;
            }
            pos_++;
        }
        return 0;
    }

    // 解析H.264的NALU类型(低5位)
    int parse_h264_type() {
        if (pos_ >= size_) return -1;
        return data_[pos_] & 0x1F;  // 低5位为类型
    }

    // 解析H.265的NALU类型(6位)
    int parse_h265_type() {
        if (pos_ + 1 >= size_) return -1;
        uint8_t byte1 = data_[pos_];
        uint8_t byte2 = data_[pos_ + 1];
        return ((byte1 & 0x3F) << 2) | ((byte2 & 0xC0) >> 6);  // 6位类型
    }
};

 

posted on 2025-05-20 15:50  飘杨......  阅读(431)  评论(0)    收藏  举报