source tree refactor and build system (to be completed)

This commit is contained in:
John Doe
2021-05-11 22:44:13 +02:00
parent cc79dd5152
commit bbc0309591
121 changed files with 259 additions and 290 deletions

38
src/v4l2/Makefile Normal file
View File

@@ -0,0 +1,38 @@
COPT = -Wall -fpic -g -no-pie -DDEBUG_LEVEL=0
DEPS = ../floatimg.h ../libfloatimg.a Makefile
LOBJ = funcs.o v4l2_pr_structs.o
all: grabvidseq t video-infos nc-camcontrol
t: t.c Makefile ${DEPS} funcs.o v4l2_pr_structs.o
gcc ${COPT} $< funcs.o v4l2_pr_structs.o ../libfloatimg.a -o $@
funcs.o: funcs.c funcs.h Makefile
gcc ${COPT} -c $<
rgb2fimg.o: rgb2fimg.c funcs.h Makefile
gcc ${COPT} -c $<
v4l2_pr_structs.o: v4l2_pr_structs.c v4l2_pr_structs.h Makefile
gcc ${COPT} -c $<
grabvidseq: grabvidseq.c ${DEPS} rgb2fimg.o
gcc ${COPT} $< rgb2fimg.o ../libfloatimg.a -lpnglite -lz -lm \
-lcfitsio -lv4l2 -ltiff -o $@
video-infos: video-infos.c Makefile funcs.o v4l2_pr_structs.o
gcc -Wall -g $< ${LOBJ} ../libfloatimg.a -o $@
nc-camcontrol: nc-camcontrol.c Makefile funcs.o v4l2_pr_structs.o
gcc -Wall -g $< ${LOBJ} ../libfloatimg.a -lcurses -o $@
# ---------------
# external things
capture: capture.c Makefile
gcc -Wall -g $< -o $@

32
src/v4l2/README.md Normal file
View File

@@ -0,0 +1,32 @@
# Images en virgule flottante, video 4 linux
## grabvidseq
```
tth@lubitel:~/Devel/FloatImg/v4l2$ ./grabvidseq -h
options :
-d /dev/? select video device
-g convert to gray
-n NNN how many frames ?
-O ./ set Output dir
-o bla.xxx set output filename
-p NN.N period in seconds
-r 90 rotate picture
-s WxH size of capture
-c mode contrast enhancement
-u try upscaling...
-v increase verbosity
```
## video-infos
```
Options :
-e N examine that, please
-d select the video device
-K set the K parameter
-l list video devices
-T bla add a title
-v increase verbosity
```

13
src/v4l2/README.txt Normal file
View File

@@ -0,0 +1,13 @@
capture video
-------------
------------------------------------------------------------------------
<paulk-leonov> tth: en faisant de la revue de patch sur V4L2, j'apprends
que V4L2_FMT_FLAG et V4L2_PIX_FMT_FLAG n'ont rien à voir:
le premier concerne le champ flags de la structure de l'ioctl enum_fmt
et le second le champ flag de la structure de g_fmt.
------------------------------------------------------------------------

670
src/v4l2/capture.c Normal file
View File

