$ git clone http://tcclient.ion.nu/tc_client.git
commit 14de811d874cfd77cc75b035f58d1fc8c3de005b
Author: Alicia <...>
Date:   Tue Dec 15 14:45:37 2015 +0100

    libcamera: added support for a virtual "Image" camera.

diff --git a/ChangeLog b/ChangeLog
index ef90879..4c55abe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 0.37:
 Reimplemented announcement of moderators.
 Reimplemented announcement of people cammed up when joining.
+libcamera: added support for a virtual "Image" camera.
 0.36:
 Implemented /whois <nick/ID> to check someone's username.
 Changed the /whois output to be more human-readable in cases where the user isn't logged in.
diff --git a/Makefile b/Makefile
index 95f9e84..d93b3f7 100644
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,10 @@ endif
 OBJ=client.o amfparser.o rtmp.o numlist.o amfwriter.o idlist.o colors.o endian.o media.o
 IRCHACK_OBJ=utilities/irchack/irchack.o utilities/compat.o
 MODBOT_OBJ=utilities/modbot/modbot.o utilities/list.o utilities/modbot/queue.o
-CAMVIEWER_OBJ=utilities/camviewer/camviewer.o utilities/compat.o
+CAMVIEWER_OBJ=utilities/camviewer/camviewer.o utilities/compat.o libcamera.a
 CURSEDCHAT_OBJ=utilities/cursedchat/cursedchat.o utilities/cursedchat/buffer.o utilities/compat.o utilities/list.o
-TC_CLIENT_GTK_OBJ=utilities/gtk/camviewer.o utilities/gtk/userlist.o utilities/gtk/media.o utilities/gtk/compat.o utilities/gtk/config.o utilities/gtk/gui.o utilities/stringutils.o utilities/gtk/logging.o utilities/compat.o
+TC_CLIENT_GTK_OBJ=utilities/gtk/camviewer.o utilities/gtk/userlist.o utilities/gtk/media.o utilities/gtk/compat.o utilities/gtk/config.o utilities/gtk/gui.o utilities/stringutils.o utilities/gtk/logging.o utilities/compat.o libcamera.a
+LIBCAMERA_OBJ=utilities/libcamera/camera.o utilities/libcamera/camera_img.o
 UTILS=irchack modbot
 ifdef GTK_LIBS
 ifdef AVCODEC_LIBS
@@ -34,10 +35,8 @@ ifdef SWSCALE_LIBS
  @echo 'To build the core (tc_client.exe), enter this directory from cygwin and type make'
   endif
   ifdef LIBV4L2_LIBS
-    CFLAGS+=-DHAVE_CAM $(LIBV4L2_CFLAGS)
+    CFLAGS+=-DHAVE_V4L2 $(LIBV4L2_CFLAGS)
     LIBCAMERA_OBJ+=utilities/libcamera/camera_v4l2.o
-    CAMVIEWER_OBJ+=libcamera.a
-    TC_CLIENT_GTK_OBJ+=libcamera.a
   endif
 endif
 endif
@@ -95,7 +94,7 @@ SOURCES+=utilities/camviewer/camviewer.c
 SOURCES+=utilities/cursedchat/cursedchat.c utilities/cursedchat/buffer.c utilities/cursedchat/buffer.h
 SOURCES+=utilities/gtk/camviewer.c utilities/gtk/userlist.c utilities/gtk/media.c utilities/gtk/compat.c utilities/gtk/config.c utilities/gtk/gui.c utilities/gtk/logging.c utilities/gtk/userlist.h utilities/gtk/media.h utilities/gtk/compat.h utilities/gtk/config.h utilities/gtk/gui.h utilities/gtk/logging.h gtkgui.glade
 SOURCES+=utilities/compat.c utilities/compat.h utilities/list.c utilities/list.h utilities/stringutils.c utilities/stringutils.h
