FFmpeg 4.0 版本源码地址 :





一、AVFormatContext 结构体的视频参数信息




1、回顾总结


在上一篇博客 【FFmpeg】解封装 ② ( 解封装代码实战 | Qt 项目搭建 | Qt 可执行程序运行环境分析 | FFmpeg 函数错误码处理 | 获取视频文件的参数信息 | 获取文 码流个数/播放时长 ) 中 , 介绍了

  • 调用 avformat_open_input 函数 打开 视频文件 ,
    • mp4 格式的文件 , 仅调用该函数 , 即可获取完整的 视频参数信息 ;
    • flv 格式的文件 , 无法通过该函数获取所有参数信息 ;
  • 调用 avformat_find_stream_info 函数 分析媒体流详细参数信息 ,
    • flv 格式的文件 , 需要额外调用该函数 , 才能获取所有的码流参数信息 ;
  • 遇到 FFmpeg 函数执行失败时 , 可 调用 av_strerror 函数 , 将错误码转为文字描述信息 ;
  • 获取 AVFormatContext 中的参数信息 :
    • url 字段 是 文件路径或地址 ;
    • nb_streams 字段 是 码流个数 ;
    • duration 字段 是 播放时长 , 单位 微秒 ;

2、AVFormatContext 的常用字段


下面是 AVFormatContext 结构体 中 的常用字段 , 每个字段设置了中文注释 ;

typedef struct AVFormatContext {
    /**
     * AVFormatContext.streams 中的元素数量。
     */
    unsigned int nb_streams;

    /**
     * 文件中所有流的列表
     */
    AVStream **streams;
	
    /**
     * 输入或输出 URL。与旧的 filename 字段不同,此字段没有
     * 长度限制。
     */
    char *url;
	
    /**
     * 流的持续时间,单位为 AV_TIME_BASE 分数秒
     */
    int64_t duration;
	
    /**
     * 总流比特率(比特/秒)
     */
    int64_t bit_rate;
}

3、对比 avformat_find_stream_info 函数的作用



① 文件准备


将 FLV / MP4 / TS 格式的三个视频文件 , 拷贝到 源码编译 输出目录中 , 这也是 执行程序 的 操作目录 ,

在这里插入图片描述
将视频放在 上述目录 " D:\002_Project\008_Qt\build-FFmpegC-Desktop_Qt_5_14_2_MSVC2015_32bit-Debug " 中 , 在 项目设置 中 的 命令行参数 CommandLine arguments 中配置 文件的 相对路径 即可 ;

在这里插入图片描述


② MP4 格式


MP4 格式的 视频文件 将文件的 元数据信息 集中存储在文件的头部 中 , 这些元数据有 : 视频流信息、音频流信息、时长、比特率、分辨率 等 ;

当调用 avformat_open_input 函数 打开 MP4 文件时 , FFmpeg 会读取 视频文件的头部数据 , 并从中提取出所有的流信息 ;

由于这些信息在文件头部就已经完整 , 后续无需 调用 avformat_find_stream_info 函数 解析流内容 ;


【FFmpeg】解封装 ② ( 解封装代码实战 | Qt 项目搭建 | Qt 可执行程序运行环境分析 | FFmpeg 函数错误码处理 | 获取视频文件的参数信息 | 获取文 码流个数/播放时长 ) 四、获取视频文件的参数信息 3、代码示例 代码的基础上 , 将 avformat_find_stream_info 函数注释掉 , 发现 不调用 avformat_find_stream_info 函数 仍然可以打印出完整的 视频参数信息 ;

在这里插入图片描述


③ FLV 格式


FLV 格式的文件 是 专门为 流媒体传输 而设计的 文件格式 , FLV 文件的 元数据结构较简单 , 文件头 只包含 文件类型、版本号、音视频标志等 基本信息 , 媒体流 的 参数信息 存储在 FLV 文件的后续数据包 ;

媒体流 的 码率、分辨率、时长 等 参数 , 都不在 FLV 头文件中 , 如果要获取这些信息 , 需要 解析 多个数据包 后才能获取到所有信息 ;

调用 avformat_find_stream_info 函数 就是 读取 后续数据包信息 , 解析媒体流的 一系列参数 ;


