当前位置: 首页 > news >正文

H.264编码格式详解:Annex-B vs AVCC

📋 概述

H.264视频编码标准在不同容器格式中采用两种不同的封装方式:

  • Annex-B格式:使用起始码标识NALU边界
  • AVCC格式:使用长度前缀标识NALU大小

理解这两种格式的区别对于视频处理、流媒体传输和系统集成至关重要。


🔍 Annex-B格式

基本特征

  • 标识方式:使用起始码标识NALU边界
  • 标准格式:H.264标准定义的原始格式
  • 流媒体友好:适合实时传输和流媒体应用

数据结构

[起始码][NALU数据][起始码][NALU数据][起始码][NALU数据]...

起始码类型

类型字节序列说明
4字节起始码00 00 00 01标准起始码,兼容性最好
3字节起始码00 00 01短起始码,节省空间

示例数据

# SPS (Sequence Parameter Set)
00 00 00 01 67 42 00 1E 9A 74 40 00 00 03 00 40 00 00 0F 03 C6 0C 44 80# PPS (Picture Parameter Set)  
00 00 00 01 68 CE 3C 80# IDR帧
00 00 00 01 65 B8 40 22 9E 3C 59 7B E1 08 40 00 00 03 00 40 00 00 0F 03 A6 0C 44 80

优势

  • ✅ 标准兼容性好
  • ✅ 流媒体播放器支持度高
  • ✅ 实时传输效率高
  • ✅ 无需额外解析长度信息

劣势

  • ❌ 数据大小略大(每个NALU多3-4字节起始码)
  • ❌ 不支持随机访问优化

📦 AVCC格式

基本特征

  • 标识方式:使用长度前缀标识NALU大小
  • 容器优化:针对MP4容器格式优化
  • 随机访问友好:支持快速定位和跳转

数据结构

[4字节长度][NALU数据][4字节长度][NALU数据][4字节长度][NALU数据]...

长度前缀解析

  • 字节序:大端序(Big-Endian)
  • 格式:4字节无符号整数
  • 计算长度 = (字节0 << 24) | (字节1 << 16) | (字节2 << 8) | 字节3

示例数据

# 长度前缀:0x1A = 26字节
00 00 00 1A 67 42 00 1E 9A 74 40 00 00 03 00 40 00 00 0F 03 C6 0C 44 80# 长度前缀:0x0C = 12字节  
00 00 00 0C 68 CE 3C 80# 长度前缀:0x1F = 31字节
00 00 00 1F 65 B8 40 22 9E 3C 59 7B E1 08 40 00 00 03 00 40 00 00 0F 03 A6 0C 44 80

优势

  • ✅ 支持随机访问和快速跳转
  • ✅ 容器格式优化
  • ✅ 数据组织更紧凑
  • ✅ 适合本地存储和播放

劣势

  • ❌ 需要解析长度前缀
  • ❌ 某些播放器兼容性较差
  • ❌ 实时传输效率略低

🌐 RTSP传输格式

标准要求

RTSP传输H.264视频时,必须使用Annex-B格式,这是由RFC 6184标准强制规定的。

原因分析

  1. 流媒体特性:RTSP是实时流媒体协议,需要支持随机接入
  2. 起始码识别:Annex-B的起始码便于接收端快速定位NALU边界
  3. 标准兼容:符合H.264标准定义,兼容性最好
  4. 实时解析:接收端无需预先知道数据长度,可以边接收边解析

传输过程

H.264 Annex-B → RTP封装 → 网络传输 → RTP解封装 → H.264 Annex-B

🔧 格式转换

AVCC → Annex-B转换

std::string ConvertToAnnexB(const uint8_t* data, int size) {std::string annex_b_data;annex_b_data.reserve(size + 1024); // 预分配空间int i = 0;while (i < size - 4) { // 至少需要4字节长度前缀// 读取4字节长度前缀(大端序)uint32_t nalu_length = (data[i] << 24) | (data[i+1] << 16) | (data[i+2] << 8) | data[i+3];// 检查长度是否合理if (nalu_length == 0 || nalu_length > size - i - 4) {break; // 长度无效,跳过剩余数据}// 添加Annex-B起始码annex_b_data.push_back(0x00);annex_b_data.push_back(0x00);annex_b_data.push_back(0x00);annex_b_data.push_back(0x01);// 添加NALU数据annex_b_data.append(reinterpret_cast<const char*>(data + i + 4), nalu_length);// 移动到下一个NALUi += 4 + nalu_length;}return annex_b_data;
}

