FFmpeg源码:avio_read_partial函数分析

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

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函数分析

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

一、avio_read_partial函数的声明

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

cpp 复制代码
/**
 * 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函数后,s->buf_ptr等成员会发生相应变化。

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

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

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

二、avio_read_partial函数的定义

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

cpp 复制代码
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)表示出错:

cpp 复制代码
    if (size < 0)
        return AVERROR(EINVAL);

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

cpp 复制代码
    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:

cpp 复制代码
    len = s->buf_end - s->buf_ptr;
    if (len == 0) {
        fill_buffer(s);
        len = s->buf_end - s->buf_ptr;
    }

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

cpp 复制代码
    if (len > size)
        len = size;
    memcpy(buf, s->buf_ptr, len);
    s->buf_ptr += len;

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

cpp 复制代码
    if (!len) {
        if (s->error)      return s->error;
        if (avio_feof(s))  return AVERROR_EOF;
    }
    return len;
相关推荐
简鹿视频24 分钟前
mp4视频转换成avi格式攻略
ffmpeg·音视频·视频编解码·格式工厂
呆萌小新@渊洁1 小时前
Linux离线环境安装ffmpeg
linux·ffmpeg·php
番茄啊2 小时前
FFmpeg 使用RTSP服务器录屏并推流
ffmpeg
CHS_Lab1 天前
“非标”MP4文件的恢复方法
ffmpeg·数据恢复·视频恢复·mp4恢复
一点晖光1 天前
ffmpeg视频分辨率转换
ffmpeg·音视频
数据库生产实战1 天前
Oracle的DBMS_SPACE.SPACE_USAGE和dba_segments计算的对象块数为什么不一样?表空间异常暴增的秘密可能就在这里!
oracle·ffmpeg·dba
hjjdebug2 天前
ffmpeg -map 是什么意思?
ffmpeg·map
黑客思维者2 天前
Python自动化截图/录屏3大方案(PIL/mss/ffmpeg)深度拆解
python·ffmpeg·自动化·录屏
一点晖光2 天前
ffmpeg处理视频命令整理
ffmpeg·音视频
Everbrilliant892 天前
FFmpeg解码视频数据OpenGL Texture播放
ffmpeg·音视频·音视频解码·ffmpeg解码·opengl播放视频·ffmpeg解码gl播放·opengl render