FFmpeg源码:avio_read_partial函数分析

ops/2024/11/19 16:38:45/

=================================================================

AVIOContext结构体和其相关的函数分析:

FFmpeg源码:avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析

FFmpeg源码:read_packet_wrapper、fill_buffer函数分析

FFmpeg源码:avio_read函数分析

FFmpeg源码:avio_seek函数分析

FFmpeg源码:avio_skip函数分析

FFmpeg源码:avio_tell函数分析

FFmpeg源码:ffurl_seek2、ffurl_seek、avio_size函数分析

FFmpeg源码:avio_feof函数分析

FFmpeg源码:avio_read_partial函数分析

FFmpeg源码:ffio_read_indirect函数分析

=================================================================

一、avio_read_partial函数的声明

avio_read_partial函数声明在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavformat/avio.h中:

/*** Read size bytes from AVIOContext into buf. Unlike avio_read(), this is allowed* to read fewer bytes than requested. The missing bytes can be read in the next* call. This always tries to read at least 1 byte.* Useful to reduce latency in certain cases.* @return number of bytes read or AVERROR*/
int avio_read_partial(AVIOContext *s, unsigned char *buf, int size);

该函数的作用是:

情况一:如果该媒体文件被打开是为了进行写入,对本地媒体文件或网络流进行读取,读取size个字节,将读上来的数据保存到形参buf指向的缓冲区中。

情况二:如果该媒体文件被打开不是为了进行写入,首先判断AVIOContext输入缓冲区中的数据被读取的状态,根据结果又会分为下面两种情况:

1.如果输入缓冲区中没有数据或者数据已被读完,通过文件描述符去读取本地媒体文件中的数据,或者通过socket接收网络流中的数据,让读上来的数据填满整个AVIOContext输入缓冲区。再读取输入缓冲区的数据,尝试读取size个字节,如果输入缓冲区读完了还没到size个字节,不继续进行读取。

2.如果输入缓冲区中存在数据且数据还未被读完,读取输入缓冲区的数据,尝试读取size个字节。如果输入缓冲区读完了还没到size个字节,不继续进行读取。

该函数的用法跟avio_read函数比较相似,不同点在于:avio_read函数保证读取size个字节数据(除非出错)。而使用avio_read_partial函数,即使输入缓冲区读取完了还没到size个字节,也不会继续对本地媒体文件或网络流进行读取,而是直接返回。由于从输入缓冲区(内存)读取的速度是远高于从本地媒体文件(硬盘)或网络流(socket)读取的,所以跟avio_read函数相比,使用avio_read_partial函数在某些情况下可用于减少延迟。

形参s:既是输入型参数也是输出型参数。指向一个AVIOContext(字节流上下文结构体)变量。执行avio_read_partial函数后,s->buf_ptr等成员会发生相应变化。

形参buf:输出型参数。保存读上来的数据的缓冲区。

形参size:输入型参数。要读取的字节数。

返回值:返回一个非负数表示成功,此时返回实际读取到的字节数;返回一个负数表示出错。

二、avio_read_partial函数的定义

avio_read_partial函数定义在源文件libavformat/aviobuf.c中:

int avio_read_partial(AVIOContext *s, unsigned char *buf, int size)
{int len;if (size < 0)return AVERROR(EINVAL);if (s->read_packet && s->write_flag) {len = read_packet_wrapper(s, buf, size);if (len > 0)s->pos += len;return len;}len = s->buf_end - s->buf_ptr;if (len == 0) {fill_buffer(s);len = s->buf_end - s->buf_ptr;}if (len > size)len = size;memcpy(buf, s->buf_ptr, len);s->buf_ptr += len;if (!len) {if (s->error)      return s->error;if (avio_feof(s))  return AVERROR_EOF;}return len;
}

三、avio_read_partial函数的内部实现分析

avio_read_partial函数中,首先判断要读取的字节数是否小于0,如果小于0,返回AVERROR(EINVAL)表示出错:

    if (size < 0)return AVERROR(EINVAL);