-SOURCES+=utilities/libcamera/camera.h utilities/libcamera/camera_v4l2.c
+SOURCES+=utilities/libcamera/camera.c utilities/libcamera/camera.h utilities/libcamera/camera_v4l2.c utilities/libcamera/camera_img.c
 tarball:
  tar -cJf tc_client-$(VERSION).tar.xz --transform='s|^|tc_client-$(VERSION)/|' $(SOURCES)
 
diff --git a/utilities/camviewer/camviewer.c b/utilities/camviewer/camviewer.c
index 73fb318..1df934a 100644
--- a/utilities/camviewer/camviewer.c
+++ b/utilities/camviewer/camviewer.c
@@ -41,7 +41,7 @@
   #include <ao/ao.h>
 #endif
 #include <gtk/gtk.h>
-#ifdef HAVE_CAM
+#ifndef _WIN32
   #include "../libcamera/camera.h"
 #endif
 #include "../compat.h"
@@ -390,7 +390,7 @@ void audiothread(int fd)
 }
 #endif
 
-#ifdef HAVE_CAM
+#ifndef _WIN32
 pid_t camproc=0;
 void togglecam(GtkButton* button, struct viddata* data)
 {
@@ -521,7 +521,7 @@ int main(int argc, char** argv)
   g_signal_connect(w, "destroy", gtk_main_quit, 0);
   data.box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
   gtk_container_add(GTK_CONTAINER(w), data.box);
-#ifdef HAVE_CAM
+#ifndef _WIN32
   data.vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);
   GtkWidget* cambutton=gtk_button_new_with_label("Broadcast cam");
   g_signal_connect(cambutton, "clicked", G_CALLBACK(togglecam), &data);
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index f51be67..3636ea8 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -45,9 +45,7 @@
 #endif
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
-#ifdef HAVE_CAM
-  #include "../libcamera/camera.h"
-#endif
+#include "../libcamera/camera.h"
 #include "userlist.h"
 #include "media.h"
 #include "compat.h"
@@ -599,7 +597,6 @@ void audiothread(int fd)
 }
 #endif
 
-#ifdef HAVE_CAM
 unsigned int cameventsource=0;
 void togglecam(GtkCheckMenuItem* item, struct viddata* data)
 {
@@ -623,7 +620,6 @@ void togglecam(GtkCheckMenuItem* item, struct viddata* data)
   GIOChannel* channel=camthread(gtk_combo_box_get_active_id(combo), data->vencoder, 100000);
   cameventsource=g_io_add_watch(channel, G_IO_IN, handledata, 0);
 }
-#endif
 
 gboolean handleresize(GtkWidget* widget, GdkEventConfigure* event, struct viddata* data)
 {
@@ -929,7 +925,6 @@ int main(int argc, char** argv)
   gtk_builder_connect_signals(gui, 0);
 
   unsigned int i;
-#ifdef HAVE_CAM
   GtkWidget* item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
   g_signal_connect(item, "toggled", G_CALLBACK(togglecam), data);
   data->vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);
@@ -949,6 +944,8 @@ int main(int argc, char** argv)
   // Signals for switching from preview to streaming
   item=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_ok"));
   g_signal_connect(item, "clicked", G_CALLBACK(camselect_accept), data->vencoder);
+  // Enable the "img" camera
+  cam_img_filepicker=camselect_file;
   // Populate list of cams
   unsigned int count;
   char** cams=cam_list(&count);
@@ -962,10 +959,6 @@ int main(int argc, char** argv)
   gtk_combo_box_set_model(combo, GTK_TREE_MODEL(list));
   g_object_unref(list);
   gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), gtk_cell_renderer_text_new(), 1);
-#else
-  GtkWidget* item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast"));
-  gtk_widget_destroy(item);
-#endif
 
   item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_options_settings"));
   g_signal_connect(item, "activate", G_CALLBACK(showsettings), gui);
