aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/test/Makefile.am2
-rw-r--r--contrib/test/v4l2grab.c261
2 files changed, 219 insertions, 44 deletions
diff --git a/contrib/test/Makefile.am b/contrib/test/Makefile.am
index 4ccb5ede..0bfa33e4 100644
--- a/contrib/test/Makefile.am
+++ b/contrib/test/Makefile.am
@@ -23,7 +23,7 @@ pixfmt_test_CFLAGS = $(X11_CFLAGS)
pixfmt_test_LDFLAGS = $(X11_LIBS)
v4l2grab_SOURCES = v4l2grab.c
-v4l2grab_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la
+v4l2grab_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la -lpthread
v4l2gl_SOURCES = v4l2gl.c
v4l2gl_LDFLAGS = $(X11_LIBS) $(GL_LIBS) $(GLU_LIBS)
diff --git a/contrib/test/v4l2grab.c b/contrib/test/v4l2grab.c
index 674cbe73..3e1be3de 100644
--- a/contrib/test/v4l2grab.c
+++ b/contrib/test/v4l2grab.c
@@ -24,8 +24,10 @@
#include <linux/videodev2.h>
#include "../../lib/include/libv4l2.h"
#include <argp.h>
+#include <pthread.h>
-#define CLEAR(x) memset(&(x), 0, sizeof(x))
+#define CLEAR_P(x,s) memset((x), 0, s)
+#define CLEAR(x) CLEAR_P(&(x), sizeof(x))
struct buffer {
void *start;
@@ -46,22 +48,206 @@ static void xioctl(int fh, unsigned long int request, void *arg)
}
}
+/* Used by the multi thread capture version */
+struct buffer_queue {
+ struct v4l2_buffer *buffers;
+ int buffers_size;
+
+ int read_pos;
+ int write_pos;
+ int n_frames;
+
+ int fd;
+
+ pthread_mutex_t mutex;
+ pthread_cond_t buffer_cond;
+};
+
+/* Gets a buffer and puts it in the buffers list at write position, then
+ * notifies the consumer that a new buffer is ready to be used */
+static void *produce_buffer (void * p)
+{
+ struct buffer_queue *bq;
+ fd_set fds;
+ struct timeval tv;
+ int i;
+ struct v4l2_buffer *buf;
+ int r;
+
+ bq = p;
+
+ for (i = 0; i < bq->n_frames; i++) {
+ printf ("Prod: %d\n", i);
+ buf = &bq->buffers[bq->write_pos % bq->buffers_size];
+ do {
+ FD_ZERO(&fds);
+ FD_SET(bq->fd, &fds);
+
+ /* Timeout. */
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ r = select(bq->fd + 1, &fds, NULL, NULL, &tv);
+ } while ((r == -1 && (errno == EINTR)));
+ if (r == -1) {
+ perror("select");
+ pthread_exit (NULL);
+ return NULL;
+ }
+
+ CLEAR_P(buf, sizeof(struct v4l2_buffer));
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->memory = V4L2_MEMORY_MMAP;
+ xioctl(bq->fd, VIDIOC_DQBUF, buf);
+
+ pthread_mutex_lock (&bq->mutex);
+ bq->write_pos++;
+ printf ("Prod: %d (done)\n", i);
+ pthread_cond_signal (&bq->buffer_cond);
+ pthread_mutex_unlock (&bq->mutex);
+
+ }
+
+ pthread_exit (NULL);
+}
+
+/* will create a separate thread that will produce the buffers and put
+ * into a circular array while this same thread will get the buffers from
+ * this array and 'render' them */
+static int capture_threads (int fd, struct buffer *buffers, int bufpool_size,
+ struct v4l2_format fmt, int n_frames,
+ char *out_dir, int sleep_ms)
+{
+ struct v4l2_buffer buf;
+ unsigned int i;
+ struct buffer_queue buf_queue;
+ pthread_t producer;
+ char out_name[25 + strlen(out_dir)];
+ FILE *fout;
+ struct timespec sleeptime;
+
+ if (sleep_ms) {
+ sleeptime.tv_sec = sleep_ms / 1000;
+ sleeptime.tv_nsec = (sleep_ms % 1000) * 1000000;
+ }
+
+ buf_queue.buffers_size = bufpool_size * 2;
+ buf_queue.buffers = calloc(buf_queue.buffers_size,
+ sizeof(struct v4l2_buffer));
+ buf_queue.fd = fd;
+ buf_queue.read_pos = 0;
+ buf_queue.write_pos = 0;
+ buf_queue.n_frames = n_frames;
+ pthread_mutex_init (&buf_queue.mutex, NULL);
+ pthread_cond_init (&buf_queue.buffer_cond, NULL);
+
+ pthread_create (&producer, NULL, produce_buffer, &buf_queue);
+
+ for (i = 0; i < n_frames; i++) {
+ printf ("Read: %d\n", i);
+
+ /* wait for a buffer to be available in the queue */
+ pthread_mutex_lock (&buf_queue.mutex);
+ while (buf_queue.read_pos == buf_queue.write_pos) {
+ pthread_cond_wait (&buf_queue.buffer_cond,
+ &buf_queue.mutex);
+ }
+ pthread_mutex_unlock (&buf_queue.mutex);
+
+ if (sleep_ms)
+ nanosleep (&sleeptime, NULL);
+
+ sprintf(out_name, "%s/out%03d.ppm", out_dir, i);
+ fout = fopen(out_name, "w");
+ if (!fout) {
+ perror("Cannot open image");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fout, "P6\n%d %d 255\n",
+ fmt.fmt.pix.width, fmt.fmt.pix.height);
+ buf = buf_queue.buffers[buf_queue.read_pos %
+ buf_queue.buffers_size];
+ fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
+ fclose(fout);
+
+ xioctl(fd, VIDIOC_QBUF, &buf);
+
+ pthread_mutex_lock (&buf_queue.mutex);
+ buf_queue.read_pos++;
+ printf ("Read: %d (done)\n", i);
+ pthread_cond_signal (&buf_queue.buffer_cond);
+ pthread_mutex_unlock (&buf_queue.mutex);
+ }
+
+ pthread_mutex_destroy (&buf_queue.mutex);
+ pthread_cond_destroy (&buf_queue.buffer_cond);
+ free (buf_queue.buffers);
+ return 0;
+}
+
+static int capture_loop (int fd, struct buffer *buffers, struct v4l2_format fmt,
+ int n_frames, char *out_dir)
+{
+ struct v4l2_buffer buf;
+ unsigned int i;
+ struct timeval tv;
+ int r;
+ fd_set fds;
+ FILE *fout;
+ char out_name[25 + strlen(out_dir)];
+
+ for (i = 0; i < n_frames; i++) {
+ do {
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ /* Timeout. */
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ r = select(fd + 1, &fds, NULL, NULL, &tv);
+ } while ((r == -1 && (errno == EINTR)));
+ if (r == -1) {
+ perror("select");
+ return errno;
+ }
+
+ CLEAR(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ xioctl(fd, VIDIOC_DQBUF, &buf);
+
+ sprintf(out_name, "%s/out%03d.ppm", out_dir, i);
+ fout = fopen(out_name, "w");
+ if (!fout) {
+ perror("Cannot open image");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fout, "P6\n%d %d 255\n",
+ fmt.fmt.pix.width, fmt.fmt.pix.height);
+ fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
+ fclose(fout);
+
+ xioctl(fd, VIDIOC_QBUF, &buf);
+ }
+ return 0;
+}
+
static int capture(char *dev_name, int x_res, int y_res, int n_frames,
- char *out_dir)
+ char *out_dir, int block, int threads, int sleep_ms)
{
struct v4l2_format fmt;
struct v4l2_buffer buf;
struct v4l2_requestbuffers req;
enum v4l2_buf_type type;
- fd_set fds;
- struct timeval tv;
- int r, fd = -1;
+ int fd = -1;
unsigned int i, n_buffers;
- char out_name[25 + strlen(out_dir)];
- FILE *fout;
struct buffer *buffers;
- fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
+ if (block)
+ fd = v4l2_open(dev_name, O_RDWR, 0);
+ else
+ fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
if (fd < 0) {
perror("Cannot open device");
exit(EXIT_FAILURE);
@@ -119,40 +305,11 @@ static int capture(char *dev_name, int x_res, int y_res, int n_frames,
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMON, &type);
- for (i = 0; i < n_frames; i++) {
- do {
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- /* Timeout. */
- tv.tv_sec = 2;
- tv.tv_usec = 0;
-
- r = select(fd + 1, &fds, NULL, NULL, &tv);
- } while ((r == -1 && (errno == EINTR)));
- if (r == -1) {
- perror("select");
- return errno;
- }
-
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- xioctl(fd, VIDIOC_DQBUF, &buf);
-
- sprintf(out_name, "%s/out%03d.ppm", out_dir, i);
- fout = fopen(out_name, "w");
- if (!fout) {
- perror("Cannot open image");
- exit(EXIT_FAILURE);
- }
- fprintf(fout, "P6\n%d %d 255\n",
- fmt.fmt.pix.width, fmt.fmt.pix.height);
- fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
- fclose(fout);
-
- xioctl(fd, VIDIOC_QBUF, &buf);
- }
+ if (threads)
+ capture_threads(fd, buffers, 2, fmt, n_frames, out_dir,
+ sleep_ms);
+ else
+ capture_loop(fd, buffers, fmt, n_frames, out_dir);
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMOFF, &type);
@@ -179,6 +336,9 @@ static const struct argp_option options[] = {
{"xres", 'x', "XRES", 0, "horizontal resolution", 0},
{"yres", 'y', "YRES", 0, "vertical resolution", 0},
{"n-frames", 'n', "NFRAMES", 0, "number of frames to capture", 0},
+ {"thread-enable", 't', "THREADS", 0, "if different threads should capture and save", 0},
+ {"blockmode-enable", 'b', "BLOCKMODE", 0, "if blocking mode should be used", 0},
+ {"sleep-time", 's', "SLEEP", 0, "how long should the consumer thread sleep to simulate the processing of a buffer (in ms)"},
{ 0, 0, 0, 0, 0, 0 }
};
@@ -188,6 +348,9 @@ static char *out_dir = ".";
static int x_res = 640;
static int y_res = 480;
static int n_frames = 20;
+static int threads = 0;
+static int block = 0;
+static int sleep_ms = 0;
static error_t parse_opt(int k, char *arg, struct argp_state *state)
{
@@ -215,6 +378,17 @@ static error_t parse_opt(int k, char *arg, struct argp_state *state)
if (val)
n_frames = val;
break;
+ case 't':
+ threads = 1;
+ break;
+ case 'b':
+ block = 1;
+ break;
+ case 's':
+ val = atoi(arg);
+ if (val)
+ sleep_ms = val;
+ break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -232,5 +406,6 @@ int main(int argc, char **argv)
{
argp_parse(&argp, argc, argv, 0, 0, 0);
- return capture(dev_name, x_res, y_res, n_frames, out_dir);
+ return capture(dev_name, x_res, y_res, n_frames, out_dir, block,
+ threads, sleep_ms);
}

Privacy Policy