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

FFmpeg 基本API av_read_frame函数内部调用流程分析

1、av_read_frame函数定义

av_read_frame 是 FFmpeg 库中的一个函数,用于从 AVFormatContext 中读取一个 AVPacket。它负责从解复用器(demuxer)获取原始编码数据包(AVPacket)。

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

参数说明:

  • s: 一个指向 AVFormatContext 结构体的指针,用于存储 AVFormatContext 对象。
  • pkt: 一个指向 AVPacket 结构体的指针,用于存储读取到的 AVPacket。
    返回值:
  • 如果读取成功,则返回 0;如果读取失败,则返回一个负值。在调用 av_read_frame 函数之后,可以通过 AVPacket 结构体中的成员来获取读取到的音视频数据,例如 data、size 和 pts 等。

注意:在使用 FFmpeg 进行音视频处理时,通常需要先调用 avformat_open_input 函数打开输入 URL,然后调用 avformat_find_stream_info 函数获取流信息,最后调用 av_read_frame 函数读取音视频数据。

大概流程如下所示:
在这里插入图片描述

2、av_read_frame内部调用逻辑

2.1 函数入口与初始化

FFFormatContext *const si = ffformatcontext(s);
const int genpts = s->flags & AVFMT_FLAG_GENPTS; // 是否生成PTS标志
int eof = 0;
int ret;
/*
关键变量:genpts:控制是否自动生成缺失的PTS(演示时间戳)si->packet_buffer:内部数据包缓存队列
*/

2.2 非GENPTS模式(简单读取)

if (!genpts) {ret = si->packet_buffer.head ? avpriv_packet_list_get(&si->packet_buffer, pkt) // 从缓存取包: read_frame_internal(s, pkt); // 直接读取新包if (ret < 0) return ret;goto return_packet; // 跳转到后处理
}
/*
逻辑流程:优先从缓存队列取包(packet_buffer)缓存为空则调用底层read_frame_internal()直接进入后处理阶段 */

2.3 GENPTS模式(复杂时间戳处理)

for (;;) {PacketListEntry *pktl = si->packet_buffer.head;if (pktl) {AVPacket *next_pkt = &pktl->pkt;// 时间戳修复逻辑...}...
}
1. 时间戳修复核心算法
if (next_pkt->dts != AV_NOPTS_VALUE) {int wrap_bits = s->streams[...]->pts_wrap_bits;while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {if (pktl->pkt.stream_index == ... && av_compare_mod(...) < 0) {if (av_compare_mod(...)) { // 非B帧next_pkt->pts = pktl->pkt.dts; // 用后续包DTS修复当前PTS}}pktl = pktl->next;}// EOF特殊处理if (eof && next_pkt->pts == AV_NOPTS_VALUE) {next_pkt->pts = last_dts + next_pkt->duration; // 用时长推算PTS}
}
/*
修复策略:
前向探测:遍历后续包寻找参考DTS
非B帧优先:优先使用I/P帧的DTS
EOF启发式:文件末尾用最后DTS+时长推算
*/2. 出队条件判断
st = s->streams[next_pkt->stream_index];
if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL &&next_pkt->dts != AV_NOPTS_VALUE && !eof)) 
{ret = avpriv_packet_list_get(...); // 满足条件出队goto return_packet;
}
/*
出队条件(满足任一):
PTS有效
流设置为丢弃所有包
DTS无效
未到文件末尾
*/3. 读取新包流程
ret = read_frame_internal(s, pkt); // 底层读包
if (ret < 0) {if (pktl && ret != AVERROR(EAGAIN)) {eof = 1;  // 标记EOF但继续处理缓存continue;}return ret; // 真实错误退出
}
// 新包加入缓存
ret = avpriv_packet_list_put(&si->packet_buffer, pkt, NULL, 0);
/*
EOF处理:标记eof但继续处理缓存包
缓存管理:新包加入队列尾部
*/

2.4 后处理阶段 (return_packet)

// 关键帧索引处理
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) 
{ff_reduce_index(s, st->index); // 索引优化av_add_index_entry(st, pkt->pos, pkt->dts, ...); // 添加索引
}// 相对时间戳转换
if (is_relative(pkt->dts)) pkt->dts -= RELATIVE_TS_BASE;
if (is_relative(pkt->pts)) pkt->pts -= RELATIVE_TS_BASE;
/*
关键操作:
索引构建:为关键帧创建 seek 索引
时间戳转换:将相对时间戳转为绝对时间戳
*/

3、av_read_frame函数调用流程图

在这里插入图片描述

http://www.dtcms.com/a/502916.html

相关文章:

  • 广东网站建设包括什么口碑好网站建设是哪家
  • 和田地区建设局网站电子商务网络营销是干嘛的
  • SAP B1实施专家指南:如何优化成本与缩短项目周期?
  • [吾爱大神原创工具] Python多功能自动化点击录入工具V1.0
  • 不备案怎么做淘宝客网站wordpress 字体调整
  • 栈及相关算法问题
  • Docker镜像分层与写时复制原理详解
  • 药物靶点研究3天入门|Day1:从疾病差异里挖“潜力靶点”,两步锁定真目标
  • WebForms ArrayList详解
  • 达梦数据库性能调优总结
  • [JavaEE初阶]HTTPS-SSL传输过程中的加密
  • 单片机开发中裸机系统有哪些(轮询、时间片、前后台.....)
  • 一次线上MySQL分页事故,搞了半夜...
  • 医院网站建设思路深圳展览设计公司
  • C#WPF关键类
  • 从文件加密到数据料理台:两款主流加密工具(EncFSMP/CyberChef)技术特性解析与开发实战选型
  • 什么是uv和传统的区别
  • FastAPI之 处理HTTP请求
  • 【2025-系统规划与管理师】第十章:云原生系统规划
  • 求一个矩阵中的鞍点
  • 《计算机视觉度量:从特征描述到深度学习》-- 大模型应用开发基础RAG方案介绍
  • 【C++】list的使用及底层逻辑实现
  • 网站开发的整体职业规划购物网站多少钱
  • 【JVM】线上JVM堆内存报警,占用超90%
  • 【JVM系列】-第1章-JVM与Java体系结构
  • 鸿蒙NEXT Wear Engine穿戴侧应用开发完全指南
  • OpenHarmony 与 HarmonyOS 的 NAPI 开发实战对比:自上而下与自下而上的差异解析
  • openHarmony之DSoftBus分布式软总线智能链路切换算法
  • TensorFlow2 Python深度学习 - 循环神经网络(GRU)示例
  • TVM | Relay