diff --git a/utilities/gtk/media.c b/utilities/gtk/media.c
index 60fe39c..d254445 100644
--- a/utilities/gtk/media.c
+++ b/utilities/gtk/media.c
@@ -18,16 +18,16 @@
 #include <string.h>
 #include <gtk/gtk.h>
 #include <libavcodec/avcodec.h>
-#ifdef HAVE_CAM
-  #include <sys/prctl.h>
-  #include <libswscale/swscale.h>
-  #if LIBAVUTIL_VERSION_MAJOR>50 || (LIBAVUTIL_VERSION_MAJOR==50 && LIBAVUTIL_VERSION_MINOR>37)
-    #include <libavutil/imgutils.h>
-  #else
-    #include <libavcore/imgutils.h>
-  #endif
-  #include "../libcamera/camera.h"
+#ifndef _WIN32
+#include <sys/prctl.h>
 #endif
+#include <libswscale/swscale.h>
+#if LIBAVUTIL_VERSION_MAJOR>50 || (LIBAVUTIL_VERSION_MAJOR==50 && LIBAVUTIL_VERSION_MINOR>37)
+  #include <libavutil/imgutils.h>
+#else
+  #include <libavcore/imgutils.h>
+#endif
+#include "../libcamera/camera.h"
 #include "../compat.h"
 #include "compat.h"
 #include "gui.h"
@@ -155,7 +155,11 @@ void camera_cleanup(void)
   free(cams);
 }
 
-#ifdef HAVE_CAM
+unsigned int* camthread_delay;
+void camthread_resetdelay(int x)
+{
+  *camthread_delay=500000;
+}
 extern unsigned int cameventsource;
 GIOChannel* camthread(const char* name, AVCodec* vencoder, unsigned int delay)
 {
@@ -166,15 +170,18 @@ GIOChannel* camthread(const char* name, AVCodec* vencoder, unsigned int delay)
     usleep(200000); // Give the previous process some time to shut down
   }
   // Set up a second pipe to be handled by handledata() to avoid overlap with tc_client's output
+  CAM* cam=cam_open(name); // Opening here in case of GUI callbacks
   int campipe[2];
   pipe(campipe);
   camproc=fork();
   if(!camproc)
   {
     close(campipe[0]);
+    if(!cam){_exit(1);}
     prctl(PR_SET_PDEATHSIG, SIGHUP);
+    camthread_delay=&delay;
+    signal(SIGUSR1, camthread_resetdelay);
     // Set up camera
-    CAM* cam=cam_open(name);
     AVCodecContext* ctx=avcodec_alloc_context3(vencoder);
     ctx->width=320;
     ctx->height=240;
@@ -226,6 +233,7 @@ GIOChannel* camthread(const char* name, AVCodec* vencoder, unsigned int delay)
     sws_freeContext(swsctx);
     _exit(0);
   }
+  if(cam){cam_close(cam);} // Leave the cam to the child process
   close(campipe[1]);
   GIOChannel* channel=g_io_channel_unix_new(campipe[0]);
   g_io_channel_set_encoding(channel, 0, 0);
@@ -255,10 +263,38 @@ void camselect_accept(GtkWidget* widget, AVCodec* vencoder)
 {
   GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
   gtk_widget_hide(window);
-  // Restart the cam thread with a high initial delay to workaround the bug in the flash client
-  GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
-  GIOChannel* channel=camthread(gtk_combo_box_get_active_id(combo), vencoder, 500000);
-  cameventsource=g_io_add_watch(channel, G_IO_IN, (void*)&handledata, 0);
+  // Tell the camthread to reset the delay to 500000 as a workaround for a quirk in the flash client
+  kill(camproc, SIGUSR1);
   dprintf(tc_client_in[1], "/camup\n");
 }
