










一、概述
在 H.264/H.265 编码中,视频数据被封装为一系列 NALU(Network Abstraction Layer Unit),每个 NALU 包含不同类型的数据(如 SPS/PPS 参数集、I 帧 / P 帧 / B 帧等)。
NALU 的结构如下:
[Start Code] [NAL Header] [NAL Payload]
0x000001 2字节
0x000001(3 字节,用于 AVC/H.264)0x00000001(4 字节,用于 AVC/H.264 和 HEVC/H.265)F(1bit):禁止位,通常为 0。NRI(2bits):重要性指示,值越大越重要(如 I 帧相关 NALU 的 NRI 较高)。Type(5bits):NALU 类型,决定了该 NALU 的用途。| 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 | 访问单元分隔符 |
| 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位类型 } };
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。