ffmpeg-AVBuffer、AVBufferRef、引用计数机制

目录

引用计数

定义

优点

AVBuffer

AVBufferRef

av_buffer_create

av_buffer_ref

av_buffer_unref

参考:


引用计数

定义

        引用计数是一种内存管理的方式,当一份内存可能被多个对象使用,可以通过引用计数的方式实现内存复用。

优点

        对于没有GC机制的语言,比如C语言,提供了一种简洁高效的内存管理方式。以ffmpg为例,使用av_buffer_create()在创建buffer的时候,引用计数为1,当有module调用av_buffer_ref()对其引用时,引用计数+1,调用av_buf_unref时,引用计数减1。av_buf_unref引用计数减1后会内部检查当前buffer的引用计数,如果变为1就会自动释放buffer。引用计数机制降低了内存浪费、实现了内存的自动销毁。

AVBuffer

        AVBuffer指向数据本身,usr不应该直接使用AVBuffer操作数据,而应该使用AVBufferRef(对AVBuffer的封装)来操作数据。

        定义来自ffmpeg5.1。ffmpeg\libavutil\buffer.h、ffmpeg\libavutil\buffer_internal.h

/**
 * The buffer was av_realloc()ed, so it is reallocatable.
 */
#define BUFFER_FLAG_REALLOCATABLE (1 << 0)
/**
 * The AVBuffer structure is part of a larger structure
 * and should not be freed.
 */
#define BUFFER_FLAG_NO_FREE       (1 << 1)

struct AVBuffer {
    uint8_t *data; /**< data described by this buffer */
    size_t size; /**< size of data in bytes */
    /**
     *  number of existing AVBufferRef instances referring to this buffer 引用计数
     */
    atomic_uint refcount;

    /**
     * a callback for freeing the data
     */
    void (*free)(void *opaque, uint8_t *data);

    /**
     * an opaque pointer, to be used by the freeing callback,内部指针,供free使用
     */
    void *opaque;

    /**
     * A combination of AV_BUFFER_FLAG_*,通常置为AV_BUFFER_FLAG_READONLY,表示是否只读
     * av_buffer_is_writable就是判断这个标志位
     */
    int flags;

    /**
     * A combination of BUFFER_FLAG_*,可能等于BUFFER_FLAG_NO_FREE、在av_buf_unref里使用
     */
    int flags_internal;
};

AVBufferRef

typedef struct AVBufferRef {
    AVBuffer *buffer;

    /**
     * The data buffer. It is considered writable if and only if
     * this is the only reference to the buffer, in which case
     * av_buffer_is_writable() returns 1.指向数据的指针,只有av_buffer_is_writable() returns 
     * 1才可写。
     */
    uint8_t *data;//=AVBuffer->data,这两个指针相同
    /**
     * Size of data in bytes.
     */
    size_t   size;//=AVBuffer->size,这两个指针相同
} AVBufferRef;

av_buffer_create

        AVBufferRef的成员data,size=AVBuffer的data、size。详见av_buffer_create和buffer_create定义。av_buffer_crate的过程申请了AVBuffer,AVBufferRef的内存,将用户传入的free函数指针进行赋值,代码比较清晰。

static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size,
                                  void (*free)(void *opaque, uint8_t *data),
                                  void *opaque, int flags)
{
    AVBufferRef *ref = NULL;

    buf->data     = data;
    buf->size     = size;
    buf->free     = free ? free : av_buffer_default_free;
    buf->opaque   = opaque;

    atomic_init(&buf->refcount, 1); //原子操作,引用计数初始化为1

    buf->flags = flags;

    ref = av_mallocz(sizeof(*ref));
    if (!ref)
        return NULL;

    ref->buffer = buf;
    ref->data   = data;//AVBuffer的data和AVBufferRef指向相同
    ref->size   = size;

    return ref;
}


AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
                              void (*free)(void *opaque, uint8_t *data),
                              void *opaque, int flags)
{
    AVBufferRef *ret;
    AVBuffer *buf = av_mallocz(sizeof(*buf));
    if (!buf)
        return NULL;

    ret = buffer_create(buf, data, size, free, opaque, flags);
    if (!ret) {
        av_free(buf);
        return NULL;
    }
    return ret;
}

av_buffer_ref

        av_buffer_ref申请了AVBufferRef的结构体大小内存,并把指向的data引用计数加1。

AVBufferRef *av_buffer_ref(const AVBufferRef *buf)
{
    AVBufferRef *ret = av_mallocz(sizeof(*ret));

    if (!ret)
        return NULL;

    *ret = *buf;

    atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed);

    return ret;
}

av_buffer_unref

        av_buffer_unref,将当前的AVBufferRef指针指向的内存释放,并对AVBufferRef指向的数据引用计数减1,如果当前数据的引用计数=1,数据内存释放。

static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
{
    AVBuffer *b;

    b = (*dst)->buffer;

    if (src) {
        **dst = **src;
        av_freep(src);
    } else
        av_freep(dst);

    if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
        /* b->free below might already free the structure containing *b,
         * so we have to read the flag now to avoid use-after-free. */
        int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE);
        b->free(b->opaque, b->data);
        if (free_avbuffer)
            av_free(b);
    }
}

void av_buffer_unref(AVBufferRef **buf)
{
    if (!buf || !*buf)
        return;

    buffer_replace(buf, NULL);
}

参考:

深入理解FFMPEG-AVBuffer/AVBufferRef/AVBufferPool_流媒体程序员的博客-CSDN博客_ffmpeg abuffer

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值