/** * slot.h — Framecache shared memory slot definitions. * * Layout per slot (/dev/shm/framecache/): * [fc_header_t — 4KB aligned] * [fc_frame_t × ring_depth — each FC_FRAME_HDR_SIZE + frame_size bytes] * * Writer advances write_cursor atomically and posts the named semaphore. * Each consumer tracks its own read_cursor independently — writer never blocks. */ #pragma once #include #include #include #define FC_MAGIC 0x46524D43u /* "FRMC" */ #define FC_VERSION 1u #define FC_RING_DEPTH 120u /* ~2s at 59.94fps */ #define FC_HEADER_SIZE 4096u /* 4KB header block */ #define FC_FRAME_HDR_SIZE 24u /* pts_us(8) + wall_us(8) + size(4) + pad(4) */ #define FC_MAX_SLOT_ID 64u /* Internal handle used by both server (writer) and client (reader) */ struct fc_slot { int shm_fd; void *base; size_t shm_size; sem_t *sem; char slot_id[FC_MAX_SLOT_ID]; char shm_path[128]; char sem_name[128]; }; /* Pixel format codes */ #define FC_PIX_UYVY422 0u typedef struct { uint32_t magic; /* FC_MAGIC */ uint32_t version; /* FC_VERSION */ uint32_t width; uint32_t height; uint32_t fps_num; uint32_t fps_den; uint32_t pixel_format; /* FC_PIX_UYVY422 */ uint32_t frame_size; /* width * height * 2 */ uint32_t ring_depth; /* FC_RING_DEPTH */ uint32_t _reserved; _Atomic uint64_t write_cursor; /* monotonically increasing frame index */ _Atomic uint64_t dropped_frames; char source_type[32]; /* "deltacast" | "blackmagic" | "srt" | "rtmp" */ char slot_id[FC_MAX_SLOT_ID]; uint8_t _pad[FC_HEADER_SIZE - 144]; } fc_header_t; /* Per-frame metadata + data (variable length — use fc_frame_at() accessor) */ typedef struct { uint64_t pts_us; uint64_t wall_us; uint32_t size; uint32_t _pad; uint8_t data[]; /* frame_size bytes */ } fc_frame_t; /* Compile-time size check */ // _Static_assert(sizeof(fc_header_t) == FC_HEADER_SIZE, // "fc_header_t must be exactly FC_HEADER_SIZE bytes"); _Static_assert(sizeof(fc_frame_t) == FC_FRAME_HDR_SIZE, "fc_frame_t header must be exactly FC_FRAME_HDR_SIZE bytes"); /* Accessor function declarations (implemented in slot.c) */ fc_header_t *fc_slot_header(struct fc_slot *s); const char *fc_slot_id(struct fc_slot *s); const char *fc_slot_shm_path(struct fc_slot *s); const char *fc_slot_sem_name(struct fc_slot *s); /** * Compute total shm size for a slot given frame_size. * = FC_HEADER_SIZE + ring_depth * (FC_FRAME_HDR_SIZE + frame_size) */ static inline size_t fc_slot_shm_size(uint32_t frame_size) { return (size_t)FC_HEADER_SIZE + (size_t)FC_RING_DEPTH * ((size_t)FC_FRAME_HDR_SIZE + frame_size); } /** * Return pointer to frame at ring index idx within a mapped shm base. */ static inline fc_frame_t *fc_frame_at(void *base, uint32_t frame_size, uint64_t idx) { uint8_t *frames = (uint8_t *)base + FC_HEADER_SIZE; return (fc_frame_t *)(frames + (idx % FC_RING_DEPTH) * ((size_t)FC_FRAME_HDR_SIZE + frame_size)); }