文章目录

  • 分隔格式
    • Annex B
    • avcC
  • 编解码器的输入输出分隔符类型

分隔格式

H.264常用的分隔方式有Annex B和avcC

Annex B

这种分隔符通常用于视频会议还有文件存储例如TS等
用VLC打开avcC格式的视频文件,编码信息中显示H264 - MPEG-4 AVC(part 10)(h264)
Annex B的格式如下,start code有可能是{0 0 0 1}或者{0 0 1},{0 0 0 1}通常用于第一个NALU、SPS和PPS,其他地方使用{0 0 1}以减少内存占用

([start code] NALU) | ( [start code] NALU) | ...

找出一帧数据中有个NALU,代码如下:

const uint8_t kNaluTypeMask = 0x1F;std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,  size_t buffer_size) {// This is sorta like Boyer-Moore, but with only the first optimization step:// given a 3-byte sequence we're looking at, if the 3rd byte isn't 1 or 0,// skip ahead to the next 3-byte sequence. 0s and 1s are relatively rare, so// this will skip the majority of reads/checks.std::vector<NaluIndex> sequences;if (buffer_size < kNaluShortStartSequenceSize)return sequences;const size_t end = buffer_size - kNaluShortStartSequenceSize;for (size_t i = 0; i < end;) {if (buffer[i + 2] > 1) {i += 3;} else if (buffer[i + 2] == 1 && buffer[i + 1] == 0 && buffer[i] == 0) {// We found a start sequence, now check if it was a 3 of 4 byte one.NaluIndex index = {i, i + 3, 0};if (index.start_offset > 0 && buffer[index.start_offset - 1] == 0)--index.start_offset;// Update length of previous entry.auto it = sequences.rbegin();if (it != sequences.rend())it->payload_size = index.start_offset - it->payload_start_offset;sequences.push_back(index);i += 3;} else {++i;}}// Update length of last entry, if any.auto it = sequences.rbegin();if (it != sequences.rend())it->payload_size = buffer_size - it->payload_start_offset;return sequences;
}

为防止编码数据和分隔符冲突,需要对编码数据进行处理,需要对编码数据做如下处理:

// 00 00 00 -> 00 00 03 00
// 00 00 01 -> 00 00 03 01
// 00 00 02 -> 00 00 03 02
// 00 00 03 -> 00 00 03 03void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination) {static const uint8_t kZerosInStartSequence = 2;static const uint8_t kEmulationByte = 0x03u;size_t num_consecutive_zeros = 0;destination->EnsureCapacity(destination->size() + length);for (size_t i = 0; i < length; ++i) {uint8_t byte = bytes[i];if (byte <= kEmulationByte &&num_consecutive_zeros >= kZerosInStartSequence) {// Need to escape.destination->AppendData(kEmulationByte);num_consecutive_zeros = 0;}destination->AppendData(byte);if (byte == 0) {++num_consecutive_zeros;} else {num_consecutive_zeros = 0;}}
}

在解码之前需要做一次反向处理,处理代码如下:

//  00 00 03 00 -> 00 00 00
//  00 00 03 01 -> 00 00 01
//  00 00 03 02 -> 00 00 02
//  00 00 03 03 -> 00 00 03std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {std::vector<uint8_t> out;out.reserve(length);for (size_t i = 0; i < length;) {// Be careful about over/underflow here. byte_length_ - 3 can underflow, and// i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_// above, and that expression will produce the number of bytes left in// the stream including the byte at i.if (length - i >= 3 && !data[i] && !data[i + 1] && data[i + 2] == 3) {// Two rbsp bytes.out.push_back(data[i++]);out.push_back(data[i++]);// Skip the emulation byte.i++;} else {// Single rbsp byte.out.push_back(data[i++]);}}return out;
}

avcC

这种分隔符通常用于文件存储例如mp4、flv,还有直播rtmp等
用VLC打开avcC格式的视频文件,编码信息中显示H264 - MPEG-4 AVC(part 10)(avc1)
avcC的格式如下,字段length所占的字节长度由extradata中的NALULengthSizeMinusOne字段决定,length的值由NALU的实际长度决定

([extradata]) | ([length] NALU) | ([length] NALU) | ...
  • extradata的数据结构如下:
bits
8   version ( always 0x01 )
8   avc profile ( sps[0][1] )
8   avc compatibility ( sps[0][2] )
8   avc level ( sps[0][3] )
6   reserved ( all bits on )
2   NALULengthSizeMinusOne
3   reserved ( all bits on )
5   number of SPS NALUs (usually 1)repeated once per SPS:16         SPS sizevariable   SPS NALU data8   number of PPS NALUs (usually 1)repeated once per PPS:16       PPS sizevariable PPS NALU data
  • extradata例子:
    profile 为Baseline,Level为31,NALULengthSizeMinusOne为3(占用4个字节),SPS的长度为14 bytes,PPS的长度为4 bytes
