FFmpeg源码:avio_tell函数分析

server/2024/9/20 4:01:40/ 标签: ffmpeg

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

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

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

FFmpeg源码:avio_tell函数分析

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

一、avio_tell函数的定义

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

/*** ftell() equivalent for AVIOContext.* @return position or AVERROR.*/
static av_always_inline int64_t avio_tell(AVIOContext *s)
{return avio_seek(s, 0, SEEK_CUR);
}

该函数作用是:得到文件位置指针当前位置(s->buf_ptr)相对于文件首(s->buffer)的偏移字节数。

形参s:输入型参数。指向一个AVIOContext(字节流上下文结构体)变量。关于AVIOContext结构体可以参考:《FFmpeg源码:avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析》。

返回值:返回一个非负数表示文件位置指针当前位置相对于文件首的偏移字节数,单位为byte。返回一个负数表示失败。

二、avio_tell函数的内部实现原理

avio_tell函数内部调用了语句:avio_seek(s, 0, SEEK_CUR)。SEEK_CUR是宏,定义在/usr/include/stdio.h中,可以看到宏定义SEEK_CUR相当于1:

/* The possibilities for the third argument to `fseek'.These values should not be changed.  */
#define SEEK_SET	0	/* Seek from beginning of file.  */
#define SEEK_CUR	1	/* Seek from current position.  */
#define SEEK_END	2	/* Seek from end of file.  */
#ifdef __USE_GNU
# define SEEK_DATA	3	/* Seek to next data.  */
# define SEEK_HOLE	4	/* Seek to next hole.  */
#endif

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

int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
{FFIOContext *const ctx = ffiocontext(s);int64_t offset1;int64_t pos;int force = whence & AVSEEK_FORCE;int buffer_size;int short_seek;whence &= ~AVSEEK_FORCE;if(!s)return AVERROR(EINVAL);if ((whence & AVSEEK_SIZE))return s->seek ? s->seek(s->opaque, offset, AVSEEK_SIZE) : AVERROR(ENOSYS);buffer_size = s->buf_end - s->buffer;// pos is the absolute position that the beginning of s->buffer corresponds to in the filepos = s->pos - (s->write_flag ? 0 : buffer_size);if (whence != SEEK_CUR && whence != SEEK_SET)return AVERROR(EINVAL);if (whence == SEEK_CUR) {offset1 = pos + (s->buf_ptr - s->buffer);if (offset == 0)return offset1;if (offset > INT64_MAX - offset1)return AVERROR(EINVAL);offset += offset1;}if (offset < 0)return AVERROR(EINVAL);short_seek = ctx->short_seek_threshold;if (ctx->short_seek_get) {int tmp = ctx->short_seek_get(s->opaque);short_seek = FFMAX(tmp, short_seek);}offset1 = offset - pos; // "offset1" is the relative offset from the beginning of s->buffers->buf_ptr_max = FFMAX(s->buf_ptr_max, s->buf_ptr);if ((!s->direct || !s->seek) &&offset1 >= 0 && offset1 <= (s->write_flag ? s->buf_ptr_max - s->buffer : buffer_size)) {/* can do the seek inside the buffer */s->buf_ptr = s->buffer + offset1;} else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) ||offset1 <= buffer_size + short_seek) &&!s->write_flag && offset1 >= 0 &&(!s->direct || !s->seek) &&(whence != SEEK_END || force)) {while(s->pos < offset && !s->eof_reached)fill_buffer(s);if (s->eof_reached)return AVERROR_EOF;s->buf_ptr = s->buf_end - (s->pos - offset);} else if(!s->write_flag && offset1 < 0 && -offset1 < buffer_size>>1 && s->seek && offset > 0) {int64_t res;pos -= FFMIN(buffer_size>>1, pos);if ((res = s->seek(s->opaque, pos, SEEK_SET)) < 0)return res;s->buf_end =s->buf_ptr = s->buffer;s->pos = pos;s->eof_reached = 0;fill_buffer(s);return avio_seek(s, offset, SEEK_SET | force);} else {int64_t res;if (s->write_flag) {flush_buffer(s);}if (!s->seek)return AVERROR(EPIPE);if ((res = s->seek(s->opaque, offset, SEEK_SET)) < 0)return res;ctx->seek_count++;if (!s->write_flag)s->buf_end = s->buffer;s->buf_ptr = s->buf_ptr_max = s->buffer;s->pos = offset;}s->eof_reached = 0;return offset;
}

语句avio_seek(s, 0, SEEK_CUR) 等价于 avio_seek(s, 0, 1)。这时,avio_seek函数可以化简为:

