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;
相关推荐
aqi0016 小时前
FFmpeg开发笔记(九十八)基于FFmpeg的跨平台图形用户界面LosslessCut
android·ffmpeg·kotlin·音视频·直播·流媒体
带土12 天前
2. Linux下FFmpeg C++音视频解码+推流开发
linux·c++·ffmpeg
aqi002 天前
FFmpeg开发笔记(九十七)国产的开源视频剪辑工具AndroidVideoEditor
android·ffmpeg·音视频·直播·流媒体
Sleepless_斑马2 天前
RTMP/RTSP流媒体服务器搭建、ffmpeg推流桌面、vlc拉流
ffmpeg·rtmp·rtsp
炼金术2 天前
SkyPlayer v1.1.0 - 在线视频播放功能更新
android·ffmpeg
喜欢吃豆2 天前
深度解析:FFmpeg 远程流式解复用原理与工程实践
人工智能·架构·ffmpeg·大模型·音视频·多模态
带土12 天前
1. FFmpeg入门
ffmpeg
Lueeee.2 天前
1.广告机项目-----ffmpeg播放准备
ffmpeg
心动啊1213 天前
FFMPeg在Python中的使用
ffmpeg
aqi003 天前
FFmpeg开发笔记(一百)国产的Android开源视频压缩工具VideoSlimmer
android·ffmpeg·音视频·直播·流媒体