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

2024-08-27 08:12

本文主要是介绍FFmpeg源码:ffurl_seek2、ffurl_seek、avio_size函数分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、ffurl_seek2函数

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

int64_t ffurl_seek2(void *urlcontext, int64_t pos, int whence)
{URLContext *h = urlcontext;int64_t ret;if (!h->prot->url_seek)return AVERROR(ENOSYS);ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);return ret;
}

该函数的作用是:改变形参urlcontext访问的资源的下一个读/写操作将使用的位置。

ffurl_seek2函数内部,h->prot->url_seek是函数指针:

typedef struct URLProtocol {
//...int64_t (*url_seek)( URLContext *h, int64_t pos, int whence);
//...
}

h->prot->url_seek不为空时,会调用h->prot->url_seek指向的回调函数:

ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);

而函数指针h->prot->url_seek一般指向libavformat/file.c中的file_seek函数。这时,执行ffurl_seek2函数等价于执行file_seek函数。关于file_seek函数用法可以参考:《FFmpeg源码:file_read、file_write、file_seek函数分析》。

所以当h->prot->url_seek指向file_seek函数时,ffurl_seek2函数的作用是:

ffurl_seek2(h,0,AVSEEK_SIZE):不改变读写位置,返回文件描述符为h->priv_data->fd的文件的大小;

ffurl_seek2(h,0,SEEK_SET):将读写位置移到文件描述符为h->priv_data->fd的文件的开头,此时返回0;

ffurl_seek2(h,0,SEEK_END):将读写位置移到文件尾,此时返回文件描述符为h->priv_data->fd的文件的大小;

ffurl_seek2(h,0,SEEK_CUR):取得目前文件位置。此时返回当前读写位置距离文件开头多少个字节;

二、ffurl_seek函数

ffurl_seek函数定义在libavformat/url.h中:

/*** Change the position that will be used by the next read/write* operation on the resource accessed by h.** @param pos specifies the new position to set* @param whence specifies how pos should be interpreted, it must be* one of SEEK_SET (seek from the beginning), SEEK_CUR (seek from the* current position), SEEK_END (seek from the end), or AVSEEK_SIZE* (return the filesize of the requested resource, pos is ignored).* @return a negative value corresponding to an AVERROR code in case* of failure, or the resulting file position, measured in bytes from* the beginning of the file. You can use this feature together with* SEEK_CUR to read the current file position.*/
static inline int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
{return ffurl_seek2(h, pos, whence);
}

可以看到该函数内部仅调用了ffurl_seek2函数,所以ffurl_seek函数和ffurl_seek2函数用法完全等价。不同点仅仅在于ffurl_seek函数用static和inline关键字修饰,内联展开节省了每次调用函数的开销,能提高程序性能,具体可以参考:《C语言static和inline》。

三、avio_size函数

avio_size函数定义在libavformat/aviobuf.c中:

/*** Get the filesize.* @return filesize or AVERROR*/
int64_t avio_size(AVIOContext *s)
{FFIOContext *const ctx = ffiocontext(s);int64_t size;if (!s)return AVERROR(EINVAL);if (ctx->written_output_size)return ctx->written_output_size;if (!s->seek)return AVERROR(ENOSYS);size = s->seek(s->opaque, 0, AVSEEK_SIZE);if (size < 0) {if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0)return size;size++;s->seek(s->opaque, s->pos, SEEK_SET);}return size;
}

该函数的作用是:返回文件描述符为s->opaque->priv_data->fd的文件的大小,单位为字节。该函数内部首先会尝试通过fstat函数获取文件大小,如果获取失败,会继续尝试通过lseek函数获取文件大小。

可以看到avio_size函数内部调用了函数指针s->seek指向的回调函数,而s->seek一般指向ffurl_seek2函数,所以下面语句相当于执行了ffurl_seek2(s->opaque,0,AVSEEK_SIZE),从而能获取到文件大小:

size = s->seek(s->opaque, 0, AVSEEK_SIZE);

从 《FFmpeg源码:file_read、file_write、file_seek函数分析》中我们可以知道,ffurl_seek2(s->opaque,0,AVSEEK_SIZE)实际相当于执行了:

/* XXX: use llseek */
static int64_t file_seek(URLContext *h, int64_t pos, int whence)
{
//...struct stat st;ret = fstat(c->fd, &st);return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);//...
}

即通过fstat函数得到文件大小。

avio_size函数中执行语句“size = s->seek(s->opaque, 0, AVSEEK_SIZE)”后,如果得到的size值小于0,会继续执行:

    if (size < 0) {if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0)return size;size++;s->seek(s->opaque, s->pos, SEEK_SET);}

意思就是如果通过fstat函数获取文件大小失败,继续尝试通过lseek函数获取文件大小:

/* XXX: use llseek */
static int64_t file_seek(URLContext *h, int64_t pos, int whence)
{
//...ret = lseek(c->fd, pos, whence);return ret < 0 ? AVERROR(errno) : ret;
}

这篇关于FFmpeg源码:ffurl_seek2、ffurl_seek、avio_size函数分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1111118

相关文章

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

pandas使用apply函数给表格同时添加多列

《pandas使用apply函数给表格同时添加多列》本文介绍了利用Pandas的apply函数在DataFrame中同时添加多列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、Pandas使用apply函数给表格同时添加多列二、应用示例一、Pandas使用apply函

Nginx内置变量应用场景分析

《Nginx内置变量应用场景分析》Nginx内置变量速查表,涵盖请求URI、客户端信息、服务器信息、文件路径、响应与性能等类别,这篇文章给大家介绍Nginx内置变量应用场景分析,感兴趣的朋友跟随小编一... 目录1. Nginx 内置变量速查表2. 核心变量详解与应用场景3. 实际应用举例4. 注意事项Ng

Java多种文件复制方式以及效率对比分析

《Java多种文件复制方式以及效率对比分析》本文总结了Java复制文件的多种方式,包括传统的字节流、字符流、NIO系列、第三方包中的FileUtils等,并提供了不同方式的效率比较,同时,还介绍了遍历... 目录1 背景2 概述3 遍历3.1listFiles()3.2list()3.3org.codeha

Python中Namespace()函数详解

《Python中Namespace()函数详解》Namespace是argparse模块提供的一个类,用于创建命名空间对象,它允许通过点操作符访问数据,比字典更易读,在深度学习项目中常用于加载配置、命... 目录1. 为什么使用 Namespace?2. Namespace 的本质是什么?3. Namesp

MySQL中如何求平均值常见实例(AVG函数详解)

《MySQL中如何求平均值常见实例(AVG函数详解)》MySQLavg()是一个聚合函数,用于返回各种记录中表达式的平均值,:本文主要介绍MySQL中用AVG函数如何求平均值的相关资料,文中通过代... 目录前言一、基本语法二、示例讲解1. 计算全表平均分2. 计算某门课程的平均分(例如:Math)三、结合

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4