av_read_frame的作用是读取一帧视频数据或者读取多帧音频数据,读取的数据都是待解码的数据,该函数的流程如下所示:

函数的源码如下所示:

int av_read_frame(AVFormatContext *s, AVPacket *pkt)
{const int genpts = s->flags & AVFMT_FLAG_GENPTS;int eof = 0;int ret;AVStream *st;//不自动生成时间戳,走此flow,好像一般不走这里if (!genpts) {// ffmpeg内部读取的时候其实是将解析出来的一帧帧数据放入一个队列中,所以此处先检查解析包队列中是否有数据,// 如果有,直接读取,否则调用真正的读取函数。// 此处为何要使用缓存队列而不是直接读取,因为在解析的时候有可能一次解析N个帧,// 如mpegts 一个PES中可能包含2帧,所以解析出来的帧直接放入队列中。ret = s->internal->packet_buffer? ff_packet_list_get(&s->internal->packet_buffer,&s->internal->packet_buffer_end, pkt): read_frame_internal(s, pkt);if (ret < 0)return ret;goto return_packet;}for (;;) {AVPacketList *pktl = s->internal->packet_buffer;if (pktl) {AVPacket *next_pkt = &pktl->pkt;if (next_pkt->dts != AV_NOPTS_VALUE) {int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;// last dts seen for this stream. if any of packets following// current one had no dts, we will set this to AV_NOPTS_VALUE.int64_t last_dts = next_pkt->dts;av_assert2(wrap_bits <= 64);while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {if (pktl->pkt.stream_index == next_pkt->stream_index &&av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2ULL << (wrap_bits - 1)) < 0) {if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2ULL << (wrap_bits - 1))) {// not B-framenext_pkt->pts = pktl->pkt.dts;}if (last_dts != AV_NOPTS_VALUE) {// Once last dts was set to AV_NOPTS_VALUE, we don't change it.last_dts = pktl->pkt.dts;}}pktl = pktl->next;}if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {// Fixing the last reference frame had none pts issue (For MXF etc).// We only do this when// 1. eof.// 2. we are not able to resolve a pts value for current packet.// 3. the packets for this stream at the end of the files had valid dts.next_pkt->pts = last_dts + next_pkt->duration;}pktl = s->internal->packet_buffer;}/* read packet from packet buffer, if there is data */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 = ff_packet_list_get(&s->internal->packet_buffer,&s->internal->packet_buffer_end, pkt);goto return_packet;}}ret = read_frame_internal(s, pkt);if (ret < 0) {if (pktl && ret != AVERROR(EAGAIN)) {eof = 1;continue;} elsereturn ret;}ret = ff_packet_list_put(&s->internal->packet_buffer,&s->internal->packet_buffer_end,pkt, 0);if (ret < 0) {av_packet_unref(pkt);return ret;}}return_packet:st = s->streams[pkt->stream_index];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, 0, 0, AVINDEX_KEYFRAME);}if (is_relative(pkt->dts))pkt->dts -= RELATIVE_TS_BASE;if (is_relative(pkt->pts))pkt->pts -= RELATIVE_TS_BASE;return ret;
}

该函数中主要调用了两个函数,如果paketList中有数据,则调用ff_packet_list_get直接从list中读取一帧数据,如果没有则调用read_frame_internal重新读取一帧数据放到list中。
ff_packet_list_get函数比较简单,直接把buf的指针置为pktl->next,其源码如下所示:

int ff_packet_list_get(AVPacketList **pkt_buffer,AVPacketList **pkt_buffer_end,AVPacket      *pkt)
{AVPacketList *pktl;av_assert0(*pkt_buffer);pktl        = *pkt_buffer;*pkt        = pktl->pkt;*pkt_buffer = pktl->next;if (!pktl->next)*pkt_buffer_end = NULL;av_freep(&pktl);return 0;
}

read_frame_internal 在ffmpeg中实现了将format格式的packet,最终转换成一帧帧的es流packet,并解析填充了packet的pts,dts等信息,为最终解码提供了重要的数据,read_frame_internal,调用ff_read_packet,该函数最终调用s->iformat->read_packet指针函数,也就是说不同的farmat的read_packet函数也不相同,具体实现可以到libavformat目录下对应的源文件查看。

这次分析暂时到这里,分析ffmpeg源码感觉像无限套娃,看来要好好提高代码阅读能力啊。

参考博客

https://blog.csdn.net/fallenink/article/details/8307104
https://blog.csdn.net/leixiaohua1020/article/details/12678577
https://blog.csdn.net/qq_39683826/article/details/115767168
https://blog.csdn.net/yihuanyihuan/article/details/88528439