@@ -0,0 +1,670 @@
/*
.. Permission is granted to copy, distribute and/or modify this
.. document under the terms of the GNU Free Documentation License,
.. Version 1.1 or any later version published by the Free Software
.. Foundation, with no Invariant Sections, no Front-Cover Texts
.. and no Back-Cover Texts. A copy of the license is included at
.. Documentation/media/uapi/fdl-appendix.rst.
file: media/v4l/capture.c
=========================
*/
/*
* V4L2 video capture example
*
* This program can be used and distributed without restrictions.
*
* This program is provided with the V4L2 API
* see https://linuxtv.org/docs.php for more information
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h> /* getopt_long() */
#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#define CLEAR(x) memset(&(x), 0, sizeof(x))
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;
}
static void process_image(const void *p, int size)
{
if (out_buf)
fwrite(p, size, 1, stdout);
fflush(stderr);
fprintf(stderr, ".");
fflush(stdout);
}
static int read_frame(void)
{
struct v4l2_buffer buf;
unsigned int i;
switch (io) {
case IO_METHOD_READ:
if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("read");
}
}
process_image(buffers[0].start, buffers[0].length);
break;
case IO_METHOD_MMAP:
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("VIDIOC_DQBUF");
}
}
assert(buf.index < n_buffers);
process_image(buffers[buf.index].start, buf.bytesused);
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
break;
case IO_METHOD_USERPTR:
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("VIDIOC_DQBUF");
}
}
for (i = 0; i < n_buffers; ++i)
if (buf.m.userptr == (unsigned long)buffers[i].start
&& buf.length == buffers[i].length)
break;
assert(i < n_buffers);
process_image((void *)buf.m.userptr, buf.bytesused);
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
break;
}
return 1;
}
static void mainloop(void)
{
unsigned int count;
count = frame_count;
while (count-- > 0) {
for (;;) {
fd_set fds;
struct timeval tv;
int r;
FD_ZERO(&fds);
FD_SET(fd, &fds);
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == r) {
if (EINTR == errno)
continue;
errno_exit("select");
}
if (0 == r) {
fprintf(stderr, "select timeout\n");
exit(EXIT_FAILURE);
}
if (read_frame())
break;
/* EAGAIN - continue select loop. */
}
}
}
static void stop_capturing(void)
{
enum v4l2_buf_type type;
switch (io) {
case IO_METHOD_READ:
/* Nothing to do. */
break;
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
errno_exit("VIDIOC_STREAMOFF");
break;
}
}
static void start_capturing(void)
{
unsigned int i;
enum v4l2_buf_type type;
switch (io) {
case IO_METHOD_READ:
/* Nothing to do. */
break;
case IO_METHOD_MMAP:
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
errno_exit("VIDIOC_STREAMON");
break;
case IO_METHOD_USERPTR:
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.index = i;
buf.m.userptr = (unsigned long)buffers[i].start;
buf.length = buffers[i].length;
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
errno_exit("VIDIOC_STREAMON");
break;
}
}
static void uninit_device(void)
{
unsigned int i;
switch (io) {
case IO_METHOD_READ:
free(buffers[0].start);
break;
case IO_METHOD_MMAP:
for (i = 0; i < n_buffers; ++i)
if (-1 == munmap(buffers[i].start, buffers[i].length))
errno_exit("munmap");
break;
case IO_METHOD_USERPTR:
for (i = 0; i < n_buffers; ++i)
free(buffers[i].start);
break;
}
free(buffers);
}
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;
CLEAR(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;
CLEAR(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;
CLEAR(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);
}
}
}
static void init_device(void)
{
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
unsigned int min;
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 does not support read i/o\n",
dev_name);
exit(EXIT_FAILURE);
}
break;
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
fprintf(stderr, "%s does not support streaming i/o\n",
dev_name);
exit(EXIT_FAILURE);
}
break;
}
/* Select video input, video standard and tune here. */
CLEAR(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. */
}
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;
}
}
static void close_device(void)
{
if (-1 == close(fd))
errno_exit("close");
fd = -1;
}
static void open_device(void)
{
struct stat st;
if (-1 == stat(dev_name, &st)) {
fprintf(stderr, "Cannot identify '%s': %d, %s\n",
dev_name, errno, strerror(errno));
exit(EXIT_FAILURE);
}
if (!S_ISCHR(st.st_mode)) {
fprintf(stderr, "%s is no device\n", dev_name);
exit(EXIT_FAILURE);
}
fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
if (-1 == fd) {
fprintf(stderr, "Cannot open '%s': %d, %s\n",
dev_name, errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
static void usage(FILE *fp, int argc, char **argv)
{
fprintf(fp,
"Usage: %s [options]\n\n"
"Version 1.3\n"
"Options:\n"
"-d | --device name Video device name [%s]\n"
"-h | --help Print this message\n"
"-m | --mmap Use memory mapped buffers [default]\n"
"-r | --read Use read() calls\n"
"-u | --userp Use application allocated buffers\n"
"-o | --output Outputs stream to stdout\n"
"-f | --format Force format to 640x480 YUYV\n"
"-c | --count Number of frames to grab [%i]\n"
"",
argv[0], dev_name, frame_count);
}
static const char short_options[] = "d:hmruofc:";
static const struct option
long_options[] = {
{ "device", required_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "mmap", no_argument, NULL, 'm' },
{ "read", no_argument, NULL, 'r' },
{ "userp", no_argument, NULL, 'u' },
{ "output", no_argument, NULL, 'o' },
{ "format", no_argument, NULL, 'f' },
{ "count", required_argument, NULL, 'c' },
{ 0, 0, 0, 0 }
};
int main(int argc, char **argv)
{
dev_name = "/dev/video0";
for (;;) {
int idx;
int c;
c = getopt_long(argc, argv,
short_options, long_options, &idx);
if (-1 == c)
break;
switch (c) {
case 0: /* getopt_long() flag */
break;
case 'd':
dev_name = optarg;
break;
case 'h':
usage(stdout, argc, argv);
exit(EXIT_SUCCESS);
case 'm':
io = IO_METHOD_MMAP;
break;
case 'r':
io = IO_METHOD_READ;
break;
case 'u':
io = IO_METHOD_USERPTR;
break;
case 'o':
out_buf++;
break;
case 'f':
force_format++;
break;
case 'c':
errno = 0;
frame_count = strtol(optarg, NULL, 0);
if (errno)
errno_exit(optarg);
break;
default:
usage(stderr, argc, argv);
exit(EXIT_FAILURE);
}
}
open_device();
init_device();
start_capturing();
mainloop();
stop_capturing();
uninit_device();
close_device();
fprintf(stderr, "\n");
return 0;
}

12
src/v4l2/essai.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# -----------------------------------------------------
TMPF="tmp.fimg"
CAM="/dev/video0"
# -----------------------------------------------------
./grabvidseq -d $CAM -n 10000 -vv -p 0 -r 90
# -----------------------------------------------------

42
src/v4l2/exemple.txt Normal file
View File

@@ -0,0 +1,42 @@
-- v4l2_capability, /dev/video0 0x7ffeee718100
driver cx231xx
card Pixelview Xcapture USB
bus info usb-0000:00:1a.0-1.2
version 0x41325
capabilities 0x85200011
vcapt vbicapt extpix rwsysc stream
device caps 0x5200001
-- inputs enumeration 'on peut voir quoi ?'
Composite1 | camera
S-Video | camera
-- v4l2_format, Experimental 0x7ffeee718030
type 1 video capture
dims 720x576
pixformat [YUYV]
field 4
padding 1440
sizeimage 829440
colorspace 1 smpte170m
-- image formats enumeration (Experimental)
0 vidcapt 0x00 [YUYV] YUYV 4:2:2
-- controls enumeration 'is that working ?'
Brightness integer [0..255]
Contrast integer [0..127]
Saturation integer [0..127]
Hue integer [-128..127]
Volume integer [0..65535]
Balance integer [0..65535]
Bass integer [0..65535]
Treble integer [0..65535]
Mute boolean [0..1]
-- extended controls enumeration 'looking for extended'
User Controls ctrl-class [0..0]
Brightness integer [0..255]
Contrast integer [0..127]
Saturation integer [0..127]
Hue integer [-128..127]
Volume integer [0..65535]
Balance integer [0..65535]
Bass integer [0..65535]
Treble integer [0..65535]
Mute boolean [0..1]

329
src/v4l2/funcs.c Normal file
View File

@@ -0,0 +1,329 @@
/*
* 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>
#include "../floatimg.h"
#include "funcs.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;
/* PLEASE EXPLAIN THAT CODE */
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 */
if (verbosity) {
fprintf(stderr, "device '%s' opened as #%d\n", device, fd);
}
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 not a 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;
}

20
src/v4l2/funcs.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* V4L2 functions - header file
*/
int open_device(char *dev_name);
int init_device(int notused);
/* --------------------------------------------------------------------- */
int x_upscaler_0(unsigned char *src, int w, int h, FloatImg *d);
int x_add_rgb2fimg(unsigned char *src, int w, int h, FloatImg *d);
int x_rgb2fimg(unsigned char *src, int w, int h, FloatImg *d);
int x_rgb2file(unsigned char *src, int w, int h, char *fname);
/* --------------------------------------------------------------------- */

427
src/v4l2/grabvidseq.c Normal file
View File

@@ -0,0 +1,427 @@
/* V4L2 video picture grabber
Origin :V4L2GRAB.C - patched by tTh
Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
#include "../floatimg.h"
#include "funcs.h"
/* --------------------------------------------------------------------- */
/* compilation control */
#define SAVE_AS_CUMUL 1
#define SAVE_AS_FIMG 0
#define NBR_BUFFERS 4
/* --------------------------------------------------------------------- */
#define CLEAR(x) memset(&(x), 0, sizeof(x))
struct buffer {
void *start;
size_t length;
};
int verbosity;
static int systrace;
/* --------------------------------------------------------------------- */
static void xioctl(int fh, int request, void *arg)
{
int r;
/* may be imagine a system for displaying all call to this function ? */
if (systrace) {
fprintf(stderr, "xioctl fd=%d req=%d arg=%p\n", fh, request, arg);
}
do {
r = v4l2_ioctl(fh, request, arg);
} while (r == -1 && ((errno == EINTR) || (errno == EAGAIN)));
if (r == -1) {
fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
sleep(1);
exit(EXIT_FAILURE);
}
}
/* --------------------------------------------------------------------- */
void help(int v)
{
if (verbosity) {
printf("compiled %s at %s\n", __DATE__, __TIME__);
fimg_print_version(1);
}
puts("options :");
puts("\t-d /dev/?\tselect video device");
puts("\t-g\t\tconvert to gray");
puts("\t-n NNN\t\thow many frames ?");
puts("\t-O ./\t\tset Output dir");
puts("\t-o bla.xxx\tset output filename");
puts("\t-p NN.N\t\tperiod in seconds");
puts("\t-r NNN\t\trotate picture");
puts("\t-s WxH\t\tsize of capture");
puts("\t-c mode\t\tcontrast enhancement");
puts("\t-u\t\ttry upscaling...");
puts("\t-v\t\tincrease verbosity");
puts("\t-Z\t\tenable systrace");
if (verbosity) {
puts("\n\t\tXXX list all the contrast modes, please\n");
}
exit(0);
}
/* --------------------------------------------------------------------- */
int main(int argc, char **argv)
{
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;
unsigned int i, n_buffers;
char *dev_name = "/dev/video0";
// XXX FILE *fout;
struct buffer *buffers;
int foo;
double period = 10.0; /* delai entre les captures
en secondes */
int nbre_capt = 1; /* nombre de captures */
int opt;
int width = 640;
int height = 480;
double t_final, maxvalue;
int to_gray = 0;
int upscaling = 0;
int contrast = CONTRAST_NONE;
int rotfactor = 0; /* only 0 or 90 here */
char *dest_dir = "."; /* no trailing slash */
char *outfile = "out.pnm";
#if SAVE_AS_CUMUL
FloatImg cumul, tmpfimg, *to_save;
#endif
while ((opt = getopt(argc, argv, "c:d:ghn:o:O:p:r:s:uvZ")) != -1) {
switch(opt) {
case 'c': contrast = fimg_id_contraste(optarg);
if (contrast < 0) {
fputs("unknow contrast\n", stderr);
exit(1);
}
break;
case 'd': dev_name = optarg; break;
case 'g': to_gray = 1; break;
case 'h': help(0); break;
case 'n': nbre_capt = atoi(optarg); break;
case 'O': dest_dir = optarg; break;
case 'o': outfile = optarg; break;
case 'p': foo = parse_double(optarg, &period);
if (foo<0) {
fprintf(stderr,
"error parsing -p arg '%s'\n",
optarg);
exit(1);
}
break;
case 'r': rotfactor = atoi(optarg); break;
case 's': parse_WxH(optarg, &width, &height);
break;
case 'u': upscaling = 1; break;
case 'v': verbosity++; break;
case 'Z': systrace = 1; break;
default:
fprintf(stderr, "option '%c' is wtf\n", opt);
exit(1);
}
}
if (verbosity > 1) {
fprintf(stderr, "*** GrabVidSeq (%s, %s) libv %d, pid=%d\n",
__DATE__, __TIME__, FIMG_VERSION, getpid());
fprintf(stderr, "grabing %d picz, ", nbre_capt);
fprintf(stderr, "period is %.3f seconds\n", period);
fprintf(stderr, "framesize is %dx%d\n", width, height);
// fprintf(stderr, "destdir is '%s'\n", dest_dir);
if (upscaling) fprintf(stderr, "upscaling is on\n");
}
if (upscaling && (nbre_capt%4)) {
fprintf(stderr, "WARN upscaling: %d bad nbre_capt\n",
nbre_capt);
}
fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
if (fd < 0) {
perror(dev_name);
exit(EXIT_FAILURE);
}
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
xioctl(fd, VIDIOC_S_FMT, &fmt);
if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
/* are others formats usable ? */
fprintf(stderr, "Libv4l didn't accept RGB24 format. Can't proceed.\n");
exit(EXIT_FAILURE);
}
if ((fmt.fmt.pix.width != width) || (fmt.fmt.pix.height != height)) {
fprintf(stderr, "Warning: driver is sending image at %dx%d\n",
fmt.fmt.pix.width, fmt.fmt.pix.height);
}
// fprintf(stderr,"--- Ok 1\n");
CLEAR(req);
req.count = NBR_BUFFERS;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
xioctl(fd, VIDIOC_REQBUFS, &req);
buffers = calloc(req.count, sizeof(*buffers));
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
xioctl(fd, VIDIOC_QUERYBUF, &buf);
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start) {
perror("v4l2_mmap");
exit(EXIT_FAILURE);
}
}
(void)fimg_timer_set(0);
for (i = 0; i < NBR_BUFFERS; ++i) {
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
xioctl(fd, VIDIOC_QBUF, &buf);
}
#if SAVE_AS_CUMUL
if (upscaling) {
foo = fimg_create(&cumul,
fmt.fmt.pix.width*2, fmt.fmt.pix.height*2,
FIMG_TYPE_RGB);
}
else {
foo = fimg_create(&cumul,
fmt.fmt.pix.width, fmt.fmt.pix.height,
FIMG_TYPE_RGB);
}
fimg_clear(&cumul);
cumul.fval = 255.0; /* must be read from camera XXX */
cumul.count = 0;
to_save = &cumul;
#endif
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMON, &type);
#if 1
if (verbosity) fprintf(stderr,"pid %d is going to grab %d picz...\n",
getpid(), nbre_capt);
#endif
/*
* START ON THE GRABBING LOOP
*/
for (i = 0; i < nbre_capt; 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; /* WTF ? a rogue return
from the main() ? */
}
if(verbosity > 1) {
fprintf(stderr, "%6d / %6d %9.3f\r", i, nbre_capt,
fimg_timer_get(0));
fflush(stderr);
}
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
xioctl(fd, VIDIOC_DQBUF, &buf);
if(verbosity > 2) {
fprintf(stderr, "xioctl VIDIOC_DQBUF done\n");
fflush(stderr);
}
#if SAVE_AS_CUMUL
if (upscaling) {
x_upscaler_0(buffers[buf.index].start,
fmt.fmt.pix.width, fmt.fmt.pix.height, &cumul);
}
else {
x_add_rgb2fimg(buffers[buf.index].start,
fmt.fmt.pix.width, fmt.fmt.pix.height, &cumul);
}
#endif
#if SAVE_AS_FIMG
sprintf(out_name, "%s/%05d.fimg", dest_dir, i);
if (verbosity > 1) fprintf(stderr, "--> %s\n", out_name);
foo = x_rgb2file(buffers[buf.index].start,
fmt.fmt.pix.width, fmt.fmt.pix.height,
out_name);
#endif
if (nbre_capt > 1 && period > 0.001) {
/* suspend execution for
microsecond intervals */
usleep((int)(period*1E6));
}
xioctl(fd, VIDIOC_QBUF, &buf);
}
if (verbosity) {
t_final = fimg_timer_get(0);
fprintf(stderr, "pid %d : elapsed %.3g s -> %.2f fps\n", getpid(),
t_final, (double)nbre_capt / t_final);
}
if (to_gray) {
if (verbosity) fputs("converting to gray\n", stderr);
foo = fimg_to_gray(&cumul);
}
#if SAVE_AS_CUMUL
// save cumul to file
if (verbosity) fprintf(stderr, "saving cumul to '%s'\n", outfile);
/* ----- nouveau 15 nov 2019 */
maxvalue = cumul.fval * cumul.count;
if (verbosity) {
fprintf(stderr, "theorical maxvalue = %g\n", maxvalue);
fprintf(stderr, "computed max value = %g\n",
fimg_get_maxvalue(&cumul));
}
switch (contrast) {
case CONTRAST_NONE:
// if (verbosity) fprintf(stderr, "contrast: none\n");
break;
case CONTRAST_SQRT:
fimg_square_root(&cumul, NULL, maxvalue);
break;
case CONTRAST_POW2:
fimg_power_2(&cumul, NULL, maxvalue);
break;
case CONTRAST_COS01:
fimg_cos_01(&cumul, NULL, maxvalue);
break;
case CONTRAST_COS010:
fimg_cos_010(&cumul, NULL, maxvalue);
break;
default:
fprintf(stderr, "bad contrast method\n");
break;
}
/* XXX warning, new from coronahome 26 mars 2020 */
to_save = &cumul;
if (90 == rotfactor) {
memset(&tmpfimg, 0, sizeof(FloatImg));
foo = fimg_rotate_90(&cumul, &tmpfimg, 0);
if (verbosity > 2) {
fprintf(stderr, "dump rot90 %p\n", &tmpfimg);
foo = fimg_save_as_png(&tmpfimg, "rot90.png", 0);
}
to_save = &tmpfimg;
}
foo = format_from_extension(outfile);
switch (foo) {
case FILE_TYPE_FIMG:
foo = fimg_dump_to_file(to_save, outfile, 0);
break;
case FILE_TYPE_PNM:
foo = fimg_save_as_pnm(to_save, outfile, 1);
break;
case FILE_TYPE_PNG:
foo = fimg_save_as_png(to_save, outfile, 0);
break;
case FILE_TYPE_FITS:
foo = fimg_save_R_as_fits(to_save, outfile, 0);
break;
case FILE_TYPE_TIFF:
foo = fimg_write_as_tiff(to_save, outfile, 0);
break;
default:
fprintf(stderr, "can't save as %s\n", outfile);
break;
}
// free buffers
fimg_destroy(&cumul);
#endif
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMOFF, &type);
for (i = 0; i < NBR_BUFFERS; ++i) {
v4l2_munmap(buffers[i].start, buffers[i].length);
}
// free(buffers); /* atomic bombing */
v4l2_close(fd);
return 0;
}

