• 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中:

    1. static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros)
    2. {
    3. //...
    4. }

    该函数在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函数的完整定义如下:

    1. static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros)
    2. {
    3. int size = nal->size;
    4. int v;
    5. while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0)
    6. size--;
    7. if (!size)
    8. return 0;
    9. v = nal->data[size - 1];
    10. if (size > INT_MAX / 8)
    11. return AVERROR(ERANGE);
    12. size *= 8;
    13. /* remove the stop bit and following trailing zeros,
    14. * or nothing for damaged bitstreams */
    15. if (v)
    16. size -= ff_ctz(v) + 1;
    17. return size;
    18. }

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

    1. while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0)
    2. 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) 。

  • 相关阅读:
    【Spring Cloud系统】- Zookeer特性与使用场景
    Packet Tracer - 确定 DR 和 BDR
    Bigder:35/100 开发同事说,我自己测了。可是上线后出问题了。
    设计模式之策略模式
    k8s-namespace-基本概念
    海水淡化除硼、饮用水除硼,超纯水除硼、废水除硼
    【自用存档】bs4爬虫代码
    Java如何更高效且大批量地读取文件数据(tsv,csv,txt等等)
    Go语言学习(二)-- 基本数据类型
    云原生之Docker的容器资源管理
  • 原文地址:https://blog.csdn.net/u014552102/article/details/139916677