forked from tTh/FloatImg
source tree refactor and build system (to be completed)
This commit is contained in:
38
src/v4l2/Makefile
Normal file
38
src/v4l2/Makefile
Normal 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
32
src/v4l2/README.md
Normal 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
13
src/v4l2/README.txt
Normal 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
670
src/v4l2/capture.c
Normal 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
12
src/v4l2/essai.sh
Executable 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
42
src/v4l2/exemple.txt
Normal 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
329
src/v4l2/funcs.c
Normal 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
20
src/v4l2/funcs.h
Normal 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
427
src/v4l2/grabvidseq.c
Normal 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
130
src/v4l2/nc-camcontrol.c
Normal 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
25
src/v4l2/notes.txt
Normal 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
135
src/v4l2/rgb2fimg.c
Normal 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
91
src/v4l2/t.c
Normal 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
300
src/v4l2/v4l2_pr_structs.c
Normal 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;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
22
src/v4l2/v4l2_pr_structs.h
Normal file
22
src/v4l2/v4l2_pr_structs.h
Normal 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
331
src/v4l2/video-infos.c
Normal 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;
|
||||
}
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user