-#endif
+
+void camselect_file_preview(GtkFileChooser* dialog, gpointer data)
+{
+  GtkImage* preview=GTK_IMAGE(data);
+  char* file=gtk_file_chooser_get_preview_filename(dialog);
+  GdkPixbuf* img=gdk_pixbuf_new_from_file_at_size(file, 256, 256, 0);
+  g_free(file);
+  gtk_image_set_from_pixbuf(preview, img);
+  if(img){g_object_unref(img);}
+  gtk_file_chooser_set_preview_widget_active(dialog, !!img);
+}
+
+const char* camselect_file(void)
+{
+  GtkWidget* preview=gtk_image_new();
+  GtkWindow* window=GTK_WINDOW(gtk_builder_get_object(gui, "camselection"));
+  GtkWidget* dialog=gtk_file_chooser_dialog_new("Open Image", window, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, (char*)0);
+  GtkFileFilter* filter=gtk_file_filter_new();
+  gtk_file_filter_add_pixbuf_formats(filter);
+  gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
+  gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview);
+  g_signal_connect(dialog, "update-preview", G_CALLBACK(camselect_file_preview), preview);
+  int res=gtk_dialog_run(GTK_DIALOG(dialog));
+  char* file;
+  if(res==GTK_RESPONSE_ACCEPT)
+  {
+    file=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+  }else{file=0;}
+  gtk_widget_destroy(dialog);
+  return file;
+}
diff --git a/utilities/gtk/media.h b/utilities/gtk/media.h
index 1824e80..8b2db74 100644
--- a/utilities/gtk/media.h
+++ b/utilities/gtk/media.h
@@ -42,9 +42,8 @@ extern struct camera* camera_find(const char* id);
 extern struct camera* camera_findbynick(const char* nick);
 extern struct camera* camera_new(void);
 extern void camera_cleanup(void);
-#ifdef HAVE_CAM
 extern GIOChannel* camthread(const char* name, AVCodec* vencoder, unsigned int delay);
 extern void camselect_change(GtkComboBox* combo, AVCodec* vencoder);
 extern gboolean camselect_cancel(GtkWidget* widget, void* x1, void* x2);
 extern void camselect_accept(GtkWidget* widget, AVCodec* vencoder);