int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
{int64_t offset1;if(!s)return AVERROR(EINVAL);buffer_size = s->buf_end - s->buffer;pos = s->pos - (s->write_flag ? 0 : buffer_size);if (whence == SEEK_CUR) {offset1 = pos + (s->buf_ptr - s->buffer);if (offset == 0)return offset1;}
}

pos的值为0的情况下,avio_seek(s, 0, 1)就是:

​
int64_t avio_seek(AVIOContext *s, 0, 1)
{int64_t offset1;if(!s)return AVERROR(EINVAL);offset1 = s->buf_ptr - s->buffer;return offset1;
}​

所以avio_tell函数,也就是avio_seek(s, 0, 1)相当于执行了:s->buf_ptr - s->buffer。从而能得到文件位置指针当前位置(s->buf_ptr)相对于文件首(s->buffer)的偏移字节数。


http://www.ppmy.cn/server/102074.html

相关文章

【数据结构详解】——归并排序(动图详解)

目录 &#x1f552; 1. 归并排序&#x1f558; 1.1 递归实现&#x1f558; 1.2 非递归实现 &#x1f552; 1. 归并排序 &#x1f4a1; 算法思想&#xff1a;归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用。将已有序的子…

UE5.4 用自带OpenCV4.55读取png、MP4、摄像头并在ui中显示的方法

创建c项目&#xff0c;项目build.cs中开启模块&#xff1a; // Copyright Epic Games, Inc. All Rights Reserved.using UnrealBuildTool;public class OpencvT : ModuleRules {public OpencvT(ReadOnlyTargetRules Target) : base(Target){PCHUsage PCHUsageMode.UseExplici…

【学习总结】JVM篇

JVM JVM基础知识 主力机型 HotSpot VM HotSpot虚拟机时OpenJDK和OracleJDK中默认的Java虚拟机。它最初并非由Sun公司所开发&#xff0c;而是由一家名为“Longview Technologies”的小公司设计。Sun公司注意到这款虚拟机在即时编译等多个方面有着优秀的理念和实际成果&#…

golang gin框架中创建自定义中间件的2种方式总结 - func(*gin.Context)方式和闭包函数方式定义gin中间件

在gin框架中&#xff0c;我们可以通过2种方式创建自定义中间件&#xff1a; 1. 直接定义一个类型为 func(*gin.Context)的函数或者方法 这种方式是我们常用的方式&#xff0c;也就是定义一个参数为*gin.Context的函数或者方法。定义的方法就是创建一个 参数类型为 gin.Handler…

xiaomi pad 6PRO 小米平板6 pro hyperOS降级 澎湃os 降级MIUI 14 教程 免解锁BL 降级,168小时解锁绑定

小米平板 6 Pro 机型代号 &#xff1a;liuqin 降级MIUI 14 小米澎湃 OS 正式版 澎湃OS安卓发布日期卡刷包线刷包OS1.0.7.0.UMYCNXM14.02024-07-13miui_LIUQIN_OS1.0.7.0.UMYCNXM_d618a5c980_14.0.zipliuqin_images_OS1.0.7.0.UMYCNXM_20240705.0000.00_14.0_cn_8cbf5920be.…

【学习笔记】Day 16-17

一、进度概述 1、ddnet_main 相关代码学习&#xff08;预计 3-4 天&#xff09; 二、详情 1、顶层结构 关于代码顶层结构的一些思考和总结&#xff0c;其中下图为师兄代码的文件结构 总结&#xff1a; 对于一个优秀的代码&#xff0c;其文件结构一定也是清晰的&#…

HarmonyOS Developer之五星好评

rating rating为评分条组件&#xff0c;用来实现用户使用感受的衡量标准条(如&#xff1a;五星好评) 在pages/index目录下的hml文件中创建一个rating组件: HTML <!-- xxx.hml --> <div class"container"><rating></rating> </div>…

类和对象(下)(1)

类和对象&#xff08;下&#xff09; 再探构造函数 我们之前在实现构造函数的时候&#xff0c;初始化成员变量使用的方式都是在函数体内进行赋值&#xff0c;其实构造函数初始化成员变量还有一种方式&#xff1a;初始化列表。 初始化列表不只是为了写得方便&#xff0c;还能解…

【Kubernetes】k8s集群图形化管理工具之rancher

目录 一.Rancher概述 1.Rancher简介 2.Rancher与k8s的关系及区别 3.Rancher具有的优势 二.Rancher的安装部署 1.实验准备 2.安装 rancher 3.rancher的浏览器使用 一.Rancher概述 1.Rancher简介 Rancher 是一个开源的企业级多集群 Kubernetes 管理平台&#xff0c;实…

