Bug Summary

File:tests/video-timer.c
Warning:line 335, column 15
Value stored to 'pending_frame' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name video-timer.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/tests -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I .. -I ../cdk -I ../cdk -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/tests -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170505-43637-1 -x c video-timer.c
1#include <math.h>
2#include <ctk/ctk.h>
3
4#include "variable.h"
5
6typedef struct {
7 gdouble angle;
8 gint64 stream_time;
9 gint64 clock_time;
10 gint64 frame_counter;
11} FrameData;
12
13static FrameData *displayed_frame;
14static CtkWidget *window;
15static GList *past_frames;
16static Variable latency_error = VARIABLE_INIT{ 0.0, 0.0, 0.0 };
17static Variable time_factor_stats = VARIABLE_INIT{ 0.0, 0.0, 0.0 };
18static int dropped_frames = 0;
19static int n_frames = 0;
20
21static gboolean pll;
22static int fps = 24;
23
24/* Thread-safe frame queue */
25
26#define MAX_QUEUE_LENGTH5 5
27
28static GQueue *frame_queue;
29static GMutex frame_mutex;
30static GCond frame_cond;
31
32static void
33queue_frame (FrameData *frame_data)
34{
35 g_mutex_lock (&frame_mutex);
36
37 while (frame_queue->length == MAX_QUEUE_LENGTH5)
38 g_cond_wait (&frame_cond, &frame_mutex);
39
40 g_queue_push_tail (frame_queue, frame_data);
41
42 g_mutex_unlock (&frame_mutex);
43}
44
45static FrameData *
46unqueue_frame (void)
47{
48 FrameData *frame_data;
49
50 g_mutex_lock (&frame_mutex);
51
52 if (frame_queue->length > 0)
53 {
54 frame_data = g_queue_pop_head (frame_queue);
55 g_cond_signal (&frame_cond);
56 }
57 else
58 {
59 frame_data = NULL((void*)0);
60 }
61
62 g_mutex_unlock (&frame_mutex);
63
64 return frame_data;
65}
66
67static FrameData *
68peek_pending_frame (void)
69{
70 FrameData *frame_data;
71
72 g_mutex_lock (&frame_mutex);
73
74 if (frame_queue->head)
75 frame_data = frame_queue->head->data;
76 else
77 frame_data = NULL((void*)0);
78
79 g_mutex_unlock (&frame_mutex);
80
81 return frame_data;
82}
83
84static FrameData *
85peek_next_frame (void)
86{
87 FrameData *frame_data;
88
89 g_mutex_lock (&frame_mutex);
90
91 if (frame_queue->head && frame_queue->head->next)
92 frame_data = frame_queue->head->next->data;
93 else
94 frame_data = NULL((void*)0);
95
96 g_mutex_unlock (&frame_mutex);
97
98 return frame_data;
99}
100
101/* Frame producer thread */
102
103static gpointer
104create_frames_thread (gpointer data)
105{
106 int frame_count = 0;
107
108 while (TRUE(!(0)))
109 {
110 FrameData *frame_data = g_slice_new0 (FrameData)((FrameData*) g_slice_alloc0 (sizeof (FrameData)));
111 frame_data->angle = 2 * M_PI3.14159265358979323846 * (frame_count % fps) / (double)fps;
112 frame_data->stream_time = (G_GINT64_CONSTANT (1000000)(1000000L) * frame_count) / fps;
113
114 queue_frame (frame_data);
115 frame_count++;
116 }
117
118 return NULL((void*)0);
119}
120
121/* Clock management:
122 *
123 * The logic here, which is activated by the --pll argument
124 * demonstrates adjusting the playback rate so that the frames exactly match
125 * when they are displayed both frequency and phase. If there was an
126 * accompanying audio track, you would need to resample the audio to match
127 * the clock.
128 *
129 * The algorithm isn't exactly a PLL - I wrote it first that way, but
130 * it oscillicated before coming into sync and this approach was easier than
131 * fine-tuning the PLL filter.
132 *
133 * A more complicated algorithm could also establish sync when the playback
134 * rate isn't exactly an integral divisor of the VBlank rate, such as 24fps
135 * video on a 60fps display.
136 */
137#define PRE_BUFFER_TIME500000 500000
138
139static gint64 stream_time_base;
140static gint64 clock_time_base;
141static double time_factor = 1.0;
142static double frequency_time_factor = 1.0;
143static double phase_time_factor = 1.0;
144
145static gint64
146stream_time_to_clock_time (gint64 stream_time)
147{
148 return clock_time_base + (stream_time - stream_time_base) * time_factor;
149}
150
151static void
152adjust_clock_for_phase (gint64 frame_clock_time,
153 gint64 presentation_time)
154{
155 static gint count = 0;
156 static gint64 previous_frame_clock_time;
157 static gint64 previous_presentation_time;
158 gint64 phase = presentation_time - frame_clock_time;
159
160 count++;
161 if (count >= fps) /* Give a second of warmup */
162 {
163 gint64 time_delta = frame_clock_time - previous_frame_clock_time;
164 gint64 previous_phase = previous_presentation_time - previous_frame_clock_time;
165
166 double expected_phase_delta;
167
168 stream_time_base += (frame_clock_time - clock_time_base) / time_factor;
169 clock_time_base = frame_clock_time;
170
171 expected_phase_delta = time_delta * (1 - phase_time_factor);
172
173 /* If the phase is increasing that means the computed clock times are
174 * increasing too slowly. We increase the frequency time factor to compensate,
175 * but decrease the compensation so that it takes effect over 1 second to
176 * avoid jitter */
177 frequency_time_factor += (phase - previous_phase - expected_phase_delta) / (double)time_delta / fps;
178
179 /* We also want to increase or decrease the frequency to bring the phase
180 * into sync. We do that again so that the phase should sync up over 1 seconds
181 */
182 phase_time_factor = 1 + phase / 2000000.;
183
184 time_factor = frequency_time_factor * phase_time_factor;
185 }
186
187 previous_frame_clock_time = frame_clock_time;
188 previous_presentation_time = presentation_time;
189}
190
191/* Drawing */
192
193static gboolean
194on_window_draw (CtkWidget *widget,
195 cairo_t *cr)
196{
197 CdkRectangle allocation;
198 double cx, cy, r;
199
200 cairo_set_source_rgb (cr, 1., 1., 1.);
201 cairo_paint (cr);
202
203 cairo_set_source_rgb (cr, 0., 0., 0.);
204 ctk_widget_get_allocation (widget, &allocation);
205
206 cx = allocation.width / 2.;
207 cy = allocation.height / 2.;
208 r = MIN (allocation.width, allocation.height)(((allocation.width) < (allocation.height)) ? (allocation.
width) : (allocation.height))
/ 2.;
209
210 cairo_arc (cr, cx, cy, r,
211 0, 2 * M_PI3.14159265358979323846);
212 cairo_stroke (cr);
213 if (displayed_frame)
214 {
215 cairo_move_to (cr, cx, cy);
216 cairo_line_to (cr,
217 cx + r * cos(displayed_frame->angle - M_PI3.14159265358979323846 / 2),
218 cy + r * sin(displayed_frame->angle - M_PI3.14159265358979323846 / 2));
219 cairo_stroke (cr);
220
221 if (displayed_frame->frame_counter == 0)
222 {
223 CdkFrameClock *frame_clock = ctk_widget_get_frame_clock (window);
224 displayed_frame->frame_counter = cdk_frame_clock_get_frame_counter (frame_clock);
225 }
226 }
227
228 return FALSE(0);
229}
230
231static void
232collect_old_frames (void)
233{
234 CdkFrameClock *frame_clock = ctk_widget_get_frame_clock (window);
235 GList *l, *l_next;
236
237 for (l = past_frames; l; l = l_next)
238 {
239 FrameData *frame_data = l->data;
240 CdkFrameTimings *timings;
241 gboolean remove = FALSE(0);
242 l_next = l->next;
243
244 timings = cdk_frame_clock_get_timings (frame_clock,
245 frame_data->frame_counter);
246 if (timings == NULL((void*)0))
247 {
248 remove = TRUE(!(0));
249 }
250 else if (cdk_frame_timings_get_complete (timings))
251 {
252 gint64 presentation_time = cdk_frame_timings_get_predicted_presentation_time (timings);
253 gint64 refresh_interval = cdk_frame_timings_get_refresh_interval (timings);
254
255 if (pll &&
256 presentation_time && refresh_interval &&
257 presentation_time > frame_data->clock_time - refresh_interval / 2 &&
258 presentation_time < frame_data->clock_time + refresh_interval / 2)
259 adjust_clock_for_phase (frame_data->clock_time, presentation_time);
260
261 if (presentation_time)
262 variable_add (&latency_error,
263 presentation_time - frame_data->clock_time);
264
265 remove = TRUE(!(0));
266 }
267
268 if (remove)
269 {
270 past_frames = g_list_delete_link (past_frames, l);
271 g_slice_free (FrameData, frame_data)do { if (1) g_slice_free1 (sizeof (FrameData), (frame_data));
else (void) ((FrameData*) 0 == (frame_data)); } while (0)
;
272 }
273 }
274}
275
276static void
277print_statistics (void)
278{
279 gint64 now = g_get_monotonic_time ();
280 static gint64 last_print_time = 0;
281
282 if (last_print_time == 0)
283 last_print_time = now;
284 else if (now -last_print_time > 5000000)
285 {
286 g_print ("dropped_frames: %d/%d\n",
287 dropped_frames, n_frames);
288 g_print ("collected_frames: %g/%d\n",
289 latency_error.weight, n_frames);
290 g_print ("latency_error: %g +/- %g\n",
291 variable_mean (&latency_error),
292 variable_standard_deviation (&latency_error));
293 if (pll)
294 g_print ("playback rate adjustment: %g +/- %g %%\n",
295 (variable_mean (&time_factor_stats) - 1) * 100,
296 variable_standard_deviation (&time_factor_stats) * 100);
297 variable_init (&latency_error);
298 variable_init (&time_factor_stats);
299 dropped_frames = 0;
300 n_frames = 0;
301 last_print_time = now;
302 }
303}
304
305static void
306on_update (CdkFrameClock *frame_clock,
307 gpointer data)
308{
309 CdkFrameTimings *timings = cdk_frame_clock_get_current_timings (frame_clock);
310 gint64 frame_time = cdk_frame_timings_get_frame_time (timings);
311 gint64 predicted_presentation_time = cdk_frame_timings_get_predicted_presentation_time (timings);
312 gint64 refresh_interval;
313 FrameData *pending_frame;
314
315 if (clock_time_base == 0)
316 clock_time_base = frame_time + PRE_BUFFER_TIME500000;
317
318 cdk_frame_clock_get_refresh_info (frame_clock, frame_time,
319 &refresh_interval, NULL((void*)0));
320
321 pending_frame = peek_pending_frame ();
322 if (stream_time_to_clock_time (pending_frame->stream_time)
323 < predicted_presentation_time + refresh_interval / 2)
324 {
325 while (TRUE(!(0)))
326 {
327 FrameData *next_frame = peek_next_frame ();
328 if (next_frame &&
329 stream_time_to_clock_time (next_frame->stream_time)
330 < predicted_presentation_time + refresh_interval / 2)
331 {
332 g_slice_free (FrameData, unqueue_frame ())do { if (1) g_slice_free1 (sizeof (FrameData), (unqueue_frame
())); else (void) ((FrameData*) 0 == (unqueue_frame ())); } while
(0)
;
333 n_frames++;
334 dropped_frames++;
335 pending_frame = next_frame;
Value stored to 'pending_frame' is never read
336 }
337 else
338 break;
339 }
340
341 if (displayed_frame)
342 past_frames = g_list_prepend (past_frames, displayed_frame);
343
344 n_frames++;
345 displayed_frame = unqueue_frame ();
346 displayed_frame->clock_time = stream_time_to_clock_time (displayed_frame->stream_time);
347
348 displayed_frame->frame_counter = cdk_frame_timings_get_frame_counter (timings);
349 variable_add (&time_factor_stats, time_factor);
350
351 collect_old_frames ();
352 print_statistics ();
353
354 ctk_widget_queue_draw (window);
355 }
356}
357
358static GOptionEntry options[] = {
359 { "pll", 'p', 0, G_OPTION_ARG_NONE, &pll, "Sync frame rate to refresh", NULL((void*)0) },
360 { "fps", 'f', 0, G_OPTION_ARG_INT, &fps, "Frame rate", "FPS" },
361 { NULL((void*)0) }
362};
363
364int
365main(int argc, char **argv)
366{
367 GError *error = NULL((void*)0);
368 CdkFrameClock *frame_clock;
369
370 if (!ctk_init_with_args (&argc, &argv, "",
371 options, NULL((void*)0), &error))
372 {
373 g_printerr ("Option parsing failed: %s\n", error->message);
374 return 1;
375 }
376
377 window = ctk_window_new (CTK_WINDOW_TOPLEVEL);
378 ctk_widget_set_app_paintable (window, TRUE(!(0)));
379 ctk_window_set_default_size (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, 300, 300);
380
381 g_signal_connect (window, "draw",g_signal_connect_data ((window), ("draw"), (((GCallback) (on_window_draw
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
382 G_CALLBACK (on_window_draw), NULL)g_signal_connect_data ((window), ("draw"), (((GCallback) (on_window_draw
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
383 g_signal_connect (window, "destroy",g_signal_connect_data ((window), ("destroy"), (((GCallback) (
ctk_main_quit))), (((void*)0)), ((void*)0), (GConnectFlags) 0
)
384 G_CALLBACK (ctk_main_quit), NULL)g_signal_connect_data ((window), ("destroy"), (((GCallback) (
ctk_main_quit))), (((void*)0)), ((void*)0), (GConnectFlags) 0
)
;
385
386 ctk_widget_show (window);
387
388 frame_queue = g_queue_new ();
389 g_mutex_init (&frame_mutex);
390 g_cond_init (&frame_cond);
391
392 g_thread_new ("Create Frames", create_frames_thread, NULL((void*)0));
393
394 frame_clock = ctk_widget_get_frame_clock (window);
395 g_signal_connect (frame_clock, "update",g_signal_connect_data ((frame_clock), ("update"), (((GCallback
) (on_update))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
396 G_CALLBACK (on_update), NULL)g_signal_connect_data ((frame_clock), ("update"), (((GCallback
) (on_update))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
397 cdk_frame_clock_begin_updating (frame_clock);
398
399 ctk_main ();
400
401 return 0;
402}