fc_slot_create, fc_slot_destroy, fc_slot_open, fc_slot_close, and fc_slot_write_frame were defined in slot.c but never declared in slot.h. Any translation unit calling them without seeing a proper prototype would fall back to implicit int return (32 bits), truncating 64-bit pointers and causing SIGSEGV on dereference. This affected framecache.c (POST /slots → fc_slot_create, DELETE → fc_slot_destroy) and other callers.
106 lines
4 KiB
C
106 lines
4 KiB
C
/**
|
||
* slot.h — Framecache shared memory slot definitions.
|
||
*
|
||
* Layout per slot (/dev/shm/framecache/<slot_id>):
|
||
* [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 <stdint.h>
|
||
#include <stdatomic.h>
|
||
#include <semaphore.h>
|
||
|
||
#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");
|
||
|
||
/* Function declarations */
|
||
struct fc_slot *fc_slot_create(const char *slot_id,
|
||
uint32_t width, uint32_t height,
|
||
uint32_t fps_num, uint32_t fps_den,
|
||
uint32_t pixel_format,
|
||
const char *source_type);
|
||
void fc_slot_destroy(struct fc_slot *s);
|
||
struct fc_slot *fc_slot_open(const char *slot_id);
|
||
void fc_slot_close(struct fc_slot *s);
|
||
void fc_slot_write_frame(struct fc_slot *s,
|
||
const uint8_t *data, uint32_t size,
|
||
uint64_t pts_us);
|
||
|
||
/* Accessor functions — inline now that struct fc_slot is defined above */
|
||
static inline fc_header_t *fc_slot_header(struct fc_slot *s) { return (fc_header_t *)s->base; }
|
||
static inline const char *fc_slot_id(struct fc_slot *s) { return s->slot_id; }
|
||
static inline const char *fc_slot_shm_path(struct fc_slot *s) { return s->shm_path; }
|
||
static inline const char *fc_slot_sem_name(struct fc_slot *s) { return s->sem_name; }
|
||
|
||
/**
|
||
* 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));
|
||
}
|