uint8_t avcc_extradata[6] = {0x01, // version0x42, // baseline0x00, // compatibility0x1F, // level 310xFF, // NALULengthSizeMinusOne is 4 bytes0xE1, // sps nalus number
};
// sps
int16_t sps_len = 14;
char sps_buf[15] = {103,  66,  192,  30,  140,  141,  64,  80,  30,  144,  15,  8,  132,  106 };
// pps
int16_t pps_len = 4;
char pps_buf[4] = {104,  206,  60,  128};
// extradata
int16_t extradata_len = 6(extradata的固定长度) + 2(sps的长度占用2bytes) + 14(sps的内容) + 1(用一个byte表示pps的长度) + 2(pps的长度占用2bytes) + 4(pps的内容);
int16_t pos = 0;
char extradata[extradata_len];// 先拷贝extradata
memcpy(extradata, avcc_extradata, 6);
pos += 6;
// extradata中表示sps大小的字节序采用大端模式(将一个多位数的低位放在较大的地址处,高位放在较小的地址处)
extradata[pos]  = 0xFF & (sps_len >> 8)
extradata[pos+1] = 0xFF & sps;
pos += 2;
// 拷贝sps的内容
memcpy(extradata + pos, sps_buf, sps_len);
pos += sps_len;// extradata中存在一个pps
extradata[pos] = 0x01;
pos += 1;// extradata中表示pps大小的字节序采用大端模式(将一个多位数的低位放在较大的地址处,高位放在较小的地址处)
extradata[pos]  = 0xFF & (pps_len >> 8)
extradata[pos+1] = 0xFF & pps_len;
pos += 2;
// 拷贝pps的内容
memcpy(extradata + pos, pps_buf, pps_len);
pos += pps_len;// 最后生成的内容如下
// 0x1 0x42 0x0 0x1f 0xff 0xe1 0x0 0xe 0x67 0x42 0xc0 0x1e 0x8c 0x8d 0x40 0x50 0x1e 0x90 0xf 0x8 0x84 0x6a 0x1 0x0 0x4 0x68 0xce 0x3c 0x80

编解码器的输入输出分隔符类型

编解码器 编码输出 解码输入
libopenh264 Annex B Annex B
MediaCodec Annex B Annex B
VideoToolbox avcC avcC

H.264 NALU分隔Annex B和avcC相关推荐

  1. h.264 NALU详细分析2

    承接上集 h.264 NALU详细分析1_杀神李的博客-CSDN博客 上集我们已经讲到了帧是由一个或者多个NALU组成 并且NALU除了存储帧的信息外 还会存储一些其他的信息 比如 SEI SPS P ...

  2. RTMP FLV H.264 NALU GOP

    RTMP GOP (通常是 2倍的帧率, 2s左右) GOP说白了就是两个I帧之间的间隔.比较说GOP为120,如果是720p60的话,那就是2s一次I帧. IDR帧是I帧,但I帧不一定是IDR帧,比 ...

  3. 码流格式: Annex-B, AVCC(H.264)与HVCC(H.265), extradata详解

    1.前言 介绍H.264结构的文章铺天盖地,无责任翻译.无责任转载以及部分经验之谈(目前搜索最靠前的一篇实际是对stackoverflow上答案的翻译..链接后面给出了),所以缺的不是资料,是叙述准确 ...

  4. H.264 媒体流 AnnexB 和 AVCC 格式分析 及 FFmpeg 解析mp4的H.264码流方法

    H264码流分两种组织方式,一种是AnnexB格式,一种是AVCC格式. 作者:码农小明 来源:https://blog.csdn.net/shaosunrise/article/details/12 ...

  5. H.264视频RTP负载格式/NALU的类型

    1. 网络抽象层单元类型(NALU) NALU 头由一个字节组成, 它的语法如下:       +===============+       |0|1|2|3|4|5|6|7|       +=+= ...

  6. H.264的NALU,RTP封包说明(转自牛人)

    H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+ ...

  7. H.264/H265码流解析

    H.264/H265码流解析 一.H.264码流解析 一个原始的H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成 一个原始的 ...

  8. H.264笔记整理3

    H.264整理3 转自:http://www.hellotongtong.com/avcodecbase/avcodecbase-h264-learning120.html 需求 在移动端做音视频开发 ...

  9. (转载)H.264码流的RTP封包说明

    H.264的NALU,RTP封包说明(转自牛人) 2010-06-30 16:28 H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) ...

最新文章

  1. java文件下载大小限制,完整PDF
  2. 学到了关于服务器磁盘阵列
  3. CCF真题 201312-2 ISBN号码
  4. qhfl-4 注册-登录-认证
  5. 创建型模式(一):FactoryMethod ( 工厂方法 )
  6. 大厂面试必问!50w字+的Java技术类校招面试题汇总
  7. Jsp用于交换数据的4个map结构
  8. 数据竞赛入门-金融风控(贷款违约预测)一、赛题介绍
  9. selenium自动化案例(二)滑动验证码破解
  10. C#学习笔记-原型模式
  11. 编程题:字符串的指针引用。用指针法实现。功能:将字符串str2复制连接到str1...
  12. webpack配置_webpack的配置
  13. 在ECSHOP模板商品列表页 显示商品的评论等级和评论数量
  14. 安装active directory
  15. 基于Java的2048小游戏设计
  16. 谷歌浏览器、Yandex浏览器使用体验分享
  17. 尺规作图切线的画法_基于尺规作图的新型公切线画法
  18. 喝杯java冷静一下是什么梗_大哥喝冰阔落是什么梗 喝冰阔落的出处在哪
  19. Photoshop - 新建纯色图层
  20. C/C++程序设计13:代码实现开机自启动--以QQ为例

热门文章

  1. windows设置定时任务执行程序命令
  2. 小米手机系统好牛,真是国产系统的佼佼者
  3. ubuntu conda 更新、下载模块包权限问题 'Permission denied'
  4. 计算机考试打字合格速度,雅思考试使用机考,打字速度决定最终成绩
  5. 基础题库:12 甲流疫情死亡率
  6. 【AI初识境】从头理解神经网络-内行与外行的分水岭
  7. 多设备monkey测试工具_基于Tkinter GUI操作
  8. docker之daemon.json文件
  9. (五)Tomcat源码阅读:Connector组件分析
  10. docker部署环境