videograb : first step
This commit is contained in:
parent
f0f8daa0fb
commit
c054054ee5
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,6 +9,8 @@ gmon.out
|
|||||||
*.fimg
|
*.fimg
|
||||||
essai
|
essai
|
||||||
|
|
||||||
|
*/*.ps
|
||||||
|
|
||||||
v4l2/t
|
v4l2/t
|
||||||
v4l2/capture
|
v4l2/capture
|
||||||
v4l2/*.o
|
v4l2/*.o
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
COPT = -Wall -fpic -g -DDEBUG_LEVEL=1
|
COPT = -Wall -fpic -g -DDEBUG_LEVEL=1
|
||||||
DEPS = ../floatimg.h ../libfloatimg.a Makefile
|
DEPS = ../floatimg.h ../libfloatimg.a Makefile
|
||||||
|
|
||||||
|
funcs.o: funcs.c funcs.h Makefile
|
||||||
|
gcc ${COPT} -c $<
|
||||||
|
|
||||||
|
t: t.c Makefile ${DEPS} funcs.o
|
||||||
|
gcc ${COPT} $< funcs.o ../libfloatimg.a -o $@
|
||||||
|
|
||||||
t: t.c Makefile ${DEPS}
|
# ---------------
|
||||||
gcc ${COPT} $< ../libfloatimg.a -o $@
|
# external things
|
||||||
|
|
||||||
# --------
|
|
||||||
# extern things
|
|
||||||
|
|
||||||
capture: capture.c Makefile
|
capture: capture.c Makefile
|
||||||
gcc -Wall $< -o $@
|
gcc -Wall $< -o $@
|
||||||
|
317
v4l2/funcs.c
Normal file
317
v4l2/funcs.c
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* V4L2 functions - ugly source code
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fcntl.h> /* low-level i/o */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
extern int verbosity;
|
||||||
|
|
||||||
|
enum io_method {
|
||||||
|
IO_METHOD_READ,
|
||||||
|
IO_METHOD_MMAP,
|
||||||
|
IO_METHOD_USERPTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buffer {
|
||||||
|
void *start;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *dev_name;
|
||||||
|
static enum io_method io = IO_METHOD_MMAP;
|
||||||
|
static int fd = -1;
|
||||||
|
struct buffer *buffers;
|
||||||
|
static unsigned int n_buffers;
|
||||||
|
static int out_buf;
|
||||||
|
static int force_format;
|
||||||
|
static int frame_count = 70;
|
||||||
|
|
||||||
|
static void errno_exit(const char *s)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
static int xioctl(int fh, int request, void *arg)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
do {
|
||||||
|
r = ioctl(fh, request, arg);
|
||||||
|
} while (-1 == r && EINTR == errno);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int open_device(char *device)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (-1 == stat(device, &st)) {
|
||||||
|
fprintf(stderr, "Cannot identify '%s': %d, %s\n",
|
||||||
|
device, errno, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISCHR(st.st_mode)) {
|
||||||
|
fprintf(stderr, "%s is no device\n", device);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(device, O_RDWR /* required */ | O_NONBLOCK, 0);
|
||||||
|
|
||||||
|
if (-1 == fd) {
|
||||||
|
fprintf(stderr, "Cannot open '%s': %d, %s\n",
|
||||||
|
device, errno, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_name = strdup(device); /* XXX */
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
static void init_read(unsigned int buffer_size)
|
||||||
|
{
|
||||||
|
buffers = calloc(1, sizeof(*buffers));
|
||||||
|
|
||||||
|
if (!buffers) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers[0].length = buffer_size;
|
||||||
|
buffers[0].start = malloc(buffer_size);
|
||||||
|
|
||||||
|
if (!buffers[0].start) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_mmap(void)
|
||||||
|
{
|
||||||
|
struct v4l2_requestbuffers req;
|
||||||
|
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
|
||||||
|
req.count = 4;
|
||||||
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
|
||||||
|
if (EINVAL == errno) {
|
||||||
|
fprintf(stderr, "%s does not support "
|
||||||
|
"memory mapping\n", dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
errno_exit("VIDIOC_REQBUFS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.count < 2) {
|
||||||
|
fprintf(stderr, "Insufficient buffer memory on %s\n",
|
||||||
|
dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers = calloc(req.count, sizeof(*buffers));
|
||||||
|
|
||||||
|
if (!buffers) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = n_buffers;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||||
|
errno_exit("VIDIOC_QUERYBUF");
|
||||||
|
|
||||||
|
buffers[n_buffers].length = buf.length;
|
||||||
|
buffers[n_buffers].start =
|
||||||
|
mmap(NULL /* start anywhere */,
|
||||||
|
buf.length,
|
||||||
|
PROT_READ | PROT_WRITE /* required */,
|
||||||
|
MAP_SHARED /* recommended */,
|
||||||
|
fd, buf.m.offset);
|
||||||
|
|
||||||
|
if (MAP_FAILED == buffers[n_buffers].start)
|
||||||
|
errno_exit("mmap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_userp(unsigned int buffer_size)
|
||||||
|
{
|
||||||
|
struct v4l2_requestbuffers req;
|
||||||
|
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
|
||||||
|
req.count = 4;
|
||||||
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
req.memory = V4L2_MEMORY_USERPTR;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
|
||||||
|
if (EINVAL == errno) {
|
||||||
|
fprintf(stderr, "%s does not support "
|
||||||
|
"user pointer i/o\n", dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
errno_exit("VIDIOC_REQBUFS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers = calloc(4, sizeof(*buffers));
|
||||||
|
|
||||||
|
if (!buffers) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
|
||||||
|
buffers[n_buffers].length = buffer_size;
|
||||||
|
buffers[n_buffers].start = malloc(buffer_size);
|
||||||
|
|
||||||
|
if (!buffers[n_buffers].start) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
int init_device(int notused)
|
||||||
|
{
|
||||||
|
struct v4l2_capability cap;
|
||||||
|
struct v4l2_cropcap cropcap;
|
||||||
|
struct v4l2_crop crop;
|
||||||
|
struct v4l2_format fmt;
|
||||||
|
unsigned int min;
|
||||||
|
|
||||||
|
#if DEBUG_LEVEL
|
||||||
|
fprintf(stderr, ">>> %s ( %d )\n", __func__, notused);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
|
||||||
|
if (EINVAL == errno) {
|
||||||
|
fprintf(stderr, "%s is no V4L2 device\n", dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
errno_exit("VIDIOC_QUERYCAP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||||
|
fprintf(stderr, "%s is no video capture device\n", dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (io) {
|
||||||
|
case IO_METHOD_READ:
|
||||||
|
if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
|
||||||
|
fprintf(stderr, "%s do not support read i/o\n", dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (verbosity) fprintf(stderr, "%s io method read OK\n", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_METHOD_MMAP:
|
||||||
|
case IO_METHOD_USERPTR:
|
||||||
|
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||||
|
fprintf(stderr, "%s do not support streaming i/o\n", dev_name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (verbosity) fprintf(stderr, "%s io mmap/userptr OK\n", __func__);
|
||||||
|
break;
|
||||||
|
} /* end switch */
|
||||||
|
|
||||||
|
/* Select video input, video standard and tune here. */
|
||||||
|
|
||||||
|
|
||||||
|
memset(&cropcap, 0, sizeof(cropcap));
|
||||||
|
|
||||||
|
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
|
if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
|
||||||
|
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
crop.c = cropcap.defrect; /* reset to default */
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
|
||||||
|
switch (errno) {
|
||||||
|
case EINVAL:
|
||||||
|
/* Cropping not supported. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Errors ignored. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Errors ignored. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
memset(&fmt, 0, sizeof(fmt)); // CLEAR(fmt);
|
||||||
|
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
if (force_format) {
|
||||||
|
fmt.fmt.pix.width = 640;
|
||||||
|
fmt.fmt.pix.height = 480;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||||
|
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||||
|
errno_exit("VIDIOC_S_FMT");
|
||||||
|
|
||||||
|
/* Note VIDIOC_S_FMT may change width and height. */
|
||||||
|
} else {
|
||||||
|
/* Preserve original settings as set by v4l2-ctl for example */
|
||||||
|
if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
|
||||||
|
errno_exit("VIDIOC_G_FMT");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buggy driver paranoia. */
|
||||||
|
min = fmt.fmt.pix.width * 2;
|
||||||
|
if (fmt.fmt.pix.bytesperline < min)
|
||||||
|
fmt.fmt.pix.bytesperline = min;
|
||||||
|
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
|
||||||
|
if (fmt.fmt.pix.sizeimage < min)
|
||||||
|
fmt.fmt.pix.sizeimage = min;
|
||||||
|
|
||||||
|
switch (io) {
|
||||||
|
case IO_METHOD_READ:
|
||||||
|
init_read(fmt.fmt.pix.sizeimage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_METHOD_MMAP:
|
||||||
|
init_mmap();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_METHOD_USERPTR:
|
||||||
|
init_userp(fmt.fmt.pix.sizeimage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
7
v4l2/funcs.h
Normal file
7
v4l2/funcs.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
* V4L2 functions - header file
|
||||||
|
*/
|
||||||
|
|
||||||
|
int open_device(char *dev_name);
|
||||||
|
|
||||||
|
int init_device(int notused);
|
27
v4l2/t.c
27
v4l2/t.c
@ -8,10 +8,26 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "funcs.h"
|
||||||
#include "floatimg.h"
|
#include "floatimg.h"
|
||||||
|
|
||||||
int verbosity;
|
int verbosity;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------- */
|
||||||
|
int essai(char *dev, int k)
|
||||||
|
{
|
||||||
|
int vfd, foo;
|
||||||
|
|
||||||
|
fprintf(stderr, ">>> %s ( '%s' %d )\n", __func__, dev, k);
|
||||||
|
|
||||||
|
vfd = open_device(dev);
|
||||||
|
fprintf(stderr, "\topen %s -> %d\n", dev, vfd);
|
||||||
|
|
||||||
|
foo = init_device(0);
|
||||||
|
fprintf(stderr, "\tinit -> %d\n", foo);
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
void help(int k)
|
void help(int k)
|
||||||
{
|
{
|
||||||
@ -23,16 +39,16 @@ puts("\t-v\tincrease verbosity");
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int foo, opt;
|
int foo, opt;
|
||||||
int W = 800, H = 600;
|
|
||||||
double tb;
|
char *device = "/dev/video0";
|
||||||
int K = 0;
|
int K = 0;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "hK:v")) != -1) {
|
while ((opt = getopt(argc, argv, "d:hK:v")) != -1) {
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
|
case 'd': device = optarg; break;
|
||||||
case 'h': help(0); break;
|
case 'h': help(0); break;
|
||||||
case 'K': K = atol(optarg); break;
|
case 'K': K = atol(optarg); break;
|
||||||
case 'v': verbosity++; break;
|
case 'v': verbosity++; break;
|
||||||
@ -41,6 +57,9 @@ while ((opt = getopt(argc, argv, "hK:v")) != -1) {
|
|||||||
|
|
||||||
if (verbosity) fimg_print_version(0);
|
if (verbosity) fimg_print_version(0);
|
||||||
|
|
||||||
|
foo = essai(device, K);
|
||||||
|
fprintf(stderr, "\tessai -> %d\n", foo);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
|
Loading…
Reference in New Issue
Block a user