$ 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);
}