-#endif
+extern const char* camselect_file(void);
diff --git a/utilities/libcamera/camera.c b/utilities/libcamera/camera.c
new file mode 100644
index 0000000..b005693
--- /dev/null
+++ b/utilities/libcamera/camera.c
@@ -0,0 +1,74 @@
+/*
+    libcamera, a camera access abstraction library
+    Copyright (C) 2015  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, version 3 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "camera.h"
+
+struct CAM_t
+{
+  unsigned int type;
+};
+
+char** cam_list(unsigned int* count)
+{
+  char** list=0;
+  *count=0;
+  #ifdef HAVE_V4L2
+  list=cam_list_v4l2(list, count);
+  #endif
+  list=cam_list_img(list, count);
+  return list;
+}
+
+CAM* cam_open(const char* name)
+{
+  #ifdef HAVE_V4L2
+  if(!strncmp(name, "v4l2:", 5)){return cam_open_v4l2(name);}
+  #endif
+  if(!strcmp(name, "Image")){return cam_open_img();}
+}
+
+void cam_resolution(CAM* cam, unsigned int* width, unsigned int* height)
+{
+  switch(cam->type)
+  {
+    #ifdef HAVE_V4L2
+    case CAMTYPE_V4L2: cam_resolution_v4l2(cam, width, height); break;
+    #endif
+    case CAMTYPE_IMG: cam_resolution_img(cam, width, height); break;
+  }
+}
+
+void cam_getframe(CAM* cam, void* pixmap)
+{
+  switch(cam->type)
+  {
+    #ifdef HAVE_V4L2
+    case CAMTYPE_V4L2: cam_getframe_v4l2(cam, pixmap); break;
+    #endif
+    case CAMTYPE_IMG: cam_getframe_img(cam, pixmap); break;
+  }
+}
+
+void cam_close(CAM* cam)
+{
+  switch(cam->type)
+  {
+    #ifdef HAVE_V4L2
+    case CAMTYPE_V4L2: cam_close_v4l2(cam); break;
+    #endif
+    case CAMTYPE_IMG: cam_close_img(cam); break;
+  }
+}
diff --git a/utilities/libcamera/camera.h b/utilities/libcamera/camera.h
index 0d3f9f6..049705d 100644
--- a/utilities/libcamera/camera.h
+++ b/utilities/libcamera/camera.h
@@ -14,6 +14,10 @@
     You should have received a copy of the GNU Affero General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
+enum{
+  CAMTYPE_V4L2,
+  CAMTYPE_IMG
+};
 struct CAM_t;
 typedef struct CAM_t CAM;
 extern char** cam_list(unsigned int* count);
@@ -22,3 +26,4 @@ extern CAM* cam_open(const char* name);
 extern void cam_resolution(CAM* cam, unsigned int* width, unsigned int* height);
 extern void cam_getframe(CAM* cam, void* pixmap);
 extern void cam_close(CAM* cam);
+extern const char*(*cam_img_filepicker)(void);
diff --git a/utilities/libcamera/camera_img.c b/utilities/libcamera/camera_img.c
new file mode 100644
index 0000000..646bcd1
--- /dev/null
+++ b/utilities/libcamera/camera_img.c
@@ -0,0 +1,113 @@
+/*
+    libcamera, a camera access abstraction library
+    Copyright (C) 2015  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, version 3 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "camera.h"
+
+typedef struct CAM_t
+{
+  unsigned int type;
+  GdkPixbufAnimation* anim;
+  GdkPixbuf* staticimg;
+  GdkPixbufAnimationIter* iter;
+} CAM;
+
+const char*(*cam_img_filepicker)(void)=0;
+
+void cam_img_fixpixels_raw(unsigned char* pixels, unsigned char* from, unsigned int pixelcount)
+{
+  unsigned int i;
+  for(i=0; i<pixelcount; ++i)
+  {
+    memmove(&pixels[i*3], &from[i*4], 3);
+  }
+}
+
+void cam_img_fixpixels(GdkPixbuf* img)
+{
+  if(gdk_pixbuf_get_n_channels(img)==4)
+  {
+    unsigned char* pixels=gdk_pixbuf_get_pixels(img);
+    unsigned int pixelcount=gdk_pixbuf_get_width(img)*gdk_pixbuf_get_height(img);
+    cam_img_fixpixels_raw(pixels, pixels, pixelcount);
+  }
+}
+
+char** cam_list_img(char** list, unsigned int* count)
+{
+  if(!cam_img_filepicker){return list;} // Don't give the option if we don't have the required callback (toolkit-agnostic)
+  ++*count;
+  list=realloc(list, sizeof(char*)*(*count));
+  list[(*count)-1]=strdup("Image");
+  return list;
+}
+
+CAM* cam_open_img(void)
+{
+  if(!cam_img_filepicker){return 0;}
+  const char* file=cam_img_filepicker();
+  if(!file){return 0;}
+  CAM* cam=malloc(sizeof(CAM));
+  cam->type=CAMTYPE_IMG;
+  cam->anim=gdk_pixbuf_animation_new_from_file(file, 0);
+  if(gdk_pixbuf_animation_is_static_image(cam->anim))
+  {
+    cam->staticimg=gdk_pixbuf_animation_get_static_image(cam->anim);
+    cam_img_fixpixels(cam->staticimg);
+    cam->iter=0;
+  }else{
+    cam->staticimg=0;
+    cam->iter=gdk_pixbuf_animation_get_iter(cam->anim, 0);
+  }
+  return cam;
+}
+
+void cam_resolution_img(CAM* cam, unsigned int* width, unsigned int* height)
+{
+  // TODO: Implement scaling of images?
+  GdkPixbuf* img;
+  if(cam->staticimg){img=cam->staticimg;}
+  else{img=gdk_pixbuf_animation_iter_get_pixbuf(cam->iter);}
+  *width=gdk_pixbuf_get_width(img);
+  *height=gdk_pixbuf_get_height(img);
+}
+
+void cam_getframe_img(CAM* cam, void* pixmap)
+{
+  GdkPixbuf* img;
+  if(cam->staticimg)
+  {
+    img=cam->staticimg;
+  }else{
+    gdk_pixbuf_animation_iter_advance(cam->iter, 0);
+    img=gdk_pixbuf_animation_iter_get_pixbuf(cam->iter);
+  }
+  void* pixels=gdk_pixbuf_get_pixels(img);
+  if(cam->iter && gdk_pixbuf_get_n_channels(img)==4) // Inefficient, but we don't get to fix the pixbuf itself and mark it as fixed, at least not with any of the ways I've tried
+  {
+    cam_img_fixpixels_raw(pixmap, pixels, gdk_pixbuf_get_width(img)*gdk_pixbuf_get_height(img));
+  }else{
+    memcpy(pixmap, pixels, gdk_pixbuf_get_width(img)*3*gdk_pixbuf_get_height(img));
+  }
+}
+
+void cam_close_img(CAM* cam)
+{
+  g_object_unref(G_OBJECT(cam->anim));
+  free(cam);
+}
diff --git a/utilities/libcamera/camera_v4l2.c b/utilities/libcamera/camera_v4l2.c
index 3a488e3..8bbee7d 100644
--- a/utilities/libcamera/camera_v4l2.c
+++ b/utilities/libcamera/camera_v4l2.c
@@ -25,14 +25,13 @@
 
 typedef struct CAM_t
 {
+  unsigned int type;
   int fd;
   unsigned int framesize;
 } CAM;
 
-char** cam_list(unsigned int* count)
+char** cam_list_v4l2(char** list, unsigned int* count)
 {
-  char** list=0;
-  *count=0;
   DIR* dir=opendir("/dev");
   struct dirent* entry;
   while((entry=readdir(dir)))
@@ -41,22 +40,23 @@ char** cam_list(unsigned int* count)
     {
       ++*count;
       list=realloc(list, sizeof(char*)*(*count));
-      char* path=malloc(strlen("/dev/0")+strlen(entry->d_name));
-      sprintf(path, "/dev/%s", entry->d_name);
+      char* path=malloc(strlen("v4l2:/dev/0")+strlen(entry->d_name));
+      sprintf(path, "v4l2:/dev/%s", entry->d_name);
       list[(*count)-1]=path;
     }
   }
   return list;
 }
 
-CAM* cam_open(const char* name)
+CAM* cam_open_v4l2(const char* name)
 {
   CAM* cam=malloc(sizeof(CAM));
-  cam->fd=v4l2_open(name, O_RDWR);
+  cam->type=CAMTYPE_V4L2;
+  cam->fd=v4l2_open(&name[5], O_RDWR);
   return cam;
 }
 
-void cam_resolution(CAM* cam, unsigned int* width, unsigned int* height)
+void cam_resolution_v4l2(CAM* cam, unsigned int* width, unsigned int* height)
 {
   struct v4l2_format fmt;
   fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -73,12 +73,12 @@ void cam_resolution(CAM* cam, unsigned int* width, unsigned int* height)
   cam->framesize=(*width)*(*height)*3;
 }
 
-void cam_getframe(CAM* cam, void* pixmap)
+void cam_getframe_v4l2(CAM* cam, void* pixmap)
 {
   v4l2_read(cam->fd, pixmap, cam->framesize);
 }
 
-void cam_close(CAM* cam)
+void cam_close_v4l2(CAM* cam)
 {
   v4l2_close(cam->fd);
   free(cam);