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) 。

相关推荐
岁月小龙10 小时前
如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
ffmpeg·origin·ffprobe·rpath
行者记2 天前
ffmpeg命令——从wireshark包中的rtp包中分离h264
测试工具·ffmpeg·wireshark
EasyCVR2 天前
国标GB28181视频平台EasyCVR私有化视频平台工地防盗视频监控系统方案
运维·科技·ffmpeg·音视频·1024程序员节·监控视频接入
hypoqqq2 天前
使用ffmpeg播放rtsp视频流
ffmpeg
cuijiecheng20182 天前
音视频入门基础:FLV专题(24)——FFmpeg源码中,获取FLV文件视频信息的实现
ffmpeg·音视频
QMCY_jason2 天前
黑豹X2 armbian 编译rkmpp ffmpeg 实现CPU视频转码
ffmpeg
苍天饶过谁?2 天前
SDL基本使用
ffmpeg
HZ355722 天前
ffmpeg视频解码
ffmpeg·音视频
runing_an_min2 天前
windows运行ffmpeg的脚本报错:av_ts2str、av_ts2timestr、av_err2str => E0029 C4576
c++·windows·ffmpeg·e0029
EelBarb2 天前
ffmpeg:视频字幕嵌入(GPU加速)
ffmpeg·音视频