• FFmpeg源码:AV_RB32宏定义分析


    一、AV_RB32宏定义的作用

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

    1. #ifndef AV_RB32
    2. # define AV_RB32(p) AV_RB(32, p)
    3. #endif

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

    uint32_t AV_RB32(uint8_t *data);

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

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

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

    二、AV_RB32宏定义的内部实现

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

    1. #ifndef AV_RB32
    2. # define AV_RB32(p) AV_RB(32, p)
    3. #endif
    4. #ifndef AV_RN32
    5. # define AV_RN32(p) AV_RN(32, p)
    6. #endif
    7. # define AV_RB(s, p) av_bswap##s(AV_RN##s(p))
    8. # define AV_RN(s, p) (((const union unaligned_##s *) (p))->l)
    9. union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias;

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

    1. #ifdef __GNUC__
    2. # define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
    3. # define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y))
    4. #else
    5. # define AV_GCC_VERSION_AT_LEAST(x,y) 0
    6. # define AV_GCC_VERSION_AT_MOST(x,y) 0
    7. #endif
    8. #define av_alias __attribute__((may_alias))
    9. #ifndef av_always_inline
    10. #if AV_GCC_VERSION_AT_LEAST(3,1)
    11. # define av_always_inline __attribute__((always_inline)) inline
    12. #elif defined(_MSC_VER)
    13. # define av_always_inline __forceinline
    14. #else
    15. # define av_always_inline inline
    16. #endif
    17. #endif
    18. #if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
    19. # define av_const __attribute__((const))
    20. #else
    21. # define av_const
    22. #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 中存在如下宏定义:

    1. #define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff))
    2. #define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16))
    3. #ifndef av_bswap32
    4. static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
    5. {
    6. return AV_BSWAP32C(x);
    7. }
    8. #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)) )

    所以

    1. static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
    2. {
    3.     return AV_BSWAP32C(x);
    4. }

      等价于 =>

    1. static __attribute__((always_inline)) inline __attribute__((const)) uint32_t av_bswap32(uint32_t x)
    2. {
    3. return ( (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) << 16 | ((((x) >> 16) << 8 & 0xff00) | (((x) >> 16) >> 8 & 0x00ff)) );
    4. }

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

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

    ( ((((((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 :

    1. #include
    2. #include
    3. #include
    4. #ifdef __GNUC__
    5. # define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
    6. # define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y))
    7. #else
    8. # define AV_GCC_VERSION_AT_LEAST(x,y) 0
    9. # define AV_GCC_VERSION_AT_MOST(x,y) 0
    10. #endif
    11. #define av_alias __attribute__((may_alias))
    12. #ifndef av_always_inline
    13. #if AV_GCC_VERSION_AT_LEAST(3,1)
    14. # define av_always_inline __attribute__((always_inline)) inline
    15. #elif defined(_MSC_VER)
    16. # define av_always_inline __forceinline
    17. #else
    18. # define av_always_inline inline
    19. #endif
    20. #endif
    21. #if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
    22. # define av_const __attribute__((const))
    23. #else
    24. # define av_const
    25. #endif
    26. #define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff))
    27. #define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16))
    28. #ifndef av_bswap32
    29. static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
    30. {
    31. return AV_BSWAP32C(x);
    32. }
    33. #endif
    34. union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias;
    35. # define AV_RN(s, p) (((const union unaligned_##s *) (p))->l)
    36. # define AV_RB(s, p) av_bswap##s(AV_RN##s(p))
    37. #ifndef AV_RB32
    38. # define AV_RB32(p) AV_RB(32, p)
    39. #endif
    40. #ifndef AV_RN32
    41. # define AV_RN32(p) AV_RN(32, p)
    42. #endif
    43. int main()
    44. {
    45. uint8_t *data = (uint8_t *)malloc(sizeof(uint8_t) * 8);
    46. if(data)
    47. {
    48. data[0] = 0x12;
    49. data[1] = 0x34;
    50. data[2] = 0x56;
    51. data[3] = 0x78;
    52. data[4] = 0x9A;
    53. data[5] = 0xBC;
    54. data[6] = 0xDE;
    55. data[7] = 0xF0;
    56. printf("%lu\n", AV_RB32(data));
    57. printf("%lu\n", AV_RB32(data + 4));
    58. free(data);
    59. data = NULL;
    60. }
    61. return 0;
    62. }

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

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

    data[4] = 0x9A;data[5] = 0xBC;data[6] = 0xDE;data[7] = 0xF0;所以AV_RB32(data + 4) 的值为0x9ABCDEF0,换算成10进制就是2596069104。

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

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

    四、参考文章

    大小端模式

  • 相关阅读:
    OLED透明拼接屏:福州鼓山风景区:徜徉于城市壮丽之
    如何在 TiDB Cloud 上使用 Databricks 进行数据分析 | TiDB Cloud 使用指南
    【飞控开发基础教程4】疯壳·开源编队无人机-串口(光流数据获取)
    学信息系统项目管理师第4版系列30_信息系统管理
    登录超时提示+踢人下线实现(spring security)
    新能源科学与工程专业概述
    修炼离线:(八)Linux使用wget安装出现Unable to establish SSL connection
    架构师社区爆火的分布式微服务神仙笔记究竟有什么魅力?
    C# GraphicsPath 类学习
    电缆隧道在线监测系统:提升电力设施安全与效率的关键
  • 原文地址:https://blog.csdn.net/u014552102/article/details/139865143