$ git clone http://tcclient.ion.nu/tc_client.git
commit 3ad7ec29ab5dbb9b3b058f4b338ecc5a333eddb4
Author: Alicia <...>
Date:   Mon Sep 26 15:19:28 2016 +0200

    libcamera(v4l2): cache the frame and if there is no data to be read, return the cache instead of blocking.

diff --git a/ChangeLog b/ChangeLog
index 232150f..95fc458 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,7 @@ tc_client-gtk: use the camera's own copy of its ID for g_timeout_add() rather th
 tc_client-gtk: cleaned up leftover windows compatibility code that is no longer necessary.
 tc_client-gtk: changed the greenscreen postprocessor to use libcamera for the background, allowing you to use either another camera or an image through the virtual "Image" camera as background.
 tc_client-gtk and camviewer: updated to libavcodec's avcodec_{send,receive}_{frame,packet} API.
+libcamera(v4l2): cache the frame and if there is no data to be read, return the cache instead of blocking.
 0.39:
 Added a /closecam command to stop receiving a cam stream.
 Use uintX_t for endianness functions instead of unsigned long*x int.
diff --git a/utilities/libcamera/camera_v4l2.c b/utilities/libcamera/camera_v4l2.c
index 4ecf72d..28233af 100644
--- a/utilities/libcamera/camera_v4l2.c
+++ b/utilities/libcamera/camera_v4l2.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <libv4l2.h>
 #include <linux/videodev2.h>
 #include "camera.h"
@@ -28,6 +29,7 @@ typedef struct CAM_t
   unsigned int type;
   int fd;
   unsigned int framesize;
+  void* cache;
 } CAM;
 
 char** cam_list_v4l2(char** list, unsigned int* count)
@@ -55,6 +57,8 @@ CAM* cam_open_v4l2(const char* name)
   CAM* cam=malloc(sizeof(CAM));
   cam->type=CAMTYPE_V4L2;
   cam->fd=fd;
+  cam->cache=0;
+  cam->framesize=0;
   return cam;
 }
 
@@ -73,18 +77,32 @@ void cam_resolution_v4l2(CAM* cam, unsigned int* width, unsigned int* height)
   *width=fmt.fmt.pix.width;
   *height=fmt.fmt.pix.height;
   cam->framesize=(*width)*(*height)*3;
+  free(cam->cache);
+  cam->cache=malloc(cam->framesize);
+  memset(cam->cache, 0x7f, cam->framesize);
 }
 
 void cam_getframe_v4l2(CAM* cam, void* pixmap)
 {
-  if(v4l2_read(cam->fd, pixmap, cam->framesize)<0)
+  if(!cam->cache){memset(pixmap, 0x7f, cam->framesize); return;}
+  // Check if there is data to read from the camera and either update the cache or return the old cache.
+  struct pollfd pfd={.fd=cam->fd, .events=POLLIN, .revents=0};
+  poll(&pfd, 1, 0);
+  if(pfd.revents && v4l2_read(cam->fd, cam->cache, cam->framesize)<1)
   {
-    memset(pixmap, 0x7f, cam->framesize);
+    // If we run into errors, close the handle and let it show as gray
+    free(cam->cache);
+    cam->cache=0;
+    v4l2_close(cam->fd);
+    cam->fd=-1;
+    return;
   }
+  memcpy(pixmap, cam->cache, cam->framesize);
 }
 
 void cam_close_v4l2(CAM* cam)
 {
   v4l2_close(cam->fd);
+  free(cam->cache);
   free(cam);
 }