当前位置: 首页 > news >正文

AVFormatContext 再分析

说明 :将 avfromatContext 的变量依次打印分析,根据ffmpeg 给的说明,猜测,结合网上的文章字节写测试代码分析。

从常用到不常用依次分析

1. unsigned int nb_streams;

代表 avfromatContext 中 AVStream **streams 的个数

    /**
     * Number of elements in AVFormatContext.streams.
     *
     * Set by avformat_new_stream(), must not be modified by any other code.
     */
    unsigned int nb_streams;

//打印在解复用时候,avformatContext的主要参数
void PrintfDeMuxingAVFormatContextMainParamter(AVFormatContext* avformatContext) {if (avformatContext == NULL) {cout << "func PrintfDeMuxingAVFormatContextMainParamter error because AVFormatContext == nullptr  " << endl;return;}cout << "avformat中有的avstream的个数为:avformatContext->nb_streams = " << avformatContext->nb_streams << endl;}

2. int64_t bit_rate;

在 AVFormatContext 结构体中,‌bit_rate 字段表示媒体文件的全局平均比特率‌(单位为 bps,即 bits per second)

    /**
     * Total stream bitrate in bit/s, 0 if not
     * available. Never set it directly if the file_size and the
     * duration are known as FFmpeg can compute it automatically.
     */
    int64_t bit_rate;

2.1 含义再说明1

从说明中可以看出来,代表的是所有 stream 的 平均比特率。啥意思呢?比如这是一个mp4文件,既有视频也有音频,我们假设有一个视频两个音频(粤语和普通话),假设视频是300kbps,普通话音频是128kbps,粤语音频是100kbps。那么 AVFormatContext 中的 bit_rate就应该等于 300 +128+100 = 628kbps,注意单位是kbps。

// 遍历所有流,计算总比特率
int64_t total_bit_rate = 0;
for (int i = 0; i < avformat_ctx->nb_streams; i++) {AVStream *stream = avformat_ctx->streams[i];total_bit_rate += stream->codecpar->bit_rate;
}

2.2 含义再说明2,在TS下无效

0 if not available

这个意思是说,这个值有可能是0,代表不可使用。

部分封装格式(如 TS 流)可能不记录全局比特率,此时 bit_rate 字段无效

2.3 含义再说明3,当文件大小和duration都知道的时候,user不要设置,ffmepg会自动计算

Never set it directly if the file_size and the duration are known as FFmpeg can compute it automatically.

2.5 动态码率场景


VBR 编码的文件中,该字段仅代表平均值,无法反映瞬时码率波动

CBR 是 (恒定比特率)

VBR(可变比特率),

mp4文件只能是 VBR。

也就是说:如果我们解析的是mp4文件,那么这个值是平均值。无法反映瞬时码率波动

2.6 典型应用场景

  • 带宽估算‌:
    结合容器和流的比特率,判断网络传输是否满足实时播放需求56。
  • 文件分析工具‌:
    统计媒体文件的码率分布,辅助编码参数优化6。

3. int64_t duration

只能用于解复用,

是 ‌AVFormatContext 结构体‌的关键成员,用于表示 ‌媒体文件的总时长‌。其数据类型为 int64_t,单位为 ‌AV_TIME_BASE‌(即微秒的倒数,通常为 1,000,000)。

该字段在 ‌成功解析媒体文件流信息后‌(调用 avformat_find_stream_info())才会被正确赋值

    /**
     * Duration of the stream, in AV_TIME_BASE fractional
     * seconds. Only set this value if you know none of the individual stream
     * durations and also do not set any of them. This is deduced from the
     * AVStream values if not set.
     *
     * Demuxing only, set by libavformat.
     */
    int64_t duration;

主要使用场景,通过 duration 计算文件时长。

换算为秒‌:

double duration_sec = (double)avformatContext->duration / AV_TIME_BASE;
 

转换为时分秒格式‌:

int64_t total_us = avformatContext->duration + 5000;  // 四舍五入修正
int hours = total_us / (3600 * AV_TIME_BASE);
int mins = (total_us % (3600 * AV_TIME_BASE)) / (60 * AV_TIME_BASE);
int secs = (total_us % (60 * AV_TIME_BASE)) / AV_TIME_BASE;

常见问题与解决方案

问题原因解决方案
返回负值或极大值未正确解析流信息或文件不完整调用 avformat_find_stream_info() 前设置 max_analyze_duration 参数
单位换算错误未使用 AV_TIME_BASE 进行转换确保除以 AV_TIME_BASE(或使用 av_rescale_q() 函数)
时间精度丢失直接截断未四舍五入添加 5000 微秒偏移(如 +5000)后再计算

AVFormatContext *fmt_ctx = NULL;
avformat_open_input(&fmt_ctx, filename, NULL, NULL);  // 打开文件
fmt_ctx->max_analyze_duration = 5 * AV_TIME_BASE;     // 限制解析时长避免卡顿
avformat_find_stream_info(fmt_ctx, NULL);              // 解析流信息if (fmt_ctx->duration != AV_NOPTS_VALUE) {int64_t duration = fmt_ctx->duration + 5000;      // 修正精度int hours = duration / (3600 * AV_TIME_BASE);int mins = (duration % (3600 * AV_TIME_BASE)) / (60 * AV_TIME_BASE);int secs = (duration % (60 * AV_TIME_BASE)) / AV_TIME_BASE;printf("Duration: %02d:%02d:%02d\n", hours, mins, secs);
} else {printf("Duration unavailable\n");
}
avformat_close_input(&fmt_ctx);                       // 释放资源

适用场景

  • 媒体信息分析工具‌:如 ffprobe 使用该字段输出文件时长。
  • 播放器开发‌:用于显示进度条总时长。
  • 流媒体处理‌:结合 AVStream 中各流时长进行同步控制。

注意‌:在网络流或实时流中,duration 可能无法获取(值为 AV_NOPTS_VALUE),需动态计算

cout << "avformat中duration为:avformatContext->duration = " << avformatContext->duration << endl;double duration_sec = (double)avformatContext->duration / AV_TIME_BASE;
cout << "avformat中秒数为:duration_sec = " << duration_sec << endl;if (avformatContext->duration != AV_NOPTS_VALUE) {int64_t duration = avformatContext->duration + 5000;      // 修正精度int hours = duration / (3600 * AV_TIME_BASE);int mins = (duration % (3600 * AV_TIME_BASE)) / (60 * AV_TIME_BASE);int secs = (duration % (60 * AV_TIME_BASE)) / AV_TIME_BASE;printf("Duration: %02d:%02d:%02d\n", hours, mins, secs);
}else {printf("Duration unavailable\n");
}avformat中duration为:avformatContext->duration = 60024000
avformat中秒数为:duration_sec = 60.024
Duration: 00:01:00

4. char *url;

    /**
     * input or output URL. Unlike the old filename field, this field has no
     * length restriction.
     *
     * - demuxing: set by avformat_open_input(), initialized to an empty
     *             string if url parameter was NULL in avformat_open_input().
     * - muxing: may be set by the caller before calling avformat_write_header()
     *           (or avformat_init_output() if that is called first) to a string
     *           which is freeable by av_free(). Set to an empty string if it
     *           was NULL in avformat_init_output().
     *
     * Freed by libavformat in avformat_free_context().
     */
    char *url;

和之前的filename不同,url是没有长度限制的。

在解码时,通过 avformat_open_input 方法 会将url 记录到 AVFormatContext ,可能会nullptr。

在编码时,需要在 调用 avformat_write_header 方法之前设置。

   char * url =  avformatContext->url;cout << "avformat中duration为 url = " << url << endl;结果为:avformat中duration为 url = ./120/400_300_25.mp4

