aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-07-24 12:49:09 (GMT)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-07-24 14:19:19 (GMT)
commitcbc8d0905488d9efe5c9ecb2e97076e27049c6b3 (patch)
tree51580318fbcd908b972f1fb74f90655afad41e81
parent343b5eb4ae59dbf5583de087326fa3423c923595 (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>
-rw-r--r--src/callbacks.c6
-rw-r--r--src/camorama-window.c65
-rw-r--r--src/main.c2
-rw-r--r--src/v4l.c68
-rw-r--r--src/v4l.h8
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",
diff --git a/src/main.c b/src/main.c
index 2a2bf90..6e9f175 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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");
diff --git a/src/v4l.c b/src/v4l.c
index f2eff32..5a00b13 100644
--- a/src/v4l.c
+++ b/src/v4l.c
@@ -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;
diff --git a/src/v4l.h b/src/v4l.h
index b29bb42..1469b5d 100644
--- a/src/v4l.h
+++ b/src/v4l.h
@@ -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);

Privacy Policy