Blob Blame History Raw
diff --git a/data/camorama.glade b/data/camorama.glade
index 9a39cd51b9e4..196d5d705405 100644
--- a/data/camorama.glade
+++ b/data/camorama.glade
@@ -2239,7 +2239,7 @@
 	      <property name="column_spacing">6</property>
 
 	      <child>
-		<widget class="GtkHScale" id="slider2">
+		<widget class="GtkHScale" id="contrast_slider">
 		  <property name="visible">True</property>
 		  <property name="can_focus">True</property>
 		  <property name="draw_value">True</property>
@@ -2260,7 +2260,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkHScale" id="slider3">
+		<widget class="GtkHScale" id="brightness_slider">
 		  <property name="visible">True</property>
 		  <property name="can_focus">True</property>
 		  <property name="draw_value">True</property>
@@ -2282,7 +2282,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkHScale" id="slider4">
+		<widget class="GtkHScale" id="color_slider">
 		  <property name="visible">True</property>
 		  <property name="can_focus">True</property>
 		  <property name="draw_value">True</property>
@@ -2304,7 +2304,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkHScale" id="slider5">
+		<widget class="GtkHScale" id="hue_slider">
 		  <property name="visible">True</property>
 		  <property name="can_focus">True</property>
 		  <property name="draw_value">True</property>
@@ -2326,7 +2326,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkHScale" id="slider6">
+		<widget class="GtkHScale" id="balance_slider">
 		  <property name="visible">True</property>
 		  <property name="can_focus">True</property>
 		  <property name="draw_value">True</property>
@@ -2348,7 +2348,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkLabel" id="label64">
+		<widget class="GtkLabel" id="contrast_label">
 		  <property name="visible">True</property>
 		  <property name="label" translatable="yes">Contrast:</property>
 		  <property name="use_underline">False</property>
@@ -2376,7 +2376,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkLabel" id="label65">
+		<widget class="GtkLabel" id="brightness_label">
 		  <property name="visible">True</property>
 		  <property name="label" translatable="yes">Brightness:</property>
 		  <property name="use_underline">False</property>
@@ -2404,7 +2404,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkLabel" id="label66">
+		<widget class="GtkLabel" id="color_label">
 		  <property name="visible">True</property>
 		  <property name="label" translatable="yes">Color:</property>
 		  <property name="use_underline">False</property>
@@ -2432,7 +2432,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkLabel" id="label67">
+		<widget class="GtkLabel" id="hue_label">
 		  <property name="visible">True</property>
 		  <property name="label" translatable="yes">Hue:</property>
 		  <property name="use_underline">False</property>
@@ -2460,7 +2460,7 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkLabel" id="label68">
+		<widget class="GtkLabel" id="balance_label">
 		  <property name="visible">True</property>
 		  <property name="label" translatable="yes">White Balance:</property>
 		  <property name="use_underline">False</property>
diff --git a/src/Makefile.am b/src/Makefile.am
index 1531700662be..19f8fc738f27 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,7 +36,7 @@ camorama_SOURCES = \
 	filter.h	\
 	$(BUILT_SOURCES)\
 	$(NULL)
-camorama_LDADD = $(PACKAGE_LIBS) -lv4l1
+camorama_LDADD = $(PACKAGE_LIBS) -lv4l2 -lm
 
 DISTCLEANFILES=$(BUILT_SOURCES)
 
diff --git a/src/Makefile.in b/src/Makefile.in
index 7d3580cab462..8380179f47d8 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -248,7 +248,7 @@ camorama_SOURCES = \
 	$(BUILT_SOURCES)\
 	$(NULL)
 
-camorama_LDADD = $(PACKAGE_LIBS) -lv4l1
+camorama_LDADD = $(PACKAGE_LIBS) -lv4l2 -lm
 DISTCLEANFILES = $(BUILT_SOURCES)
 all: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) all-am
diff --git a/src/callbacks.c b/src/callbacks.c
index 8f86c7d29009..0b193c804266 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -9,7 +9,7 @@
 #include <libgnomeui/gnome-propertybox.h>
 #include <libgnomeui/gnome-window-icon.h>
 #include <pthread.h>
-#include <libv4l1.h>
+#include <libv4l2.h>
 
 extern GtkWidget *main_window, *prefswindow;
 //extern state func_state;
@@ -20,7 +20,6 @@ extern int seconds;
 extern GtkWidget *dentry, *entry2, *string_entry;
 extern GtkWidget *host_entry,
     *directory_entry, *filename_entry, *login_entry, *pw_entry;
-int frame;
 
 /*
  * pref callbacks
@@ -369,88 +368,41 @@ void on_change_size_activate (GtkWidget * widget, cam * cam)
     name = gtk_widget_get_name (widget);
     printf("name = %s\n",name);
     if (strcmp (name, "small") == 0) {
-        cam->x = cam->vid_cap.minwidth;
-        cam->y = cam->vid_cap.minheight;
+        cam->width = cam->min_width;
+        cam->height = cam->min_height;
         if (cam->debug) {
             printf ("\nsmall\n");
         }
     } else if (strcmp (name, "medium") == 0) {
-        cam->x = cam->vid_cap.maxwidth / 2;
-        cam->y = cam->vid_cap.maxheight / 2;
+        cam->width = cam->max_width / 2;
+        cam->height = cam->max_height / 2;
         if (cam->debug) {
             printf ("\nmed\n");
         }
     } else {
-        cam->x = cam->vid_cap.maxwidth;
-        cam->y = cam->vid_cap.maxheight;
+        cam->width = cam->max_width;
+        cam->height = cam->max_height;
         if (cam->debug) {
             printf ("\nlarge\n");
         }
     }
 
-
-    /*
-     * if(cam->read == FALSE) {
-     *  cam->pic = v4l1_mmap(0, cam->vid_buf.size, PROT_READ | PROT_WRITE, MAP_SHARED, cam->dev, 0);
-     *  
-     *  if((unsigned char *) -1 == (unsigned char *) cam->pic) {
-     *   if(cam->debug == TRUE) {
-     *   fprintf(stderr, "Unable to capture image (mmap).\n");
-     *   }
-     *   error_dialog(_("Unable to capture image."));
-     *   exit(-1);
-     *  }
-     *  }else{
-     *   cam->pic_buf = malloc(cam->x * cam->y * cam->depth);
-     *   v4l1_read(cam->dev,cam->pic,(cam->x * cam->y * 3));
-     *  } 
-     */
-
-    cam->vid_win.x = 0;
-    cam->vid_win.y = 0;
-    cam->vid_win.width = cam->x;
-    cam->vid_win.height = cam->y;
-    cam->vid_win.chromakey = 0;
-    cam->vid_win.flags = 0;
-
+    if (cam->read == FALSE)
+       stop_streaming(cam);
     set_win_info (cam);
-    // get_win_info(cam);
-    cam->vid_map.height = cam->y;
-    cam->vid_map.width = cam->x;
-    /*
-     * cam->vid_win.height = cam->y;
-     * * cam->vid_win.width = cam->x;
-     * * get_win_info(cam); 
-     */
-    cam->vid_map.format = cam->vid_pic.palette;
-    // get_win_info(cam);
-    /*
-     * if(cam->read == FALSE) {
-     * * for(frame = 0; frame < cam->vid_buf.frames; frame++) {
-     * * cam->vid_map.frame = frame;
-     * * if(v4l1_ioctl(cam->dev, VIDIOCMCAPTURE, &cam->vid_map) < 0) {
-     * * if(cam->debug == TRUE) {
-     * * fprintf(stderr, "Unable to capture image (VIDIOCMCAPTURE) during resize.\n");
-     * * }
-     * * //error_dialog(_("Unable to capture image."));
-     * * //exit(-1);
-     * * }
-     * * }
-     * * } 
-     */
-    get_win_info (cam);
+    if (cam->read == FALSE)
+       start_streaming(cam);
 