在上面的代码基础上 , 将命令行参数设置为 test.flv , 解析 FLV 格式的视频文件 ;

在这里插入图片描述

调用 avformat_open_input 函数 后 , 只能解析头文件 , 头文件没有媒体流的参数信息 ,

Input #0, flv, from 'test.flv':
  Duration: N/A, start: 0.000000, bitrate: N/A

在这里插入图片描述

将 avformat_find_stream_info 函数调用的注释打开 , 再次执行应用 , 对 FLV 格式的视频文件进行解封装 , 此时可以完整的打印出 FLV 文件的 媒体流 详细参数信息 ;

在这里插入图片描述





二、获取视频文件码率




1、媒体流的比特率


AVFormatContext 结构体 int64_t bit_rate 字段 视频文件 或 音频文件 的 媒体流 的 比特率 , 单位是 bps 比特每秒 , 比特率 反映 媒体流的 质量 和 压缩程度 ;

typedef struct AVFormatContext {
    /**
     * 总流比特率(比特/秒),如果不可用则为 0。
     * 如果文件大小和持续时间已知,请勿直接设置它,因为 FFmpeg 可以自动计算。
     */
    int64_t bit_rate;
} AVFormatContext;

bit_rate 字段 是一个 64 位的整数 , 其 单位是 比特每秒 bit/s , 该值是文件的 总比特率 , 通常在多媒体文件的头部 会有这个信息 , 这个比特率是对整个文件或流的压缩率的一个度量 ;

  • 对于视频文件 , 比特率 通常指的是 视频流 和 音频流 的 总比特率 ;
  • 对于流媒体 , 比特率 表示 媒体流 的 传输比特率 ;

比特率 只是一个大致的估计值 , 尤其是在网络宽带不稳定的的情况下 , 网络流的比特率 不是精确的值 ;


获取 视频总比特率代码 :

    // 8. 获取视频文件的总比特率 , 单位为bps
    printf("\nbit_rate : %lld bps\n",(int64_t)(fmt_ctx->bit_rate));

执行结果 :

bit_rate : 286624 bps

在这里插入图片描述


2、比特率 与 存储单位 的 换算基数


比特率 的 单位 是 比特每秒 bps ,

按照理论来说 , 比特率应该按照 1024 进行换算 , 1 Kbps = 1024 bps ;

比特率 主要是用于描述 网络传输速度 和 信号带宽 , 一般 遵循 国际单位制 , 而国际单位制 规定 : 单位之间的换算使用 1000 , 因此 在实际使用时 , 一般都按照如下进行单位换算 :

  • 1 Kbps = 1000 bps
  • 1 Mbps = 1000 Kbps = 1,000,000 bps
  • 1 Gbps = 1000 Mbps = 1,000,000,000 bps

与之相对的是 存储单位的换算 , 在计算机存储和内存的容量度量中 , 通常使用 1024 作为换算基数 ;

  • 1 KiB (Kibibyte) = 1024 bytes
  • 1 MiB (Mebibyte) = 1024 KiB = 1,048,576 bytes
  • 1 GiB (Gibibyte) = 1024 MiB = 1,073,741,824 bytes

3、常见的音视频比特率


常见的音视频比特率 :

  • 音频 比特率 : 通常 以 Kbps 为单位 , 音频的 比特率 越高 , 音质通常越好 , 但文件或数据流的大小也会增加 ; 常见的 MP3 音频比特率为 128 Kbps、192 Kbps、256 Kbps、320 Kbps ;
  • 视频 比特率 : 视频 比特率 表示 每秒钟传输的视频数据量 , 通常以 Kbps 或 Mbps 为单位 ; 视频比特率越高 , 视频的画质通常越好 , 但文件的大小也会增大 ;
    • 1000 Kbps 是 低清视频 ;
    • 2500 Kbps 是 标清视频 ;
    • 5000 Kbps 是 高清 720p 视频 ;
    • 8000 Kbps 是 全高清 1080p 视频 ;




三、分析媒体流数据




1、媒体流遍历