如果指向读取数据包的回调函数存在(s->read_packet为真),并且该媒体文件被打开是为了写入的(s->write_flag为真),通过read_packet_wrapper函数对本地媒体文件或网络流进行读取,读取size个字节,将读上来的数据保存到形参buf指向的缓冲区中,返回实际读取到的字节数:

    if (s->read_packet && s->write_flag) {len = read_packet_wrapper(s, buf, size);if (len > 0)s->pos += len;return len;}

 如果不满足上面情况,判断AVIOContext输入缓冲区中还有多少数据未被读取。如果输入缓冲区中没有数据或者数据已被读完,调用fill_buffer函数,通过文件描述符去读取本地媒体文件中的数据,或者通过socket接收网络流中的数据,让读上来的数据填满整个AVIOContext输入缓冲区。重新得到AVIOContext输入缓冲区中未被读取的数据的字节数,赋值给变量len:

    len = s->buf_end - s->buf_ptr;if (len == 0) {fill_buffer(s);len = s->buf_end - s->buf_ptr;}

读取输入缓冲区的数据,尝试读取size个字节。如果输入缓冲区读取完了还没到size个字节,不继续进行读取:

    if (len > size)len = size;memcpy(buf, s->buf_ptr, len);s->buf_ptr += len;

成功读取,返回实际读取到的字节数;否则返回负数表示出错:

    if (!len) {if (s->error)      return s->error;if (avio_feof(s))  return AVERROR_EOF;}return len;


http://www.ppmy.cn/ops/135020.html

相关文章

ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。ojdbc8版本23.2.0.0驱动BUG【已解决】

问题描述 JDK8使用ojdbc8驱动操作oracle11g数据库&#xff0c;使用JDBC复用 PreparedStatement 对象执行Insert操作时&#xff0c;报错java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。&#xff0c;经测试发现&#xff0c;是预编译对象某个占位符号被赋…

大型语言模型综述 A Survey of Large Language Models

文章源自 2303.18223 (arxiv.org) 如有侵权&#xff0c;请通知下线 这是一篇关于大语言模型&#xff08;LLMs&#xff09;的综述论文&#xff0c;主要介绍了 LLMs 的发展历程、技术架构、训练方法、应用领域以及面临的挑战等方面&#xff0c;具体内容如下&#xff1a; 摘要…

Android OpenGL ES详解——几何着色器

目录 一、概念 1、图元 2、几何着色器 1、输入类型 2、输出类型 3、输出顶点数量最大值限制 二、使用几何着色器 三、应用举例——造几个房子 四、应用举例——爆破物体 1、获取法向量 2、显示法线 五、应用举例——细分三角形 六、应用举例——广告牌技术 一、概…

8. 基于 Redis 实现限流

在高并发的分布式系统中&#xff0c;限流是保证服务稳定性的重要手段之一。通过限流机制&#xff0c;可以控制系统处理请求的频率&#xff0c;避免因瞬时流量过大导致系统崩溃。Redis 是一种高效的缓存数据库&#xff0c;具备丰富的数据结构和原子操作&#xff0c;适合用来实现…

最长连续序列

题目描述 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [100,4,200,1,3,2] 输出&#…

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…

前端pdf预览方案

前端pdf预览方案 pdf预览一般不需要前端生成pdf文件&#xff0c;pdf文件一般是通过接口&#xff0c;获取pdf文件【responseType:‘blob’,】或二进制文件流【responseType: ‘arraybuffer’,】或者已有的pdf文件。 前端PDF预览通常是通过读取现有的PDF文件&#xff0c;并使用…

基于Canny边缘检测和轮廓检测

这段代码实现了基于Canny边缘检测和轮廓检测&#xff0c;从图像中筛选出面积较大的矩形&#xff0c;并使用OpenCV和Matplotlib显示结果。主要流程如下&#xff1a; 步骤详解&#xff1a; 读取图像&#xff1a; img cv2.imread(U:/1.png)使用cv2.imread()加载图像。 转换为灰…