-    cam->pixmap = gdk_pixmap_new (NULL, cam->x, cam->y, cam->desk_depth);
+    cam->pixmap = gdk_pixmap_new (NULL, cam->width, cam->height, cam->desk_depth);
     gtk_widget_set_size_request (glade_xml_get_widget (cam->xml, "da"),
-                                 cam->x, cam->y);
+                                 cam->width, cam->height);
 
-    frame = 0;
     gtk_window_resize (GTK_WINDOW
                        (glade_xml_get_widget (cam->xml, "main_window")), 320,
                        240);
 
-    title = g_strdup_printf ("Camorama - %s - %dx%d", cam->vid_cap.name,
-                             cam->x, cam->y);
+    title = g_strdup_printf ("Camorama - %s - %dx%d", cam->name,
+                             cam->width, cam->height);
     gtk_window_set_title (GTK_WINDOW
                           (glade_xml_get_widget (cam->xml, "main_window")),
                           title);
@@ -530,14 +482,14 @@ static void
 apply_filters(cam* cam) {
 	/* v4l has reverse rgb order from what camora expect so call the color
 	   filter to fix things up before running the user selected filters */
-	camorama_filter_color_filter(NULL, cam->pic_buf, cam->x, cam->y, cam->depth);
-	camorama_filter_chain_apply(cam->filter_chain, cam->pic_buf, cam->x, cam->y, cam->depth);
+	camorama_filter_color_filter(NULL, cam->pic_buf, cam->width, cam->height, cam->depth);
+	camorama_filter_chain_apply(cam->filter_chain, cam->pic_buf, cam->width, cam->height, cam->depth);
 #warning "FIXME: enable the threshold channel filter"
 //	if((effect_mask & CAMORAMA_FILTER_THRESHOLD_CHANNEL)  != 0) 
-//		threshold_channel (cam->pic_buf, cam->x, cam->y, cam->dither);
+//		threshold_channel (cam->pic_buf, cam->width, cam->height, cam->dither);
 #warning "FIXME: enable the threshold filter"
 //	if((effect_mask & CAMORAMA_FILTER_THRESHOLD)  != 0) 
-//		threshold (cam->pic_buf, cam->x, cam->y, cam->dither);
+//		threshold (cam->pic_buf, cam->width, cam->height, cam->dither);
 }
 
 /*
@@ -547,24 +499,24 @@ gint
 read_timeout_func(cam* cam) {
     int i, count = 0;
     GdkGC *gc;
+    unsigned char *pic_buf = cam->pic_buf;
 
-    v4l1_read (cam->dev, cam->pic, (cam->x * cam->y * 3));
+    v4l2_read (cam->dev, cam->pic_buf, (cam->width * cam->height * cam->depth / 8));
     frames2++;
     /*
      * update_rec.x = 0;
      * update_rec.y = 0;
-     * update_rec.width = cam->x;
-     * update_rec.height = cam->y; 
+     * update_rec.width = cam->width;
+     * update_rec.height = cam->height;
      */
     count++;
     /*
      * refer the frame 
      */
-    cam->pic_buf = cam->pic;    // + cam->vid_buf.offsets[frame];
 
-    if (cam->vid_pic.palette == VIDEO_PALETTE_YUV420P) {
-        yuv420p_to_rgb (cam->pic_buf, cam->tmp, cam->x, cam->y, cam->depth);
-        cam->pic_buf = cam->tmp;
+    if (cam->pixformat == V4L2_PIX_FMT_YUV420) {
+        yuv420p_to_rgb (cam->pic_buf, cam->tmp, cam->width, cam->height, cam->depth);
+        pic_buf = cam->tmp;
     }
 
 	apply_filters(cam);
@@ -572,12 +524,12 @@ read_timeout_func(cam* cam) {
     gc = gdk_gc_new (cam->pixmap);
     gdk_draw_rgb_image (cam->pixmap,
                         gc, 0, 0,
-                        cam->vid_win.width, cam->vid_win.height,
-                        GDK_RGB_DITHER_NORMAL, cam->pic_buf,
-                        cam->vid_win.width * cam->depth);
+                        cam->width, cam->height,
+                        GDK_RGB_DITHER_NORMAL, pic_buf,
+                        cam->width * cam->depth / 8);
 
     gtk_widget_queue_draw_area (glade_xml_get_widget (cam->xml, "da"), 0,
-                                0, cam->x, cam->y);
+                                0, cam->width, cam->height);
     return 1;
 
 }
@@ -586,34 +538,17 @@ gint timeout_func (cam * cam)
 {
     int i, count = 0;
     GdkGC *gc;
+    unsigned char *pic_buf = cam->pic_buf;
 
-    i = -1;
-    while (i < 0) {
-        i = v4l1_ioctl (cam->dev, VIDIOCSYNC, &frame);
+    capture_buffers(cam, cam->pic_buf, cam->width * cam->height * cam->bytesperline);
 
-        if (i < 0 && errno == EINTR) {
-            if (cam->debug == TRUE) {
-                printf ("i = %d\n", i);
-            }
-            continue;
-        }
-        if (i < 0) {
-            if (cam->debug == TRUE) {
-                fprintf (stderr, "Unable to capture image (VIDIOCSYNC)\n");
-            }
-            error_dialog (_("Unable to capture image."));
-            exit (-1);
-        }
-        break;
-    }
     count++;
     /*
      * refer the frame 
      */
-    cam->pic_buf = cam->pic + cam->vid_buf.offsets[frame];
-    if (cam->vid_pic.palette == VIDEO_PALETTE_YUV420P) {
-        yuv420p_to_rgb (cam->pic_buf, cam->tmp, cam->x, cam->y, cam->depth);
-        cam->pic_buf = cam->tmp;
+    if (cam->pixformat == V4L2_PIX_FMT_YUV420) {
+        yuv420p_to_rgb (cam->pic_buf, cam->tmp, cam->width, cam->height, cam->depth);
+        pic_buf = cam->tmp;
     }
 
 	apply_filters(cam);
@@ -623,33 +558,12 @@ gint timeout_func (cam * cam)
 
     gdk_draw_rgb_image (cam->pixmap,
                         gc, 0, 0,
-                        cam->vid_win.width, cam->vid_win.height,
-                        GDK_RGB_DITHER_NORMAL, cam->pic_buf,
-                        cam->vid_win.width * cam->depth);
+                        cam->width, cam->height,
+                        GDK_RGB_DITHER_NORMAL, pic_buf,
+                        cam->width * cam->depth / 8);
 
     gtk_widget_queue_draw_area (glade_xml_get_widget (cam->xml, "da"), 0,
-                                0, cam->x, cam->y);
-
-    cam->vid_map.frame = frame;
-    if (v4l1_ioctl (cam->dev, VIDIOCMCAPTURE, &cam->vid_map) < 0) {
-        if (cam->debug == TRUE) {
-            fprintf (stderr, "Unable to capture image (VIDIOCMCAPTURE)\n");
-        }
-        error_dialog (_("Unable to capture image."));
-        exit (-1);
-    }
-
-    /*
-     * next frame 
-     */
-    frame++;
-
-    /*
-     * reset to the 1st frame 
-     */
-    if (frame >= cam->vid_buf.frames) {
-        frame = 0;
-    }
+                                0, cam->width, cam->height);
 
     frames2++;
     g_object_unref ((gpointer) gc);
@@ -675,45 +589,15 @@ void on_status_show (GtkWidget * sb, cam * cam)
     cam->status = sb;
 }
 