AVFormatContext 结构体 unsigned int nb_streams 成员 是 媒体流个数 , AVStream **streams 是 媒体流 的实际数据 , 每个 AVStream 都表示一个媒体流 , 可参考本博客 第一章 的 AVFormatContext 结构体 源码 ;

AVStream 媒体流 可以是 :

  • 视频流
  • 音频流
  • 字幕流

使用下面的方式 , 可以遍历 视频文件 的 媒体流 ;

AVFormatContext *fmt_ctx = NULL

// ... 初始化 AVFormatContext 结构体数据

for (uint32_t i = 0; i < fmt_ctx->nb_streams; i++){
    // 解析的第 i 个媒体流 , 可能是 视频流 / 音频流 / 字幕流
    AVStream *in_stream = fmt_ctx->streams[i];
    
    // 解析 AVStream 操作 
}

2、AVStream 中的 codecpar 成员


AVStream 结构体 中的 AVCodecParameters *codecpar 成员 是一个指向 AVCodecParameters 结构体的指针 , 用于 描述媒体流的编解码器相关参数 ;

typedef struct AVStream {
    /**
     * 与此流关联的编解码器参数。在调用 avformat_new_stream() 时由 libavformat 分配,
     * 并在调用 avformat_free_context() 时由 libavformat 释放。
     *
     * - 解复用:在流创建时或调用 avformat_find_stream_info() 时由 libavformat 填充。
     * - 复用:在调用 avformat_write_header() 之前由调用方填充。
     */
    AVCodecParameters *codecpar;    
} AVStream;

AVCodecParameters 是一个 轻量级的结构体 , 仅存储描述媒体流的静态属性 , 如 : 编码格式、分辨率、采样率 等 ;

AVCodecParameters 结构体中 不包含运行时的状态信息 , 不依赖具体的 解码器 或 编码器 实现 , 比 AVCodecContext 结构体 更适合 作为 描述媒体流 的 独立结构体 ;


AVStream 的 AVCodecContext *codec 成员 , 已经被标记为废弃状态 , 不推荐使用 , 仅用于兼容老旧代码 ;

typedef struct AVStream {
    /**
     * @deprecated use the codecpar struct instead
     */
    attribute_deprecated
    AVCodecContext *codec;
} AVStream;

3、AVCodecParameters 结构体


AVCodecParameters 结构体 定义在 libavcodec/avcodec.h 头文件 中 , 该结构体中 的成员分为如下几类 :

  • 通用参数 : 媒体类型 codec_type , 编解码器 ID codec_id , 编码器标记 codec_tag , 比特率 bit_rate ;
  • 视频流参数 : 视频宽高 width height , 像素格式 format , 画面宽高比 sample_aspect_ratio ;
  • 音频流参数 : 音频采样率 sample_rate , 声道数 channels , 采样位数 format , 每帧采样数 frame_size ;
  • 字幕流参数 : 字幕宽高 width height , 字幕像素格式 format ;

注意 : 某些字段 , 多种媒体流使用会有不同的含义 ;

typedef struct AVCodecParameters {
    enum AVMediaType codec_type;    /**< 媒体类型 (如音频、视频、字幕等) */
    enum AVCodecID codec_id;        /**< 编解码器 ID (如 H.264, AAC) */
    uint32_t codec_tag;             /**< 编解码器标记 (格式标识符,如 avc1, mp4a) */

    uint8_t *extradata;             /**< 附加数据 (如 SPS/PPS 信息) */
    int extradata_size;             /**< 附加数据大小 (单位: 字节) */

    int format;                     /**< 像素格式 (视频) 或采样格式 (音频) */
    int bit_rate;                   /**< 比特率 (单位: bit/s) */

    int bits_per_coded_sample;      /**< 每编码样本位数 */
    int bits_per_raw_sample;        /**< 每原始样本位数 */
    int profile;                    /**< 编解码器配置 (如 H.264 的 High Profile) */
    int level;                      /**< 编解码器级别 (如 H.264 的 Level 4.1) */

    // 视频相关字段
    int width;                      /**< 视频帧宽度 (单位: 像素) */
    int height;                     /**< 视频帧高度 (单位: 像素) */
    AVRational sample_aspect_ratio; /**< 显示宽高比 (SAR) */
    enum AVFieldOrder field_order;  /**< 字段顺序 (如逐行、隔行) */
    int color_range;                /**< 颜色范围 (如 MPEG 或 JPEG 范围) */
    int color_primaries;            /**< 颜色原色 */
    int color_trc;                  /**< 颜色传递特性 */
    int color_space;                /**< 颜色空间 (如 BT.601, BT.709) */
    int chroma_location;            /**< 色度位置 */
    int video_delay;                /**< 视频延迟 (单位: 帧) */

    // 音频相关字段
    int channel_layout;             /**< 声道布局 (如立体声、5.1 声道) */
    int channels;                   /**< 声道数 */
    int sample_rate;                /**< 音频采样率 (单位: Hz) */
    int block_align;                /**< 对齐块大小 */
    int frame_size;                 /**< 每帧采样点数 */
    int initial_padding;            /**< 解码器初始填充样本数 */
    int trailing_padding;           /**< 解码器尾部填充样本数 */
    int seek_preroll;               /**< 回放时需要的预卷样本数 */
} AVCodecParameters;