5. int64_t start_time;

    /**
     * Position of the first frame of the component, in
     * AV_TIME_BASE fractional seconds. NEVER set this value directly:
     * It is deduced from the AVStream values.
     *
     * Demuxing only, set by libavformat.
     */
    int64_t start_time;

组件第一帧的位置,以AV_TIME_BASE  为单位。 
切勿直接设置此值:它是从AVStream值推断出来的。

这玩意有啥用呢?表示该avformatContext 第一帧的开始时间,那么应该都是0。

可能的点:todo

如果我们从文件的中间位置读取的,那么这个值就不是0?

在网络流的时候用?

   int64_t starttime = avformatContext->start_time;cout << "avformat中duration为 starttime = " << starttime << endl;avformat中duration为 starttime = 0

6. 接下来都是非重点 AVCodec* audio_codec;

    /**
     * Forced audio codec.
     * This allows forcing a specific decoder, even when there are multiple with the same codec_id.
     * Demuxing: Set by user
     */
    AVCodec *audio_codec;

这里从翻译来看,意思是该变量是为了 音频的编解码。

允许在解码的时候,允许强制使用特定的解码器,即使存在多个具有相同codec_id的解码器

/**
 * Forced audio codec.
 * This allows forcing a specific decoder, even when there are multiple with the same codec_id.
 * Demuxing: Set by user
 * AVCodec* audio_codec;
 * 在 音频 编解码器 的时候使用,
 * 在解复用的时候,允许强制使用特定的解码器,即使存在多个具有相同codec_id的解码器
 * 我们使用test02测试
 */

avformatContext->audio_codec;cout << "avformatContext->audio_codec = " << avformatContext->audio_codec << endl;


 * 在 音频 编解码器 的时候使用,
 * 在解复用的时候,允许强制使用特定的解码器,即使存在多个具有相同codec_id的解码器

   AVCodec* audioavcodec = avformatContext->audio_codec;if (audioavcodec == nullptr) {cout << "audioavcodec == nullptr" << endl;}else {cout << "audioavcodec != nullptr  audioavcodec->id = " << audioavcodec->id << endl;}log 为:audioavcodec == nullptr

last

相关文章:

  • python+adafruit_pca9685 测试舵机存储当前角度
  • 中国区域250米归一化植被指数数据集(2000-2023)
  • 数据库3,
  • 前端Ui设计工具
  • BP 算法探秘 :神经网络的幕后引擎
  • 单值映射、多值映射
  • 单点登录(双token)的简单总结
  • C++ 类与对象(中)—— 默认成员函数与运算符重载的深度解析:构造函数,析构函数,拷贝构造函数,赋值运算符重载,普通取地址重载,const取地址重载
  • Java使用微信云服务HTTP API操作微信云开发数据库
  • WebGIS面试题目整合资料
  • 《TVM模式匹配实战:从DFPatternNode到DFPattern的高级用法》
  • PPIO X OWL:一键开启任务自动化的高效革命
  • Codeforces Round 1021 (Div. 2) D. Baggage Claim(建图)
  • PLC在仪表控制系统中的应用
  • 代码随想录算法训练营第60期第二十天打卡
  • Python爬虫(6)静态页面解析实战:BeautifulSoup与lxml(XPath)高效提取数据指南
  • 能源行业数字化转型:利用大数据与人工智能提升效率与可持续性
  • MCP Server On FC 之旅1: MCP 协议的深度解析与云上适配最佳实践
  • Docker 部署 flink1.19.2
  • Golang 学习指南
  • 亮剑浦江丨上海网信部门处罚一批医疗服务类互联网企业,三大类问题值得关注
  • 美情报机构攻击中国大型商用密码产品提供商,调查报告公布
  • 四川苍溪县教育局通报“工作人员辱骂举报学生”:停职检查
  • 热点问答|第三轮间接谈判结束,美伊分歧还有多大?
  • 李在明当选韩国共同民主党总统候选人
  • 伊朗港口爆炸已造成25人死亡,灭火行动已近尾声