-void init_cam (GtkWidget * capture, cam * cam)
-{
-    cam->pic =
-        v4l1_mmap (0, cam->vid_buf.size, PROT_READ | PROT_WRITE,
-              MAP_SHARED, cam->dev, 0);
-
-    if ((unsigned char *) -1 == (unsigned char *) cam->pic) {
-        if (cam->debug == TRUE) {
-            fprintf (stderr, "Unable to capture image (mmap).\n");
-        }
-        error_dialog (_("Unable to capture image."));
-        exit (-1);
-    }
-    cam->vid_map.height = cam->y;
-    cam->vid_map.width = cam->x;
-    cam->vid_map.format = cam->vid_pic.palette;
-    for (frame = 0; frame < cam->vid_buf.frames; frame++) {
-        cam->vid_map.frame = frame;
-        if (v4l1_ioctl (cam->dev, VIDIOCMCAPTURE, &cam->vid_map) < 0) {
-            if (cam->debug == TRUE) {
-                fprintf (stderr,
-                         "Unable to capture image (VIDIOCMCAPTURE).\n");
-            }
-            error_dialog (_("Unable to capture image."));
-            exit (-1);
-        }
-    }
-    frame = 0;
-}
-
 void capture_func (GtkWidget * widget, cam * cam)
 {
     if (cam->debug == TRUE) {
         printf
             ("capture_func\nx = %d, y = %d, depth = %d, realloc size = %d\n",
-             cam->x, cam->y, cam->depth, (cam->x * cam->y * cam->depth));
+             cam->width, cam->height, cam->depth, (cam->width * cam->height * cam->depth / 8));
     }
 
-    memcpy (cam->tmp, cam->pic_buf, cam->x * cam->y * cam->depth);
+    memcpy (cam->tmp, cam->pic_buf, cam->width * cam->height * cam->depth / 8);
 
     if (cam->rcap == TRUE) {
         remote_save (cam);
@@ -728,7 +612,7 @@ gint timeout_capture_func (cam * cam)
 {
     /* GdkRectangle rect;
      * rect->x = 0; rect->y = 0;
-     * rect->width = cam->x; rect->height = cam->y; */
+     * rect->width = cam->width; rect->height = cam->height; */
 
     /* need to return true, or the timeout will be destroyed - don't forget! :) */
     if (cam->hidden == TRUE) {
@@ -742,7 +626,7 @@ gint timeout_capture_func (cam * cam)
         pt2Function (cam);
 
     }
-    memcpy (cam->tmp, cam->pic_buf, cam->x * cam->y * cam->depth);
+    memcpy (cam->tmp, cam->pic_buf, cam->width * cam->height * cam->depth / 8);
 
     if (cam->cap == TRUE) {
         local_save (cam);
@@ -756,39 +640,36 @@ gint timeout_capture_func (cam * cam)
 void contrast_change (GtkHScale * sc1, cam * cam)
 {
 
-    cam->vid_pic.contrast =
-        256 * (int) gtk_range_get_value ((GtkRange *) sc1);
-    set_pic_info (cam);
+    cam->contrast = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
+    v4l2_set_control(cam->dev, V4L2_CID_CONTRAST, cam->contrast);
 }
 
 void brightness_change (GtkHScale * sc1, cam * cam)
 {
 
-    cam->vid_pic.brightness =
-        256 * (int) gtk_range_get_value ((GtkRange *) sc1);
-    set_pic_info (cam);
+    cam->brightness = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
+    v4l2_set_control(cam->dev, V4L2_CID_BRIGHTNESS, cam->brightness);
 }
 
 void colour_change (GtkHScale * sc1, cam * cam)
 {
 
-    cam->vid_pic.colour = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
-    set_pic_info (cam);
+    cam->colour = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
+    v4l2_set_control(cam->dev, V4L2_CID_SATURATION, cam->colour);
 }
 
 void hue_change (GtkHScale * sc1, cam * cam)
 {
 
-    cam->vid_pic.hue = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
-    set_pic_info (cam);
+    cam->hue = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
+    v4l2_set_control(cam->dev, V4L2_CID_HUE, cam->hue);
 }
 
 void wb_change (GtkHScale * sc1, cam * cam)
 {
 
-    cam->vid_pic.whiteness =
-        256 * (int) gtk_range_get_value ((GtkRange *) sc1);
-    set_pic_info (cam);
+    cam->whiteness = 256 * (int) gtk_range_get_value ((GtkRange *) sc1);
+    v4l2_set_control(cam->dev, V4L2_CID_WHITENESS, cam->whiteness);
 }
 
 void help_cb (GtkWidget * widget, gpointer data)
diff --git a/src/callbacks.h b/src/callbacks.h
index a4294f9161b8..6cebc103866a 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -43,7 +43,6 @@ void prefs_func (GtkWidget *, cam *);
 gint io_func (cam *, gint, GdkInputCondition);
 void capture_func2 (GtkWidget *, cam *);
 void capture_func (GtkWidget *, cam *);
-void init_cam (GtkWidget * capture, cam * cam);
 gint timeout_capture_func (cam *);
 gint fps (GtkWidget *);
 gint timeout_func (cam *);
diff --git a/src/camorama-window.c b/src/camorama-window.c
index c420b388895f..62beec38b003 100644
--- a/src/camorama-window.c
+++ b/src/camorama-window.c
@@ -243,8 +243,8 @@ load_interface(cam* cam) {
      * glade_xml_signal_autoconnect(xml);
      * this won't work, can't pass data to callbacks.  have to do it individually :(*/
 
-    title = g_strdup_printf ("Camorama - %s - %dx%d", cam->vid_cap.name,
-                             cam->x, cam->y);
+    title = g_strdup_printf ("Camorama - %s - %dx%d", cam->name,
+                             cam->width, cam->height);
     gtk_window_set_title (GTK_WINDOW
                           (glade_xml_get_widget (cam->xml, "main_window")),
                           title);
@@ -283,31 +283,61 @@ load_interface(cam* cam) {
                                    G_CALLBACK (delete_event), NULL);
 
     /* sliders */
-    glade_xml_signal_connect_data (cam->xml, "contrast_change",
-                                   G_CALLBACK (contrast_change), cam);
-    gtk_range_set_value ((GtkRange *)
-                         glade_xml_get_widget (cam->xml, "slider2"),
-                         (int) (cam->contrast / 256));
-    glade_xml_signal_connect_data (cam->xml, "brightness_change",
-                                   G_CALLBACK (brightness_change), cam);
-    gtk_range_set_value ((GtkRange *)
-                         glade_xml_get_widget (cam->xml, "slider3"),
-                         (int) (cam->brightness / 256));
-    glade_xml_signal_connect_data (cam->xml, "colour_change",
-                                   G_CALLBACK (colour_change), cam);
-    gtk_range_set_value ((GtkRange *)
-                         glade_xml_get_widget (cam->xml, "slider4"),
-                         (int) (cam->colour / 256));
-    glade_xml_signal_connect_data (cam->xml, "hue_change",
-                                   G_CALLBACK (hue_change), cam);
-    gtk_range_set_value ((GtkRange *)
-                         glade_xml_get_widget (cam->xml, "slider5"),
-                         (int) (cam->hue / 256));
-    glade_xml_signal_connect_data (cam->xml, "wb_change",
-                                   G_CALLBACK (wb_change), cam);
-    gtk_range_set_value ((GtkRange *)
-                         glade_xml_get_widget (cam->xml, "slider6"),
-                         (int) (cam->wb / 256));
+    if (cam->contrast < 0) {
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "contrast_icon"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "contrast_label"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "contrast_slider"));
+    } else {
+        glade_xml_signal_connect_data (cam->xml, "contrast_change",
+                                    G_CALLBACK (contrast_change), cam);
+        gtk_range_set_value ((GtkRange *)
+                             glade_xml_get_widget (cam->xml, "contrast_slider"),
+                             (int) (cam->contrast / 256));
+    }
+    if (cam->brightness < 0) {
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "brightness_icon"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "brightness_label"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "brightness_slider"));
+    } else {
+        glade_xml_signal_connect_data (cam->xml, "brightness_change",
+                                    G_CALLBACK (brightness_change), cam);
+        gtk_range_set_value ((GtkRange *)
+                            glade_xml_get_widget (cam->xml, "brightness_slider"),
+                            (int) (cam->brightness / 256));
+    }
+    if (cam->colour < 1) {
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "color_icon"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "color_label"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "color_slider"));
+    } else {
+        glade_xml_signal_connect_data (cam->xml, "colour_change",
+                                    G_CALLBACK (colour_change), cam);
+        gtk_range_set_value ((GtkRange *)
+                            glade_xml_get_widget (cam->xml, "color_slider"),
+                            (int) (cam->colour / 256));
+    }
+    if (cam->hue < 0) {
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "hue_icon"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "hue_label"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "hue_slider"));
+    } else {
+        glade_xml_signal_connect_data (cam->xml, "hue_change",
+                                    G_CALLBACK (hue_change), cam);
+        gtk_range_set_value ((GtkRange *)
+                             glade_xml_get_widget (cam->xml, "hue_slider"),
+                             (int) (cam->hue / 256));
+    }
+    if (cam->whiteness < 0) {
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "balance_icon"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "balance_label"));
+        gtk_widget_hide(glade_xml_get_widget (cam->xml, "balance_slider"));
+    } else {
+        glade_xml_signal_connect_data (cam->xml, "wb_change",
+                                    G_CALLBACK (wb_change), cam);
+        gtk_range_set_value ((GtkRange *)
+                            glade_xml_get_widget (cam->xml, "balance_slider"),
+                            (int) (cam->whiteness / 256));
+    }
 
     /* buttons */
     glade_xml_signal_connect_data (cam->xml, "on_status_show",
@@ -459,7 +489,7 @@ load_interface(cam* cam) {
                               (cam->xml, "string_entry"), cam->usestring);
 
     gtk_widget_set_size_request (glade_xml_get_widget (cam->xml, "da"),
-                                 cam->x, cam->y);
+                                 cam->width, cam->height);
 
     prefswindow = glade_xml_get_widget (cam->xml, "prefswindow");
 }
