FFmpeg源码:get_bit_length函数分析

一、get_bit_length函数的作用

get_bit_length函数的定义放在FFmpeg源码(本文演示用的FFmpeg源码版本为5.0.3,该ffmpeg在CentOS 7.5上通过10.2.1版本的gcc编译)的源文件libavcodec/h2645_parse.c中:

cpp 复制代码
static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros)
{
//...
}

该函数在H.264/H.265解码时被调用。当FFmpeg对H.264/H.265解码执行完ff_h2645_extract_rbsp函数后,指针nal->data会指向一个缓冲区(该缓冲区存放"NALU Header + RBSP",详情可以参考FFmpeg源码:ff_h2645_extract_rbsp函数分析)。然后调用get_bit_length函数,可以得到nal->data指向的缓冲区的去掉补齐后的位数(bit),也就是NALU Header + SODB的位数。关于RBSP、SODB的概念可以参考《音视频入门基础:H.264专题(3)------EBSP, RBSP和SODB

形参nal:输入型参数:

nal->data:指向一个缓冲区,该缓冲区存放"NALU Header + RBSP"。

nal->size:nal->data指向的缓冲区的大小,单位为字节。

形参skip_trailing_zeros:计算返回值的位数(bit)时是否忽略nal->data指向的缓冲区最后ASCII码值为0的字符。值为0表示不忽略,1表示忽略。一般skip_trailing_zeros的值为1。

返回值:NALU Header + SODB的位数(bit)。注意这个返回值的单位是bit不是byte。8 bit 等于 1 byte,也就是1个字节等于8位。

二、get_bit_length函数的内部实现

get_bit_length函数的完整定义如下:

cpp 复制代码
static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros)
{
    int size = nal->size;
    int v;

    while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0)
        size--;

    if (!size)
        return 0;

    v = nal->data[size - 1];

    if (size > INT_MAX / 8)
        return AVERROR(ERANGE);
    size *= 8;

    /* remove the stop bit and following trailing zeros,
     * or nothing for damaged bitstreams */
    if (v)
        size -= ff_ctz(v) + 1;

    return size;
}

get_bit_length函数中首先会通过语句int size = nal->size;拿到 nal->data指向的缓冲区的大小(单位为字节)。然后通过:

cpp 复制代码
while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0)
        size--;

去掉nal->data指向的缓冲区中最后ASCII码值为0的字符(因为最后ASCII码值为0的字符可能是下一个NALU的起始码的一部分。H.264 RBSP的最后必定是值为1的stop bit + 补齐用的rbsp_alignment_zero_bit,故最后ASCII码值为0的字符不可能是RBSP的结尾,所以得去掉)。

执行完上述语句后,size的值为NALU Header + RBSP 的实际长度(单位为字节)。

然后通过v = nal->data[size - 1] 得到RBSP最后一个字节的数据。由于8 bit 等于1 byte,通过size *= 8;得到NALU Header + RBSP的总位数,单位为bit。

通过ff_ctz(v),得到RBSP stop bit后面rbsp_alignment_zero_bit的位数。关于ff_ctz函数,可以参考:《FFmpeg源码:ff_ctz / ff_ctz_c函数分析》。

所以 ff_ctz(v) + 1 等于RBSP stop bit 加上 rbsp_alignment_zero_bit的位数。

语句size -= ff_ctz(v) + 1 等价于 size = size -( ff_ctz(v) + 1)。执行完后size的值即为NALU Header + SODB的位数(bit) 。

相关推荐
雨夜和阳晨2 小时前
FFmpeg录制屏幕及声音
ffmpeg
吴声子夜歌2 小时前
FFmpeg——基础知识及FFmpeg框架
ffmpeg
aqi0019 小时前
FFmpeg开发笔记(七十二)Linux给FFmpeg集成MPEG-5视频编解码器EVC
android·ffmpeg·音视频·流媒体
不太会编程的IT男2 天前
在 Jetson Orin 开发套件上使用 Hardware Encoder / Decoder 构建 FFmpeg
ffmpeg·视频编解码·h.264
m0_687399842 天前
写一个Ununtu C++ 程序,调用ffmpeg API, 来判断一个数字电影的视频文件mxf 是不是Jpeg2000?
开发语言·c++·ffmpeg
aqi002 天前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
Java患者·2 天前
【小白】linux安装ffmpeg | java转码 【超详细】
ffmpeg
suifen_2 天前
RK平台ffmpeg支持硬件编解码
ffmpeg
feiyangqingyun2 天前
全网唯一/Qt结合ffmpeg实现手机端采集摄像头推流到rtsp或rtmp/可切换前置后置摄像头/指定分辨率帧率
qt·智能手机·ffmpeg
melonbo2 天前
使用FFmpeg将H.264码流封装为MP4
ffmpeg·音视频·h.264