summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Scally <dan.scally@ideasonboard.com>2022-11-30 13:31:08 +0000
committerDaniel Scally <dan.scally@ideasonboard.com>2022-11-30 13:48:26 +0000
commit1c18c451f3a48507e876cfdb03c0a6f2187f62cb (patch)
tree1ea466f89e854c35236b7a229981f123a6b8496d /lib
parent90955f728061d0cbec4b470849a7f564637a6e3a (diff)
lib/timer: Add timer infrastructure
Some sources simply fill the buffers passed by the USB subsystem and return them as quickly as possible. Particularly with compressed formats operating at superspeed this rapidly results in unrealistic frame rates. Add infrastructure that allows us to define a specific framerate and introduce blocking calls that constrain those sources to the framerates expected by the host. Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/meson.build1
-rw-r--r--lib/timer.c96
2 files changed, 97 insertions, 0 deletions
diff --git a/lib/meson.build b/lib/meson.build
index f6991d5..a0d67d5 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -6,6 +6,7 @@ libuvcgadget_sources = files([
'jpg-source.c',
'stream.c',
'test-source.c',
+ 'timer.c',
'uvc.c',
'v4l2.c',
'v4l2-source.c',
diff --git a/lib/timer.c b/lib/timer.c
new file mode 100644
index 0000000..6627656
--- /dev/null
+++ b/lib/timer.c
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * libuvcgadget timer utils
+ *
+ * Copyright (C) 2022 Daniel Scally
+ *
+ * Contact: Daniel Scally <dan.scally@ideasonboard.com>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+#include "timer.h"
+
+struct timer {
+ int fd;
+ struct itimerspec settings;
+};
+
+struct timer *timer_new(void)
+{
+ struct timer *timer;
+
+ timer = malloc(sizeof(*timer));
+ if (!timer)
+ return NULL;
+
+ memset(timer, 0, sizeof(*timer));
+
+ timer->fd = timerfd_create(CLOCK_REALTIME, 0);
+ if (timer->fd < 0) {
+ fprintf(stderr, "failed to create timer: %s (%d)\n",
+ strerror(errno), errno);
+ goto err_free_timer;
+ }
+
+ return timer;
+
+err_free_timer:
+ free(timer);
+
+ return NULL;
+}
+
+void timer_set_fps(struct timer *timer, int fps)
+{
+ int ns_per_frame = 1000000000 / fps;
+
+ timer->settings.it_value.tv_nsec = ns_per_frame;
+ timer->settings.it_interval.tv_nsec = ns_per_frame;
+}
+
+int timer_arm(struct timer *timer)
+{
+ int ret;
+
+ ret = timerfd_settime(timer->fd, 0, &timer->settings, NULL);
+ if (ret)
+ fprintf(stderr, "failed to change timer settings: %s (%d)\n",
+ strerror(errno), errno);
+
+ return ret;
+}
+
+int timer_disarm(struct timer *timer)
+{
+ static const struct itimerspec disable_settings = {
+ { 0, 0 },
+ { 0, 0 },
+ };
+ int ret;
+
+ ret = timerfd_settime(timer->fd, 0, &disable_settings, NULL);
+ if (ret)
+ fprintf(stderr, "failed to disable timer: %s (%d)\n",
+ strerror(errno), errno);
+
+ return ret;
+}
+
+void timer_wait(struct timer *timer)
+{
+ char read_buf[8];
+
+ read(timer->fd, read_buf, 8);
+}
+
+void timer_destroy(struct timer *timer)
+{
+ close(timer->fd);
+ free(timer);
+}