FFmpeg源码:AV_RB32宏定义分析

一、AV_RB32宏定义的作用

AV_RB32是FFmpeg源码中经常出现的一个宏,其定义如下:

cpp 复制代码
#ifndef AV_RB32
#   define AV_RB32(p)    AV_RB(32, p)
#endif

该宏定义有多层。把它简化为函数,其函数声明可以等价于:

cpp 复制代码
uint32_t AV_RB32(uint8_t *data);

该函数作用是:按照大端模式 读取形参data指向的缓冲区的前四个字节,并返回。

形参data:输入型参数。指向某个缓冲区。

返回值:按照大端模式 读取到的 "形参data指向的缓冲区的前四个字节"。

二、AV_RB32宏定义的内部实现

FFmpeg源码目录下的libavutil/intreadwrite.h 中存在如下宏定义:

cpp 复制代码
#ifndef AV_RB32
#   define AV_RB32(p)    AV_RB(32, p)
#endif

#ifndef AV_RN32
#   define AV_RN32(p) AV_RN(32, p)
#endif

#   define AV_RB(s, p)    av_bswap##s(AV_RN##s(p))

#   define AV_RN(s, p) (((const union unaligned_##s *) (p))->l)

union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias;

libavutil/attributes.h 中存在如下宏定义:

cpp 复制代码
#ifdef __GNUC__
#    define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#    define AV_GCC_VERSION_AT_MOST(x,y)  (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y))
#else
#    define AV_GCC_VERSION_AT_LEAST(x,y) 0
#    define AV_GCC_VERSION_AT_MOST(x,y)  0
#endif


#define av_alias __attribute__((may_alias))

#ifndef av_always_inline
#if AV_GCC_VERSION_AT_LEAST(3,1)
#    define av_always_inline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#    define av_always_inline __forceinline
#else
#    define av_always_inline inline
#endif
#endif

#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
#    define av_const __attribute__((const))
#else
#    define av_const
#endif

所以 # define AV_RB32(p) AV_RB(32, p) 等价于 =>

define AV_RB32(p) av_bswap32(AV_RN(32, p)) 等价于 =>

define AV_RB32(p) av_bswap32((((const union unaligned_32 *) (p))->l))

libavutil/bswap.h 中存在如下宏定义:

cpp 复制代码
#define AV_BSWAP16C(x) (((x) << 8 & 0xff00)  | ((x) >> 8 & 0x00ff))
#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16))

#ifndef av_bswap32
static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
{
    return AV_BSWAP32C(x);
}
#endif

所以AV_BSWAP32C(x) 等价于 =>

(AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) 等价于 =>

( (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) << 16 | ((((x) >> 16) << 8 & 0xff00) | (((x) >> 16) >> 8 & 0x00ff)) )

所以

cpp 复制代码
static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
{
    return AV_BSWAP32C(x);
}

等价于 =>

cpp 复制代码
static __attribute__((always_inline)) inline __attribute__((const)) uint32_t av_bswap32(uint32_t x)
{
    return ( (((x) << 8 & 0xff00)  | ((x) >> 8 & 0x00ff)) << 16 | ((((x) >> 16) << 8 & 0xff00)  | (((x) >> 16) >> 8 & 0x00ff)) );
}

所以 AV_RB32(p); 等价于 =>

av_bswap32((((const union unaligned_32 *) (p))->l)); 等价于 =>

cpp 复制代码
( ((((((const union unaligned_32 *) (p))->l)) << 8 & 0xff00)  | (((((const union unaligned_32 *) (p))->l)) >> 8 & 0x00ff)) << 16 | (((((((const union unaligned_32 *) (p))->l)) >> 16) << 8 & 0xff00)  | ((((((const union unaligned_32 *) (p))->l)) >> 16) >> 8 & 0x00ff)) );

三、编写测试例子,测试AV_RB32

main.c :

cpp 复制代码
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>


#ifdef __GNUC__
#    define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#    define AV_GCC_VERSION_AT_MOST(x,y)  (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y))
#else
#    define AV_GCC_VERSION_AT_LEAST(x,y) 0
#    define AV_GCC_VERSION_AT_MOST(x,y)  0
#endif


#define av_alias __attribute__((may_alias))

