summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-02-24 23:56:53 -0500
committerpommicket <pommicket@gmail.com>2025-02-25 15:16:08 -0500
commite8c5a90014982f423fbdcd3f8b3e7edacdb4b91c (patch)
tree8ecea8dfe07421691707aa7a20d527d544e7b373
parentcfd34de0dbedc7c2aca2c03853ddbd4489a1244e (diff)
adjustable framerate
-rw-r--r--camera.c7
-rw-r--r--main.c63
2 files changed, 52 insertions, 18 deletions
diff --git a/camera.c b/camera.c
index 871a06a..ed0510d 100644
--- a/camera.c
+++ b/camera.c
@@ -251,6 +251,10 @@ uint32_t *camera_get_pixfmts(Camera *camera) {
PictureFormat camera_closest_picfmt(Camera *camera, PictureFormat desired) {
PictureFormat best_format = {0};
int32_t best_score = INT32_MIN;
+ if (desired.pixfmt == 0) {
+ // sensible default
+ desired.pixfmt = V4L2_PIX_FMT_RGB24;
+ }
arr_foreach_ptr(camera->formats, const PictureFormat, fmt) {
int32_t score = 0;
if (fmt->pixfmt != desired.pixfmt) {
@@ -796,7 +800,8 @@ bool camera_set_format(Camera *camera, PictureFormat picfmt, int desired_framera
}
if (!force
&& camera->access_method == access
- && picture_format_cmp_qsort((PictureFormat[1]) { camera_picture_format(camera) }, &picfmt) == 0) {
+ && picture_format_cmp_qsort((PictureFormat[1]) { camera_picture_format(camera) }, &picfmt) == 0
+ && (desired_framerate == 0 || camera->framerate == desired_framerate)) {
// no changes needed
return true;
}
diff --git a/main.c b/main.c
index 9267228..a731874 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,6 @@
/*
TODO
--adjustable camera framerate
+-figure out why audio is broken for low framerate videos
-save/restore settings
*/
#define _GNU_SOURCE
@@ -87,6 +87,7 @@ typedef struct {
int32_t image_resolution[2];
int32_t video_resolution[2];
int video_framerate;
+ int image_framerate;
ImageFormat image_format;
char *output_dir;
} Settings;
@@ -136,23 +137,31 @@ static void APIENTRY gl_message_callback(GLenum source, GLenum type, unsigned in
}
#endif
-static PictureFormat settings_desired_picture_format(State *state) {
+static PictureFormat settings_picture_format_for_camera(State *state, Camera *camera) {
Settings *settings = &state->settings;
- return (PictureFormat) {
+ PictureFormat picfmt = {
.width = state->mode == MODE_VIDEO ? settings->video_resolution[0] : settings->image_resolution[0],
.height = state->mode == MODE_VIDEO ? settings->video_resolution[1] : settings->image_resolution[1],
.pixfmt = settings->pixel_format
};
-}
-
-static PictureFormat settings_picture_format_for_camera(State *state, Camera *camera) {
- PictureFormat picfmt = settings_desired_picture_format(state);
- return camera_closest_picfmt(camera, picfmt);
+ if (state->mode == MODE_VIDEO && (!picfmt.width || !picfmt.height)) {
+ // default for video
+ picfmt.width = 1280;
+ picfmt.height = 720;
+ }
+ if (state->mode == MODE_VIDEO)
+ picfmt.pixfmt = V4L2_PIX_FMT_YUV420;
+ picfmt = camera_closest_picfmt(camera, picfmt);
+ if (state->mode == MODE_VIDEO)
+ picfmt.pixfmt = V4L2_PIX_FMT_YUV420;
+ return picfmt;
}
static int settings_desired_framerate(State *state) {
Settings *settings = &state->settings;
- return state->mode == MODE_VIDEO ? settings->video_framerate : 0;
+ // by default, aim for 30FPS for video (60FPS may be too much to handle)
+ int video_framerate = settings->video_framerate ? settings->video_framerate : 30;
+ return state->mode == MODE_VIDEO ? video_framerate : settings->image_framerate;
}
// compile a GLSL shader
@@ -435,6 +444,29 @@ static void menu_select(State *state) {
} else if (state->curr_menu == MENU_SET_OUTPUT_DIR) {
state->curr_menu = MENU_MAIN;
state->menu_needs_rerendering = true;
+ } else if (state->curr_menu == MENU_FRAMERATE) {
+ int sel = state->menu_sel[MENU_FRAMERATE];
+ int framerate = INT_MAX;
+ if (sel > 0) {
+ uint64_t supported = camera_framerates_supported(state->camera);
+ for (framerate = 0; framerate < 64; framerate++) {
+ if (supported & ((uint64_t)1 << framerate)) {
+ if (--sel == 0) {
+ break;
+ }
+ }
+ }
+ }
+ if (framerate < 64) {
+ PictureFormat picfmt = settings_picture_format_for_camera(state, state->camera);
+ if (state->mode == MODE_VIDEO)
+ settings->video_framerate = framerate;
+ else
+ settings->image_framerate = framerate;
+ camera_set_format(state->camera, picfmt, framerate, 0, false);
+ }
+ state->curr_menu = MENU_MAIN;
+ state->menu_needs_rerendering = true;
}
}
@@ -659,10 +691,10 @@ static bool take_picture(State *state) {
break;
case MODE_VIDEO:
if (state->camera) {
- // TODO: adjustable video quality and framerate
+ // TODO: adjustable video quality
success = video_start(state->video, path,
camera_frame_width(state->camera), camera_frame_height(state->camera),
- 30, 5);
+ camera_framerate(state->camera), 5);
}
break;
case MODE_COUNT:
@@ -1035,6 +1067,8 @@ void main() {\n\
// our special camera got disconnected ):
video_stop(state->video);
state->camera = NULL;
+ if (state->curr_menu != MENU_HELP)
+ state->curr_menu = 0;
}
for (size_t i = 0; i < arr_len(state->cameras); ) {
if (strcmp(camera_devnode(state->cameras[i]), devnode) == 0) {
@@ -1093,12 +1127,7 @@ void main() {\n\
0, false);
break;
case MODE_VIDEO: {
- PictureFormat desired = settings_desired_picture_format(state);
- desired.pixfmt = V4L2_PIX_FMT_YUV420;
- // default to 720p for video
- if (!desired.width) desired.width = 1280;
- if (!desired.height) desired.height = 720;
- PictureFormat picfmt = camera_closest_picfmt(state->camera, desired);
+ PictureFormat picfmt = settings_picture_format_for_camera(state, state->camera);
// force V4L2 to do the conversion if we have to
picfmt.pixfmt = V4L2_PIX_FMT_YUV420;
camera_set_format(state->camera, picfmt, settings_desired_framerate(state), 0, false);