130
src/v4l2/nc-camcontrol.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* tests pour capturer les webcams
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
// #include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <inttypes.h>
#include <curses.h>
#include <linux/videodev2.h>
#include "../floatimg.h"
#include "v4l2_pr_structs.h"
#include "funcs.h"
int verbosity;
/* --------------------------------------------------------------------- */
void help(int n)
{
puts("camera controls");
puts("\t-d bla\t\tselect video device");
puts("\t-e nnn\t\tset 'etype'");
puts("\t-K nnn\t\tinteger parameter");
puts("\t-n bla\t\tset title");
exit(0);
}
/* --------------------------------------------------------------------- */
int init_screen(char *title)
{
int foo;
#if DEBUG_LEVEL
fprintf(stderr, ">>> %s ( '%s' )\n", __func__, title);
#endif
initscr();
standout(); mvaddstr(1, 5, title); standend(); refresh();
return -1;
}
/* --------------------------------------------------------------------- */
int end_screen(void)
{
endwin();
return 0;
}
/* --------------------------------------------------------------------- */
int preparation_v4l2(char *devname, int param)
{
int fd, foo;
struct v4l2_capability cap;
#if DEBUG_LEVEL
fprintf(stderr, ">>> %s ( '%s' %d )\n", __func__, devname, param);
#endif
fd = open_device(devname);
if (fd < 0) {
fprintf(stderr, "err %d on %s opening\n", errno, devname);
return -2;
}
/* est-ce un device qui permet la capture video */
foo = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (-1 == foo) {
perror("VIDIOC_QUERYCAP");
return -2;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr, "%s is not a video capture device\n", devname);
return -3;
}
return fd;
}
/* --------------------------------------------------------------------- */
int interactive(int fd, char *text, int notused)
{
fprintf(stderr, "file descriptor = %d\n", fd);
init_screen("prototype");
sleep(2);
end_screen();
return 0;
}
/* --------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
int foo, opt, devnum;
int etype = 0;
char *device = "/dev/video0";
char *title = NULL;
int K = 0;
while ((opt = getopt(argc, argv, "d:e:hK:lT:v")) != -1) {
switch(opt) {
case 'd': device = optarg; break;
case 'e': etype = atol(optarg); break;
case 'h': help(0); break;
case 'K': K = atol(optarg); break;
// case 'l': liste_des_devices(0); break;
case 't': title = optarg;
case 'v': verbosity++; break;
}
}
devnum = preparation_v4l2(device, K);
if (devnum < 0) {
fprintf(stderr, "%s : erreur init video device\n", argv[0]);
exit(1);
}
foo = interactive(devnum, title, 0);
return 0;
}
/* --------------------------------------------------------------------- */

