From c054054ee5fdbfa1ee9e3209db61ba02557f3ea9 Mon Sep 17 00:00:00 2001 From: Tonton Th Date: Sat, 25 May 2019 16:16:24 +0200 Subject: [PATCH] videograb : first step --- .gitignore | 2 + v4l2/Makefile | 11 +- v4l2/funcs.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++ v4l2/funcs.h | 7 ++ v4l2/t.c | 27 ++++- 5 files changed, 355 insertions(+), 9 deletions(-) create mode 100644 v4l2/funcs.c create mode 100644 v4l2/funcs.h diff --git a/.gitignore b/.gitignore index bb58569..dde6e14 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ gmon.out *.fimg essai +*/*.ps + v4l2/t v4l2/capture v4l2/*.o diff --git a/v4l2/Makefile b/v4l2/Makefile index 5f5081a..916636a 100644 --- a/v4l2/Makefile +++ b/v4l2/Makefile @@ -3,13 +3,14 @@ COPT = -Wall -fpic -g -DDEBUG_LEVEL=1 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 $@ - -# -------- -# extern things +# --------------- +# external things capture: capture.c Makefile gcc -Wall $< -o $@ diff --git a/v4l2/funcs.c b/v4l2/funcs.c new file mode 100644 index 0000000..ff78abc --- /dev/null +++ b/v4l2/funcs.c @@ -0,0 +1,317 @@ +/* + * V4L2 functions - ugly source code + */ + +#include +#include +#include + +#include /* low-level i/o */ +#include +#include +#include +#include +#include + +#include + +/* --------------------------------------------------------------------- */ + +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; +} + diff --git a/v4l2/funcs.h b/v4l2/funcs.h new file mode 100644 index 0000000..90393ab --- /dev/null +++ b/v4l2/funcs.h @@ -0,0 +1,7 @@ +/* + * V4L2 functions - header file + */ + +int open_device(char *dev_name); + +int init_device(int notused); \ No newline at end of file diff --git a/v4l2/t.c b/v4l2/t.c index 8844c8f..a368cb2 100644 --- a/v4l2/t.c +++ b/v4l2/t.c @@ -8,10 +8,26 @@ #include #include +#include "funcs.h" #include "floatimg.h" 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) { @@ -23,16 +39,16 @@ puts("\t-v\tincrease verbosity"); exit(0); } /* --------------------------------------------------------------------- */ - int main(int argc, char *argv[]) { int foo, opt; -int W = 800, H = 600; -double tb; + +char *device = "/dev/video0"; int K = 0; -while ((opt = getopt(argc, argv, "hK:v")) != -1) { +while ((opt = getopt(argc, argv, "d:hK:v")) != -1) { switch(opt) { + case 'd': device = optarg; break; case 'h': help(0); break; case 'K': K = atol(optarg); break; case 'v': verbosity++; break; @@ -41,6 +57,9 @@ while ((opt = getopt(argc, argv, "hK:v")) != -1) { if (verbosity) fimg_print_version(0); +foo = essai(device, K); +fprintf(stderr, "\tessai -> %d\n", foo); + return 0; } /* --------------------------------------------------------------------- */