FFmpeg源码:av_buffer_is_writable、av_buffer_realloc函数分析

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

FFmpeg内存管理相关的源码分析:

FFmpeg中内存分配和释放相关的源码:av_malloc函数、av_mallocz函数、av_free函数和av_freep函数分析

FFmpeg源码:av_realloc、av_reallocp、size_mult、av_realloc_f函数分析
FFmpeg引用计数数据缓冲区相关的结构体:AVBuffer、AVBufferRef简介

FFmpeg源码:buffer_create、av_buffer_create、av_buffer_default_free、av_buffer_alloc、av_buffer_allocz函数分析

FFmpeg源码:av_buffer_ref、av_buffer_unref函数分析

FFmpeg源码:av_buffer_is_writable、av_buffer_realloc函数分析

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

一、av_buffer_is_writable函数

(一)av_buffer_is_writable函数的声明

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

cpp 复制代码
/**
 * @return 1 if the caller may write to the data referred to by buf (which is
 * true if and only if buf is the only reference to the underlying AVBuffer).
 * Return 0 otherwise.
 * A positive answer is valid until av_buffer_ref() is called on buf.
 */
int av_buffer_is_writable(const AVBufferRef *buf);

该函数作用是:判断是否可以对buf引用的数据(buf->buffer->data,buf->data)进行写入,当且仅当buf是对底层AVBuffer的唯一引用(buf->buffer->refcount的值为1)时可以写入。如果可以写入,返回1,否则返回0。

(二)av_buffer_is_writable函数的定义

av_buffer_is_writable函数定义在FFmpeg源码的源文件libavutil/buffer.c中:

cpp 复制代码
/**
 * Always treat the buffer as read-only, even when it has only one
 * reference.
 */
#define AV_BUFFER_FLAG_READONLY (1 << 0)

int av_buffer_is_writable(const AVBufferRef *buf)
{
    if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY)
        return 0;

    return atomic_load(&buf->buffer->refcount) == 1;
}

该函数内部,首先通过buf->buffer->flags判断是否始终将缓冲区视为只读的,如果是,返回0,表示不可对buf引用的数据进行写入:

cpp 复制代码
if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY)
        return 0;

然后通过atomic_load函数读取buf->buffer->refcount的值。如果该值为1,表示引用buf缓冲区的现有AVBufferRef实例的数目为1,即引用计数为1,此时av_buffer_is_writable函数返回1,表示可以对buf引用的数据进行写入;如果引用计数不为1,av_buffer_is_writable函数返回0,表示不可写入:

cpp 复制代码
return atomic_load(&buf->buffer->refcount) == 1;

二、av_buffer_realloc函数

(一)av_buffer_realloc函数的声明

av_buffer_realloc函数声明在头文件libavutil/buffer.h中:

cpp 复制代码
/**
 * Reallocate a given buffer.
 *
 * @param buf  a buffer reference to reallocate. On success, buf will be
 *             unreferenced and a new reference with the required size will be
 *             written in its place. On failure buf will be left untouched. *buf
 *             may be NULL, then a new buffer is allocated.
 * @param size required new buffer size.
 * @return 0 on success, a negative AVERROR on failure.
 *
 * @note the buffer is actually reallocated with av_realloc() only if it was
 * initially allocated through av_buffer_realloc(NULL) and there is only one
 * reference to it (i.e. the one passed to this function). In all other cases
 * a new buffer is allocated and the data is copied.
 */
int av_buffer_realloc(AVBufferRef **pbuf, size_t size);

该函数作用是:

1.如果(*pbuf)为空,说明AVBufferRef对象不存在。分配一个新的内存块给(*pbuf)指向的AVBufferRef对象,并给(*pbuf)->buffer分配内存,给(*pbuf)->data分配大小为size个字节的内存。然后给(*pbuf)->buffer->flags_internal设置为BUFFER_FLAG_REALLOCATABLE,表示该AVBufferRef对象的缓冲区是可重新分配的。

2.如果(*pbuf)不为空(AVBufferRef对象存在),并且(*pbuf)->size的值等于形参size的值,表示

需要给(*pbuf)->data重新分配的大小等于原来的值,此时av_buffer_realloc函数返回0,不执行也不需要执行其它操作。