#ifndef av_always_inline
#if AV_GCC_VERSION_AT_LEAST(3,1)
#    define av_always_inline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#    define av_always_inline __forceinline
#else
#    define av_always_inline inline
#endif
#endif

#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
#    define av_const __attribute__((const))
#else
#    define av_const
#endif


#define AV_BSWAP16C(x) (((x) << 8 & 0xff00)  | ((x) >> 8 & 0x00ff))
#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16))

#ifndef av_bswap32
static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
{
    return AV_BSWAP32C(x);
}
#endif


union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias;

#   define AV_RN(s, p) (((const union unaligned_##s *) (p))->l)
#   define AV_RB(s, p)    av_bswap##s(AV_RN##s(p))

#ifndef AV_RB32
#   define AV_RB32(p)    AV_RB(32, p)
#endif

#ifndef AV_RN32
#   define AV_RN32(p) AV_RN(32, p)
#endif



int main()
{
    uint8_t *data = (uint8_t *)malloc(sizeof(uint8_t) * 8);
    if(data)
    {
        data[0] = 0x12;
        data[1] = 0x34;
        data[2] = 0x56;
        data[3] = 0x78;
        data[4] = 0x9A;
        data[5] = 0xBC;
        data[6] = 0xDE;
        data[7] = 0xF0;

        printf("%lu\n", AV_RB32(data));
        printf("%lu\n", AV_RB32(data + 4));
        free(data);
	    data = NULL;
    }
    return 0;
}

Linux平台下使用gcc编译(我用的是CentOS 7.5,通过10.2.1版本的gcc编译)。输出为:

由于AV_RB32是按照大端模式读取。而data0 = 0x12,data1 = 0x34,data2 = 0x56,data3 = 0x78; 所以AV_RB32(data) 的值为0x12345678,换算成10进制就是305419896。

data4 = 0x9A;data5 = 0xBC;data6 = 0xDE;data7 = 0xF0;所以AV_RB32(data + 4) 的值为0x9ABCDEF0,换算成10进制就是2596069104。

AV_RB32(data) 将宏展开,实际就是:

cpp 复制代码
( ((((((const union unaligned_32 *) (data))->l)) << 8 & 0xff00)  | (((((const union unaligned_32 *) (data))->l)) >> 8 & 0x00ff)) << 16 | (((((((const union unaligned_32 *) (data))->l)) >> 16) << 8 & 0xff00)  | ((((((const union unaligned_32 *) (data))->l)) >> 16) >> 8 & 0x00ff)) )

四、参考文章

大小端模式

相关推荐
工具派1 天前
口播视频怎么自动剪掉冷场?视频静音删除的阈值实测
ffmpeg·音视频·视频
❀͜͡傀儡师1 天前
移动端 360° 商品展示方案:从 20MB 雪碧图到 800KB 丝滑视频
ffmpeg·webgl·sprite
2501_930472441 天前
深度复盘|数据库迁移实战(上):腾讯云助手解析慢查询日志,定位索引缺失与语法不兼容
数据库·阿里云·ffmpeg·云计算·腾讯云·aws
我就是DaLing呀!1 天前
flutter + ffmpeg_kit_extended_flutter 大视频合并下载
flutter·ffmpeg·音视频
可乐鸡翅yeah_3 天前
多浏览器 HLS 兼容性差异排查,Chrome、Firefox、Safari 表现不一致定位
chrome·ffmpeg·音视频·firefox·safari·m3u8
行者-全栈开发4 天前
Spring Boot + FFmpeg 视频批量处理实战:压缩、HLS切片与异步任务引擎
spring boot·ffmpeg·异步处理·视频压缩·hls切片·批量任务·redis队列
可乐鸡翅yeah_4 天前
M3U8测试流使用指南,流媒体开发自测与环境校验标准化方案
网络·ffmpeg·音视频·m3u8·m3u8在线·音视频在线播放
heqingchun164 天前
Ubuntu 22.04 交叉编译 RK3568 MPP + FFmpeg 完整指南
linux·ubuntu·ffmpeg
刘广睿4 天前
音频降噪实战:ffmpeg 滤镜、RNNoise 与人声分离方案对比
ffmpeg·音视频·效率工具·剪辑
IvorySQL5 天前
代价比较的变革——PostgreSQL执行计划干预增强深度解析
数据库·postgresql·ffmpeg