25
src/v4l2/notes.txt Normal file
View File

@@ -0,0 +1,25 @@
Heisenbug dans la capture d'image
=================================
Contexte : Debian 10 32 bits sur Sony Vaio,
webcam Logitech classique.
Mon soft 'grabvidseq' part _parfois_ en torche oo, à la louche une
fois sur cent. Mais toujours au même endroit, au début de la boucle
de capture des images, précisément dans cet appel système :
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
xioctl(fd, VIDIOC_DQBUF, &buf);
Quand le programme semble figé, un strace -p <pid> sort le même
message en rafale _très_ féroce :
ioctl(3, VIDIOC_DQBUF, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE}) = -1 EAGAIN (Resource temporarily unavailable)
ioctl(3, VIDIOC_DQBUF, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE}) = -1 EAGAIN (Resource temporarily unavailable)
ioctl(3, VIDIOC_DQBUF, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE^Cstrace: Process 11181 detached
WTF ?

135
src/v4l2/rgb2fimg.c Normal file
View File

@@ -0,0 +1,135 @@
#include <stdio.h>
#include <stdlib.h>
#include "../floatimg.h"
#include "funcs.h"
extern int verbosity;
/*
* Be careful, these functions are not yet fireproof,
* and calling conventions are fluctuating.
*/
/* --------------------------------------------------------------------- */
int x_upscaler_0(unsigned char *src, int w, int h, FloatImg *d)
{
int x, y, xx, yy, ox, oy;
// float *rp, *gp, *bp;
float r, g, b;
static unsigned short modz;
/*
* check in image sizes are correct
*/
if ( d->width != w*2 || d->height != h*2 ) {
fprintf(stderr, "%s: dimension error\n", __func__);
fprintf(stderr, "\tw = %d h = %d\n", w, h);
fprintf(stderr, "\tdest image is %dx%d\n", d->width, d->height);
#if MUST_ABORT
abort();
#endif
return -2;
}
ox = ! ! (modz & 2);
oy = ! ! (modz & 1);
if (verbosity>2) fprintf(stderr, "%s %5d %d %d\n", __func__,
modz, ox, oy);
for (y=0; y<h; y++) {
yy = (y*2) + oy;
for (x=0; x<w; x++) {
xx = (x*2) + ox;
r = (float)*src++;
g = (float)*src++;
b = (float)*src++;
/* may be, here, we can speed up the job */
fimg_add_rgb(d, xx, yy, r, g, b);
/* or may be jump directly to asm and SSE2
http://www.mikekohn.net/stuff/image_processing.php */
}
}
modz++; /* next displacment index */
if ( ! (modz & 0x03)) {
d->count++; /* one more frame in the accumulator */
}
return -1;
}
/* --------------------------------------------------------------------- */
int x_rgb2fimg(unsigned char *src, int w, int h, FloatImg *d)
{
int iter, size;
float *rp, *gp, *bp;
size = w * h;
rp = d->R, gp = d->G, bp = d->B;
for (iter=0; iter<size; iter++) {
*rp++ = (float)*src++;
*gp++ = (float)*src++;
*bp++ = (float)*src++;
}
return 0;
}
/* --------------------------------------------------------------------- */
int x_add_rgb2fimg(unsigned char *src, int w, int h, FloatImg *d)
{
int iter, size;
float *rp, *gp, *bp;
size = w * h;
rp = d->R, gp = d->G, bp = d->B;
for (iter=0; iter<size; iter++) {
*rp++ += (float)*src++;
*gp++ += (float)*src++;
*bp++ += (float)*src++;
}
d->count++; /* one more frame in the accumulator */
return 0;
}
/* --------------------------------------------------------------------- */
int x_rgb2file(unsigned char *src, int w, int h, char *fname)
{
FloatImg buff;
int foo;
#if DEBUG_LEVEL
fprintf(stderr, ">>> %s ( %p %d %d '%s' )\n", __func__,
src, w, h, fname);
#endif
foo = fimg_create(&buff, w, h, FIMG_TYPE_RGB);
if (foo) {
fprintf(stderr, "Crash on create in %s %s\n", __FILE__, __func__);
exit(1);
}
foo = x_rgb2fimg(src, w, h, &buff);
if (foo) {
fprintf(stderr, "Crash on bit massage in %s %s\n", __FILE__, __func__);
exit(1);
}
foo = fimg_dump_to_file(&buff, fname, 0);
if (foo) {
fprintf(stderr, "Crash on dump in %s %s\n", __FILE__, __func__);
exit(1);
}
fimg_destroy(&buff);
return -1;
}
/* --------------------------------------------------------------------- */

91
src/v4l2/t.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* tests pour capturer les webcams
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <linux/videodev2.h>
#include "../floatimg.h"
#include "funcs.h"
#include "v4l2_pr_structs.h"
int verbosity;
/* --------------------------------------------------------------------- */
int essai_get_fmt(char *dev, int k)
{
int vfd, foo;
struct v4l2_format fmt;
// struct v4l2_requestbuffers reqbuf;
fprintf(stderr, ">>> %s ( '%s' %d )\n", __func__, dev, k);
vfd = open_device(dev);
if (verbosity) fprintf(stderr, "\topen %s -> %d\n", dev, vfd);
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
foo = ioctl(vfd, VIDIOC_G_FMT, &fmt);
fprintf(stderr, "%s : ioctl -> %d\n", __func__, foo);
if (0 != foo) {
perror("ioctl G_FMT");
return -1;
}
pr_v4l2_format("after ioctl VIDIOC_G_FMT", &fmt);
/* this function is bugged */
close(vfd);
return k;
}
/* --------------------------------------------------------------------- */
void help(int k)
{
puts("Options :");
puts("\t-d\tselect the video device");
puts("\t-K\tset the K parameter");
puts("\t-v\tincrease verbosity");
if (verbosity) { puts(""); fimg_print_version(1); }
exit(0);
}
/* --------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
int foo, opt;
char *device = "/dev/video0";
int K = 0;
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;
}
}
if (verbosity) fimg_print_version(0);
foo = essai_get_fmt(device, K);
fprintf(stderr, "\tessai -> %d\n", foo);
return 0;
}
/* --------------------------------------------------------------------- */

300
src/v4l2/v4l2_pr_structs.c Normal file
View File

@@ -0,0 +1,300 @@
/*
* fonctions pour afficher les structures de V4L2
*/
#include <stdio.h>
#include <inttypes.h>
#include <linux/videodev2.h>
#include "v4l2_pr_structs.h"
#define FP (stdout)
extern int verbosity;
/* --------------------------------------------------------------------- */
static char *fmttype2str(int type)
{
switch(type) {
case 0: return "[zero]";
case V4L2_BUF_TYPE_VIDEO_CAPTURE: return "video capture";
case V4L2_BUF_TYPE_VIDEO_OUTPUT: return "video output";
case 13: return "META capture";
}
return "XXX";
}
/* --------------------------------------------------------------------- */
static void pr_capabilities(uint32_t caps)
{
fputs(" ", FP);
if (caps & V4L2_CAP_VIDEO_CAPTURE) fputs("vcapt ", FP);
if (caps & V4L2_CAP_VIDEO_OUTPUT) fputs("vout ", FP);
if (caps & V4L2_CAP_VIDEO_OVERLAY) fputs("overlay ", FP);
if (caps & V4L2_CAP_VBI_CAPTURE) fputs("vbicapt ", FP);
if (caps & V4L2_CAP_VBI_OUTPUT) fputs("vbiout ", FP);
/* to be continued */
if (caps & V4L2_CAP_AUDIO) fputs("audio ", FP);
if (caps & V4L2_CAP_SDR_CAPTURE) fputs("sdrcapt ", FP);
if (caps & V4L2_CAP_EXT_PIX_FORMAT) fputs("extpix ", FP);
if (caps & V4L2_CAP_SDR_OUTPUT) fputs("sdrout ", FP);
if (caps & V4L2_CAP_READWRITE) fputs("rwsysc ", FP);
if (caps & V4L2_CAP_ASYNCIO) fputs("asyncio ", FP);
if (caps & V4L2_CAP_STREAMING) fputs("stream ", FP);
fputs("\n", FP);
}
/* --------------------------------------------------------------------- */
int pr_v4l2_capability(char *txt, struct v4l2_capability *ptr)
{
fprintf(FP, "## v4l2_capability, %-15s %p\n", txt, ptr);
fprintf(FP, " driver %s\n", ptr->driver);
fprintf(FP, " card %s\n", ptr->card);
fprintf(FP, " bus info %s\n", ptr->bus_info);
fprintf(FP, " version 0x%X\n", ptr->version);
fprintf(FP, " capabilities 0x%X\n", ptr->capabilities);
pr_capabilities(ptr->capabilities);
fprintf(FP, " device caps 0x%X\n", ptr->device_caps);
return -1;
}
/* --------------------------------------------------------------------- */
/*
* warning, this function return a pointer to a static
* strint, so it was NOT reentrant !
*/
char *str_fourcc(uint32_t fcc)
{
static char chaine[10];
chaine[0] = '['; chaine[5] = ']'; chaine[6] = '\0';
chaine[1] = (fcc>>0) & 0xff;
chaine[2] = (fcc>>8) & 0xff;
chaine[3] = (fcc>>16) & 0xff;
chaine[4] = (fcc>>24) & 0xff;
return chaine;
}
/* --------------------------------------------------------------------- */
char *str_buf_type(int type)
{
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: return "vidcapt";
case V4L2_BUF_TYPE_VIDEO_OUTPUT: return "vidout";
case V4L2_BUF_TYPE_VIDEO_OVERLAY: return "vidovrl";
case V4L2_BUF_TYPE_VBI_CAPTURE: return "vbicapt";
case V4L2_BUF_TYPE_VBI_OUTPUT: return "vbicapt";
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: return "slicevcapt";
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: return "slicevout";
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return "v-outover";
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: return "v-captmpla";
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: return "v-outmpla";
case V4L2_BUF_TYPE_SDR_CAPTURE: return "sdrcapt";
case V4L2_BUF_TYPE_SDR_OUTPUT: return "sdrout";
/* Deprecated, do not use */
case V4L2_BUF_TYPE_PRIVATE: return "private";
}
return "???";
}
/* --------------------------------------------------------------------- */
int pr_v4l2_fmtdesc(char *txt, struct v4l2_fmtdesc *ptr)
{
fprintf(FP, "## v4l2_fmtdesc, %-15s %p\n", txt, ptr);
fprintf(FP, " index %d\n", ptr->index);
fprintf(FP, " type %d\n", ptr->type); /* enum v4l2_buf_type */
fprintf(FP, " flags 0x%X\n", ptr->flags);
fprintf(FP, " description %s\n", ptr->description);
fprintf(FP, " pixel format 0x%X\n", ptr->pixelformat); /* FOURCC */
return -1;
}
/* --------------------------------------------------------------------- */
char *str_input_type(int t)
{
switch (t) {
case V4L2_INPUT_TYPE_TUNER: return "tuner";
case V4L2_INPUT_TYPE_CAMERA: return "camera";
case V4L2_INPUT_TYPE_TOUCH: return "touch";
}
return "???";
}
/* --------------------------------------------------------------------- */
static void pr_input_status(uint32_t st)
{
if (st & V4L2_IN_ST_NO_POWER) fputs("nopow ", FP);
if (st & V4L2_IN_ST_NO_SIGNAL) fputs("nosig ", FP);
if (st & V4L2_IN_ST_NO_COLOR) fputs("nocol ", FP);
if (st & V4L2_IN_ST_HFLIP) fputs("hflip ", FP);
if (st & V4L2_IN_ST_VFLIP) fputs("vflip ", FP);
if (st & V4L2_IN_ST_NO_H_LOCK) fputs("nohlck ", FP);
if (st & V4L2_IN_ST_COLOR_KILL) fputs("colkil ", FP);
if (st & V4L2_IN_ST_NO_V_LOCK) fputs("novlck ", FP);
if (st & V4L2_IN_ST_NO_STD_LOCK) fputs("nostdlk ", FP);
if (st & V4L2_IN_ST_NO_EQU) fputs("noequ ", FP);
if (st & V4L2_IN_ST_NO_CARRIER) fputs("nocarr ", FP);
if (st & V4L2_IN_ST_MACROVISION) fputs("macrov ", FP);
if (st & V4L2_IN_ST_NO_ACCESS) fputs("noacces ", FP);
if (st & V4L2_IN_ST_VTR) fputs("VTR ", FP);
/* to be continued ?*/
}
/* --------------------------------------------------------------------- */
static void pr_input_capabilities(uint32_t st)
{
if (st & V4L2_IN_CAP_DV_TIMINGS) fputs("DVtime ", FP);
if (st & V4L2_IN_CAP_STD) fputs("s_std ", FP);
if (st & V4L2_IN_CAP_NATIVE_SIZE) fputs("nativsz ", FP);
}
/* --------------------------------------------------------------------- */
int pr_v4l2_input(char *txt, struct v4l2_input *ptr)
{
fprintf(FP, "## v4l2_input, %-15s %p\n", txt, ptr);
fprintf(FP, " index %d\n", ptr->index);
fprintf(FP, " name %s\n", ptr->name);
fprintf(FP, " type %d %s\n", ptr->type,
str_input_type(ptr->type));
fprintf(FP, " audioset 0x%X\n", ptr->audioset);
fprintf(FP, " tuner 0x%X\n", ptr->tuner);
/* XXX v4l2_std_id std; */
fprintf(FP, " status 0x%X\n", ptr->status);
if (ptr->status) {
fputs(" ",FP);
pr_input_status(ptr->status);
fputs("\n",FP);
}
fprintf(FP, " capabilities 0x%X\n", ptr->capabilities);
if (ptr->capabilities) {
fputs(" ",FP);
pr_input_capabilities(ptr->capabilities);
fputs("\n",FP);
}
return -1;
}
/* --------------------------------------------------------------------- */
char * str_colorspace(int colspace)
{
switch(colspace) {
case V4L2_COLORSPACE_DEFAULT: return "default";
case V4L2_COLORSPACE_SMPTE170M: return "smpte170m";
case V4L2_COLORSPACE_SMPTE240M: return "smpte240m";
case V4L2_COLORSPACE_REC709: return "rec709";
case V4L2_COLORSPACE_BT878: return "bt878";
case V4L2_COLORSPACE_470_SYSTEM_M: return "470-sys-M";
case V4L2_COLORSPACE_470_SYSTEM_BG: return "470-sys-BG";
case V4L2_COLORSPACE_JPEG: return "jpeg";
case V4L2_COLORSPACE_SRGB: return "srgb";
case V4L2_COLORSPACE_ADOBERGB: return "adobergb";
case V4L2_COLORSPACE_BT2020: return "bt2020";
case V4L2_COLORSPACE_RAW: return "raw";
case V4L2_COLORSPACE_DCI_P3: return "dci-p3";
}
return "???";
}
/* --------------------------------------------------------------------- */
int pr_v4l2_format(char *txt, struct v4l2_format *ptr)
{
fprintf(FP, "## v4l2_format, %-15s %p\n", txt, ptr);
fprintf(FP, " type %d %s\n", ptr->type,/* enum v4l2_buf_type */
fmttype2str(ptr->type));
switch(ptr->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
fprintf(FP, " dims %dx%d\n",
ptr->fmt.pix.width,
ptr->fmt.pix.height);
fprintf(FP, " pixformat %s\n",
str_fourcc(ptr->fmt.pix.pixelformat));
fprintf(FP, " field %d\n",
ptr->fmt.pix.field); /* enum v4l2_field */
fprintf(FP, " padding %d\n",
ptr->fmt.pix.bytesperline);
fprintf(FP, " sizeimage %d\n",
ptr->fmt.pix.sizeimage);
fprintf(FP, " colorspace %d %s\n",
ptr->fmt.pix.colorspace,
str_colorspace(ptr->fmt.pix.colorspace));
break;
default: fprintf(FP, "XXX type %d unknow\n", ptr->type);
break;
}
return 0;
}
/* --------------------------------------------------------------------- */
int pr_v4l2_requestbuffers(char *txt, struct v4l2_requestbuffers *ptr)
{
fprintf(FP, "## v4l2_requestbuffers, %s %p\n", txt, ptr);
fprintf(FP, " type %d\n", ptr->type); /* enum v4l2_buf_type */
return 0;
}
/* --------------------------------------------------------------------- */
char *str_ctrl_type(int type)
{
switch (type) {
case V4L2_CTRL_TYPE_INTEGER: return "integer";
case V4L2_CTRL_TYPE_BOOLEAN: return "boolean";
case V4L2_CTRL_TYPE_MENU: return "menu";
case V4L2_CTRL_TYPE_BUTTON: return "button";
case V4L2_CTRL_TYPE_INTEGER64: return "int64";
case V4L2_CTRL_TYPE_CTRL_CLASS: return "ctrl-class";
case V4L2_CTRL_TYPE_STRING: return "string";
case V4L2_CTRL_TYPE_BITMASK: return "bitmask";
case V4L2_CTRL_TYPE_INTEGER_MENU: return "int-menu";
}
return "???";
}
/* --------------------------------------------------------------------- */
/*
The 32-bit qctrl.id value is subdivided into three bit ranges:
the top 4 bits are reserved for flags (e. g. V4L2_CTRL_FLAG_NEXT_CTRL)
and are not actually part of the ID.
The remaining 28 bits form the control ID, of which the most significant
12 bits define the control class and the least significant
16 bits identify the control within the control class.
*/
void pr_ctrl_id(uint32_t id)
{
if (verbosity>1) fprintf(FP, "%08x : ", id);
fprintf(FP, "%x %03lx %04x", (id>>28)&0xf,
V4L2_CTRL_ID2CLASS(id)>>16, id&0xffff);
}
/* --------------------------------------------------------------------- */
int pr_v4l2_control(char *txt, struct v4l2_control *ptr)
{
return -1;
}
/* --------------------------------------------------------------------- */

