18 SET_ERRNO(ERROR_INVALID_PARAM,
"Client ID is 0");
22 video_frame_buffer_t *vfb = SAFE_CALLOC(1,
sizeof(video_frame_buffer_t), video_frame_buffer_t *);
24 vfb->client_id = client_id;
28 vfb->front_buffer = &vfb->frames[0];
29 vfb->back_buffer = &vfb->frames[1];
32 const size_t frame_size = (size_t)MAX_FRAME_BUFFER_SIZE;
36 vfb->frames[0].size = 0;
37 vfb->frames[1].size = 0;
38 vfb->frames[0].data = NULL;
39 vfb->frames[1].data = NULL;
42 vfb->allocated_buffer_size = frame_size;
49 if (!vfb->frames[0].data || !vfb->frames[1].data) {
52 if (!vfb->frames[0].data)
53 vfb->frames[0].data = SAFE_MALLOC_ALIGNED(frame_size, 64,
void *);
54 if (!vfb->frames[1].data)
55 vfb->frames[1].data = SAFE_MALLOC_ALIGNED(frame_size, 64,
void *);
60 if (vfb->frames[0].data) {
61 memset(vfb->frames[0].data, 0, frame_size);
63 if (vfb->frames[1].data) {
64 memset(vfb->frames[1].data, 0, frame_size);
69 SET_ERRNO(ERROR_PLATFORM_INIT,
"Failed to initialize mutex for video frame buffer");
73 atomic_store(&vfb->new_frame_available,
false);
76 atomic_store(&vfb->total_frames_received, 0);
77 atomic_store(&vfb->total_frames_dropped, 0);
78 atomic_store(&vfb->last_frame_sequence, 0);
80 log_debug(
"Created video frame buffer for client %u with double buffering", client_id);
86 SET_ERRNO(ERROR_INVALID_PARAM,
"Video frame buffer is NULL");
94 if (vfb->frames[0].data) {
98 SAFE_FREE(vfb->frames[0].data);
101 if (vfb->frames[1].data) {
105 SAFE_FREE(vfb->frames[1].data);
129 SET_ERRNO(ERROR_INVALID_PARAM,
"Video frame buffer or active is NULL");
133 SET_ERRNO(ERROR_INVALID_STATE,
"vfb->active is not true");
138 if (atomic_load(&vfb->new_frame_available)) {
140 uint64_t drops = atomic_fetch_add(&vfb->total_frames_dropped, 1) + 1;
142 if (drops == 1 || drops % 100 == 0) {
143 log_dev_every(4500 * US_PER_MS_INT,
"Dropping frame for client %u (reader too slow, total drops: %llu)",
144 vfb->client_id, (
unsigned long long)drops);
152 mutex_lock(&vfb->swap_mutex);
153 video_frame_t *temp = vfb->front_buffer;
154 vfb->front_buffer = vfb->back_buffer;
155 vfb->back_buffer = temp;
156 mutex_unlock(&vfb->swap_mutex);
159 atomic_store(&vfb->new_frame_available,
true);
160 atomic_fetch_add(&vfb->total_frames_received, 1);
165 SET_ERRNO(ERROR_INVALID_PARAM,
"Video frame buffer is not active");
169 SET_ERRNO(ERROR_INVALID_STATE,
"vfb->active is not true");
174 atomic_exchange(&vfb->new_frame_available,
false);
179 mutex_lock(&vfb->swap_mutex);
180 const video_frame_t *result = vfb->front_buffer;
181 mutex_unlock(&vfb->swap_mutex);
187 if (!vfb || !stats) {
188 SET_ERRNO(ERROR_INVALID_PARAM,
"Video frame buffer or stats is NULL");
192 SET_ERRNO(ERROR_INVALID_STATE,
"vfb->active is not true");
196 stats->total_frames = atomic_load(&vfb->total_frames_received);
197 stats->dropped_frames = atomic_load(&vfb->total_frames_dropped);
198 stats->drop_rate = (stats->total_frames > 0) ? (
float)stats->dropped_frames / (float)stats->total_frames : 0.0f;
199 stats->avg_decode_time_ns = atomic_load(&vfb->avg_decode_time_ns);
200 stats->avg_render_time_ns = atomic_load(&vfb->avg_render_time_ns);
205 simple_frame_swap_t *sfs = SAFE_CALLOC(1,
sizeof(simple_frame_swap_t), simple_frame_swap_t *);
208 const size_t frame_size = (size_t)MAX_FRAME_BUFFER_SIZE;
209 sfs->frame_a.data = SAFE_MALLOC(frame_size,
void *);
210 sfs->frame_b.data = SAFE_MALLOC(frame_size,
void *);
212 atomic_store(&sfs->current_frame, (uintptr_t)&sfs->frame_a);
213 atomic_store(&sfs->use_frame_a,
false);
230 SET_ERRNO(ERROR_INVALID_PARAM,
"Simple frame swap or data is NULL");
235 bool use_a = atomic_load(&sfs->use_frame_a);
236 video_frame_t *write_frame = use_a ? &sfs->frame_a : &sfs->frame_b;
239 if (size <= (
size_t)MAX_FRAME_BUFFER_SIZE) {
240 SAFE_MEMCPY(write_frame->data, size, data, size);
241 write_frame->size = size;
245 atomic_store(&sfs->current_frame, (uintptr_t)write_frame);
248 atomic_store(&sfs->use_frame_a, !use_a);