diff --git a/src/fileio.c b/src/fileio.c
index 43ee0b2744aa..ff6897f62208 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -112,7 +112,7 @@ void remote_save (cam * cam)
     //cam->tmp = NULL;
 
     if (cam->rtimestamp == TRUE) {
-        add_rgb_text (cam->tmp, cam->x, cam->y, cam->ts_string,
+        add_rgb_text (cam->tmp, cam->width, cam->height, cam->ts_string,
                       cam->date_format, cam->usestring, cam->usedate);
     }
 
@@ -129,8 +129,8 @@ void remote_save (cam * cam)
     filename = g_strdup_printf ("camorama.%s", ext);
     //g_free(ext);
     pb = gdk_pixbuf_new_from_data (cam->tmp, GDK_COLORSPACE_RGB, FALSE, 8,
-                                   cam->x, cam->y,
-                                   cam->x * cam->vid_pic.depth / 8, NULL,
+                                   cam->width, cam->height,
+                                   cam->width * cam->depth / 8, NULL,
                                    NULL);
  
     if (pb == NULL) {
@@ -174,10 +174,10 @@ void remote_save (cam * cam)
      * exit (0);
      * }
      * 
-     * tmp = malloc (sizeof (char) * cam->x * cam->y * cam->depth * 2);
+     * tmp = malloc (sizeof (char) * cam->width * cam->height * cam->depth * 2);
      * while (!feof (fp))
      * {
-     * bytes += fread (tmp, 1, cam->x * cam->y * cam->depth, fp);
+     * bytes += fread (tmp, 1, cam->width * cam->height * cam->depth, fp);
      * }
      * fclose (fp);
      * 
@@ -280,9 +280,9 @@ void save_thread (cam * cam)
         //exit (0);
     }
 
-    tmp = malloc (sizeof (char) * cam->x * cam->y * cam->depth * 2);
+    tmp = malloc (sizeof (char) * cam->width * cam->height * cam->depth * 2);
     while (!feof (fp)) {
-        bytes += fread (tmp, 1, cam->x * cam->y * cam->depth, fp);
+        bytes += fread (tmp, 1, cam->width * cam->height * cam->depth, fp);
     }
     fclose (fp);
 
@@ -367,10 +367,10 @@ int local_save (cam * cam)
         ext = g_strdup ((gchar *) "jpeg");
     }
     //cam->tmp = NULL;
