How data objects are categorized by ownership and sharing semantics.
Every data object in promeki falls into one of two categories based on its size, usage patterns, and sharing semantics.
Small, lightweight value types that are always used directly. They have no RefCount overhead and cannot be wrapped in SharedPtr. Copying is cheap (a few words of memory), so there is no benefit to reference counting.
| Class | Description |
|---|---|
Point | N-dimensional coordinate |
Rational | Exact fraction (num/den) |
Size2Du32 / Size2Di32 | 2D width/height pair |
Rect2Di32 | 2D rectangle (position + size) |
UUID | 128-bit unique identifier |
Timecode | SMPTE timecode (H:M:S:F) |
TimeStamp | Steady-clock time point |
XYZColor | CIE XYZ color triple |
Color | Float[4] color value with ColorModel |
ColorModel | Color model / color space descriptor (TypeRegistry) |
MemSpace | Memory space descriptor (TypeRegistry) |
PixelMemLayout | Pixel memory layout descriptor (TypeRegistry) |
PixelFormat | Full pixel description: format + color model + ranges (TypeRegistry) |
Pair | Typed pair of two values |
Result | Pair<T, Error> for fallible operations |
Span | Non-owning view over contiguous storage |
Stack | LIFO stack (std::stack wrapper) |
PriorityQueue | Priority queue (std::priority_queue wrapper) |
Duration | Time duration value |
FrameNumber | Absolute frame index along a media timeline |
FrameCount | Frame count (with empty / unknown / infinity sentinels) |
MediaDuration | Start frame plus a frame count (defines FrameRange) |
FrameRate | Frame rate descriptor |
AudioLevel | Audio level in dBFS |
InspectorEvent | Per-frame measurement record produced by InspectorMediaIO |
InspectorSnapshot | Aggregate accumulator state from InspectorMediaIO |
InspectorDiscontinuity | One detected discontinuity in the inspector's frame stream |
ContentLightLevel | HDR content light level (MaxCLL / MaxFALL, CTA-861.3) |
MasteringDisplay | HDR mastering display color volume (SMPTE ST 2086) |
Plain value types that wrap an internal SharedPtr<Data> to provide copy-on-write semantics. Copying one is O(1) — an atomic refcount bump on the shared storage — and any mutator detaches a private copy on first write. These types deliberately do not expose a Ptr alias: a value is already as cheap to pass around as a raw shared pointer would be, so adding an extra layer of pointer indirection only obscures the model.
| Class | Description |
|---|---|
String | Text everywhere; rides through every API |
Buffer | Cross-thread / cross-domain memory handoff |
VariantDatabase | Typed key/value store; base of Metadata and friends |
Metadata | Typed key-value metadata (CoW via VariantDatabase) |
Frame | Pipeline-wide container of payloads + metadata |
JsonObject | JSON object container wrapping nlohmann::json |
JsonArray | JSON array container wrapping nlohmann::json |
XmlDocument | XML document handle backed by pugixml |
XmlElement | XML element subtree backed by pugixml (each handle is its own pugi document holding one root element) |
Value types that store their data directly as member variables (no internal SharedPtr). Each class includes PROMEKI_SHARED_FINAL so it can be wrapped in SharedPtr when shared ownership is needed. Every shareable class provides a Ptr typedef:
When used as a local variable or as a member of another class, no heap allocation or reference counting occurs — the object is a plain value.
Shareable classes also provide convenience type aliases for collections:
List — a promeki::List of plain objects (e.g. Image::List)PtrList — a promeki::List of Ptr (e.g. Buffer::PtrList)| Class | Description |
|---|---|
AudioDesc | Audio format descriptor |
ImageDesc | Image format descriptor |
MediaDesc | Media format descriptor |
List | Generic list (std::vector wrapper) |
Map | Ordered map (std::map wrapper) |
Set | Ordered set (std::set wrapper) |
HashMap | Unordered map (std::unordered_map wrapper) |
HashSet | Unordered set (std::unordered_set wrapper) |
Deque | Double-ended queue (std::deque wrapper) |
Array | Fixed-size array (std::array wrapper) |
Image | Image descriptor + pixel buffer planes (compressed images carry an attached VideoPacket) |
Audio | Audio descriptor + sample buffer (compressed audio carries an attached AudioPacket) |
MediaPacket | Abstract polymorphic base for encoded bitstream access units |
VideoPacket | Encoded video access unit — attached to a compressed Image |
AudioPacket | Encoded audio access unit — attached to a compressed Audio |
EncodedDesc | Compressed/encoded media descriptor |
Data objects are not internally thread-safe. Concurrent reads and writes to the same instance require external synchronization. The recommended pattern for sharing data between threads depends on whether the object already manages internal copy-on-write storage (Frame, String, VariantDatabase, Metadata, Buffer, JsonObject, JsonArray, XmlDocument, XmlElement) or exposes a Ptr type for explicit shared ownership: once you pass a value or Ptr to another thread, do not mutate the underlying object from the original thread.
Frame, Buffer, String, VariantDatabase (and its Metadata subclass), JsonObject, JsonArray, XmlDocument, and XmlElement are value-type handles that wrap an internal SharedPtr<Data>. Copying one is an atomic refcount bump, so a value-typed Frame (for example) is just as cheap to pass between threads as a raw Frame::Ptr was — and the mutators do copy-on-write internally so each consumer gets its own private clone the first time it writes.
For data objects that still expose a Ptr type (e.g. MediaPayload::Ptr, Image::Ptr), wrap the object in its Ptr type when handing it across threads. The atomic reference counting in SharedPtr makes the pointer itself safe to copy across threads.
When you need to share multiple related values across threads, compose them into a shareable data object and share that object via Ptr:
Simple data objects are small and cheap to copy. When sharing them across threads, just capture or pass by value — no Ptr needed:
Do not protect data objects with a Mutex as a general practice. If you find yourself wrapping a data object in a mutex, restructure so that each thread works on its own copy or uses the Ptr handoff pattern. The exception is explicitly thread-safe classes like Queue that manage their own internal synchronization.
See also: