FFmpeg5.0 source code reading - memory pool AVBufferPool

Abstract : Most of the data storage in FFmpeg, for example AVFrame, AVPacketis AVBufferRefmanaged, and the structure of the carrying data is AVBuffer. AVBufferThis article mainly analyzes the related implementation in FFmpeg through FFmpeg source code .
Keywords : AVBuffer, AVBufferPool,AVBufferPool

1. AVBufferRef

1.1 AVBufferStructure Definition

  AVBufferThe declaration is in libavutil/buffer_internal.hthe file, and the related operation functions are defined in libavutil/buffer.c. First look at AVBufferthe structure briefly:

struct AVBuffer {
    
    
    uint8_t *data;          /**< data described by this buffer */
    size_t size;                /**< size of data in bytes */
    atomic_uint refcount;   //number of existing AVBufferRef instances referring to this **buffer**
    void (*free)(void *opaque, uint8_t *data);//a callback for freeing the data
    void *opaque;//an opaque pointer, to be used by the freeing callback
    int flags;//A combination of AV_BUFFER_FLAG_*
    int flags_internal;//A combination of BUFFER_FLAG_*
};

  The structure is relatively simple, it is a data type with a reference count:

  • data: Data pointer in buffer;
  • size: The size of the data, that is, datathe size of the data in the middle;
  • refcount: Reference counting, needless to say, when the reference count is 0, the corresponding memory is destroyed. The operation of this variable is atomic. ffmpeg internally implements a set of derived variables for different compilation periods and platforms. The specifics are in-depth, just understand the meaning;
  • free: The function pointer to release the memory, if not specified, the default function pointer will be used av_buffer_default_freeto release the memory;
  • opaque: A user-defined pointer through which the user can pass data to freethe function;
  • flags: currently only one value AV_BUFFER_FLAG_READONLY;
  • flags_internal: currently only one value BUFFER_FLAG_REALLOCATABLE;

1.2 AVBufferRefStructure Definition

  AVBufferRefIt can be regarded AVBufferas a handle to operate AVBuffer:

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.
     */
    uint8_t *data;
    size_t   size;//Size of data in bytes.
} AVBufferRef;

  AVBufferRefThe structure is relatively simple and will not be described in detail. The main attention datais that the fields point to its members buffer.data.

1.3 Operation function

  • AVBufferRef *av_buffer_create(uint8_t *data, size_t size, void (*free)(void *opaque, uint8_t *data), void *opaque, int flags): This function is used to create one AVBufferRef, specifically, the application memory function initializes each member according to the parameters. Note that the returned pointer and its members bufferare on the heap, and AVBuferRef::data == AVBufferRef::buffer::data;
  • AVBufferRef *av_buffer_alloc(size_t size): By av_buffer_createcreating an object, but the parameters are all default values;
  • AVBufferRef *av_buffer_allocz(size_t size): compared to av_buffer_allocjust 0-initialization of memory;
  • AVBufferRef *av_buffer_ref(AVBufferRef *buf): The API ending in FFmpeg _refis the meaning of reference count +1, and the opposite _unrefis reference count -1. But you need to pay attention to two points:
    • Here is not a simple reference count + 1, but malloca AVBufferRefreturn value, and then shallow copy the input parameters;
    • Only the reference count is atomic, similarly shared_ptr, the object itself is not thread-safe;
  • void av_buffer_unref(AVBufferRef **buf): Reference count -1, release memory, call freerelease datamemory;
  • int av_buffer_is_writable(const AVBufferRef *buf): When flagsset AV_BUFFER_FLAG_READONLY, it is always non-writable, otherwise it can only be written when the reference count is 1;
  • int av_buffer_make_writable(AVBufferRef **pbuf): The implementation is copy-on-writeto pbufcopy a copy to avoid writing shared memory from affecting other objects;
  • int av_buffer_realloc(AVBufferRef **pbuf, size_t size): Re-apply for memory, if the input is *pbufempty, it will be createone copy. When the input object is not writable or not, BUFFER_FLAG_REALLOCATABLEa copy will be made realloc;
  • int av_buffer_replace(AVBufferRef **pdst, AVBufferRef *src): It can be simply understood that *pds=*srcwhen pdstand srcpoint to the same one buffer, nothing will be done, and the copy constructor similar to the object in C++ will be implemented;