3.不满足上述条件1和条件2的情况时,如果该AVBufferRef对象的缓冲区不可重新分配(通过语句!(buf->buffer->flags_internal & BUFFER_FLAG_REALLOCATABLE)判断)或者不可对该AVBufferRef引用的数据进行写入(通过语句!av_buffer_is_writable(buf)判断)或者(*buf)->data 的地址不等于 (*pbuf)->buffer->data的地址。此时表示该AVBufferRef对象的缓冲区无法重新分配,分配新的可重新分配缓冲区并复制数据到这块新的缓冲区。

4.不满足上述条件1、条件2、条件3的情况时,根据size的值扩展或缩小(*buf)->buffer->data指向的内存块。然后(*buf)->buffer->data指向的内存块的大小会变为size。

形参pbuf:既是输入型参数也是输出型参数,为指针的指针。(*pbuf)指向需要重新分配缓冲区的AVBufferRef对象。

形参size:输入型参数,需要给(*pbuf)->data指向的缓冲区重新分配的内存块的大小,单位为字节。

返回值:返回0表示成功,返回AVERROR(ENOMEM)表示分配内存失败。

(二)av_buffer_realloc函数的定义

av_buffer_realloc函数定义在源文件libavutil/buffer.c中:

cpp 复制代码
int av_buffer_realloc(AVBufferRef **pbuf, size_t size)
{
    AVBufferRef *buf = *pbuf;
    uint8_t *tmp;
    int ret;

    if (!buf) {
        /* allocate a new buffer with av_realloc(), so it will be reallocatable
         * later */
        uint8_t *data = av_realloc(NULL, size);
        if (!data)
            return AVERROR(ENOMEM);

        buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
        if (!buf) {
            av_freep(&data);
            return AVERROR(ENOMEM);
        }

        buf->buffer->flags_internal |= BUFFER_FLAG_REALLOCATABLE;
        *pbuf = buf;

        return 0;
    } else if (buf->size == size)
        return 0;

    if (!(buf->buffer->flags_internal & BUFFER_FLAG_REALLOCATABLE) ||
        !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) {
        /* cannot realloc, allocate a new reallocable buffer and copy data */
        AVBufferRef *new = NULL;

        ret = av_buffer_realloc(&new, size);
        if (ret < 0)
            return ret;

        memcpy(new->data, buf->data, FFMIN(size, buf->size));

        buffer_replace(pbuf, &new);
        return 0;
    }

    tmp = av_realloc(buf->buffer->data, size);
    if (!tmp)
        return AVERROR(ENOMEM);

    buf->buffer->data = buf->data = tmp;
    buf->buffer->size = buf->size = size;
    return 0;
}
相关推荐
彷徨而立10 分钟前
【FFmpeg】销毁解码器时,必须清理剩余帧吗?
ffmpeg
骄傲的心别枯萎18 分钟前
项目1:FFMPEG推流器讲解(五):FFMPEG时间戳、时间基、时间转换的讲解
ffmpeg·音视频·视频编解码·时间戳·rv1126
彷徨而立3 小时前
【FFmpeg】HW 解码器销毁时,资源回收顺序
ffmpeg
彷徨而立10 小时前
【FFmpeg】如何判断 HW解码器输出的是 硬件帧?
ffmpeg
派阿喵搞电子10 小时前
基于ffmpeg库,在AGX上编译jetsonFFmpeg库带有硬件加速的h264_nvmpi视频编解码器
ffmpeg·视频编解码
彷徨而立10 小时前
【FFmpeg】HW解码器输出 硬件帧 or 软件帧
ffmpeg
长沙红胖子Qt11 小时前
FFmpeg开发笔记(十三):ffmpeg采集麦克风音频pcm重采样为aac录音为AAC文件
笔记·ffmpeg·音视频
feiyangqingyun12 小时前
全网首发/Qt结合ffmpeg实现rist推拉流/可信赖的互联网流媒体协议/跨平台支持各个系统
qt·ffmpeg·rist推拉流
shenhuxi_yu1 天前
ffmpeg avio使用示例
ffmpeg
aqi002 天前
FFmpeg开发笔记(八十二)使用国产直播服务器smart_rtmpd执行推流操作
ffmpeg·音视频·直播·流媒体