diff options
author | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2018-07-24 09:49:09 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2018-07-24 11:19:19 -0300 |
commit | cbc8d0905488d9efe5c9ecb2e97076e27049c6b3 (patch) | |
tree | 51580318fbcd908b972f1fb74f90655afad41e81 /src | |
parent | 343b5eb4ae59dbf5583de087326fa3423c923595 (diff) |
Allow selecting the image resolution instead of "small/midium/large"resolution_improvement
The concept of small, midium, large is relative, as it depends on
whatever the camera supports.
Instead of using it, it is a way better to show a list of the
supported resolutions. That works fine for most cameras, with
uses a fixed set.
On cameras with a scale, the Kernel actually exports the resolution
range. On this case, let's present 4 resolutions between the
minimum and maximum one. That should be reasonable for most
usecases.
Nowadays, all drivers should be reporting resolutions via
VIDIOC_ENUM_FRAMESIZES. Yet, as one might run camorama with
very legacy kernels, provide backward support, using
small/midium/large resolutions just like before.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/callbacks.c | 6 | ||||
-rw-r--r-- | src/camorama-window.c | 65 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/v4l.c | 68 | ||||
-rw-r--r-- | src/v4l.h | 8 |
5 files changed, 129 insertions, 20 deletions
diff --git a/src/callbacks.c b/src/callbacks.c index 3db9ba5..0b7aaa1 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -364,7 +364,7 @@ void on_change_size_activate (GtkWidget * widget, cam * cam) { gchar const *name; gchar *title; - int width, height; + int width = 0, height = 0; name = gtk_widget_get_name (widget); @@ -374,9 +374,11 @@ void on_change_size_activate (GtkWidget * widget, cam * cam) } else if (strcmp (name, "medium") == 0) { width = cam->max_width / 2; height = cam->max_height / 2; - } else { + } else if (strcmp (name, "large") == 0) { width = cam->max_width; height = cam->max_height; + } else { + sscanf(name, "%dx%d", &width, &height); } try_set_win_info(cam, &width, &height); diff --git a/src/camorama-window.c b/src/camorama-window.c index d08e29c..3018e1a 100644 --- a/src/camorama-window.c +++ b/src/camorama-window.c @@ -275,28 +275,57 @@ load_interface(cam* cam) { /* - * Just one resolution is at the XML files. The other ones are - * dynamically-created + * Dynamically generate the resolutions based on what the camera + * actually supports. Provide a fallback method, if the camera driver + * is too old and doesn't support formats enumeration. */ - glade_xml_signal_connect_data (cam->xml, "activate", - G_CALLBACK (on_change_size_activate), cam); - small_res = glade_xml_get_widget (cam->xml, "small"); - new_res = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(small_res), "Medium"); - gtk_menu_append(GTK_MENU(glade_xml_get_widget (cam->xml, "menuitem4_menu")), new_res); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_res), FALSE); - gtk_widget_show (new_res); - g_signal_connect(new_res, "activate", G_CALLBACK (on_change_size_activate), cam); - gtk_widget_set_name(new_res, "medium"); - - new_res = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(small_res), "Large"); - gtk_menu_append(GTK_MENU(glade_xml_get_widget (cam->xml, "menuitem4_menu")), new_res); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_res), FALSE); - gtk_widget_show (new_res); - g_signal_connect(new_res, "activate", G_CALLBACK (on_change_size_activate), cam); - gtk_widget_set_name(new_res, "large"); + /* Get all supported resolutions by cam->pixformat */ + get_supported_resolutions(cam); + + if (cam->n_res > 0) { + int i; + + for (i = 0; i < cam->n_res; i++) { + char name[32]; + + sprintf(name, "%dx%d", cam->res[i].x, cam->res[i].y); + + new_res = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(small_res), name); + gtk_menu_append(GTK_MENU(glade_xml_get_widget (cam->xml, "menuitem4_menu")), new_res); + gtk_widget_show (new_res); + g_signal_connect(new_res, "activate", + G_CALLBACK (on_change_size_activate), cam); + gtk_widget_set_name(new_res, name); + + if (cam->width == cam->res[i].x && cam->height == cam->res[i].y) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_res), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_res), FALSE); + } + + /* We won't actually use the small res */ + gtk_widget_hide (small_res); + } else { + glade_xml_signal_connect_data (cam->xml, "activate", + G_CALLBACK (on_change_size_activate), cam); + + new_res = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(small_res), "Medium"); + gtk_menu_append(GTK_MENU(glade_xml_get_widget (cam->xml, "menuitem4_menu")), new_res); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_res), FALSE); + gtk_widget_show (new_res); + g_signal_connect(new_res, "activate", G_CALLBACK (on_change_size_activate), cam); + gtk_widget_set_name(new_res, "medium"); + + new_res = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(small_res), "Large"); + gtk_menu_append(GTK_MENU(glade_xml_get_widget (cam->xml, "menuitem4_menu")), new_res); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_res), FALSE); + gtk_widget_show (new_res); + g_signal_connect(new_res, "activate", G_CALLBACK (on_change_size_activate), cam); + gtk_widget_set_name(new_res, "large"); + } //glade_xml_signal_connect_data(cam->xml, "capture_func", G_CALLBACK(on_change_size_activate), cam); glade_xml_signal_connect_data (cam->xml, "capture_func", @@ -106,6 +106,8 @@ main(int argc, char *argv[]) { cam->read = FALSE; cam->width = 0; cam->height = 0; + cam->res = NULL; + cam->n_res = 0; bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); @@ -2,6 +2,7 @@ #include<time.h> #include<errno.h> #include<gnome.h> +#include<stdlib.h> #include <sys/select.h> #include "support.h" @@ -20,6 +21,73 @@ void print_cam(cam *cam){ } +void insert_resolution(cam * cam, int x, int y) +{ + int i; + + try_set_win_info(cam, &x, &y); + for (i = 0; i++; i < cam->n_res) { + if (cam->res[i].x == x && cam->res[i].y == y) + return; + } + + cam->res = realloc(cam->res, (cam->n_res + 1) * sizeof(struct resolutions)); + + cam->res[cam->n_res].x = x; + cam->res[cam->n_res].y = y; + cam->n_res++; +} + +static int sort_func(const void *__b, + const void *__a) +{ + const struct resolutions *a = __a; + const struct resolutions *b = __b; + int r; + + r = b->x - a->x; + if (!r) + r = b->y - a->y; + + return r; +} + +void get_supported_resolutions(cam * cam) +{ + struct v4l2_fmtdesc fmt; + struct v4l2_frmsizeenum frmsize; + struct v4l2_frmivalenum frmival; + int i, x, y; + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + for (fmt.index = 0; + !v4l2_ioctl(cam->dev, VIDIOC_ENUM_FMT, &fmt); + fmt.index++) { + if (cam->pixformat != fmt.pixelformat) + continue; + + frmsize.pixel_format = fmt.pixelformat; + frmsize.index = 0; + while (!v4l2_ioctl(cam->dev, VIDIOC_ENUM_FRAMESIZES, &frmsize)) { + if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + insert_resolution(cam, frmsize.discrete.width, + frmsize.discrete.height); + } else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + for (i = 0; i < 4; i++) { + x = frmsize.stepwise.min_width + + i * (frmsize.stepwise.max_width - frmsize.stepwise.min_width) / 4; + y = frmsize.stepwise.min_height + + i * (frmsize.stepwise.max_height - frmsize.stepwise.min_height) / 4; + insert_resolution(cam, x, y); + } + } + frmsize.index++; + } + } + qsort(cam->res, cam->n_res, sizeof(struct resolutions), sort_func); +} + void camera_cap(cam * cam) { char *msg; @@ -39,6 +39,10 @@ struct buffer_start_len { size_t length; }; +struct resolutions { + int x, y; +}; + typedef struct camera { int dev; int width; @@ -53,6 +57,9 @@ typedef struct camera { int min_width, min_height, max_width, max_height; + int n_res; + struct resolutions *res; + char *video_dev; unsigned char *image; gchar *capturefile, *rcapturefile; @@ -90,6 +97,7 @@ void try_set_win_info(cam * cam, int *x, int *y); void set_win_info (cam * cam); void get_pic_info (cam *); void get_win_info (cam *); +void get_supported_resolutions(cam * cam); void start_streaming(cam * cam); void capture_buffers(cam * cam, unsigned char *outbuf, int len); void stop_streaming(cam * cam); |