View File

@@ -0,0 +1,22 @@
/*
* fonctions pour afficher les structures de V4L2
*
* WARNING : this is a work in progress !
*/
/* --------------------------------------------------------------------- */
int pr_v4l2_capability(char *txt, struct v4l2_capability *ptr);
int pr_v4l2_input(char *txt, struct v4l2_input *ptr);
int pr_v4l2_format(char *txt, struct v4l2_format *ptr);
int pr_v4l2_requestbuffers(char *txt, struct v4l2_requestbuffers *ptr);
int pr_v4l2_fmtdesc(char *txt, struct v4l2_fmtdesc *ptr);
char *str_input_type(int t);
char *str_ctrl_type(int type);
char *str_buf_type(int type);
char *str_fourcc(uint32_t fcc); /* NOT REENTRANT */
void pr_ctrl_id(uint32_t id); /* bit dissector */
/* --------------------------------------------------------------------- */

331
src/v4l2/video-infos.c Normal file
View File

@@ -0,0 +1,331 @@
/*
* tests pour capturer les webcams
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <inttypes.h>
#include <linux/videodev2.h>
#include "../floatimg.h"
#include "v4l2_pr_structs.h"
#include "funcs.h"
int verbosity;
/* --------------------------------------------------------------------- */
/*
* this code was written from a strace output :)
*/
int enum_image_framesizes(int fd, char *txt, int k)
{
int foo, idx;
struct v4l2_frmsizeenum fmtsz;
printf("## image framesizes enumeration (%s)\n", txt);
for (idx=0; ; idx++) {
memset(&fmtsz, 0, sizeof(fmtsz));
fmtsz.index = idx;
foo = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fmtsz);
if (foo) {
if (EINVAL==errno) {
break;
}
else {
perror(__func__);
break;
}
}
printf("%4d %4d %4d\n", idx, fmtsz.pixel_format, fmtsz.type);
}
return 0;
}
/* --------------------------------------------------------------------- */
int enum_image_formats(int fd, char *txt, int k)
{
int foo, idx;
struct v4l2_fmtdesc fmtd;
printf("## image formats enumeration (%s)\n", txt);
idx = 0;
for (;;) {
memset(&fmtd, 0, sizeof(fmtd));
fmtd.index = idx;
fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
foo = ioctl(fd, VIDIOC_ENUM_FMT, &fmtd);
// fprintf(stderr, "B idx=%d, foo=%d, errno=%d\n", idx, foo, errno);
if (foo) {
if (EINVAL==errno) {
break;
}
else {
perror(__func__);
break;
}
}
// pr_v4l2_fmtdesc(__func__, &fmtd);
printf(" %2d %-10s 0x%02x %s %-32s \n",
fmtd.index, str_buf_type(fmtd.type), fmtd.flags,
str_fourcc(fmtd.pixelformat), fmtd.description);
idx++;
}
return -1;
}
/* --------------------------------------------------------------------- */
static int enum_inputs(int fd, char *txt, int k)
{
int index, foo;
struct v4l2_input input;
char ligne[50];
printf("## inputs enumeration (%s)\n", txt);
index = 0;
for(;;) {
memset (&input, 0, sizeof (input));
input.index = index;
foo = ioctl(fd, VIDIOC_ENUMINPUT, &input);
if (foo) {
if (EINVAL==errno) { break; }
else {
perror("enuminput");
return -1;
}
}
if (verbosity) {
sprintf(ligne, "input %d", index);
pr_v4l2_input(ligne, &input);
}
else {
printf("%-32s | %-10s\n", input.name,
str_input_type(input.type));
}
index++;
}
return 0;
}
/* --------------------------------------------------------------------- */
int enum_controls(int fd, char *txt, int k)
{
struct v4l2_queryctrl qctrl;
int idx;
printf("## controls enumeration '%s'\n", txt);
memset (&qctrl, 0, sizeof (qctrl));
/* V4L2_CID_BASE defined in linux/v4l2-controls.h */
for (idx=V4L2_CID_BASE; idx<V4L2_CID_LASTP1; idx++) {
qctrl.id = idx;
// if (verbosity>1) printf(" id %d ", idx);
if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &qctrl)) {
if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
printf("disabled\n");
continue;
}
printf(" %-40s %-10s [%d..%d]\n",
qctrl.name,
str_ctrl_type(qctrl.type),
qctrl.minimum, qctrl.maximum);
}
else if (EINVAL==errno) {
#if DEBUG_LEVEL
if (verbosity) fprintf(stderr, "id %d einval\n", idx);
#endif
continue;
}
else {
printf("err %d %s\n", errno, strerror(errno));
}
fflush(stdout); fflush(stderr);
}
return -1;
}
/* --------------------------------------------------------------------- */
/*
* code based on :
https://www.linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.html
*
*/
int enum_extended_controls(int fd, char *txt, int k)
{
struct v4l2_queryctrl qctrl;
int idx;
printf("##- extended controls enumeration '%s'\n", txt);
memset(&qctrl, 0, sizeof(qctrl));
qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
idx = 0;
while (0 == ioctl (fd, VIDIOC_QUERYCTRL, &qctrl)) {
if (verbosity) pr_ctrl_id(qctrl.id);
printf(" %-32s %-10s [%d..%d]\n",
qctrl.name,
str_ctrl_type(qctrl.type),
qctrl.minimum, qctrl.maximum);
qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
idx++;
}
return -1;
}
/* --------------------------------------------------------------------- */
int show_webcam_infos(char *devname, char *title, int k, int type)
{
int vfd, foo;
char ligne[100];
struct v4l2_capability cap;
struct v4l2_format fmt;
// struct v4l2_input input;
// int index;
// struct v4l2_requestbuffers reqbuf;
#if DEBUG_LEVEL
fprintf(stderr, ">>> %s ( '%s' %d %d)\n", __func__, devname, k, type);
#endif
vfd = open_device(devname);
if (vfd < 0) {
perror(devname);
return -3;
}
fprintf(stderr, "\topen %s -> %d\n", devname, vfd);
memset(&cap, 0, sizeof(cap));
foo = ioctl(vfd, VIDIOC_QUERYCAP, &cap);
if (foo < 0) {
perror("ioctl QUERYCAP");
return -4;
}
pr_v4l2_capability(devname, &cap);
foo = enum_inputs(vfd, "on peut voir quoi ?", 0);
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
foo = ioctl(vfd, VIDIOC_G_FMT, &fmt);
if (0 != foo) {
perror("ioctl G_FMT");
}
else {
pr_v4l2_format("Experimental", &fmt);
}
if (type) {
;
}
else {
foo = enum_image_formats(vfd, "Experimental", 0);
foo = enum_controls(vfd, "is that working ?", 0);
foo = enum_extended_controls(vfd, "looking for extended", 0);
enum_image_framesizes(vfd, "code pas fini", 0);
}
close(vfd);
return 0;
}
/* --------------------------------------------------------------------- */
int liste_des_devices(int flag)
{
fprintf(stderr, "%s not implemented\n", __func__);
return -1;
}
/* --------------------------------------------------------------------- */
static void help(int k)
{
puts("Options :");
puts("\t-e N\t\texamine that, please");
puts("\t-d\t\tselect the video device");
puts("\t-K\t\tset the K parameter");
puts("\t-l\t\tlist video devices");
puts("\t-T bla\t\tadd a title");
puts("\t-v\t\tincrease verbosity");
// if (verbosity)
{ puts(""); fimg_print_version(1); }
exit(0);
}
/* --------------------------------------------------------------------- */
static void print_title(char *txt)
{
int foo, l;
l = strlen(txt);
for (foo=0; foo<l+18; foo++)
putchar('*');
puts("");
printf("****** %s ******\n", txt);
for (foo=0; foo<l+18; foo++)
putchar('*');
puts("\n");
}
/* --------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
int foo, opt;
int etype = 0;
char *device = "/dev/video0";
char *title = NULL;
int K = 0;
while ((opt = getopt(argc, argv, "d:e:hK:lT:v")) != -1) {
switch(opt) {
case 'd': device = optarg; break;
case 'e': etype = atol(optarg); break;
case 'h': help(0); break;
case 'K': K = atol(optarg); break;
case 'l': liste_des_devices(0); break;
case 'T': title = optarg; break;
case 'v': verbosity++; break;
}
}
if (NULL != title) {
print_title(title);
}
foo = show_webcam_infos(device, "", K, etype);
fprintf(stderr, "\n\tshow_webcam_infos -> %d\n", foo);
return 0;
}
/* --------------------------------------------------------------------- */