转换要点

  1. 长度解析:正确读取大端序长度值
  2. 边界检查:确保数据完整性
  3. 起始码添加:为每个NALU添加标准起始码
  4. 数据复制:保持NALU数据内容不变

🎯 应用场景

Annex-B格式适用

  • 实时流媒体:RTSP、HLS、DASH
  • 广播系统:DVB、ATSC
  • 网络传输:RTP封装
  • TS容器:MPEG-2 Transport Stream

AVCC格式适用

  • 本地存储:MP4、MOV、3GP文件
  • 点播系统:支持随机访问
  • 编辑软件:视频编辑和后期处理
  • 移动设备:iOS、Android原生支持

📊 性能对比

特性Annex-BAVCC
解析速度快(直接查找起始码)中等(需要读取长度)
内存占用稍高(起始码开销)较低(无额外开销)
兼容性优秀良好
随机访问困难容易
流媒体优秀中等

🔧 实际应用

CyberRT兼容性

  • 期望格式:Annex-B格式
  • MP4处理:需要自动转换为Annex-B
  • TS处理:直接使用原始数据
  • 播放器支持:确保H.264数据能被正确解析

格式检测和转换

// 获取H.264数据并进行格式转换
std::string h264_data;
if (IsMP4Format()) {// MP4格式:转换为Annex-B格式h264_data = ConvertToAnnexB(packet_->data, packet_->size);
} else {// 非MP4格式(如TS):直接使用原始数据h264_data = std::string(reinterpret_cast<const char*>(packet_->data), packet_->size);
}

📝 总结

H.264在TS和MP4中的编码格式差异主要体现在NALU边界标识方式上:

  • TS文件使用起始码标识,兼容性好,适合流媒体
  • MP4文件使用长度前缀,支持随机访问,适合本地存储
  • RTSP传输强制使用Annex-B格式,确保实时流媒体兼容性

在实际应用中,需要根据目标播放器的要求进行相应的格式转换,确保H.264数据能被正确解析和播放。特别是从MP4文件提取H.264数据并通过RTSP传输时,必须先将AVCC格式转换为Annex-B格式。

http://www.dtcms.com/a/331598.html

相关文章:

  • 14、Docker Compose 安装 Redis 集群(三主三从)
  • 嵌入式学习笔记--MCU阶段--DAY12实时操作系统rt_thread1
  • Cypher注入详解:原理、类型与测试方法
  • 使用免费API开发口播数字人
  • 数智化与全球化,双轮驱动艾芬达持续引领行业变革
  • 嵌入式 - Linux软件编程:进程
  • PIDGenRc函数中lpstrRpc的由来和InitializePidVariables函数的关系
  • 什么是期权ETF分仓的意思呢?
  • 安全加固4(K8S最小化微服务安全)
  • java-JVM详解
  • 如何安装 scikit-learn Python 库
  • Azure微软云内网接入问题
  • 大规模调用淘宝商品详情 API 的分布式请求调度实践
  • ant design vue pro 1.7.8 自定义渲染菜单,多页签,keep-alive 详细教程 vue2.x版
  • day33-LNMP
  • PostgreSQL——视图
  • 六十五、【Linux数据库】MySQL表结构 、 MySQL键值
  • 重学JS-003 --- JavaScript算法与数据结构(三)JavaScript 基础调试方法
  • Codeforces 1042 Div3(ABCDEFG)
  • 【科研日常】使用tensorflow实现自注意力机制和交叉注意力机制
  • Java中Record的应用
  • Flink Stream API 源码走读 - socketTextStream
  • Spark Shuffle机制原理
  • STM32HAL 快速入门(七):GPIO 输入之光敏传感器控制蜂鸣器
  • 深入理解管道(下):括号命令 `()`、`-ExpandProperty` 与 AD/CSV 实战
  • Java 大视界 -- Java 大数据在智能家居能耗监测与节能优化中的应用探索(396)
  • 【漏洞复现】WinRAR 目录穿越漏洞(CVE-2025-8088)
  • JavaScript 解构赋值语法详解
  • iOS Sqlite3
  • Playwright初学指南 (3):深入解析交互操作