欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > FFmpeg源码:avio_tell函数分析

FFmpeg源码:avio_tell函数分析

2024/10/25 0:33:29 来源:https://blog.csdn.net/u014552102/article/details/141180974  浏览:    关键词:FFmpeg源码:avio_tell函数分析

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

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)的偏移字节数。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com