aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-09-21 14:56:02 (GMT)
committerGitHub <noreply@github.com>2018-09-21 14:56:02 (GMT)
commit9633a727969717cca93921e15e8d020db0426342 (patch)
tree99a65497a01a22b7e4ee19ba4e4e938853827d79 /src
parentc3ded86231683afed4d80022ad18f5329fdc1e94 (diff)
parent3f18b148224d93c8673ecab0eb93c2ec8ecc5f87 (diff)
Merge pull request #27 from mchehab/video_device_selection0.20.6
Video device selection
Diffstat (limited to 'src')
-rw-r--r--src/callbacks.c465
-rw-r--r--src/callbacks.h15
-rw-r--r--src/camorama-window.c77
-rw-r--r--src/main.c116
-rw-r--r--src/v4l.c43
-rw-r--r--src/v4l.h2
6 files changed, 535 insertions, 183 deletions
diff --git a/src/callbacks.c b/src/callbacks.c
index be7a4ac..d8e31fc 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -2,10 +2,14 @@
#include "interface.h"
#include "support.h"
#include "filter.h"
+
+#include <assert.h>
+#include <ftw.h>
#include <glib/gi18n.h>
#include <config.h>
#include <pthread.h>
#include <libv4l2.h>
+#include <sys/sysmacros.h>
#define GPL_LICENSE \
"GPL version 2.\n\n" \
@@ -644,35 +648,16 @@ static inline void show_buffer(cam_t *cam)
/*
* get image from cam - does all the work ;)
*/
-gint read_timeout_func(cam_t *cam)
-{
- unsigned char *pic_buf = cam->pic_buf;
-
- v4l2_read(cam->dev, cam->pic_buf,
- (cam->width * cam->height * cam->bpp / 8));
-
- if (cam->pixformat == V4L2_PIX_FMT_YUV420) {
- yuv420p_to_rgb(cam->pic_buf, cam->tmp, cam->width, cam->height,
- cam->bpp / 8);
- pic_buf = cam->tmp;
- }
- apply_filters(cam, pic_buf);
- cam->pb = gdk_pixbuf_new_from_data(pic_buf, GDK_COLORSPACE_RGB, FALSE, 8,
- cam->width, cam->height,
- (cam->width * cam->bpp / 8),
- NULL, NULL);
-
- show_buffer(cam);
-
- return TRUE;
-}
-
gint timeout_func(cam_t *cam)
{
unsigned char *pic_buf = cam->pic_buf;
- capture_buffers(cam, cam->pic_buf,
- cam->width * cam->height * cam->bytesperline);
+ if (cam->read)
+ v4l2_read(cam->dev, cam->pic_buf,
+ (cam->width * cam->height * cam->bpp / 8));
+ else
+ capture_buffers(cam, cam->pic_buf,
+ cam->width * cam->height * cam->bytesperline);
if (cam->pixformat == V4L2_PIX_FMT_YUV420) {
yuv420p_to_rgb(cam->pic_buf, cam->tmp, cam->width, cam->height,
@@ -736,10 +721,10 @@ gint timeout_capture_func(cam_t *cam)
* maybe add a "window_state_event" handler to do the same when
* window is iconified
*/
- pt2Function(cam);
- pt2Function(cam);
- pt2Function(cam);
- pt2Function(cam);
+ timeout_func(cam);
+ timeout_func(cam);
+ timeout_func(cam);
+ timeout_func(cam);
}
memcpy(cam->tmp, cam->pic_buf,
@@ -788,3 +773,425 @@ void wb_change(GtkScale *sc1, cam_t *cam)
cam->whiteness = 256 * (int)gtk_range_get_value((GtkRange *) sc1);
v4l2_set_control(cam->dev, V4L2_CID_WHITENESS, cam->whiteness);
}
+
+/*
+ * Video device selection
+ */
+
+unsigned int n_devices = 0, n_valid_devices = 0;
+struct devnodes *devices = NULL;
+
+static int handle_video_devs(const char *file,
+ const struct stat *st,
+ int flag)
+{
+ int dev_minor, first_device = -1, fd;
+ unsigned int i;
+ struct v4l2_capability vid_cap = { 0 };
+
+
+ /* Discard devices that can't be a videodev */
+ if (!S_ISCHR(st->st_mode) || major(st->st_rdev) != 81)
+ return 0;
+
+ dev_minor = minor(st->st_rdev);
+
+ /* check if it is an already existing device */
+ if (devices) {
+ for (i = 0; i < n_devices; i++) {
+ if (dev_minor == devices[i].minor) {
+ first_device = i;
+ break;
+ }
+ }
+ }
+
+ devices = realloc(devices, (n_devices + 1) * sizeof(struct devnodes));
+ if (!devices) {
+ char *msg = g_strdup_printf(_("Can't allocate memory to store devices"));
+ error_dialog(msg);
+ g_free(msg);
+ exit(0);
+ }
+ memset(&devices[n_devices], 0, sizeof(struct devnodes));
+
+ if (first_device < 0) {
+ fd = v4l2_open(file, O_RDWR);
+ if (fd < 0) {
+ devices[n_devices].is_valid = FALSE;
+ } else {
+ if (v4l2_ioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1) {
+ devices[n_devices].is_valid = FALSE;
+ } else if (!(vid_cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ devices[n_devices].is_valid = FALSE;
+ } else {
+ n_valid_devices++;
+ devices[n_devices].is_valid = TRUE;
+ }
+ }
+
+ v4l2_close(fd);
+ } else {
+ devices[n_devices].is_valid = devices[first_device].is_valid;
+ }
+
+ devices[n_devices].fname = g_strdup(file);
+ devices[n_devices].minor = dev_minor;
+ n_devices++;
+
+ return(0);
+}
+
+/*
+ * Sort order:
+ *
+ * - Valid devices comes first
+ * - Lowest minors comes first
+ *
+ * For devnode names, it sorts on this order:
+ * - custom udev given names
+ * - /dev/v4l/by-id/
+ * - /dev/v4l/by-path/
+ * - /dev/video
+ * - /dev/char/
+ *
+ * - Device name is sorted alphabetically if follows same pattern
+ */
+static int sort_devices(const void *__a, const void *__b)
+{
+ const struct devnodes *a = __a;
+ const struct devnodes *b = __b;
+ int val_a, val_b;
+
+ if (a->is_valid != b->is_valid)
+ return !a->is_valid - !b->is_valid;
+
+ if (a->minor != b->minor)
+ return a->minor - b->minor;
+
+ /* Ensure that /dev/video* devices will stay at the top */
+
+ if (strstr(a->fname, "by-id"))
+ val_a = 1;
+ if (strstr(a->fname, "by-path"))
+ val_a = 2;
+ else if (strstr(a->fname, "/dev/video"))
+ val_a = 3;
+ else if (strstr(a->fname, "char"))
+ val_a = 4;
+ else /* Customized names comes first */
+ val_a = 0;
+
+ if (strstr(b->fname, "by-id"))
+ val_b = 1;
+ if (strstr(b->fname, "by-path"))
+ val_b = 2;
+ else if (strstr(b->fname, "/dev/video"))
+ val_b = 3;
+ else if (strstr(b->fname, "char"))
+ val_b = 4;
+ else /* Customized names comes first */
+ val_b = 0;
+
+ if (val_a != val_b)
+ return val_a - val_b;
+
+ /* Finally, just use alphabetic order */
+ return strcmp(a->fname, b->fname);
+}
+
+static void videodev_response(GtkDialog *dialog,
+ cam_t *cam)
+{
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET(gtk_builder_get_object(cam->xml, "videodev_window"));
+ gtk_widget_hide(widget);
+}
+
+void retrieve_video_dev(cam_t *cam)
+{
+ int last_minor = -1;
+ unsigned int i;
+ GtkWidget *widget;
+
+ /* This function is not meant to be called more than once */
+ assert (n_devices == 0);
+
+ /* Get all video devices */
+ if (ftw("/dev", handle_video_devs, 4) || !n_devices) {
+ char *msg = g_strdup_printf(_("Didn't find any camera"));
+ error_dialog(msg);
+ g_free(msg);
+ exit(0);
+ }
+ qsort(devices, n_devices, sizeof(struct devnodes), sort_devices);
+
+ if (cam->debug)
+ for (i = 0; i < n_devices; i++)
+ printf("Device[%d]: %s (%s)\n", i, devices[i].fname,
+ devices[i].is_valid ? "OK" : "NOK");
+
+ /* While we have Gtk 2 support, should be aligned with select_video_dev() */
+ widget = GTK_WIDGET(gtk_builder_get_object(cam->xml, "videodev_combo"));
+ for (i = 0; i < n_devices; i++) {
+ if (devices[i].is_valid) {
+ if (devices[i].minor == last_minor)
+ continue;
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget),
+ devices[i].fname);
+ last_minor = devices[i].minor;
+ }
+ }
+
+ widget = GTK_WIDGET(gtk_builder_get_object(cam->xml, "videodev_ok"));
+ g_signal_connect(G_OBJECT(widget), "clicked",
+ G_CALLBACK(videodev_response), cam);
+}
+
+int select_video_dev(cam_t *cam)
+{
+ GtkWidget *window, *widget;
+ int ret;
+#if GTK_MAJOR_VERSION < 3
+ unsigned int i;
+ int index, last_minor = -1, p = 0;
+#endif
+
+ /* Only ask if there are multiple cameras */
+ if (n_valid_devices == 1) {
+ cam->video_dev = devices[0].fname;
+ return 0;
+ }
+
+ /* There are multiple devices. Ask the user */
+
+ window = GTK_WIDGET(gtk_builder_get_object(cam->xml, "videodev_window"));
+ widget = GTK_WIDGET(gtk_builder_get_object(cam->xml, "videodev_combo"));
+
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0);
+
+ gtk_widget_show(window);
+
+ ret = gtk_dialog_run(GTK_DIALOG(window));
+
+#if GTK_MAJOR_VERSION >= 3
+ cam->video_dev = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget));
+#else
+ /*
+ * For whatever weird reason, gtk_combo_box_text_get_active_text()
+ * is not work with Gtk 2.24. We might implement a map, but, as we'll
+ * probably drop support for it in the future, better to use the more
+ * optimized way for Gtk 3 and Gtk 4.
+ */
+
+ index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
+
+ /* Should be aligned with the similar logic at retrieve_video_dev() */
+ for (i = 0; i < n_devices; i++) {
+ if (devices[i].is_valid) {
+ if (devices[i].minor == last_minor)
+ continue;
+ if (p == index)
+ break;
+ last_minor = devices[i].minor;
+ p++;
+ }
+ }
+ if (i < n_devices)
+ cam->video_dev = devices[i].fname;
+#endif
+
+ gtk_widget_hide(window);
+ return ret;
+}
+
+void on_change_camera(GtkWidget *widget, cam_t *cam)
+{
+ gchar *old_cam;
+
+ old_cam = g_strdup(cam->video_dev);
+ select_video_dev(cam);
+
+ /* Trivial case: nothing changed */
+ if (!strcmp(cam->video_dev, old_cam)) {
+ g_free(old_cam);
+ return;
+ }
+ g_free(old_cam);
+
+ start_camera(cam);
+}
+
+static void add_gtk_view_resolutions(cam_t *cam)
+{
+ GtkWidget *small_res, *new_res;
+ unsigned int i;
+
+ /*
+ * 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.
+ */
+
+ small_res = GTK_WIDGET(gtk_builder_get_object(cam->xml, "small"));
+
+ /* Get all supported resolutions by cam->pixformat */
+ get_supported_resolutions(cam);
+
+ if (cam->n_res > 0) {
+ for (i = 0; i < cam->n_res; i++) {
+ char name[80];
+
+ if (cam->res[i].max_fps > 0)
+ sprintf(name, _("%dx%d (max %.1f fps)"),
+ cam->res[i].x, cam->res[i].y,
+ (double)cam->res[i].max_fps);
+ else
+ 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_container_add(GTK_CONTAINER(GTK_WIDGET(gtk_builder_get_object(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 {
+ g_signal_connect(gtk_builder_get_object(cam->xml, "small"),
+ "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_container_add(GTK_CONTAINER(GTK_WIDGET(gtk_builder_get_object(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_container_add(GTK_CONTAINER(GTK_WIDGET(gtk_builder_get_object(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");
+ }
+}
+
+void start_camera(cam_t *cam)
+{
+ unsigned int bufsize;
+ GList *children, *iter;
+ GtkWidget *widget, *container;
+
+ /* First step: free used resources, if any */
+
+ if (cam->idle_id) {
+ g_source_remove(cam->idle_id);
+ cam->idle_id = 0;
+ }
+
+ if (cam->dev >= 0) {
+ if (cam->read == FALSE)
+ stop_streaming(cam);
+
+ cam->pb = NULL;
+
+ v4l2_close(cam->dev);
+ }
+
+ if (cam->timeout_id) {
+ g_source_remove(cam->timeout_id);
+ cam->timeout_id = 0;
+ }
+
+ if (cam->pic_buf) {
+ free(cam->pic_buf);
+ cam->pic_buf = NULL;
+ }
+
+ if (cam->tmp) {
+ free(cam->tmp);
+ cam->tmp = NULL;
+ }
+
+ /* Reset also frame counts, as the new camera can use a different fps */
+ frames = 0;
+ frames2 = 0;
+ seconds = 0;
+
+ /* Second step: clean-up all resolutions */
+
+ container = GTK_WIDGET(gtk_builder_get_object(cam->xml, "menuitem4_menu"));
+ children = gtk_container_get_children(GTK_CONTAINER(container));
+ for (iter = children; iter != NULL; iter = g_list_next(iter)) {
+ widget = GTK_WIDGET(iter->data);
+ if (strstr(gtk_widget_get_name(widget), "x"))
+ gtk_widget_destroy(widget);
+ }
+
+ /* Third step: allocate them again */
+
+ if (cam->read)
+ cam->dev = v4l2_open(cam->video_dev, O_RDWR);
+ else
+ cam->dev = v4l2_open(cam->video_dev, O_RDWR | O_NONBLOCK);
+
+ if (camera_cap(cam))
+ exit(-1);
+
+ get_win_info(cam);
+
+ set_win_info(cam);
+ get_win_info(cam);
+
+ /* get picture attributes */
+ get_pic_info(cam);
+
+ /* Only store the device name after being able to successfully use it */
+ g_settings_set_string(cam->gc, CAM_SETTINGS_DEVICE, cam->video_dev);
+
+ bufsize = cam->max_width * cam->max_height * cam->bpp / 8;
+ cam->pic_buf = malloc(bufsize);
+ cam->tmp = malloc(bufsize);
+
+ if (!cam->pic_buf || !cam->tmp) {
+ printf("Failed to allocate memory for buffers\n");
+ exit(0);
+ }
+
+ if (cam->read == FALSE)
+ start_streaming(cam);
+ else
+ printf("using read()\n");
+
+ cam->idle_id = g_idle_add((GSourceFunc) timeout_func, (gpointer) cam);
+
+ if (cam->debug == TRUE)
+ print_cam(cam);
+
+ /* Add resolutions */
+ add_gtk_view_resolutions(cam);
+
+ /* Adjust image scale */
+ set_image_scale(cam);
+}
diff --git a/src/callbacks.h b/src/callbacks.h
index 678d261..273743c 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -4,6 +4,15 @@
#include "v4l.h"
#include "fileio.h"
+struct devnodes {
+ char *fname;
+ int minor;
+ gboolean is_valid;
+};
+
+extern unsigned int n_devices, n_valid_devices;
+extern struct devnodes *devices;
+
G_BEGIN_DECLS
void on_change_size_activate(GtkWidget * widget, cam_t *cam);
@@ -28,7 +37,6 @@ void rjpg_func(GtkWidget *, cam_t *);
void rpng_func(GtkWidget *, cam_t *);
void draw_callback(GtkWidget *, cairo_t *, cam_t *cam);
-gint(*pt2Function) (cam_t *);
void rppm_func(GtkWidget *, cam_t *);
void on_preferences1_activate(GtkMenuItem *menuitem, gpointer user_data);
void on_about_activate(GtkMenuItem *menuitem, cam_t *cam);
@@ -42,7 +50,6 @@ void capture_func(GtkWidget *, cam_t *);
gint timeout_capture_func(cam_t *);
gint fps(GtkWidget *);
gint timeout_func(cam_t *);
-gint read_timeout_func(cam_t *);
void edge_func1(GtkToggleButton *, gpointer);
void sobel_func(GtkToggleButton *, gpointer);
void fix_colour_func(GtkToggleButton *, char *);
@@ -64,6 +71,10 @@ void wb_change(GtkScale *, cam_t *);
gboolean on_drawingarea_expose_event(GtkWidget *, GdkEventExpose *,
cam_t *);
void set_image_scale(cam_t *cam);
+void retrieve_video_dev(cam_t *cam);
+int select_video_dev(cam_t *cam);
+void on_change_camera(GtkWidget *widget, cam_t *cam);
+void start_camera(cam_t *cam);
G_END_DECLS
diff --git a/src/camorama-window.c b/src/camorama-window.c
index 33fd847..2a28fae 100644
--- a/src/camorama-window.c
+++ b/src/camorama-window.c
@@ -196,7 +196,7 @@ void load_interface(cam_t *cam)
unsigned int i;
GdkPixbuf *logo = NULL;
GtkCellRenderer *cell;
- GtkWidget *small_res, *new_res;
+ GtkWidget *video_dev;
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(cam->xml,
"main_window"));
GtkTreeView *treeview;
@@ -205,6 +205,8 @@ void load_interface(cam_t *cam)
gtk_application_add_window(cam->app, GTK_WINDOW(window));
#endif
+ gtk_widget_show(window);
+
prefswindow = GTK_WIDGET(gtk_builder_get_object(cam->xml, "prefswindow"));
menu_item_filter_type = g_quark_from_static_string("camorama-menu-item-filter-type");
@@ -266,72 +268,11 @@ void load_interface(cam_t *cam)
"toggled", G_CALLBACK(on_show_adjustments_activate),
cam);
- /*
- * 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.
- */
-
- small_res = GTK_WIDGET(gtk_builder_get_object(cam->xml, "small"));
-
- /* Get all supported resolutions by cam->pixformat */
- get_supported_resolutions(cam);
-
- if (cam->n_res > 0) {
- for (i = 0; i < cam->n_res; i++) {
- char name[80];
-
- if (cam->res[i].max_fps > 0)
- sprintf(name, _("%dx%d (max %.1f fps)"),
- cam->res[i].x, cam->res[i].y,
- (double)cam->res[i].max_fps);
- else
- 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_container_add(GTK_CONTAINER(GTK_WIDGET(gtk_builder_get_object(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 {
- g_signal_connect(gtk_builder_get_object(cam->xml, "small"),
- "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_container_add(GTK_CONTAINER(GTK_WIDGET(gtk_builder_get_object(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_container_add(GTK_CONTAINER(GTK_WIDGET(gtk_builder_get_object(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");
+ if (n_valid_devices > 1) {
+ video_dev = GTK_WIDGET(gtk_builder_get_object(cam->xml, "change_camera"));
+ gtk_widget_show(video_dev);
+ g_signal_connect(video_dev, "activate",
+ G_CALLBACK(on_change_camera), cam);
}
//g_signal_connect(cam->xml, "capture_func", G_CALLBACK(on_change_size_activate), cam);
@@ -555,6 +496,4 @@ void load_interface(cam_t *cam)
set_sensitive(cam);
gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(cam->xml, "string_entry")),
cam->usestring);
-
- set_image_scale(cam);
}
diff --git a/src/main.c b/src/main.c
index b38d368..913669c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,10 +11,11 @@
#include <glib/gi18n.h>
#include <locale.h>
#include <libv4l2.h>
+#include <stdlib.h>
static int ver = 0, max = 0, min;
-static int half = 0, use_read = 0, buggery = 0;
-static gchar *poopoo = NULL;
+static int half = 0, use_read = 0, debug = 0;
+static gchar *video_dev = NULL;
static int x = 0, y = 0;
#pragma GCC diagnostic push
@@ -23,9 +24,9 @@ static int x = 0, y = 0;
static GOptionEntry options[] = {
{"version", 'V', 0, G_OPTION_ARG_NONE, &ver,
N_("show version and exit"), NULL},
- {"device", 'd', 0, G_OPTION_ARG_STRING, &poopoo,
+ {"device", 'd', 0, G_OPTION_ARG_STRING, &video_dev,
N_("v4l device to use"), NULL},
- {"debug", 'D', 0, G_OPTION_ARG_NONE, &buggery,
+ {"debug", 'D', 0, G_OPTION_ARG_NONE, &debug,
N_("enable debugging code"), NULL},
{"width", 'x', 0, G_OPTION_ARG_INT, &x,
N_("capture width"), NULL},
@@ -106,9 +107,8 @@ static void activate(GtkApplication *app)
#endif
{
cam_t *cam = &cam_object;
- GSettings *gc;
GtkWidget *widget, *window;
- unsigned int bufsize;
+ unsigned int i;
/* set some default values */
cam->frame_number = 0;
@@ -120,6 +120,7 @@ static void activate(GtkApplication *app)
cam->res = NULL;
cam->n_res = 0;
cam->scale = 1.f;
+ cam->dev = -1;
#if GTK_MAJOR_VERSION >= 3
cam->app = app;
#endif
@@ -127,7 +128,7 @@ static void activate(GtkApplication *app)
/* gtk is initialized now */
camorama_filters_init();
- cam->debug = buggery;
+ cam->debug = debug;
get_geometry(cam);
@@ -148,19 +149,59 @@ static void activate(GtkApplication *app)
printf("Forcing read mode\n");
cam->read = TRUE;
}
- gc = g_settings_new(CAM_SETTINGS_SCHEMA);
- cam->gc = gc;
- if (!poopoo) {
- gchar const *gconf_device = g_settings_get_string(cam->gc, CAM_SETTINGS_DEVICE);
+ cam->xml = gtk_builder_new();
+
+ if (!gtk_builder_add_from_file(cam->xml,
+ PACKAGE_DATA_DIR "/camorama/" CAMORAMA_UI,
+ NULL)) {
+ error_dialog(_("Couldn't load builder file"));
+ exit(1);
+ }
+
+ retrieve_video_dev(cam);
+
+ cam->gc = g_settings_new(CAM_SETTINGS_SCHEMA);
+
+ if (!video_dev) {
+ gchar const *gconf_device = g_settings_get_string(cam->gc,
+ CAM_SETTINGS_DEVICE);
if (gconf_device)
cam->video_dev = g_strdup(gconf_device);
else
- cam->video_dev = g_strdup("/dev/video0");
+ cam->video_dev = NULL;
} else {
- cam->video_dev = g_strdup(poopoo);
+ cam->video_dev = g_strdup(video_dev);
}
+ if (cam->video_dev) {
+ for (i = 0; i < n_devices; i++)
+ if (!strcmp(cam->video_dev, devices[i].fname) && devices[i].is_valid)
+ break;
+
+ /* Not found, or doesn't work. Falling back to the first device */
+ if (i == n_devices) {
+ char *msg;
+
+ if (n_valid_devices == 1)
+ msg = g_strdup_printf(_("%s not found. Falling back to %s"),
+ cam->video_dev, devices[0].fname);
+ else
+ msg = g_strdup_printf(_("%s not found."),
+ cam->video_dev);
+ error_dialog(msg);
+ g_free(msg);
+
+ /* Ask user or get the only one device, if it is the case */
+ select_video_dev(cam);
+ }
+ } else {
+ cam->video_dev = devices[0].fname;
+ }
+
+ if (cam->debug)
+ printf("Using videodev: %s\n", cam->video_dev);
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
cam->date_format = "%Y-%m-%d %H:%M:%S";
@@ -206,49 +247,7 @@ static void activate(GtkApplication *app)
else
cam->height = g_settings_get_int(cam->gc, CAM_SETTINGS_HEIGHT);
- if (use_read)
- cam->dev = v4l2_open(cam->video_dev, O_RDWR);
- else
- cam->dev = v4l2_open(cam->video_dev, O_RDWR | O_NONBLOCK);
-
- camera_cap(cam);
- get_win_info(cam);
-
- set_win_info(cam);
- get_win_info(cam);
-
- /* get picture attributes */
- get_pic_info(cam);
-
- bufsize = cam->max_width * cam->max_height * cam->bpp / 8;
- cam->pic_buf = malloc(bufsize);
- cam->tmp = malloc(bufsize);
-
- if (!cam->pic_buf || !cam->tmp) {
- printf("Failed to allocate memory for buffers\n");
- exit(0);
- }
- //cam->read = FALSE;
- /* initialize cam and create the window */
-
- if (cam->read == FALSE) {
- pt2Function = timeout_func;
- start_streaming(cam);
- } else {
- printf("using read()\n");
- pt2Function = read_timeout_func;
- }
-
- cam->xml = gtk_builder_new();
-
- if (!gtk_builder_add_from_file(cam->xml,
- PACKAGE_DATA_DIR "/camorama/" CAMORAMA_UI,
- NULL)) {
- error_dialog(_("Couldn't load builder file"));
- exit(1);
- }
-
- g_settings_set_string(cam->gc, CAM_SETTINGS_DEVICE, cam->video_dev);
+ start_camera(cam);
load_interface(cam);
@@ -265,12 +264,7 @@ static void activate(GtkApplication *app)
gtk_widget_show(widget);
- cam->idle_id = g_idle_add((GSourceFunc) pt2Function, (gpointer) cam);
-
cam->timeout_fps_id = g_timeout_add(2000, (GSourceFunc) fps, cam->status);
-
- if (cam->debug == TRUE)
- print_cam(cam);
}
int main(int argc, char *argv[])
diff --git a/src/v4l.c b/src/v4l.c
index 6af1d88..c5aa797 100644
--- a/src/v4l.c
+++ b/src/v4l.c
@@ -71,7 +71,7 @@ static int sort_func(const void *__b, const void *__a)
static float get_max_fps_discrete(cam_t *cam,
struct v4l2_frmsizeenum *frmsize)
{
- struct v4l2_frmivalenum frmival;
+ struct v4l2_frmivalenum frmival = { 0 };
float fps, max_fps = -1;
frmival.width = frmsize->discrete.width;
@@ -91,11 +91,16 @@ static float get_max_fps_discrete(cam_t *cam,
void get_supported_resolutions(cam_t *cam)
{
- struct v4l2_fmtdesc fmt;
- struct v4l2_frmsizeenum frmsize;
+ struct v4l2_fmtdesc fmt = { 0 };
+ struct v4l2_frmsizeenum frmsize = { 0 };
int i;
unsigned int x, y;
+ if (cam->n_res) {
+ free(cam->res);
+ cam->res = NULL;
+ cam->n_res = 0;
+ }
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
for (fmt.index = 0;
@@ -113,7 +118,7 @@ void get_supported_resolutions(cam_t *cam)
frmsize.discrete.height,
get_max_fps_discrete(cam, &frmsize));
} else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
- for (i = 0; i < 4; i++) {
+ for (i = 0; i <= 4; i++) {
x = frmsize.stepwise.min_width +
i * (frmsize.stepwise.max_width -
frmsize.stepwise.min_width) / 4;
@@ -129,7 +134,7 @@ void get_supported_resolutions(cam_t *cam)
qsort(cam->res, cam->n_res, sizeof(struct resolutions), sort_func);
}
-void camera_cap(cam_t *cam)
+int camera_cap(cam_t *cam)
{
char *msg;
int i;
@@ -139,15 +144,13 @@ void camera_cap(cam_t *cam)
/* Query device capabilities */
if (v4l2_ioctl(cam->dev, VIDIOC_QUERYCAP, &vid_cap) == -1) {
- if (cam->debug == TRUE) {
- fprintf(stderr,
- "VIDIOC_QUERYCAP -- could not get camera capabilities, exiting.....\n");
- }
- msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."),
- cam->video_dev);
+
+ msg = g_strdup_printf(_("Could not connect to video device (%s).\n"
+ "Please check connection. Error: %d"),
+ cam->video_dev, errno);
error_dialog(msg);
g_free(msg);
- exit(0);
+ return 1;
}
/* Query supported resolutions */
@@ -244,19 +247,15 @@ void camera_cap(cam_t *cam)
}
}
- if (!(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
- if (cam->debug == TRUE) {
- fprintf(stderr,
- "VIDIOC_QUERYCAP -- it is not a capture device, exiting.....\n");
- }
- msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."),
+ if (!(vid_cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ msg = g_strdup_printf(_("Device %s is not a video capture device."),
cam->video_dev);
error_dialog(msg);
g_free(msg);
- exit(0);
+ return 1;
}
- if (!(vid_cap.capabilities & V4L2_CAP_STREAMING))
+ if (!(vid_cap.device_caps & V4L2_CAP_STREAMING))
cam->read = TRUE;
strncpy(cam->name, (const char *)vid_cap.card, sizeof(cam->name));
@@ -265,12 +264,14 @@ void camera_cap(cam_t *cam)
if (cam->debug == TRUE) {
printf("\nVIDIOC_QUERYCAP\n");
printf("device name = %s\n", vid_cap.card);
- printf("device caps = 0x%08x\n", vid_cap.capabilities);
+ printf("device caps = 0x%08x\n", vid_cap.device_caps);
printf("max width = %d\n", cam->max_width);
printf("max height = %d\n", cam->max_height);
printf("min width = %d\n", cam->min_width);
printf("min height = %d\n", cam->min_height);
}
+
+ return 0;
}
void get_pic_info(cam_t *cam)
diff --git a/src/v4l.h b/src/v4l.h
index 2fc706e..69df548 100644
--- a/src/v4l.h
+++ b/src/v4l.h
@@ -102,7 +102,7 @@ typedef struct camera {
} *buffers;
} cam_t;
-void camera_cap(cam_t *);
+int camera_cap(cam_t *);
void print_cam(cam_t *);
void try_set_win_info(cam_t *cam, unsigned int *x, unsigned int *y);
void set_win_info(cam_t *cam);

Privacy Policy