x264_nal_decode:nal 代码详解

本文详细介绍了H.264中NAL单元的解码过程,包括如何从字节流中提取NAL单元类型和优先级,并去除无效填充数据。通过具体代码示例,展示了NAL单元解码的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/****************************************************************************
 * x264_nal_decode:nal单元解码
 * 解码一个缓冲区 nal (p_data) 到 一个 x264_nal_t 结构体 (*nal)
 * 思路:网络传输过来的是一个字节,并不是如结构体x264_nal_t定义的用int表示的一个个结构体字段
 *      我们要把传来的第一个字节拆开用结构体中的int字段来表示,把前3比特放到x264_nal_t.i_ref_idc
 *      后5比特放到x264_nal_t.i_type
 *       http://wmnmtm.blog.163.com   

 ****************************************************************************/
int x264_nal_decode( x264_nal_t *nal, void *p_data, int i_data )
{
    uint8_t *src = p_data; //缓冲区起始地址,   unsigned char,就是一个8位的char,一个字节
    uint8_t *end = &src[i_data]; //缓冲区结束地址,
    uint8_t *dst = nal->p_payload; //指向有效荷载的起始地址

/*
 * 0 1 2 3 4 5 6 7 第一字节的8比特
 * | | | + + + + + 前3比特是优先级;后5比特是nal单元类型
 * --3-- ----5----
*/
    nal->i_type    = src[0]&0x1f; //类型占本字节的5位 0x1f-> 0001 1111 本字节与0001 1111按位与,取出nal的类型值
    nal->i_ref_idc = (src[0] >> 5)&0x03;//第1个字节右移5,得到优先级,占本字节的2位

    src++; //第2个字节及后面的字节

    while( src < end ) //循环第2及以后字节
    {
        if( src < end - 3 && src[0] == 0x00 && src[1] == 0x00  && src[2] == 0x03 )
//开始地址 < 结束地址 并且 第1字节 == 0x00
//   并且 第2字节 == 0x00
//   并且 第3字节 == 0x03
        {
            *dst++ = 0x00;//dst后移1字节
            *dst++ = 0x00;//同上

            src += 3; //src=src+3
/*
 * src   最初的src地址是起始的第一字节
 * src++ 移到了第2字节(while前的那句)
 * src += 3 即 src = src + 3
 * 比如起始地址为0, src = 0 + 3
 * 0 1 2 3  
 * 可以看到,3实际是第4个字节了
 * 这样,0x 00 00 03 01 虽然只是比较了前3字节,但是
 * src += 3 ,实际上把后面的01也跳过了
*/
            continue;
        }
        *dst++ = *src++;//左边是dst的值(*dst)++,右侧是(*src)++
//先结合* ,然后指针自增1
// 这样理解,++后置的情况下,先用它的值,最后才++
//是*src给*dst
/* 等价于如下的三行代码:
* *dst = *src
* dst++;
* src++;
* -----------------
* *j++的理解还应该是 *(j++)
* *(j++)就是*j
* 注意:不是先计算括号里面的++
*/
    }//去掉添加的0x00 00 03 01 (4字节)

    nal->i_payload = dst - (uint8_t*)p_data;//i_payload是有效载荷的长度,以字节为单位
/* 直观的理解,负载的长度为 nal->p_payload 的地址 减
 * 1字节的Nal Header 减
 * 0x00 00 03 01 (4字节)(如果有的话) 减  * 
 * NAL起始地址p_data
 * -----------------------
 * dst经过几次移动
 * 第一次,uint8_t *dst = nal->p_payload; //指向有效荷载的起始地址
 * 第二次,*dst++ = 0x00;
 * 第三次,*dst++ = 0x00;
 * 第四次,*dst++ = *src++;
*/
    return 0;
}

x264_nal_decode:nal 代码详解 - 加菲 - 视频会议 - 加菲
x264_nal_decode:nal 代码详解 - 加菲 - 视频会议 - 加菲
关于*dst++ = *src++,测试例子如下:
H.264 ing(450291883)  22:30:09
#include<iostream>
using namespace std;
int main()
{

char a[10]="abc123";
char b[10]="edf456";
char *src,*des;
src=b;
des=a;
while(*des++=*src++);
cout<<a<<endl;
return 0;
}

x264_nal_decode:nal 代码详解 - 加菲 - 视频会议 - 加菲
 
 
H.264 ing(450291883)  22:13:06
#include<iostream>
using namespace std;
int main()
{
int a[3]={1,2,3};
int *p1,*p2;
p1=a;
p2=a;
cout<<*p1++<<endl;
cout<<*(p2++)<<endl;
return 0;
}
x264_nal_decode:nal 代码详解 - 加菲 - 视频会议 - 加菲
 




`x264_nal_t`结构体是x264库中用于存储编码后的NAL数据信息的结构体,其中不包含PTS、DTS、Duration和Index等信息,需要使用外部变量或函数进行传递或计算。具体实现时,可以按照以下步骤获取PTS、DTS、Duration和Index等信息: 1. 在调用x264_encoder_encode函数进行编码时,可以将PTS和DTS作为x264_picture_t结构体变量的i_pts和i_dts字段进行设置,例如: ``` x264_picture_t pic_in, pic_out; // 设置图像数据 pic_in.i_pts = pts; pic_in.i_dts = dts; // 编码一帧图像 int ret = x264_encoder_encode(encoder, &nal, &nnal, &pic_in, &pic_out); ``` 2. 在编码完成后,可以根据视频帧率和编码时长计算出Duration信息,例如: ``` int frame_rate = 25; // 视频帧率 int duration = 1000 / frame_rate; // 每帧编码时长(毫秒) ``` 3. 在传递x264_nal_t结构体变量时,可以使用外部变量或函数传递Index信息,例如: ``` int nal_index = 0; // NAL序号 for (int i = 0; i < nnal; i++) { x264_nal_t *nal_ptr = &nal[i]; // 设置NAL信息 nal_ptr->i_ref_idc = 0; nal_ptr->i_type = NAL_SLICE; nal_ptr->i_payload = nal_size[i]; nal_ptr->p_payload = nal_data[i]; nal_ptr->i_nal_units = nnal; nal_ptr->i_nal_unit = i; nal_ptr->i_temporal_reference = nal_index++; } ``` 通过以上步骤,就可以获取到PTS、DTS、Duration和Index等信息,并将编码后的NAL数据存储到x264_nal_t结构体中。需要注意的是,具体实现时还需要根据具体情况进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值