aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-09-21 09:50:46 -0300
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-09-21 09:50:46 -0300
commit115a30ce7f2508c764a3fb13cf67b1f0fb5946d0 (patch)
treee64c13a63340f6eabe71cd8484d5cb09e077e005 /src
parentc17f7baf89a3ef65c4eb866adc1df65729ac548b (diff)
Add an item to allow switching cameras in realtime
When camorama detects multiple cameras, it should now be possible to swich between them in real time without stopping it. Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'src')
-rw-r--r--src/callbacks.c183
-rw-r--r--src/callbacks.h2
-rw-r--r--src/camorama-window.c74
-rw-r--r--src/main.c41
-rw-r--r--src/v4l.c11
5 files changed, 204 insertions, 107 deletions
diff --git a/src/callbacks.c b/src/callbacks.c
index 15fd1ce..a1a62a6 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -1005,3 +1005,186 @@ int select_video_dev(cam_t *cam)
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;
+ }
+
+ /* 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);
+}
diff --git a/src/callbacks.h b/src/callbacks.h
index 1ea424f..273743c 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -73,6 +73,8 @@ gboolean on_drawingarea_expose_event(GtkWidget *, GdkEventExpose *,
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 c8595a9..7832efd 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;
@@ -268,72 +268,14 @@ 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");
+ if (n_valid_devices > 1) {
+ video_dev = gtk_menu_item_new_with_label("Change camera");
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");
+ video_dev);
+ 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);
diff --git a/src/main.c b/src/main.c
index 02ce378..913669c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -108,7 +108,7 @@ static void activate(GtkApplication *app)
{
cam_t *cam = &cam_object;
GtkWidget *widget, *window;
- unsigned int bufsize, i;
+ 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
@@ -246,38 +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);
-
- 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");
+ start_camera(cam);
load_interface(cam);
@@ -294,12 +264,7 @@ static void activate(GtkApplication *app)
gtk_widget_show(widget);
- cam->idle_id = g_idle_add((GSourceFunc) timeout_func, (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 d8732c6..d54bbfb 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;

Privacy Policy