4、媒体流类型


AVStream 结构体 中 的 AVCodecParameters *codecpar 结构体成员 中 的 enum AVMediaType codec_type 枚举成员 表示的是 媒体流类型 ;

AVMediaType 枚举 表示 媒体流类型 , 该枚举 定义在 libavutil/avutil.h 文件中 ;


下面是 AVMediaType 枚举 的原型 :

typedef enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1, /**< 未知类型 */
    AVMEDIA_TYPE_VIDEO,        /**< 视频 */
    AVMEDIA_TYPE_AUDIO,        /**< 音频 */
    AVMEDIA_TYPE_DATA,         /**< 数据 (通常为未解码的补充数据) */
    AVMEDIA_TYPE_SUBTITLE,     /**< 字幕 */
    AVMEDIA_TYPE_ATTACHMENT,   /**< 附件 (如字体或图片) */
    AVMEDIA_TYPE_NB            /**< 媒体类型的数量 (仅用于计数) */
} AVMediaType;
  • AVMEDIA_TYPE_UNKNOWN : 未知 媒体流 类型 , 如果没有识别出流的类型就会设置 该枚举选项 ;
  • AVMEDIA_TYPE_VIDEO : 视频流 类型 , 包括编码的或未编码的 视频帧数据 , 如 : H.264 ;
  • AVMEDIA_TYPE_AUDIO : 音频流 类型 , 包括各种音频编码格式 , 如 : acc / mp3 / pcm ;
  • AVMEDIA_TYPE_DATA : 数据流 类型 , 包含 未解码 或 额外的非音视频数据 , 如 : 元数据 / 统计信息 ;
  • AVMEDIA_TYPE_SUBTITLE : 字幕流 类型 , 包含 ASS / SRT 文字字幕 或 图片字幕 ;
  • AVMEDIA_TYPE_ATTACHMENT : 附件流 类型 , 通常为媒体文件中包含的 字体 或 缩略图 等 外部资源 ;
  • AVMEDIA_TYPE_NB : 媒体类型的数量 , 用于标记 AVMediaType 中的枚举条目总数 ;

5、判断媒体流类型


核心代码示例 : 在下面的代码中 , 遍历 AVFormatContext 中的 AVStream **streams 成员 , 这是所有的媒体流 , 通过判断 AVStream 的 codecpar->codec_type 成员 , 判定媒体流的类型 ;

    // 9. 遍历媒体流
    for (uint32_t i = 0; i < fmt_ctx->nb_streams; i++)
    {
        // 获取第 i 个媒体流 , 该媒体流可以是 音频流、视频流、字幕流
        AVStream *in_stream = fmt_ctx->streams[i];

        if (AVMEDIA_TYPE_AUDIO == in_stream->codecpar->codec_type) // 解析音频流参数
        {
            printf("\n\n==== Audio info ===\n\n");
        }
        else if (AVMEDIA_TYPE_VIDEO == in_stream->codecpar->codec_type)  //解析视频流参数
        {
            printf("\n\n==== Vedio info ===\n\n");
        }
    }

执行结果如下 :

在这里插入图片描述

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