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

相关文章

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Java function函数式接口的使用方法与实例

《Javafunction函数式接口的使用方法与实例》:本文主要介绍Javafunction函数式接口的使用方法与实例,函数式接口如一支未完成的诗篇,用Lambda表达式作韵脚,将代码的机械美感... 目录引言-当代码遇见诗性一、函数式接口的生物学解构1.1 函数式接口的基因密码1.2 六大核心接口的形态学

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

python中os.stat().st_size、os.path.getsize()获取文件大小

《python中os.stat().st_size、os.path.getsize()获取文件大小》本文介绍了使用os.stat()和os.path.getsize()函数获取文件大小,文中通过示例代... 目录一、os.stat().st_size二、os.path.getsize()三、函数封装一、os