2. AVBufferRef

2.1 Structure Definition

  AVBufferPoolIs a singly linked list, used to manage it AVBuffer.

typedef struct BufferPoolEntry {
    
    
    uint8_t *data;
    /*
     * Backups of the original opaque/free of the AVBuffer corresponding to
     * data. They will be used to free the buffer when the pool is freed.
     */
    void *opaque;
    void (*free)(void *opaque, uint8_t *data);
    AVBufferPool *pool;
    struct BufferPoolEntry *next;
} BufferPoolEntry;

  It can be seen from the structure definition BufferPollEntrythat the nodes in the linked list are used to manage the corresponding AVBufferRef. But if you look carefully, you find that there are no pointer nodes, but function pointers AVBufferare saved , because with these two values, we can release the corresponding ones smoothly , and the corresponding allocate function pointers can be created in the pool. object.opaquefreeAVBuffer

  • data: AVBufferThe address pointed to, because there is no saved AVBufferaddress, a pointer is needed to point to the data;
  • opaque: In the implementation BufferPoolEntry::opaque->AVBuffer::opaque->BufferPoolEntry, this can ensure that AVBufferthe handle that manages itself can be found when calling the release function;
  • free: Release the function pointer, which is actually fixed pool_release_buffer;
  • pool: Directly point to the current memory pool;
  • next: the node pointer of the linked list;
struct AVBufferPool {
    
    
    AVMutex mutex;
    BufferPoolEntry *pool;
    /*
     * This is used to track when the pool is to be freed.
     * The pointer to the pool itself held by the caller is considered to
     * be one reference. Each buffer requested by the caller increases refcount
     * by one, returning the buffer to the pool decreases it by one.
     * refcount reaches zero when the buffer has been uninited AND all the
     * buffers have been released, then it's safe to free the pool and all
     * the buffers in it.
     */
    atomic_uint refcount;

    size_t size;
    void *opaque;
    AVBufferRef* (*alloc)(size_t size);
    AVBufferRef* (*alloc2)(void *opaque, size_t size);
    void         (*pool_free)(void *opaque);
};

  AVBufferPoolIt is the management object of the memory pool:

  • mutex: Lock for thread safety;
  • opaque: pool_freethe first parameter of the function pointer;
  • alloc: By default it will be set to av_buffer_alloc;
  • alloc2: A custom allocation function, which AVBufferRefis used first when applying, and used if not specified alloc;
  • pool_free: The callback to release the memory pool;
  • size: The size of a single object, that is, the size of objects managed by the entire memory pool is the same;
  • refcount: The sum of reference counts of nodes currently allocated from the memory pool but not in the memory pool linked list.

2.2 Interface implementation

  • AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef* (*alloc)(void *opaque, size_t size), void (*pool_free)(void *opaque)): Initialize the linked list of the pool, set the corresponding members according to the parameters, alloc2the input parameters will be set alloc, and - allocwill be set to av_buffer_alloc;
  • AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size))alloc: It will only apply for the memory setting related parameters of the pool. If alloc is empty, the setting in the pool is av_buffer_alloc;
  • void av_buffer_pool_uninit(AVBufferPool **ppool): Destroy the pool, and destroy the object if the reference count is 1 (I don’t know why the naming is not similar _unref, maybe because there is no ref);
  • AVBufferRef *av_buffer_pool_get(AVBufferPool *pool): Get a AVBufferRefmemory that is managed by pool.

2.3 Memory Management

  AVBufferPoolIt is a stack memory pool implemented in the form of a singly linked list. The basic process is that if the linked list is not empty, the node at the head of the stack will be popped out; otherwise, a node will be created and returned AVBUfferRefto the user when applying for memory, and the node will be pushed into the stack to the head node when the user releases it, and applying and releasing memory is thread-safe. AVBufferPoolIt is a free linked list stack, which manages the memory by specifying the corresponding AVBufferRefrelease function .   For a memory pool that has just been initialized, applying for two Buffers consecutively is in the following state:pool_release_buffer

insert image description here

  Continuously apply for 3 buffers, and release 2 more, which is the following state (red is the connecting line of the linked list):
insert image description here

Guess you like

Origin blog.csdn.net/GrayOnDream/article/details/128945416