ffmpeg av_read_frame函数解析相关推荐

  1. FFmpeg中调用av_read_frame函数导致的内存泄漏问题

    使用FFmpeg的av_read_frame函数后,每读完一个packet,必须调用av_packet_unref函数进行内存释放,否则会导致内存释泄漏. 在vs(博主所用的ffmpeg版本是3.4. ...

  2. ffmpeg之-AVFrame解析(五)

    1.前言 AVFrame 位于libavutil/frame.h中,AVpacket一样,是FFmpeg中很重要的结构体.它用于表示未压缩的音视频数据(编码前或者解码后),使用了引用计数机制来管理内存 ...

  3. oracle rpad mysql_Oracle生成不重复票号与LPAD,RPAD与NEXTVAL函数解析

    SELECT TO_CHAR(SYSDATE,'YYMMDD')||LPAD(REFUNDSEQ.NEXTVAL,6,'0') AS RES_ORDER_NO FROM DUAL 该语句拼接 时间 与 ...

  4. json数据解析_VBA 实践指南 -- Split函数解析Json数据

    什么是JSON? JSON(JavaScript Object Notation) 是一种及其轻量级的数据交换格式,它是 ECMAScript (欧洲计算机协会制定的JavaScript规范)的一个子 ...

  5. C/C++ sizeof函数解析——解决sizeof求结构体大小的问题

    C/C++ sizeof函数解析--解决sizeof求结构体大小的问题 参考文章: (1)C/C++ sizeof函数解析--解决sizeof求结构体大小的问题 (2)https://www.cnbl ...

  6. ffmpeg avcodec_encode_video2 函数报错

    ffmpeg avcodec_encode_video2 函数报错 参考:https://blog.csdn.net/shuihappy1/article/details/71721374 总结此次出 ...

  7. 【Socket网络编程】12. send()、recv()、sendto() 和 recvfrom() 函数解析

    send().recv().sendto()和recvfrom()函数解析 一般情况下,send().recv()在TCP协议下使用,sendto().recvfrom()在UDP协议下使用,也可以在 ...

  8. main() 函数解析(一)——Linux-0.11 剖析笔记(六)

    文章目录 1. 宏定义`_syscall0` 2. `setup.s`读取的参数 3. 读取CMOS实时时钟信息 3.1 `outb_p(value,port)` 3.2 `inb_p(port)` ...

  9. main 函数解析(二)—— Linux-0.11 学习笔记(六)

    main函数解析(二)--Linux-0.11 学习笔记(六) 4.6 blk_dev_init函数 void blk_dev_init(void) {int i;for (i=0 ; i<NR ...

最新文章

  1. Redis实现分布式锁全局锁—Redis客户端Redisson中分布式锁RLock实现
  2. 笔记本电脑按开机键没反应怎么办?(先记得长按开机键,大约10秒钟看看可以吗)
  3. MapReduce01
  4. mysql索引_mysql系列:深入理解mysql 索引特性(屡试不爽的mysql索引总结)
  5. 乐鑫代理启明云端分享:用ESP32单片机控制LED教程示例
  6. Java 第二章 程序设计基础
  7. 将分享按钮加入到页面中
  8. c 字符串数组_在C++中将字符串转换为char数组
  9. vue父组件、子组件,父子组件交互
  10. Oracle 获取每月最后一天的函数
  11. SDL 1.2.14在windows平台下的编译及例子
  12. 80-30-010-原理-React模式-简介
  13. mac os x 安装mysql遇到 Access denied for user 'root'@'localhost' (using password: YES)的解决方法...
  14. java js 加密解密算法_JS自己实现字符串加密和解密算法
  15. HDMI 接口电路信号完整性
  16. 基于蒙特卡洛的大规模电动汽车充电行为分析(Matlab代码实现)
  17. android6.0连接WIFI后显示“已连接,但无法访问互联网”实际可以上网
  18. 李小铭计算机专业应聘书作文,应聘申请书英语作文
  19. 论文阅读_Show, Attend and Tell: Netural Image Caption Generation with Visual Attention
  20. 云服务器部署ssl证书

热门文章

  1. python中pygame背景颜色为啥没生效_如何更改pygame中的背景图像?
  2. 4.ADS操作入门_Circuit Envelope Simulation with Modulated Sources
  3. [golang gin框架] 27.Gin 商城项目-购物车
  4. 如何将微服务应用设计为四层结构:平台层/服务层/边界层/客户端层
  5. C++ string类和常用接口的实现
  6. 在面试中如何回答面试官的问题
  7. 【ultraiso制作ubuntu启动盘(包括U盘和光盘)】
  8. 高精度电流源如何设计出来
  9. UVA - 1647 Computer Transformation(计算机变换)(找规律)
  10. stm32 led屏控制卡_如何实现LED双面透明显示屏,双面LED透明屏