-    //memcpy (cam->tmp, cam->pic_buf, cam->x * cam->y * cam->depth);
+    //memcpy (cam->tmp, cam->pic_buf, cam->width * cam->height * cam->depth);
 
     if (cam->timestamp == TRUE) {
-        add_rgb_text (cam->tmp, cam->x, cam->y, cam->ts_string,
+        add_rgb_text (cam->tmp, cam->width, cam->height, cam->ts_string,
                       cam->date_format, cam->usestring, cam->usedate);
     }
 
@@ -421,8 +421,8 @@ int local_save (cam * cam)
     }
 
     pb = gdk_pixbuf_new_from_data (cam->tmp, GDK_COLORSPACE_RGB, FALSE, 8,
-                                   cam->x, cam->y,
-                                   (cam->x * cam->vid_pic.depth / 8), NULL,
+                                   cam->width, cam->height,
+                                   (cam->width * cam->depth / 8), NULL,
                                    NULL);
     pbs = gdk_pixbuf_save (pb, filename, ext, NULL, NULL);
      if (pbs == FALSE) {
diff --git a/src/main.c b/src/main.c
index 8fb289aeea9f..8cda62e08ee2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,6 +2,8 @@
 #include "interface.h"
 
 #include "callbacks.h"
+#include "filter.h"
+#include "camorama-window.h"
 #include "support.h"
 #include <config.h>
 
@@ -9,7 +11,7 @@
 #include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
 #include <gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h>
 #include <locale.h>
-#include <libv4l1.h>
+#include <libv4l2.h>
 
 #include "camorama-display.h"
 #include "camorama-stock-items.h"
@@ -71,6 +73,7 @@ main(int argc, char *argv[]) {
     gboolean buggery = FALSE;
     GtkWidget *button;
     GConfClient *gc;
+    unsigned int bufsize;
 
     const struct poptOption popt_options[] = {
         {"version", 'V', POPT_ARG_NONE, &ver, 0,
@@ -97,11 +100,12 @@ main(int argc, char *argv[]) {
     cam = &cam_object;
     /* set some default values */
     cam->frame_number = 0;
-    cam->pic = NULL;
     cam->pixmap = NULL;
     cam->size = PICHALF;
     cam->video_dev = NULL;
     cam->read = FALSE;
+    cam->width = 0;
+    cam->height = 0;
 
     bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -120,8 +124,8 @@ main(int argc, char *argv[]) {
 
     cam->debug = buggery;
 
-	cam->x = x;
-	cam->y = y;
+	cam->width = x;
+	cam->height = y;
 	glade_gnome_init ();
 	glade_set_custom_handler (camorama_glade_handler,
 				  cam);
@@ -141,7 +145,7 @@ main(int argc, char *argv[]) {
         cam->size = PICHALF;
     }
     if (use_read) {
-        printf ("gah!\n");
+        printf ("Forcing read mode\n");
         cam->read = TRUE;
     }
     gc = gconf_client_get_default ();
@@ -198,7 +202,7 @@ main(int argc, char *argv[]) {
     cam->acap = gconf_client_get_bool (cam->gc, KEY20, NULL);
     cam->timeout_interval = gconf_client_get_int (cam->gc, KEY21, NULL);
     cam->show_adjustments = gconf_client_get_bool (cam->gc, KEY22, NULL);
-	 cam->show_effects = gconf_client_get_bool (cam->gc, KEY23, NULL);
+    cam->show_effects = gconf_client_get_bool (cam->gc, KEY23, NULL);
 
 
     /* get desktop depth */
@@ -207,53 +211,37 @@ main(int argc, char *argv[]) {
     gdk_pixbuf_xlib_init (display, 0);
     cam->desk_depth = xlib_rgb_get_depth ();
 
-    cam->dev = v4l1_open (cam->video_dev, O_RDWR);
+    cam->dev = v4l2_open (cam->video_dev, O_RDWR | O_NONBLOCK);
 
     camera_cap (cam);
     get_win_info (cam);
 
-    /* query/set window attributes */
-    cam->vid_win.x = 0;
-    cam->vid_win.y = 0;
-    cam->vid_win.width = cam->x;
-    cam->vid_win.height = cam->y;
-    cam->vid_win.chromakey = 0;
-    cam->vid_win.flags = 0;
-
     set_win_info (cam);
     get_win_info (cam);
 
     /* get picture attributes */
     get_pic_info (cam);
-    set_pic_info (cam);
-    cam->contrast = cam->vid_pic.contrast;
-    cam->brightness = cam->vid_pic.brightness;
-    cam->colour = cam->vid_pic.colour;
-    cam->hue = cam->vid_pic.hue;
-    cam->wb = cam->vid_pic.whiteness;
-    cam->depth = cam->vid_pic.depth / 8;
-    cam->pic_buf = malloc (cam->x * cam->y * cam->depth);
-    cam->tmp =
-        malloc (cam->vid_cap.maxwidth * cam->vid_cap.maxheight * cam->depth);
-    //cam->tmp = NULL;
-    /* set the buffer size */
-    if (cam->read == FALSE) {
-        set_buffer (cam);
+
+    bufsize = cam->max_width * cam->max_height * cam->depth / 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;
-        init_cam (NULL, cam);
+        start_streaming (cam);
     } else {
         printf ("using read()\n");
-        cam->pic =
-            realloc (cam->pic,
-                     (cam->vid_cap.maxwidth * cam->vid_cap.maxheight * 3));
         pt2Function = read_timeout_func;
     }
-    cam->pixmap = gdk_pixmap_new (NULL, cam->x, cam->y, cam->desk_depth);
+    cam->pixmap = gdk_pixmap_new (NULL, cam->width, cam->height, cam->desk_depth);
 
     filename =
         gnome_program_locate_file (NULL,
@@ -285,8 +273,10 @@ main(int argc, char *argv[]) {
 
     gtk_timeout_add (2000, (GSourceFunc) fps, cam->status);
     gtk_main ();
-    v4l1_munmap(cam->pic, cam->vid_buf.size);
-    v4l1_close(cam->dev);
-    
+    if (cam->read == FALSE) {
+        stop_streaming (cam);
+    }
+    v4l2_close(cam->dev);
+
     return 0;
 }
diff --git a/src/v4l.c b/src/v4l.c
index f848ce7f944a..47c0fe60bb7d 100644
--- a/src/v4l.c
+++ b/src/v4l.c
@@ -2,260 +2,496 @@
 #include<time.h>
 #include<errno.h>
 #include<gnome.h>
-#include <libv4l1.h>
+#include <sys/select.h>
 #include "support.h"
 
 extern int frame_number;
 extern int errno;
 
 void print_cam(cam *cam){
-	printf("\nCamera Info\n");
-	printf("-------------\n");
-	printf("device = %s, x = %d, y = %d\n",cam->video_dev, cam->x,cam->y);
-	printf("depth = %d, desk_depth = %d, size = %d\n",cam->depth,cam->desk_depth,cam->size);
-	printf("capture directory = %s, capture file = %s\n",cam->pixdir, cam->capturefile);
-	printf("remote capture directory = %s, remote capture file = %s\n",cam->rpixdir, cam->rcapturefile);
-	printf("remote host = %s, remote login = %s\n",cam->rhost,cam->rlogin);
-	printf("timestamp = %s\n\n",cam->ts_string);
-	
-}
-void print_palette(int p)
-{
-
-   switch (p) {
-   case VIDEO_PALETTE_HI240:
-      printf("High 240 cube (BT848)\n");
-      break;
-
-   case VIDEO_PALETTE_RGB565:
-      printf("565 16 bit RGB\n");
-      break;
-
-   case VIDEO_PALETTE_RGB24:
-      printf("24bit RGB\n");
-      break;
+   printf("\nCamera Info\n");
+   printf("-------------\n");
+   printf("device = %s, x = %d, y = %d\n",cam->video_dev, cam->width,cam->height);
+   printf("depth = %d, desk_depth = %d, size = %d\n",cam->depth,cam->desk_depth,cam->size);
+   printf("capture directory = %s, capture file = %s\n",cam->pixdir, cam->capturefile);
+   printf("remote capture directory = %s, remote capture file = %s\n",cam->rpixdir, cam->rcapturefile);
+   printf("remote host = %s, remote login = %s\n",cam->rhost,cam->rlogin);
+   printf("timestamp = %s\n\n",cam->ts_string);
 
-   case VIDEO_PALETTE_RGB32:
-      printf("32bit RGB\n");
-      break;
-
-   case VIDEO_PALETTE_RGB555:
-      printf("555 15bit RGB\n");
-      break;
+}
 
-   case VIDEO_PALETTE_YUV422:
-      printf("YUV422 capture");
-      break;
+void camera_cap(cam * cam)
+{
+   char *msg;
+   int i;
+   struct v4l2_capability vid_cap = { 0 };
+   struct v4l2_fmtdesc fmtdesc = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+   struct v4l2_format fmt;
 
-   case VIDEO_PALETTE_YUYV:
-      printf("YUYV\n");
-      break;
+   /* 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);
+      error_dialog(msg);
+      g_free(msg);
+      exit(0);
+   }
 
-   case VIDEO_PALETTE_UYVY:
-      printf("UYVY\n");
-      break;
+   /* Query supported resolutions */
 
-   case VIDEO_PALETTE_YUV420:
-      printf("YUV420\n");
-      break;
+   cam->min_width = -1;
+   cam->min_height = -1;
+   cam->max_width = 0;
+   cam->max_height = 0;
+   for (i = 0; ; i++) {
+      fmtdesc.index = i;
 
-   case VIDEO_PALETTE_YUV411:
-      printf("YUV411 capture\n");
-      break;
+      if (v4l2_ioctl(cam->dev, VIDIOC_ENUM_FMT, &fmtdesc))
+         break;
 
-   case VIDEO_PALETTE_RAW:
-      printf("RAW capture (BT848)\n");
-      break;
+   if(cam->debug == TRUE)
+      printf("format index %d: FOURCC: '%c%c%c%c' (%08x)%s\n", i,
+             fmtdesc.pixelformat & 0xff,
+             (fmtdesc.pixelformat >> 8) & 0xff,
+             (fmtdesc.pixelformat >> 16) & 0xff,
+             fmtdesc.pixelformat >> 24,
+             fmtdesc.pixelformat,
+             fmtdesc.flags & V4L2_FMT_FLAG_EMULATED ? " (emulated)" : ""
+            );
 
-   case VIDEO_PALETTE_YUV422P:
-      printf("YUV 4:2:2 Planar");
-      break;
+      /* FIXME: add a check for emulated formats */
 
-   case VIDEO_PALETTE_YUV411P:
-      printf("YUV 4:1:1 Planar\n");
-      break;
+      memset(&fmt, 0, sizeof(fmt));
+      fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      fmt.fmt.pix.pixelformat = fmtdesc.pixelformat;
+      fmt.fmt.pix.width = 48;
+      fmt.fmt.pix.height = 32;
 
-   case VIDEO_PALETTE_YUV420P:
-      printf("YUV 4:2:0 Planar\n");
-      break;
+      if (!v4l2_ioctl(cam->dev, VIDIOC_TRY_FMT, &fmt)) {
+         if (fmt.fmt.pix.width < cam->min_width)
+            cam->min_width = fmt.fmt.pix.width;
+         if (fmt.fmt.pix.height < cam->min_height)
+            cam->min_height = fmt.fmt.pix.height;
+         if (cam->debug == TRUE)
+            printf("  MIN: %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
+      }
 
-   case VIDEO_PALETTE_YUV410P:
-      printf("YUV 4:1:0 Planar\n");
-      break;
-   }
-}
+      memset(&fmt, 0, sizeof(fmt));
+      fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      fmt.fmt.pix.pixelformat = fmtdesc.pixelformat;
+      fmt.fmt.pix.width = 100000;
+      fmt.fmt.pix.height = 100000;
 
-void camera_cap(cam * cam)
-{
-   char *msg;
-   if(v4l1_ioctl(cam->dev, VIDIOCGCAP, &cam->vid_cap) == -1) {
-      if(cam->debug == TRUE) {
-         fprintf(stderr, "VIDIOCGCAP  --  could not get camera capabilities, exiting.....\n");
+      if (!v4l2_ioctl(cam->dev, VIDIOC_TRY_FMT, &fmt)) {
+         if (fmt.fmt.pix.width > cam->max_width)
+            cam->max_width = fmt.fmt.pix.width;
+         if (fmt.fmt.pix.height > cam->max_height)
+            cam->max_height = fmt.fmt.pix.height;
+         if(cam->debug == TRUE)
+            printf("  MAX: %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
       }
-      msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
-      error_dialog(msg);
-      g_free(msg);
-      exit(0);
    }
-   if(cam->x > 0 && cam->y > 0) {
-      if(cam->vid_cap.maxwidth < cam->x) {
-         cam->x = cam->vid_cap.maxwidth;
+
+   /* Adjust camera resolution */
+
+   if(cam->width > 0 && cam->height > 0) {
+      if(cam->max_width < cam->width) {
+         cam->width = cam->max_width;
       }
-      if(cam->vid_cap.minwidth > cam->x) {
-         cam->x = cam->vid_cap.minwidth;
+      if(cam->min_width > cam->width) {
+         cam->width = cam->min_width;
       }
-      if(cam->vid_cap.maxheight < cam->y) {
-         cam->y = cam->vid_cap.maxheight;
+      if(cam->max_height < cam->height) {
+         cam->height = cam->max_height;
       }
-      if(cam->vid_cap.minheight > cam->y) {
-         cam->y = cam->vid_cap.minheight;
+      if(cam->min_height > cam->height) {
+         cam->height = cam->min_height;
       }
    } else {
       switch (cam->size) {
       case PICMAX:
-         cam->x = cam->vid_cap.maxwidth;
-         cam->y = cam->vid_cap.maxheight;
+         cam->width = cam->max_width;
+         cam->height = cam->max_height;
          break;
 
       case PICMIN:
-         cam->x = cam->vid_cap.minwidth;
-         cam->y = cam->vid_cap.minheight;
+         cam->width = cam->min_width;
+         cam->height = cam->min_height;
          break;
 
       case PICHALF:
-         cam->x = cam->vid_cap.maxwidth / 2;
-         cam->y = cam->vid_cap.maxheight / 2;
+         cam->width = cam->max_width / 2;
+         cam->height = cam->max_height / 2;
          break;
 
       default:
-         cam->x = cam->vid_cap.maxwidth / 2;
-         cam->y = cam->vid_cap.maxheight / 2;
+         cam->width = cam->max_width / 2;
+         cam->height = cam->max_height / 2;
          break;
       }
    }
-   if((cam->vid_cap.type & VID_TYPE_CAPTURE) != 1) {
+
+   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."), cam->video_dev);
+      error_dialog(msg);
+      g_free(msg);
+      exit(0);
+   }
+
+   if(!(vid_cap.capabilities & V4L2_CAP_STREAMING)) {
       cam->read = TRUE;
    }
 
+   strncpy(cam->name, vid_cap.card, sizeof(cam->name));
+   cam->name[sizeof(cam->name) - 1] = '\0';
+
    if(cam->debug == TRUE) {
-      printf("\nVIDIOCGCAP\n");
-      printf("device name = %s\n", cam->vid_cap.name);
-      printf("device type = %d\n", cam->vid_cap.type);
-      if(cam->read == FALSE){
-		  printf("can use mmap()\n");
-	  }
-      printf("# of channels = %d\n", cam->vid_cap.channels);
-      printf("# of audio devices = %d\n", cam->vid_cap.audios);
-      printf("max width = %d\n", cam->vid_cap.maxwidth);
-      printf("max height = %d\n", cam->vid_cap.maxheight);
-      printf("min width = %d\n", cam->vid_cap.minwidth);
-      printf("min height = %d\n", cam->vid_cap.minheight);
+      printf("\nVIDIOC_QUERYCAP\n");
+      printf("device name = %s\n", vid_cap.card);
+      printf("device caps = 0x%08x\n", vid_cap.capabilities);
+      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);
    }
 }
 
-void
-set_pic_info(cam* cam) {
-	char *msg;
-	if(cam->debug) {
-		g_message("SET PIC");
-	}
-	cam->vid_pic.palette = VIDEO_PALETTE_RGB24;
-	cam->vid_pic.depth = 24;
-	//cam->vid_pic.palette = VIDEO_PALETTE_YUV420P;
-	if(v4l1_ioctl(cam->dev, VIDIOCSPICT, &cam->vid_pic) == -1) {
-		if(cam->debug) {
-			g_message("VIDIOCSPICT  --  could not set picture info, exiting....");
-		}
-		msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
-		error_dialog(msg);
-		g_free(msg);
-		exit(0);
-	}
-}
-
 void get_pic_info(cam * cam){
-//set_pic_info(cam);
    char *msg;
-	
-   if(v4l1_ioctl(cam->dev, VIDIOCGPICT, &cam->vid_pic) == -1) {
-      msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
-      error_dialog(msg);
-      if(cam->debug == TRUE) {
-         fprintf(stderr, "VIDIOCGPICT  --  could not get picture info, exiting....\n");
-      }
-      g_free(msg);
-      exit(0);
+   int i;
+
+   if(cam->debug == TRUE)
+      printf("\nVideo control settings:\n");
+
+   i = v4l2_get_control(cam->dev, V4L2_CID_HUE);
+   if (i >= 0) {
+      cam->hue = i;
+      if(cam->debug == TRUE)
+         printf("hue = %d\n", cam->hue);
+   } else {
+      cam->hue = -1;
    }
-	
-   if(cam->debug == TRUE) {
-      printf("\nVIDIOCGPICT:\n");
-      printf("bright = %d\n", cam->vid_pic.brightness);
-      printf("hue = %d\n", cam->vid_pic.hue);
-      printf("colour = %d\n", cam->vid_pic.colour);
-      printf("contrast = %d\n", cam->vid_pic.contrast);
-      printf("whiteness = %d\n", cam->vid_pic.whiteness);
-      printf("colour depth = %d\n", cam->vid_pic.depth);
-      print_palette(cam->vid_pic.palette);
+   i = v4l2_get_control(cam->dev, V4L2_CID_SATURATION);
+   if (i >= 0) {
+      cam->colour = i;
+      if(cam->debug == TRUE)
+         printf("colour = %d\n", cam->colour);
+   } else {
+      cam->colour = -1;
+   }
+   i = v4l2_get_control(cam->dev, V4L2_CID_CONTRAST);
+   if (i >= 0) {
+      cam->contrast = i;
+      if(cam->debug == TRUE)
+         printf("contrast = %d\n", cam->contrast);
+   } else {
+      cam->contrast = -1;
+   }
+   i = v4l2_get_control(cam->dev, V4L2_CID_WHITENESS);
+   if (i >= 0) {
+      cam->whiteness = i;
+      if(cam->debug == TRUE)
+         printf("whiteness = %d\n", cam->whiteness);
+   } else {
+      cam->whiteness = -1;
+   }
+   i = v4l2_get_control(cam->dev, V4L2_CID_BRIGHTNESS);
+   if (i >= 0) {
+      cam->brightness = i;
+      if(cam->debug == TRUE)
+         printf("brightness = %d\n", cam->brightness);
+   } else {
+      cam->brightness = -1;
    }
 }
 
 void get_win_info(cam * cam)
 {
    gchar *msg;
-   if(v4l1_ioctl(cam->dev, VIDIOCGWIN, &cam->vid_win) == -1) {
+   struct v4l2_format fmt = { 0 };
+
+   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+   if (v4l2_ioctl(cam->dev, VIDIOC_G_FMT, &fmt)) {
       msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
       error_dialog(msg);
       if(cam->debug == TRUE) {
-         fprintf(stderr, "VIDIOCGWIN  --  could not get window info, exiting....\n");
+         g_message("VIDIOC_G_FMT  --  could not get picture info");
       }
-      exit(0);
+      return;
    }
+
    if(cam->debug == TRUE) {
-      printf("\nVIDIOCGWIN\n");
-      printf("x = %d\n", cam->vid_win.x);
-      printf("y = %d\n", cam->vid_win.y);
-      printf("width = %d\n", cam->vid_win.width);
-      printf("height = %d\n", cam->vid_win.height);
-      printf("chromakey = %d\n", cam->vid_win.chromakey);
-      printf("flags = %d\n", cam->vid_win.flags);
+      printf("\nVIDIOC_G_FMT\n");
+      printf("format FOURCC: '%c%c%c%c' (%08x)\n",
+             fmt.fmt.pix.pixelformat & 0xff,
+             (fmt.fmt.pix.pixelformat >> 8) & 0xff,
+             (fmt.fmt.pix.pixelformat >> 16) & 0xff,
+             fmt.fmt.pix.pixelformat >> 24,
+             fmt.fmt.pix.pixelformat);
+      printf("x = %d\n", fmt.fmt.pix.width);
+      printf("y = %d\n", fmt.fmt.pix.height);
+      if (fmt.fmt.pix.bytesperline)
+         printf("bytes/line = %d\n", fmt.fmt.pix.bytesperline);
+   }
+
+   if (!fmt.fmt.pix.bytesperline) {
+      if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+         fmt.fmt.pix.bytesperline = fmt.fmt.pix.width * 2;
+      else
+         fmt.fmt.pix.bytesperline = fmt.fmt.pix.width * 3;
+   }
+
+   if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24 ||
+       fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+
+      cam->pixformat = fmt.fmt.pix.pixelformat;
+      cam->depth = ((fmt.fmt.pix.bytesperline << 3) + (fmt.fmt.pix.width - 1)) / fmt.fmt.pix.width;
+      cam->width = fmt.fmt.pix.width;
+      cam->height = fmt.fmt.pix.height;
+      cam->bytesperline = fmt.fmt.pix.bytesperline;
    }
 }
+
 void set_win_info(cam * cam)
 {
    gchar *msg;
-   if(v4l1_ioctl(cam->dev, VIDIOCSWIN, &cam->vid_win) == -1) {
+   struct v4l2_format fmt;
+
+   memset(&fmt, 0, sizeof(fmt));
+   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+   /* Get current settings, apply our changes and try the new setting */
+   if (v4l2_ioctl(cam->dev, VIDIOC_G_FMT, &fmt)) {
+      if(cam->debug) {
+         g_message("VIDIOC_G_FMT  --  could not get window info, exiting....");
+      }
       msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
       error_dialog(msg);
-      if(cam->debug == TRUE) {
-         fprintf(stderr, "VIDIOCSWIN  --  could not set window info, exiting....\nerrno = %d", errno);
+      g_free(msg);
+      exit(0);
+   }
+
+   if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24 &&
+      fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420)
+      cam->pixformat = V4L2_PIX_FMT_BGR24;
+
+   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+   fmt.fmt.pix.pixelformat = cam->pixformat;
+   fmt.fmt.pix.width  = cam->width;
+   fmt.fmt.pix.height = cam->height;
+   if (v4l2_ioctl(cam->dev, VIDIOC_S_FMT, &fmt)) {
+      if(cam->debug) {
+         g_message("VIDIOC_S_FMT  --  could not set window info, exiting....");
+      }
+      msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
+      error_dialog(msg);
+      g_free(msg);
+      exit(0);
+   }
+
+   /* Check if returned format is valid */
+   if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_BGR24 &&
+      fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) {
+      if(cam->debug) {
+         g_message("VIDIOC_S_FMT  --  could not set format to %c%c%c%c (was set to %c%c%c%c instead), exiting....",
+                   cam->pixformat & 0xff,
+                   (cam->pixformat >> 8) & 0xff,
+                   (cam->pixformat >> 16) & 0xff,
+                   cam->pixformat >> 24,
+                   fmt.fmt.pix.pixelformat & 0xff,
+                   (fmt.fmt.pix.pixelformat >> 8) & 0xff,
+                   (fmt.fmt.pix.pixelformat >> 16) & 0xff,
+                   fmt.fmt.pix.pixelformat >> 24);
       }
+      msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
+      error_dialog(msg);
       g_free(msg);
       exit(0);
    }
 
-   cam->x = cam->vid_win.width;
-   cam->y = cam->vid_win.height;
+   /* Resolution may have changed. Store the retrieved one */
+   cam->pixformat = fmt.fmt.pix.pixelformat;
+   cam->bytesperline = fmt.fmt.pix.bytesperline;
+
+   cam->depth = ((fmt.fmt.pix.bytesperline << 3) + (fmt.fmt.pix.width - 1)) / fmt.fmt.pix.width;
+
+   cam->width = fmt.fmt.pix.width;
+   cam->height = fmt.fmt.pix.height;
 }
 
-void set_buffer(cam * cam)
+void start_streaming(cam * cam)
 {
    char *msg;
-   if(v4l1_ioctl(cam->dev, VIDIOCGMBUF, &cam->vid_buf) == -1) {
-      msg = g_strdup_printf(_("Could not connect to video device (%s).\nPlease check connection."), cam->video_dev);
+   unsigned int i;
+   enum v4l2_buf_type type;
+   struct v4l2_buffer buf;
+
+   memset(&cam->req, 0, sizeof(cam->req));
+   cam->req.count = 2;
+   cam->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+   cam->req.memory = V4L2_MEMORY_MMAP;
+   if (v4l2_ioctl(cam->dev, VIDIOC_REQBUFS, &cam->req)) {
+      msg = g_strdup_printf(_("VIDIOC_REQBUFS  --  could not request buffers (%s), exiting...."), cam->video_dev);
       error_dialog(msg);
-      if(cam->debug == TRUE) {
-         fprintf(stderr, "VIDIOCGMBF  --  could not set buffer info, exiting...\n");
+      g_free(msg);
+      exit(0);
+   }
+
+   cam->buffers = calloc(cam->req.count, sizeof(*cam->buffers));
+   for (cam->n_buffers = 0; cam->n_buffers < cam->req.count; ++cam->n_buffers) {
+      memset(&buf, 0, sizeof(buf));
+
+      buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index  = cam->n_buffers;
+
+      if (v4l2_ioctl(cam->dev, VIDIOC_QUERYBUF, &buf)) {
+         msg = g_strdup_printf(_("VIDIOC_QUERYBUF  --  could not query buffers (%s), exiting...."), cam->video_dev);
+         error_dialog(msg);
+         g_free(msg);
+         exit(0);
+      }
+
+      cam->buffers[cam->n_buffers].length = buf.length;
+      cam->buffers[cam->n_buffers].start = v4l2_mmap(NULL, buf.length,
+                                                     PROT_READ | PROT_WRITE,
+                                                     MAP_SHARED,
+                                                     cam->dev, buf.m.offset);
+
+      if (MAP_FAILED == cam->buffers[cam->n_buffers].start) {
+         msg = g_strdup_printf(_("failed to memory map buffers (%s), exiting...."), cam->video_dev);
+         error_dialog(msg);
+         g_free(msg);
+         exit(0);
       }
+   }
+
+   for (i = 0; i < cam->n_buffers; ++i) {
+      memset(&buf, 0, sizeof(buf));
+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      if (v4l2_ioctl(cam->dev, VIDIOC_QBUF, &buf)) {
+         msg = g_strdup_printf(_("VIDIOC_QBUF  --  could not enqueu buffers (%s), exiting...."), cam->video_dev);
+         error_dialog(msg);
+         g_free(msg);
+         exit(0);
+      }
+   }
+   type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+   if (v4l2_ioctl(cam->dev, VIDIOC_STREAMON, &type)) {
+      msg = g_strdup_printf(_("failed to start streaming (%s), exiting...."), cam->video_dev);
+      error_dialog(msg);
       g_free(msg);
       exit(0);
+   }
+}
+
+void capture_buffers(cam * cam, unsigned char *outbuf, int len)
+{
+   char *msg;
+   unsigned char *inbuf;
+   int r, y;
+   fd_set fds;
+   struct v4l2_buffer buf;
+   struct timeval tv;
+
+   do {
+      FD_ZERO(&fds);
+      FD_SET(cam->dev, &fds);
+
+      /* Timeout. */
+      tv.tv_sec = 2;
+      tv.tv_usec = 0;
 
+      r = select(cam->dev + 1, &fds, NULL, NULL, &tv);
+   } while ((r == -1 && (errno == EINTR)));
+
+   if (r == -1) {
+      msg = g_strdup_printf(_("Timeout while waiting for frames (%s)"), cam->video_dev);
+      error_dialog(msg);
+      g_free(msg);
+      exit(0);
    }
-   
-   if(cam->debug == TRUE) {
-      printf("\nVIDIOCGMBUF\n");
-      printf("mb.size = %d\n", cam->vid_buf.size);
-      printf("mb.frames = %d\n", cam->vid_buf.frames);
-      printf("mb.offset = %d\n", cam->vid_buf.offsets[1]);
+
+   memset(&buf, 0, sizeof(buf));
+   buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+   buf.memory = V4L2_MEMORY_MMAP;
+   v4l2_ioctl(cam->dev, VIDIOC_DQBUF, &buf);
+
+   if (len > buf.bytesused)
+      len = buf.bytesused;
+
+   inbuf = cam->buffers[buf.index].start;
+   for (y = 0; y < cam->height; y++) {
+      memcpy(outbuf, inbuf, cam->width * cam->depth / 8);
+      outbuf += cam->width * cam->depth / 8;
+      inbuf += cam->bytesperline;
    }
 
+   v4l2_ioctl(cam->dev, VIDIOC_QBUF, &buf);
+}
+
+
+void stop_streaming(cam * cam)
+{
+   char *msg;
+   unsigned int i;
+   int r;
+   enum v4l2_buf_type		type;
+   fd_set fds;
+   struct v4l2_buffer buf;
+   struct timeval tv;
+
+   /* Dequeue all pending buffers */
+   for (i = 0; i < cam->n_buffers; ++i) {
+      FD_ZERO(&fds);
+      FD_SET(cam->dev, &fds);
+
+      /* Timeout. */
+      tv.tv_sec = 2;
+      tv.tv_usec = 0;
+
+      r = select(cam->dev + 1, &fds, NULL, &fds, &tv);
+      if (r == -1 && errno == EINTR)
+         continue;
+
+      if (r != -1) {
+         memset(&buf, 0, sizeof(buf));
+         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+         buf.memory = V4L2_MEMORY_MMAP;
+         if (v4l2_ioctl(cam->dev, VIDIOC_DQBUF, &buf))
+            break;
+      }
+   };
+
+   /* Streams off */
+   type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+   if (v4l2_ioctl(cam->dev, VIDIOC_STREAMOFF, &type)) {
+      msg = g_strdup_printf(_("failed to stop streaming (%s), exiting...."), cam->video_dev);
+      error_dialog(msg);
+      g_free(msg);
+      exit(0);
+   }
+
+   /* Unmap buffers */
+   for (i = 0; i < cam->n_buffers; ++i)
+      v4l2_munmap(cam->buffers[i].start, cam->buffers[i].length);
+
+   /* Free existing buffers */
+   memset(&cam->req, 0, sizeof(cam->req));
+   cam->req.count = 0;
+   cam->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+   cam->req.memory = V4L2_MEMORY_MMAP;
+   v4l2_ioctl(cam->dev, VIDIOC_REQBUFS, &cam->req);
+
+   free(cam->buffers);
+   cam->buffers = NULL;
 }
diff --git a/src/v4l.h b/src/v4l.h
index 24479f5dad50..1c076410c779 100644
--- a/src/v4l.h
+++ b/src/v4l.h
@@ -12,7 +12,9 @@
 #include <sys/mman.h>
 #include <fcntl.h>
 #include <gtk/gtk.h>
-#include <libv4l1.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <libv4l2.h>
 #include <signal.h>
 #include <png.h>
 #include <glade/glade.h>
@@ -21,62 +23,75 @@
 #include "camorama-filter-chain.h"
 
 typedef enum {
-	PICMAX = 0,
-	PICMIN = 1,
-	PICHALF = 2
+   PICMAX = 0,
+   PICMIN = 1,
+   PICHALF = 2
 } CamoImageSize;
 
 enum {
-	JPEG = 0,
-	PNG = 1,
-	PPM = 2
+   JPEG = 0,
+   PNG = 1,
+   PPM = 2
+};
+
+struct buffer_start_len {
+   void   *start;
+   size_t length;
 };
 
 typedef struct camera {
-    int dev;
-    int x;
-    int y;
-    int depth;
-    int desk_depth;
-    CamoImageSize size;
-    int contrast, brightness, colour, hue, wb;
-    int frame_number;
-    struct video_capability vid_cap;
-    struct video_picture vid_pic;
-    struct video_window vid_win;
-    struct video_mbuf vid_buf;
-    struct video_mmap vid_map;
-    char *video_dev;
-    unsigned char *pic;
-    unsigned char *image;
-    gchar *capturefile, *rcapturefile;
-    gchar *pixdir, *rpixdir;
-    int savetype, rsavetype;
-    gchar *rhost, *rlogin, *rpw;
-    gchar *ts_string;
-    gchar *date_format;
-    gboolean debug, read, hidden;
-    gboolean cap, rcap, acap, show_adjustments, show_effects;
-    gboolean timestamp, rtimestamp, usedate, usestring;
-    gboolean rtimefn, timefn;
-	GdkPixmap *pixmap;
-	GtkWidget *da, *tray_tooltip, *status;
-	unsigned char *pic_buf, *tmp;
-    guint timeout_id, idle_id;
-    guint32 timeout_interval;
-    GConfClient *gc;
-    GladeXML *xml;
-    GtkStatusIcon *tray_icon;
+   int dev;
+   int width;
+   int height;
+   int depth;
+   int desk_depth;
+   CamoImageSize size;
+   char name[32];
+   int contrast, brightness, whiteness, colour, hue, bytesperline;
+   unsigned int pixformat;
+   int frame_number;
+
+   int min_width, min_height, max_width, max_height;
+
+   char *video_dev;
+   unsigned char *image;
+   gchar *capturefile, *rcapturefile;
+   gchar *pixdir, *rpixdir;
+   int savetype, rsavetype;
+   gchar *rhost, *rlogin, *rpw;
+   gchar *ts_string;
+   gchar *date_format;
+   gboolean debug, read, hidden;
+   gboolean cap, rcap, acap, show_adjustments, show_effects;
+   gboolean timestamp, rtimestamp, usedate, usestring;
+   gboolean rtimefn, timefn;
+   GdkPixmap *pixmap;
+   GtkWidget *da, *tray_tooltip, *status;
+   unsigned char *pic_buf, *tmp;
+   guint timeout_id, idle_id;
+   guint32 timeout_interval;
+   GConfClient *gc;
+   GladeXML *xml;
+   GtkStatusIcon *tray_icon;
+
+   CamoramaFilterChain* filter_chain;
 
-    CamoramaFilterChain* filter_chain;
+   /* Buffer handling - should be used only inside v4l.c */
+   struct v4l2_requestbuffers req;
+   unsigned int n_buffers;
+   struct  {
+      void   *start;
+      size_t length;
+   } *buffers;
 } cam;
 
 void camera_cap (cam *);
 void set_win_info (cam * cam);
 void get_pic_info (cam *);
-void set_pic_info (cam *);
 void get_win_info (cam *);
-void set_buffer (cam *);
+void start_streaming(cam * cam);
+void capture_buffers(cam * cam, unsigned char *outbuf, int len);
+void stop_streaming(cam * cam);
 
 #endif /* !CAMORAMA_V4L_H */