mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
210 lines
7.6 KiB
Text
210 lines
7.6 KiB
Text
GstMemory
|
|
---------
|
|
|
|
This document describes the design of the memory objects.
|
|
|
|
GstMemory objects are usually added to GstBuffer objects and contain the
|
|
multimedia data passed around in the pipeline.
|
|
|
|
Requirements
|
|
~~~~~~~~~~~~
|
|
|
|
- It must be possible to have different memory allocators
|
|
- It must be possible to efficiently share memory objects, copy, span
|
|
and trim.
|
|
|
|
|
|
Allocators
|
|
~~~~~~~~~~
|
|
|
|
GstMemory objects are created by allocators. Allocators are created from
|
|
a GstMemoryInfo structure.
|
|
|
|
struct _GstMemoryInfo {
|
|
const gchar *mem_type;
|
|
|
|
GstAllocatorAllocFunction alloc;
|
|
|
|
GstMemoryMapFunction mem_map;
|
|
GstMemoryUnmapFunction mem_unmap;
|
|
GstMemoryFreeFunction mem_free;
|
|
|
|
GstMemoryCopyFunction mem_copy;
|
|
GstMemoryShareFunction mem_share;
|
|
GstMemoryIsSpanFunction mem_is_span;
|
|
};
|
|
|
|
Allocators are refcounted. It is also possible to register the allocator to the
|
|
GStreamer system. This way, the allocator can be retrieved by name.
|
|
|
|
After an allocator is created, new GstMemory can be created with
|
|
|
|
GstMemory * gst_allocator_alloc (const GstAllocator * allocator,
|
|
gsize maxsize, gsize align);
|
|
|
|
The GstMemory object is a refcounted object that must be freed with
|
|
gst_memory_unref ().
|
|
|
|
It is also possible to create a new GstMemory object that wraps existing
|
|
memory with:
|
|
|
|
GstMemory * gst_memory_new_wrapped (GstMemoryFlags flags,
|
|
gpointer data, gsize maxsize,
|
|
gsize offset, gsize size,
|
|
gpointer user_data,
|
|
GDestroyNotify notify);
|
|
|
|
Lifecycle
|
|
~~~~~~~~~
|
|
|
|
GstMemory objects are refcounted. When the GstMemory object is first created, it
|
|
has a refcount of 1.
|
|
|
|
Each variable holding a reference to the GstMemory object is responsible for
|
|
updating the refcount.
|
|
|
|
When the refcount reaches 0, and thus no objects hold a reference anymore, we
|
|
can free the memory. The GstMemoryFreeFunction of the allocator will be called
|
|
to cleanup the memory.
|
|
|
|
|
|
Access management
|
|
-----------------
|
|
|
|
GstMemory objects can be shared between multiple GstBuffer objects. It is
|
|
important that when a thread writes to the shared GstMemory that the other
|
|
buffers don't not see the changes.
|
|
|
|
We need 2 concepts:
|
|
|
|
- count how many objects are sharing this GstMemory (exclusive counter)
|
|
- control the READ/WRITE access to the GstMemory (locking)
|
|
|
|
* exclusive counter
|
|
|
|
Each object that wants to keep a reference to the GstMemory and doesn't want to
|
|
see the changes from other owners of the same GstMemory needs to lock the
|
|
GstMemory in EXCLUSIVE mode, which will increase the exclusive counter.
|
|
|
|
The exclusive counter counts the amount of objects that share this GstMemory
|
|
object. The counter is initially 0, meaning that the object is not shared with
|
|
any object. When a GstBuffer (or other object) receives a ref to a GstMemory,
|
|
it will lock in EXCLUSIVE mode.
|
|
|
|
When the GstMemory is removed from the buffer, both the ref count and the
|
|
exclusive counter will be decreased with gst_object_unref() and
|
|
gst_memory_unlock () respectively.
|
|
|
|
* locking
|
|
|
|
All read and write access must be performed between a gst_memory_lock() and
|
|
gst_memory_unlock() pair with the requested access method.
|
|
|
|
A gst_memory_lock() can fail when a WRITE lock is requested and the exclusive
|
|
counter is > 1. Indeed a GstMemory object with an exclusive counter > 1 is
|
|
locked EXCLUSIVELY by at least 2 objects and is therefore not writable.
|
|
|
|
Once the memory is locked with a certain access mode, it can be recursively
|
|
locked with the same or narrower access mode. For example, first locking the
|
|
memory in READWRITE mode allows you to recusively lock the memory in
|
|
READWRITE, READ and WRITE mode. Memory locked in READ mode cannot be locked
|
|
recursively in WRITE or READWRITE mode.
|
|
|
|
Note that multiple threads can READ lock the memory concurrently but cannot
|
|
lock the memory in WRITE mode because the exclusive counter must be > 1.
|
|
|
|
All calls to gst_memory_lock() need to be paired with one gst_memory_unlock()
|
|
call with the same access mode. When the last refcount of the memory is
|
|
removed, the should be no more outstanding locks.
|
|
|
|
Note that a shared counter of both 0 and 1 leaves the memory writable. The
|
|
reason is to make it easy to create and pass ownership of the memory to
|
|
another object while keeping it the memory writable. When the memory is
|
|
created with a shared count of 0, it is writable. When the memory is then
|
|
added to another object, the shared count is incremented to 1 and the memory
|
|
remains writable. The 0 share counter has a similar purpose as the floating
|
|
reference in GObject.
|
|
|
|
|
|
Memory layout
|
|
~~~~~~~~~~~~~
|
|
|
|
GstMemory manages a memory region. The accesible part of the managed region is
|
|
defined by an offset relative to the start of the region and a size. This
|
|
means that the managed region can be larger than what is visible to the user of
|
|
GstMemory API.
|
|
|
|
Schematically, GstMemory has a pointer to a memory region of _maxsize_. The area
|
|
starting from _offset_ and _size_ is accessible.
|
|
|
|
memory
|
|
GstMemory ->*----------------------------------------------------*
|
|
^----------------------------------------------------^
|
|
maxsize
|
|
^--------------------------------------^
|
|
offset size
|
|
|
|
The current properties of the accessible memory can be retrieved with:
|
|
|
|
gsize gst_memory_get_sizes (GstMemory *mem, gsize *offset, gsize *maxsize);
|
|
|
|
The offset and size can be changed with:
|
|
|
|
void gst_memory_resize (GstMemory *mem, gssize offset, gsize size);
|
|
|
|
|
|
Data Access
|
|
~~~~~~~~~~~
|
|
|
|
Access to the memory region is always controlled with a map and unmap method
|
|
call. This allows the implementation to monitor the access patterns or set up
|
|
the required memory mappings when needed.
|
|
|
|
Mapping a memory region requires the caller to specify the access method: READ
|
|
and/or WRITE. Mapping a memory region will first try to get a lock on the
|
|
memory in the requested access mode. This means that the map operation can
|
|
fail when WRITE access is requested on a non-writable memory object (it has
|
|
an exclusive counter > 1, the memory is already locked in an incompatible
|
|
access mode or the memory is marked readonly).
|
|
|
|
After the data has been accessed in the object, the unmap call must be
|
|
performed, which will unlock the memory again.
|
|
|
|
It is allowed to map multiple times with different access modes. for each of
|
|
the map calls, an corresponding unmap call needs to be made. WRITE-only memory
|
|
cannot be mapped in READ mode and READ-only memory cannot be mapped in WRITE
|
|
mode.
|
|
|
|
The memory pointer returned from the map call is guaranteed to remain valid in
|
|
the requested mapping mode until the corresponding unmap call is performed on
|
|
the pointer.
|
|
|
|
When multiple map operations are nested and return the same pointer, the pointer
|
|
is valid until the last unmap call is done.
|
|
|
|
When the final reference on a memory object is dropped, all outstanding
|
|
mappings should have been unmapped.
|
|
|
|
Resizing a GstMemory does not influence any current mappings an any way.
|
|
|
|
Copy
|
|
~~~~
|
|
|
|
A GstMemory copy can be made with the gst_memory_copy() call. Normally,
|
|
allocators will implement a custom version of this function to make a copy of
|
|
the same kind of memory as the original one.
|
|
|
|
This is what the fallback version of the copy function will do, albeit slower
|
|
than what as custom implementation could do.
|
|
|
|
The copy operation is only required to copy the visible range of the memory
|
|
block.
|
|
|
|
|
|
Share
|
|
~~~~~
|
|
|
|
A memory region can be shared between GstMemory object with the
|
|
gst_memory_share() operation.
|
|
|
|
|