Nginx与Tomcat的区别

Nginx与Tomcat的区别 —— 经验笔记 引言 在现代Web开发中&#xff0c;选择合适的服务器软件对于构建高性能、可靠的应用程序至关重要。Nginx 和 Tomcat 是两种常见的服务器软件&#xff0c;尽管它们都可以被归类为Web服务器&#xff0c;但它们的设计目标和应用场景有着本质的…

WordPress网站速度优化

提升网站速度对用户体验和搜索引擎排名至关重要。无论你是新手博主&#xff0c;还是经验丰富的网站开发人员&#xff0c;要想优化WordPress网站&#xff0c;需要长时间的努力和坚持。以下是按入门、中级和专家级别介绍的12个实用方法&#xff0c;帮助你提升WordPress网站的整体…

zigbee笔记:十、ZStack(2.3.0-1.4.0)的OSAL使用分析

zigbee笔记&#xff1a;九中&#xff0c;我们已经学会了利用模板&#xff0c;定制自己的个性开发工程&#xff0c;本文为协议栈&#xff08;ZStack-CC2530-2.3.0-1.4.0&#xff09;代码使用分析笔记&#xff0c;来进一步掌握协议栈的使用。 一、协议栈使用知识点 1、协调器、路…

fetch跨域请求数据的前端设置和后端php的header设置

跨源请求&#xff0c;也称为CORS&#xff08;Cross-Origin Resource Sharing&#xff09;请求&#xff0c;是Web开发中常见的一种需求&#xff0c;允许一个网页的JavaScript代码向与该网页不同源的服务器发出HTTP请求。以下是使用JavaScript中的fetch函数进行跨源请求的一个基本…

【51单片机】让AI识别电路图,帮你进行编码(以51单片机为例)

让AI识别电路图,帮你进行编码&#xff08;以51单片机为例&#xff09; ​ 这里使用的AI大模型使用的是 Copilot。&#xff08;两个前提&#xff1a;1. 科学上网、2. 有微软账号&#xff09; 今天测试了一下Copilot识别图片的能力&#xff0c;能力还是可圈可点的。 首先准备一…

C语言日常练习 Day17

目录 一、找出一个二维数组的鞍点 二、有一篇文章&#xff0c;共有3行文字&#xff0c;每行有80个字符。要求分别统计出其中的英文大写字母、小写字母、数字、空格以及其他字符的个数 三、有一行电文&#xff0c;已按下面规律编译成密码&#xff1a;A->Z,a->z,B->Y,…

wordpress视频模板

视频背景wordpress官网主题 红色风格的wordpress主题&#xff0c;首页视频背景&#xff0c;鼠标滚动翻转展示内容&#xff0c;适合公司官网使用。 https://www.jianzhanpress.com/?p7288 MCN传媒wordpress主题 红色风格wordpress大视频背景主题&#xff0c;适合做直播业务的…

【Harmony OS 4.0】水果排行榜案例

ets/example2/Models export class FruitsData {id: stringname: stringvote: stringconstructor(id: string, name: string, vote: string) {this.id idthis.name namethis.vote vote} }ets/example2/TitleComponent // app标题子组件 import APPContext from ohos.app.a…

【ARM 芯片 安全与攻击 5.4 -- Meltdown 攻击与防御介绍】

文章目录 什么是 Meltdown 攻击?Meltdown 攻击的基本原理Meltdown 攻击代码示例Meltdown 攻击在芯片中的应用应用场景Meltdown 攻击与瞬态攻击、测信道攻击的关系针对 Meltdown 攻击的防御硬件级防御Summary什么是 Meltdown 攻击? Meltdown 攻击是一种利用处理器乱序执行(o…

【网络编程】组播的实现(C语言,linux,Ubuntu)

组播 1> 组播也是实现一对多的通信方式&#xff0c;对于广播而言&#xff0c;网络需要对每个消息进行复制转发&#xff0c;会占用大量的带宽&#xff0c;导致网络拥塞 2> 组播可以实现小范围的数据传播&#xff1a;将需要接收数据的接收端加入多播组&#xff0c;发送端…

Linux---05---用户组权限

课程回顾 vim编辑器 本章重点 文件权限 用户管理 用户组管理 一、文件权限 由于Linux是一个多人多任务的系统&#xff0c;因此经常会出现同一台机器同时有多个人进行操作&#xff0c;为了考虑每个人的隐私权以及每个人喜好的工作环境&#xff0c;所以文件的权限归属就至关…