当前位置: 首页 > 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

http://www.xdnf.cn/news/173971.html

相关文章:

  • 手写SpringMVC(基本框架)
  • 视觉“解锁”触觉操控:Franka机器人如何玩转刚柔物体?
  • matlab simulink中理想变压激磁电流容易有直流偏置的原因分析。
  • C++ AVL树的实现
  • 日语学习-日语知识点小记-进阶-JLPT-N2阶段(9):语法单词
  • 目标跟踪最新文章阅读列表
  • 极简主义在 UI 设计中的应用与实践:打造简洁高效界面
  • 基于定制开发开源AI智能名片S2B2C商城小程序的会员存量池构建策略研究
  • MCP:人工智能时代的HTTP?探索AI通信新标准
  • cached-property - 类属性缓存装饰器
  • 如何让自己的博客可以在百度、谷歌、360上搜索到(让自己写的CSDN博客可以有更多的人看到)
  • Win11 配置 Git 绑定 Github 账号的方法与问题汇总
  • 有效的字母异位词
  • 10 DPSK原始对话记录
  • ultralytics-YOLO模型在windows环境部署
  • Redis 笔记(三)-Redis 基本知识及五大数据类型
  • day004
  • PostgreSQL WAL 幂等性详解
  • PH热榜 | 2025-04-26
  • 论文速报《ChatBEV:理解BEV地图的视觉语言模型新突破》
  • uniapp自定义一个选择年月日时分的组件。
  • Linux CentOS 安装Python 3.8.0
  • 8、HTTPD服务--CGI机制
  • BR_单时隙/多时隙灵敏度(Sensitivity-single/multi slot packets)
  • Apache Tomcat 漏洞(CVE-2025-24813)导致服务器面临 RCE 风险
  • 域名系统DNS
  • 03.04、化栈为队
  • PAT第七题素数对猜想
  • 手机充电进入“秒充“时代:泡面刚下锅,电量已满格
  • 贪心算法和动态规划