前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >H.264中NALU、RBSP、SODB的关系

H.264中NALU、RBSP、SODB的关系

作者头像
lcyw
发布2022-06-10 19:24:39
8390
发布2022-06-10 19:24:39
举报
文章被收录于专栏:machh的专栏machh的专栏

SODB: 数据比特串-->最原始的编码数据( 长度不一定是8的倍数,故需要补齐)

RBSP: 原始数据字节序列-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若干比特“0”,以便字节对齐。

EBSP: 扩展字节序列载荷-- >在RBSP基础上填加了仿校验字节(0X03)它的原因是: 在NALU加到Annexb上时,需要填加每组NALU之前的开始码 StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示 ox000001.

为了使NALU主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉。 也称为脱壳操作。

NALU: 每个NAL单元是一个一定语法元素的可变长字节字符串,包括包含一个字节的头信息(用来表示数据类型),以及若干整数字节的负荷数据。一个NAL单元可以携带一个编码片、A/B/C型数据分割或一个序列或图像参数集

逻辑关系:

SODB + RBSP trailing bits = RBSP

NAL header(1 byte) + RBSP = NALU

Start Code Prefix(3 bytes) + NALU + Start Code Prefix(3 bytes) + NALU + ...+ = H.264BitsStream

说明:

1. SODB即编码形成的真实码流,为了使一个RBSP为整字节数,需要加trailing bits, 具体加的方法可以看JM8.6中的SODBtoRBSP函数.

void SODBtoRBSP(Bitstream *currStream)

{

currStream->byte_buf <<= 1;

currStream->byte_buf |= 1;

currStream->bits_to_go--;

currStream->byte_buf <<= currStream->bits_to_go;

currStream->streamBuffer[currStream->byte_pos++] = currStream->byte_buf;

currStream->bits_to_go = 8;

currStream->byte_buf = 0;

}

2. NALU header为一个字节,这8个比特分别对应forbidden_zero_bit, nal_ref_idc, nal_unit_type. NALU的body其实就是RBSP. 由RBSP转NALU是由RBSPtoNALU函数来实现的.

typedef struct

{

int startcodeprefix_len; //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)

unsigned len; //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)

unsigned max_size; //! Nal Unit Buffer size

int nal_unit_type; //! NALU_TYPE_xxxx

int nal_reference_idc; //! NALU_PRIORITY_xxxx

int forbidden_bit; //! should be always FALSE

byte *buf; //! conjtains the first byte followed by the EBSP

} NALU_t;

int RBSPtoNALU (char *rbsp, NALU_t *nalu, int rbsp_size, int nal_unit_type, int nal_reference_idc,

int min_num_bytes, int UseAnnexbLongStartcode)

{

int len;

// 断言,以后要学会用assert进行断言,很重要滴.

assert (nalu != NULL);

assert (nal_reference_idc <=3 && nal_reference_idc >=0);

assert (nal_unit_type > 0 && nal_unit_type <= 10);

assert (rbsp_size < MAXRBSPSIZE);

// 下面这个是必须的,所以不需要通过参数传进来

nalu->forbidden_bit = 0;

// 下面两个通过参数传进来

nalu->nal_reference_idc = nal_reference_idc;

nalu->nal_unit_type = nal_unit_type;

// 判断是否在Start Code Prefix前面加Ox00

nalu->startcodeprefix_len = UseAnnexbLongStartcode?4:3;

// 对nalu->buf[i]进行赋值

nalu->buf[0] =

nalu->forbidden_bit << 7 |

nalu->nal_reference_idc << 5 |

nalu->nal_unit_type;

memcpy (&nalu->buf[1], rbsp, rbsp_size);

// printf ("First Byte %x\n", nalu->buf[0]);

// printf ("RBSPtoNALU: Before: NALU len %d\t RBSP %x %x %x %x\n", rbsp_size, (unsigned) nalu->buf[1], (unsigned) nalu->buf[2], (unsigned) nalu->buf[3], (unsigned) nalu->buf[4]);

len = 1 + RBSPtoEBSP (&nalu->buf[1], 0, rbsp_size, min_num_bytes);

// printf ("RBSPtoNALU: After : NALU len %d\t EBSP %x %x %x %x\n", rbsp_size, (unsigned) nalu->buf[1], (unsigned) nalu->buf[2], (unsigned) nalu->buf[3], (unsigned) nalu->buf[4]);

// printf ("len %d\n\n", len);

nalu->len = len;

return len;

}

3. Start Code Prefix为3个字节. 但是,为了寻址方便,要求数据流在长度上对齐,因此H.264建议在Start Code Prefix前面加若干个0.

4. 为了简便起见,上面的逻辑关系图没有考虑"防止竞争"机制.

编码foreman_part_qcif.yuv的第一帧,码流如下: (对照trace_enc.txt分析即可,由于码流太多,篇幅有限,故不一一分析)

0000000000000000000000000000000101100111010000100000000000011110111100010110000101100010011000100000000000000000000000000

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-09-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 音视频开发训练营 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档