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

相关推荐
智能直播1 天前
网络RTMP拉流不卡顿、声音不同步,一文讲透缓冲区、时间戳
开发语言·ffmpeg·php·音视频·视频编解码
八月的雨季 最後的冰吻2 天前
FFmepg-- 42-ffplay.c 线程安全机制深度分析
c语言·安全·ffmpeg
开开心心就好3 天前
把手机变成电脑麦克风,WiFi连接就能用
智能手机·ffmpeg·计算机外设·电脑·word·音视频
@嵌入式扫地僧3 天前
FFmpeg 解码 H.264 流提取 SEI 用户数据实战
ffmpeg·h.264·流媒体开发·sei 解析·自定义 sei
VimorphTech3 天前
ffmpeg.wasm 实战:浏览器提取视频音频,如何处理进度、取消和资源释放?
ffmpeg
小小龙学IT3 天前
FFmpeg 开源多媒体处理框架深度解析:从命令行到 libav* 全家桶
c语言·ffmpeg·开源
ofoxcoding4 天前
Gemini TTS 与 ElevenLabs 语音合成实测:同一段视频旁白效果对比
ai·ffmpeg·音视频
_大峰_4 天前
索尼 A7M4 误删视频恢复实战:基于原始卡镜像重建 MP4 数据
ffmpeg·数据恢复·音视频·mp4·exfat
Anhty5 天前
3 款手机音频剪辑 APP 横评,短视频配音后期,免费工具怎么选?
功能测试·ffmpeg·音视频
VidDown6 天前
自动给视频挑一张能看的封面:帧评分、构图与批量生成
python·ffmpeg·音视频·视频