summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4l1
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-03-12 11:10:42 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-12 11:10:42 -0300
commit7787613f5c5a3a00ebd6aca9893ef2c4ad679bc1 (patch)
tree4ffb8dbda509405c10b484edacb44807b16c5466 /v4l2-apps/libv4l/libv4l1
parent84c19b03d182a3ad1a04fa4be0772ef587225fe6 (diff)
parentd32bcc1401cca5f2ea369ce78ab70947034b5c8f (diff)
downloadmediapointer-dvb-s2-7787613f5c5a3a00ebd6aca9893ef2c4ad679bc1.tar.gz
mediapointer-dvb-s2-7787613f5c5a3a00ebd6aca9893ef2c4ad679bc1.tar.bz2
merge: http://jusst.de/hg/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l/libv4l1')
-rw-r--r--v4l2-apps/libv4l/libv4l1/Makefile83
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1-priv.h83
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1.c837
-rw-r--r--v4l2-apps/libv4l/libv4l1/log.c145
-rw-r--r--v4l2-apps/libv4l/libv4l1/v4l1compat.c127
5 files changed, 1275 insertions, 0 deletions
diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile
new file mode 100644
index 000000000..27848477e
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/Makefile
@@ -0,0 +1,83 @@
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
+
+CFLAGS := -g -O1
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
+
+LIBS = -lpthread
+
+V4L1_OBJS = libv4l1.o log.o
+V4L1COMPAT = v4l1compat.so
+V4L1COMPAT_O = v4l1compat.o libv4l1.so
+TARGETS = $(V4L1_LIB) libv4l1.pc
+INCLUDES = ../include/libv4l1.h
+
+ifeq ($(LINKTYPE),static)
+V4L1_LIB = libv4l1.a
+else
+V4L1_LIB = libv4l1.so
+V4L1_OBJS += ../libv4l2/libv4l2.so
+TARGETS += $(V4L1COMPAT)
+override CPPFLAGS += -fPIC
+endif
+
+ifeq ($(LIB_RELEASE),)
+LIB_RELEASE = 0
+endif
+
+ifeq ($(PREFIX),)
+PREFIX = /usr/local
+endif
+
+ifeq ($(LIBDIR),)
+LIBDIR = $(PREFIX)/lib
+endif
+
+all: $(TARGETS)
+
+
+$(V4L1_LIB): $(V4L1_OBJS)
+
+$(V4L1COMPAT): $(V4L1COMPAT_O) $(V4L1_LIB)
+
+libv4l1.pc:
+ @echo prefix=$(PREFIX) > libv4l1.pc
+ @echo libdir=$(LIBDIR) >> libv4l1.pc
+ @echo >> libv4l1.pc
+ @echo 'Name: libv4l1' >> libv4l1.pc
+ @echo 'Description: v4l1 compatibility library' >> libv4l1.pc
+ @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4l1.pc
+ @echo 'Requires: libv4l2' >> libv4l1.pc
+ @echo 'Libs: -L$${libdir} -lv4l1' >> libv4l1.pc
+ @echo 'Libs.private: -lpthread' >> libv4l1.pc
+ @echo 'Cflags: -I$${prefix}/include' >> libv4l1.pc
+
+install: all
+ mkdir -p $(DESTDIR)$(PREFIX)/include
+ install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include
+ifeq ($(LINKTYPE),static)
+ mkdir -p $(DESTDIR)$(LIBDIR)
+ install -m 644 $(V4L1_LIB) $(DESTDIR)$(LIBDIR)
+else
+ mkdir -p $(DESTDIR)$(LIBDIR)/libv4l
+ install -m 755 $(V4L1_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR)
+ cd $(DESTDIR)$(LIBDIR) && \
+ ln -f -s $(V4L1_LIB).$(LIB_RELEASE) $(V4L1_LIB)
+ install -m 755 $(V4L1COMPAT).$(LIB_RELEASE) \
+ $(DESTDIR)$(LIBDIR)/libv4l/$(V4L1COMPAT)
+endif
+ mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
+ install -m 644 libv4l1.pc $(DESTDIR)$(LIBDIR)/pkgconfig
+
+clean::
+ rm -f *.a *.so* *.o *.d libv4l1.pc log *~
+
+%.o: %.c
+ $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+%.so:
+ $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS)
+ ln -f -s $@.$(LIB_RELEASE) $@
+
+%.a:
+ $(AR) cqs $@ $^
+
diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
new file mode 100644
index 000000000..651599255
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
@@ -0,0 +1,83 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4L1_PRIV_H
+#define __LIBV4L1_PRIV_H
+
+#include <stdio.h>
+#include <pthread.h>
+
+/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
+#ifdef __NR_mmap2
+#define SYS_mmap2 __NR_mmap2
+#define MMAP2_PAGE_SHIFT 12
+#else
+#define SYS_mmap2 SYS_mmap
+#define MMAP2_PAGE_SHIFT 0
+#endif
+
+#define V4L1_MAX_DEVICES 16
+#define V4L1_NO_FRAMES 4
+#define V4L1_FRAME_BUF_SIZE (4096 * 4096)
+
+extern FILE *v4l1_log_file;
+
+#define V4L1_LOG_ERR(...) \
+ do { \
+ if (v4l1_log_file) { \
+ fprintf(v4l1_log_file, "libv4l1: error " __VA_ARGS__); \
+ fflush(v4l1_log_file); \
+ } else \
+ fprintf(stderr, "libv4l1: error " __VA_ARGS__); \
+ } while(0)
+
+#define V4L1_LOG_WARN(...) \
+ do { \
+ if (v4l1_log_file) { \
+ fprintf(v4l1_log_file, "libv4l1: warning " __VA_ARGS__); \
+ fflush(v4l1_log_file); \
+ } else \
+ fprintf(stderr, "libv4l1: warning " __VA_ARGS__); \
+ } while(0)
+
+#define V4L1_LOG(...) \
+ do { \
+ if (v4l1_log_file) { \
+ fprintf(v4l1_log_file, "libv4l1: " __VA_ARGS__); \
+ fflush(v4l1_log_file); \
+ } \
+ } while(0)
+
+struct v4l1_dev_info {
+ int fd;
+ int flags;
+ int open_count;
+ int v4l1_frame_buf_map_count;
+ pthread_mutex_t stream_lock;
+ unsigned int depth;
+ unsigned int v4l1_pal; /* VIDEO_PALETTE */
+ unsigned int v4l2_pixfmt; /* V4L2_PIX_FMT */
+ unsigned int min_width, min_height, max_width, max_height;
+ unsigned int width, height;
+ unsigned char *v4l1_frame_pointer;
+};
+
+/* From log.c */
+void v4l1_log_ioctl(unsigned long int request, void *arg, int result);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c
new file mode 100644
index 000000000..797c8768a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c
@@ -0,0 +1,837 @@
+/*
+# libv4l1 userspace v4l1 api emulation for v4l2 devices
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* MAKING CHANGES TO THIS FILE?? READ THIS FIRST!!!
+
+ Important note to people making changes to this file: All functions
+ (v4l1_close, v4l1_ioctl, etc.) are designed to function as their regular
+ counterpart when they get passed a fd that is not "registered" by libv4l1,
+ there are 2 reasons for this:
+ 1) This allows us to get completely out of the way when dealing with non
+ capture only devices, or non v4l2 devices.
+ 2) libv4l1 is the base of the v4l1compat.so wrapper lib, which is a .so
+ which can be LD_PRELOAD-ed and the overrules the libc's open/close/etc,
+ and when opening /dev/videoX or /dev/v4l/ calls v4l1_open. Because we
+ behave as the regular counterpart when the fd is not known (instead of
+ say throwing an error), v4l1compat.so can simply call the v4l1_ prefixed
+ function for all wrapped functions. This way the wrapper does not have
+ to keep track of which fd's are being handled by libv4l1, as libv4l1
+ already keeps track of this itself.
+
+ This also means that libv4l1 may not use any of the regular functions
+ it mimics, as for example open could be a symbol in v4l1compat.so, which
+ in turn will call v4l1_open, so therefor v4l1_open (for example) may not
+ use the regular open()!
+*/
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <asm/types.h>
+#include <linux/ioctl.h>
+/* end broken header workaround includes */
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <libv4l2.h>
+#include "libv4l1.h"
+#include "libv4l1-priv.h"
+
+#define V4L1_SUPPORTS_ENUMINPUT 0x01
+#define V4L1_SUPPORTS_ENUMSTD 0x02
+#define V4L1_PIX_FMT_TOUCHED 0x04
+#define V4L1_PIX_SIZE_TOUCHED 0x08
+
+static pthread_mutex_t v4l1_open_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct v4l1_dev_info devices[V4L1_MAX_DEVICES] = { { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }};
+static int devices_used = 0;
+
+static unsigned int palette_to_pixelformat(unsigned int palette)
+{
+ switch (palette) {
+ case VIDEO_PALETTE_GREY:
+ return V4L2_PIX_FMT_GREY;
+ case VIDEO_PALETTE_RGB555:
+ return V4L2_PIX_FMT_RGB555;
+ case VIDEO_PALETTE_RGB565:
+ return V4L2_PIX_FMT_RGB565;
+ case VIDEO_PALETTE_RGB24:
+ return V4L2_PIX_FMT_BGR24;
+ case VIDEO_PALETTE_RGB32:
+ return V4L2_PIX_FMT_BGR32;
+ case VIDEO_PALETTE_YUYV:
+ return V4L2_PIX_FMT_YUYV;
+ case VIDEO_PALETTE_YUV422:
+ return V4L2_PIX_FMT_YUYV;
+ case VIDEO_PALETTE_UYVY:
+ return V4L2_PIX_FMT_UYVY;
+ case VIDEO_PALETTE_YUV410P:
+ return V4L2_PIX_FMT_YUV410;
+ case VIDEO_PALETTE_YUV420:
+ case VIDEO_PALETTE_YUV420P:
+ return V4L2_PIX_FMT_YUV420;
+ case VIDEO_PALETTE_YUV411P:
+ return V4L2_PIX_FMT_YUV411P;
+ case VIDEO_PALETTE_YUV422P:
+ return V4L2_PIX_FMT_YUV422P;
+ }
+ return 0;
+}
+
+static unsigned int pixelformat_to_palette(unsigned int pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_GREY:
+ return VIDEO_PALETTE_GREY;
+ case V4L2_PIX_FMT_RGB555:
+ return VIDEO_PALETTE_RGB555;
+ case V4L2_PIX_FMT_RGB565:
+ return VIDEO_PALETTE_RGB565;
+ case V4L2_PIX_FMT_BGR24:
+ return VIDEO_PALETTE_RGB24;
+ case V4L2_PIX_FMT_BGR32:
+ return VIDEO_PALETTE_RGB32;
+ case V4L2_PIX_FMT_YUYV:
+ return VIDEO_PALETTE_YUYV;
+ case V4L2_PIX_FMT_UYVY:
+ return VIDEO_PALETTE_UYVY;
+ case V4L2_PIX_FMT_YUV410:
+ case V4L2_PIX_FMT_YUV420:
+ return VIDEO_PALETTE_YUV420P;
+ case V4L2_PIX_FMT_YUV411P:
+ return VIDEO_PALETTE_YUV411P;
+ case V4L2_PIX_FMT_YUV422P:
+ return VIDEO_PALETTE_YUV422P;
+ }
+ return 0;
+}
+
+static int v4l1_set_format(int index, unsigned int width,
+ unsigned int height, int v4l1_pal, int width_height_may_differ)
+{
+ int result;
+ unsigned int v4l2_pixfmt;
+ struct v4l2_format fmt2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+
+ if (v4l1_pal != -1) {
+ v4l2_pixfmt = palette_to_pixelformat(v4l1_pal);
+ if (!v4l2_pixfmt) {
+ V4L1_LOG("Unknown v4l1 palette number: %d\n", v4l1_pal);
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ v4l2_pixfmt = devices[index].v4l2_pixfmt;
+ v4l1_pal = devices[index].v4l1_pal;
+ }
+
+ /* Do we need to change the resolution / format ? */
+ if (width == devices[index].width && height == devices[index].height &&
+ v4l2_pixfmt == devices[index].v4l2_pixfmt)
+ return 0;
+
+ /* Get current settings, apply our changes and try the new setting */
+ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_G_FMT, &fmt2))) {
+ int saved_err = errno;
+ V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ fmt2.fmt.pix.pixelformat = v4l2_pixfmt;
+ fmt2.fmt.pix.width = width;
+ fmt2.fmt.pix.height = height;
+ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, &fmt2)))
+ {
+ int saved_err = errno;
+ V4L1_LOG("error trying pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ /* Check if we get what we asked for */
+ if (fmt2.fmt.pix.pixelformat != v4l2_pixfmt || (!width_height_may_differ &&
+ (fmt2.fmt.pix.width != width || fmt2.fmt.pix.height != height))) {
+ V4L1_LOG("requested fmt, width, height combo not available\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Maybe after the TRY_FMT things haven't changed after all ? */
+ if (fmt2.fmt.pix.width == devices[index].width &&
+ fmt2.fmt.pix.height == devices[index].height &&
+ fmt2.fmt.pix.pixelformat == devices[index].v4l2_pixfmt) {
+ devices[index].v4l1_pal = v4l1_pal;
+ return 0;
+ }
+
+ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_S_FMT, &fmt2))) {
+ int saved_err = errno;
+ V4L1_LOG_ERR("setting pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ devices[index].width = fmt2.fmt.pix.width;
+ devices[index].height = fmt2.fmt.pix.height;
+ devices[index].v4l2_pixfmt = v4l2_pixfmt;
+ devices[index].v4l1_pal = v4l1_pal;
+ devices[index].depth = ((fmt2.fmt.pix.bytesperline << 3) +
+ (fmt2.fmt.pix.width - 1)) / fmt2.fmt.pix.width;
+
+ return result;
+}
+
+static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2)
+{
+ int i;
+ struct v4l2_fmtdesc fmtdesc2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+
+ devices[index].min_width = -1;
+ devices[index].min_height = -1;
+ devices[index].max_width = 0;
+ devices[index].max_height = 0;
+
+ for (i = 0; ; i++) {
+ fmtdesc2.index = i;
+
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2))
+ break;
+
+ fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
+ fmt2->fmt.pix.width = 48;
+ fmt2->fmt.pix.height = 32;
+
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
+ if (fmt2->fmt.pix.width < devices[index].min_width)
+ devices[index].min_width = fmt2->fmt.pix.width;
+ if (fmt2->fmt.pix.height < devices[index].min_height)
+ devices[index].min_height = fmt2->fmt.pix.height;
+ }
+
+ fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
+ fmt2->fmt.pix.width = 100000;
+ fmt2->fmt.pix.height = 100000;
+
+ if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
+ if (fmt2->fmt.pix.width > devices[index].max_width)
+ devices[index].max_width = fmt2->fmt.pix.width;
+ if (fmt2->fmt.pix.height > devices[index].max_height)
+ devices[index].max_height = fmt2->fmt.pix.height;
+ }
+ }
+}
+
+
+int v4l1_open (const char *file, int oflag, ...)
+{
+ int index, fd;
+ char *lfname;
+ struct v4l2_capability cap2;
+ struct v4l2_format fmt2;
+ struct v4l2_input input2;
+ struct v4l2_standard standard2;
+ int v4l_device = 0;
+
+ /* check if we're opening a video4linux2 device */
+ if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) {
+ /* Some apps open the device read only, but we need rw rights as the
+ buffers *MUST* be mapped rw */
+ oflag = (oflag & ~O_ACCMODE) | O_RDWR;
+ v4l_device = 1;
+ }
+
+ /* original open code */
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = syscall(SYS_open, file, oflag, mode);
+
+ va_end(ap);
+ } else
+ fd = syscall(SYS_open, file, oflag);
+ /* end of original open code */
+
+ if (fd == -1 || !v4l_device)
+ return fd;
+
+ /* check that this is an v4l2 device, no need to emulate v4l1 on
+ a v4l1 device */
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap2))
+ return fd;
+
+ /* IMPROVEME */
+ /* we only support simple video capture devices which do not do overlay */
+ if ((cap2.capabilities & 0x0F) != V4L2_CAP_VIDEO_CAPTURE)
+ return fd;
+
+ /* If no log file was set by the app, see if one was specified through the
+ environment */
+ if (!v4l1_log_file && (lfname = getenv("LIBV4L1_LOG_FILENAME")))
+ v4l1_log_file = fopen(lfname, "w");
+
+ /* redirect libv4l2 log messages to our logfile if no libv4l2 logfile is
+ specified */
+ if (!v4l2_log_file)
+ v4l2_log_file = v4l1_log_file;
+
+ /* Get initial width, height and pixelformat */
+ fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) {
+ int saved_err = errno;
+ V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ syscall(SYS_close, fd);
+ errno = saved_err;
+ return -1;
+ }
+
+ /* Register with libv4l2, as we use that todo format conversion and read()
+ emulation for us */
+ if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) {
+ int saved_err = errno;
+ syscall(SYS_close, fd);
+ errno = saved_err;
+ return -1;
+ }
+
+ /* So we have a device on which we can (and want to) emulate v4l1, register
+ it in our devices array */
+ pthread_mutex_lock(&v4l1_open_mutex);
+ for (index = 0; index < V4L1_MAX_DEVICES; index++)
+ if(devices[index].fd == -1) {
+ devices[index].fd = fd;
+ break;
+ }
+ pthread_mutex_unlock(&v4l1_open_mutex);
+
+ if (index == V4L1_MAX_DEVICES) {
+ V4L1_LOG_ERR("attempting to open more then %d video devices\n",
+ V4L1_MAX_DEVICES);
+ v4l2_close(fd);
+ errno = EBUSY;
+ return -1;
+ }
+
+ if (index >= devices_used)
+ devices_used = index + 1;
+
+ devices[index].flags = 0;
+ devices[index].open_count = 1;
+ devices[index].v4l1_frame_buf_map_count = 0;
+ devices[index].v4l1_frame_pointer = MAP_FAILED;
+ devices[index].width = fmt2.fmt.pix.width;
+ devices[index].height = fmt2.fmt.pix.height;
+ devices[index].v4l2_pixfmt = fmt2.fmt.pix.pixelformat;
+ devices[index].v4l1_pal = pixelformat_to_palette(fmt2.fmt.pix.pixelformat);
+ devices[index].depth = ((fmt2.fmt.pix.bytesperline << 3) +
+ (fmt2.fmt.pix.width - 1)) / fmt2.fmt.pix.width;
+
+ v4l1_find_min_and_max_size(index, &fmt2);
+
+ /* Check ENUM_INPUT and ENUM_STD support */
+ input2.index = 0;
+ if (v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2) == 0)
+ devices[index].flags |= V4L1_SUPPORTS_ENUMINPUT;
+
+ standard2.index = 0;
+ if (v4l2_ioctl(fd, VIDIOC_ENUMSTD, &input2) == 0)
+ devices[index].flags |= V4L1_SUPPORTS_ENUMSTD;
+
+ V4L1_LOG("open: %d\n", fd);
+
+ return fd;
+}
+
+/* Is this an fd for which we are emulating v4l1 ? */
+static int v4l1_get_index(int fd)
+{
+ int index;
+
+ /* We never handle fd -1 */
+ if (fd == -1)
+ return -1;
+
+ for (index = 0; index < devices_used; index++)
+ if (devices[index].fd == fd)
+ break;
+
+ if (index == devices_used)
+ return -1;
+
+ return index;
+}
+
+
+int v4l1_close(int fd) {
+ int index, result;
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_close, fd);
+
+ /* Abuse stream_lock to stop 2 closes from racing and trying to free the
+ resources twice */
+ pthread_mutex_lock(&devices[index].stream_lock);
+ devices[index].open_count--;
+ result = devices[index].open_count != 0;
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ if (result)
+ return v4l2_close(fd);
+
+ /* Free resources */
+ if (devices[index].v4l1_frame_pointer != MAP_FAILED) {
+ if (devices[index].v4l1_frame_buf_map_count)
+ V4L1_LOG("v4l1 capture buffer still mapped: %d times on close()\n",
+ devices[index].v4l1_frame_buf_map_count);
+ else
+ syscall(SYS_munmap, devices[index].v4l1_frame_pointer,
+ V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE);
+ devices[index].v4l1_frame_pointer = MAP_FAILED;
+ }
+
+ /* Remove the fd from our list of managed fds before closing it, because as
+ soon as we've done the actual close the fd maybe returned by an open in
+ another thread and we don't want to intercept calls to this new fd. */
+ devices[index].fd = -1;
+
+ result = v4l2_close(fd);
+
+ V4L1_LOG("close: %d\n", fd);
+
+ return result;
+}
+
+int v4l1_dup(int fd)
+{
+ int index;
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_dup, fd);
+
+ devices[index].open_count++;
+
+ return v4l2_dup(fd);
+}
+
+
+int v4l1_ioctl (int fd, unsigned long int request, ...)
+{
+ void *arg;
+ va_list ap;
+ int result, index, saved_err, stream_locked = 0;
+
+ va_start (ap, request);
+ arg = va_arg (ap, void *);
+ va_end (ap);
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_ioctl, fd, request, arg);
+
+ /* Appearantly the kernel and / or glibc ignore the 32 most significant bits
+ when long = 64 bits, and some applications pass an int holding the req to
+ ioctl, causing it to get sign extended, depending upon this behavior */
+ request = (unsigned int)request;
+
+ /* do we need to take the stream lock for this ioctl? */
+ switch (request) {
+ case VIDIOCSPICT:
+ case VIDIOCGPICT:
+ case VIDIOCSWIN:
+ case VIDIOCGWIN:
+ case VIDIOCGMBUF:
+ case VIDIOCMCAPTURE:
+ case VIDIOCSYNC:
+ case VIDIOC_S_FMT:
+ pthread_mutex_lock(&devices[index].stream_lock);
+ stream_locked = 1;
+ }
+
+ switch (request) {
+
+ case VIDIOCGCAP:
+ {
+ struct video_capability *cap = arg;
+
+ result = syscall(SYS_ioctl, fd, request, arg);
+
+ /* override kernel v4l1 compat min / max size with our own more
+ accurate values */
+ cap->minwidth = devices[index].min_width;
+ cap->minheight = devices[index].min_height;
+ cap->maxwidth = devices[index].max_width;
+ cap->maxheight = devices[index].max_height;
+ }
+ break;
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture *pic = arg;
+
+ devices[index].flags |= V4L1_PIX_FMT_TOUCHED;
+
+ v4l2_set_control(fd, V4L2_CID_BRIGHTNESS, pic->brightness);
+ v4l2_set_control(fd, V4L2_CID_HUE, pic->hue);
+ v4l2_set_control(fd, V4L2_CID_CONTRAST, pic->contrast);
+ v4l2_set_control(fd, V4L2_CID_SATURATION, pic->colour);
+ v4l2_set_control(fd, V4L2_CID_WHITENESS, pic->whiteness);
+
+ result = v4l1_set_format(index, devices[index].width,
+ devices[index].height, pic->palette, 0);
+ }
+ break;
+
+ case VIDIOCGPICT:
+ {
+ struct video_picture *pic = arg;
+
+ /* If our v4l2 pixformat has no corresponding v4l1 palette, and the
+ app has not touched the pixformat sofar, try setting a palette which
+ does (and which we emulate when necessary) so that applications
+ which just query the current format and then take whatever they get
+ will work */
+ if (!(devices[index].flags & V4L1_PIX_FMT_TOUCHED) &&
+ !pixelformat_to_palette(devices[index].v4l2_pixfmt))
+ v4l1_set_format(index, devices[index].width,
+ devices[index].height,
+ VIDEO_PALETTE_RGB24,
+ (devices[index].flags &
+ V4L1_PIX_SIZE_TOUCHED) ? 0 : 1);
+
+ devices[index].flags |= V4L1_PIX_FMT_TOUCHED;
+
+ pic->depth = devices[index].depth;
+ pic->palette = devices[index].v4l1_pal;
+ pic->hue = v4l2_get_control(devices[index].fd, V4L2_CID_HUE);
+ pic->colour = v4l2_get_control(devices[index].fd, V4L2_CID_SATURATION);
+ pic->contrast = v4l2_get_control(devices[index].fd, V4L2_CID_CONTRAST);
+ pic->whiteness = v4l2_get_control(devices[index].fd,
+ V4L2_CID_WHITENESS);
+ pic->brightness = v4l2_get_control(devices[index].fd,
+ V4L2_CID_BRIGHTNESS);
+
+ result = 0;
+ }
+ break;
+
+ case VIDIOCSWIN:
+ {
+ struct video_window *win = arg;
+
+ devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
+
+ result = v4l1_set_format(index, win->width, win->height, -1, 1);
+ if (result == 0) {
+ win->width = devices[index].width;
+ win->height = devices[index].height;
+ }
+ }
+ break;
+
+ case VIDIOCGWIN:
+ devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
+ result = syscall(SYS_ioctl, fd, request, arg);
+ break;
+
+ case VIDIOCGCHAN:
+ {
+ struct v4l2_input input2;
+ struct video_channel *chan = arg;
+
+ if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) &&
+ (devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) {
+ result = syscall(SYS_ioctl, fd, request, arg);
+ break;
+ }
+
+ /* Set some defaults */
+ chan->tuners = 0;
+ chan->flags = 0;
+ chan->type = VIDEO_TYPE_CAMERA;
+ chan->norm = 0;
+
+ /* In case of no ENUMSTD support, ignore the norm member of the
+ channel struct */
+ if (devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) {
+ input2.index = chan->channel;
+ result = v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2);
+ if (result == 0) {
+ snprintf(chan->name, sizeof(chan->name), "%s", (char*)input2.name);
+ if (input2.type == V4L2_INPUT_TYPE_TUNER) {
+ chan->tuners = 1;
+ chan->type = VIDEO_TYPE_TV;
+ chan->flags = VIDEO_VC_TUNER;
+ }
+ }
+ break;
+ }
+
+ /* No ENUMINPUT support, fake it (assume its a Camera in this case) */
+ if (chan->channel == 0) {
+ snprintf(chan->name, sizeof(chan->name), "Camera");
+ result = 0;
+ } else {
+ errno = EINVAL;
+ result = -1;
+ }
+ }
+ break;
+
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *chan = arg;
+ if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) &&
+ (devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) {
+ result = syscall(SYS_ioctl, fd, request, arg);
+ break;
+ }
+ /* In case of no ENUMSTD support, ignore the norm member of the
+ channel struct */
+ if (devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) {
+ result = v4l2_ioctl(fd, VIDIOC_S_INPUT, &chan->channel);
+ break;
+ }
+ /* No ENUMINPUT support, fake it (assume its a Camera in this case) */
+ if (chan->channel == 0) {
+ result = 0;
+ } else {
+ errno = EINVAL;
+ result = -1;
+ }
+ }
+ break;
+
+ case VIDIOCGMBUF:
+ /* When VIDIOCGMBUF is done, we don't necessarrily know the format the
+ application wants yet (with some apps this is passed for the first
+ time through VIDIOCMCAPTURE), so we just create an anonymous mapping
+ that should be large enough to hold any sort of frame. Note this only
+ takes virtual memory, and does not use memory until actually used. */
+ {
+ int i;
+ struct video_mbuf *mbuf = arg;
+
+ mbuf->size = V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE;
+ mbuf->frames = V4L1_NO_FRAMES;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = i * V4L1_FRAME_BUF_SIZE;
+ }
+
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
+ devices[index].v4l1_frame_pointer = (void *)syscall(SYS_mmap2, NULL,
+ (size_t)mbuf->size,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
+ saved_err = errno;
+ V4L1_LOG_ERR("allocating v4l1 buffer: %s\n", strerror(errno));
+ errno = saved_err;
+ result = -1;
+ break;
+ }
+ V4L1_LOG("allocated v4l1 buffer @ %p\n",
+ devices[index].v4l1_frame_pointer);
+ }
+ result = 0;
+ }
+ break;
+
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap *map = arg;
+
+ devices[index].flags |= V4L1_PIX_FMT_TOUCHED |
+ V4L1_PIX_SIZE_TOUCHED;
+
+ result = v4l1_set_format(index, map->width, map->height,
+ map->format, 0);
+ }
+ break;
+
+ case VIDIOCSYNC:
+ {
+ int *frame_index = arg;
+
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED ||
+ *frame_index < 0 || *frame_index >= V4L1_NO_FRAMES) {
+ errno = EINVAL;
+ result = -1;
+ break;
+ }
+
+ result = v4l2_read(devices[index].fd,
+ devices[index].v4l1_frame_pointer +
+ *frame_index * V4L1_FRAME_BUF_SIZE,
+ V4L1_FRAME_BUF_SIZE);
+ result = (result > 0) ? 0:result;
+ }
+ break;
+
+ /* We are passing through v4l2 calls to libv4l2 for applications which are
+ using v4l2 through libv4l1 (possible with the v4l1compat.so wrapper).
+
+ So the application could be calling VIDIOC_S_FMT, in this case update
+ our own bookkeeping of the cam's format. Note that this really only is
+ relevant if an application is mixing and matching v4l1 and v4l2 calls,
+ which is crazy, but better safe then sorry. */
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *fmt2 = arg;
+
+ result = v4l2_ioctl(fd, request, arg);
+
+ if (result == 0 && fmt2->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (devices[index].v4l2_pixfmt != fmt2->fmt.pix.pixelformat) {
+ devices[index].v4l2_pixfmt = fmt2->fmt.pix.pixelformat;
+ devices[index].v4l1_pal =
+ pixelformat_to_palette(fmt2->fmt.pix.pixelformat);
+ }
+ devices[index].width = fmt2->fmt.pix.width;
+ devices[index].height = fmt2->fmt.pix.height;
+ }
+ }
+ break;
+
+ default:
+ /* Pass through libv4l2 for applications which are using v4l2 through
+ libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
+ result = v4l2_ioctl(fd, request, arg);
+ }
+
+ if (stream_locked)
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ saved_err = errno;
+ v4l1_log_ioctl(request, arg, result);
+ errno = saved_err;
+
+ return result;
+}
+
+
+ssize_t v4l1_read(int fd, void* buffer, size_t n)
+{
+ int index;
+ ssize_t result;
+
+ if ((index = v4l1_get_index(fd)) == -1)
+ return syscall(SYS_read, fd, buffer, n);
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+ result = v4l2_read(fd, buffer, n);
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ return result;
+}
+
+
+void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset)
+{
+ int index;
+ void *result;
+
+ /* Check if the mmap data matches our answer to VIDIOCGMBUF, if not
+ pass through libv4l2 for applications which are using v4l2 through
+ libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
+ if ((index = v4l1_get_index(fd)) == -1 || start || offset ||
+ length != (V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE))
+ return v4l2_mmap(start, length, prot, flags, fd, offset);
+
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ /* It could be that we get called with an mmap which seems to match what
+ we expect, but no VIDIOCGMBUF has been done yet, then it is certainly not
+ for us so pass it through */
+ if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
+ result = v4l2_mmap(start, length, prot, flags, fd, offset);
+ goto leave;
+ }
+
+ devices[index].v4l1_frame_buf_map_count++;
+
+ V4L1_LOG("v4l1 buffer @ %p mapped by application\n",
+ devices[index].v4l1_frame_pointer);
+
+ result = devices[index].v4l1_frame_pointer;
+
+leave:
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ return result;
+}
+
+int v4l1_munmap(void *_start, size_t length)
+{
+ int index;
+ unsigned char *start = _start;
+
+ /* Is this memory ours? */
+ if (start != MAP_FAILED &&
+ length == (V4L1_FRAME_BUF_SIZE * V4L1_NO_FRAMES)) {
+ for (index = 0; index < devices_used; index++)
+ if (devices[index].fd != -1 &&
+ start == devices[index].v4l1_frame_pointer)
+ break;
+
+ if (index != devices_used) {
+ int unmapped = 0;
+
+ pthread_mutex_lock(&devices[index].stream_lock);
+
+ /* Redo our checks now that we have the lock, things may have changed */
+ if (start == devices[index].v4l1_frame_pointer) {
+ if (devices[index].v4l1_frame_buf_map_count > 0)
+ devices[index].v4l1_frame_buf_map_count--;
+
+ unmapped = 1;
+ }
+
+ pthread_mutex_unlock(&devices[index].stream_lock);
+
+ if (unmapped) {
+ V4L1_LOG("v4l1 buffer munmap %p, %d\n", start, (int)length);
+ return 0;
+ }
+ }
+ }
+
+ V4L1_LOG("v4l1 unknown munmap %p, %d\n", start, (int)length);
+
+ /* If not pass through libv4l2 for applications which are using v4l2 through
+ libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
+ return v4l2_munmap(start, length);
+}
diff --git a/v4l2-apps/libv4l/libv4l1/log.c b/v4l2-apps/libv4l/libv4l1/log.c
new file mode 100644
index 000000000..9ff0cea46
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/log.c
@@ -0,0 +1,145 @@
+/*
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/ioctl.h>
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <asm/types.h>
+/* end broken header workaround includes */
+#include <linux/videodev.h>
+#include "libv4l1-priv.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+FILE *v4l1_log_file = NULL;
+
+static const char *v4l1_ioctls[] = {
+ [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
+ [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
+ [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
+ [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
+ [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
+ [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
+ [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
+ [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
+ [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
+ [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
+ [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
+ [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
+ [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
+ [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
+ [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
+ [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
+ [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
+ [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
+ [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
+ [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
+ [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
+ [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
+ [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
+ [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
+ [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
+ [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
+ [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
+ [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
+ [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT",
+};
+
+void v4l1_log_ioctl(unsigned long int request, void *arg, int result)
+{
+ const char *ioctl_str = "unknown";
+ char buf[40];
+
+ if (!v4l1_log_file)
+ return;
+
+ /* Don't log v4l2 ioctl's as unknown we pass them to libv4l2 which will
+ log them for us */
+ if (_IOC_TYPE(request) == 'V')
+ return;
+
+ if (_IOC_TYPE(request) == 'v' && _IOC_NR(request) < ARRAY_SIZE(v4l1_ioctls))
+ ioctl_str = v4l1_ioctls[_IOC_NR(request)];
+ else {
+ snprintf(buf, sizeof(buf), "unknown request: %c %d\n",
+ (int)_IOC_TYPE(request), (int)_IOC_NR(request));
+ ioctl_str = buf;
+ }
+
+ fprintf(v4l1_log_file, "request == %s\n", ioctl_str);
+
+ switch(request)
+ {
+ case VIDIOCGCAP:fprintf(v4l1_log_file,"name %s\n",( (struct video_capability*)arg)->name );
+ fprintf(v4l1_log_file,"type %d\n",( (struct video_capability*)arg)->type );
+ fprintf(v4l1_log_file,"channels %d\n",( (struct video_capability*)arg)->channels );
+ fprintf(v4l1_log_file,"audios %d\n",( (struct video_capability*)arg)->audios );
+ fprintf(v4l1_log_file,"maxwidth %d\n",( (struct video_capability*)arg)->maxwidth );
+ fprintf(v4l1_log_file,"maxheight %d\n",( (struct video_capability*)arg)->maxheight );
+ fprintf(v4l1_log_file,"minwidth %d\n",( (struct video_capability*)arg)->minwidth );
+ fprintf(v4l1_log_file,"minheight %d\n",( (struct video_capability*)arg)->minheight );
+ break;
+ case VIDIOCGWIN:
+ case VIDIOCSWIN:
+ fprintf(v4l1_log_file,"width\t%u\n",
+ ((struct video_window *)arg)->width);
+ fprintf(v4l1_log_file,"height\t%u\n",
+ ((struct video_window *)arg)->height);
+ break;
+
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
+ fprintf(v4l1_log_file,"channel %d\n",( (struct video_channel*)arg)->channel );
+ fprintf(v4l1_log_file,"name %s\n",( (struct video_channel*)arg)->name );
+ break;
+
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ fprintf(v4l1_log_file,"brightness %d\n",( (int)((struct video_picture*)arg)->brightness) );
+ fprintf(v4l1_log_file,"hue %d\n",( (int)((struct video_picture*)arg)->hue) );
+ fprintf(v4l1_log_file,"colour %d\n",( (int)((struct video_picture*)arg)->colour) );
+ fprintf(v4l1_log_file,"contrast %d\n",( (int)((struct video_picture*)arg)->contrast) );
+ fprintf(v4l1_log_file,"whiteness %d\n",( (int)((struct video_picture*)arg)->whiteness) );
+ fprintf(v4l1_log_file,"depth %d\n",( (int)((struct video_picture*)arg)->depth) );
+ fprintf(v4l1_log_file,"palette %d\n",( (int)((struct video_picture*)arg)->palette) );
+ break;
+
+ case VIDIOCCAPTURE: fprintf(v4l1_log_file,"on/off? %d\n", *((int *)arg) );
+ break;
+
+ case VIDIOCSYNC: fprintf(v4l1_log_file,"sync %d\n", *((int *)arg) );
+ break;
+
+ case VIDIOCMCAPTURE:
+ fprintf(v4l1_log_file,"frame %u\n",( (struct video_mmap*)arg)->frame );
+ fprintf(v4l1_log_file,"width %d\n",( (struct video_mmap*)arg)->width );
+ fprintf(v4l1_log_file,"height %d\n",( (struct video_mmap*)arg)->height );
+ fprintf(v4l1_log_file,"format %u\n",( (struct video_mmap*)arg)->format );
+ break;
+
+ case VIDIOCGMBUF:
+ fprintf(v4l1_log_file,"size %d\n",( (struct video_mbuf*)arg)->size );
+ fprintf(v4l1_log_file,"frames %d\n",( (struct video_mbuf*)arg)->frames );
+ break;
+ }
+ fprintf(v4l1_log_file, "result == %d\n", result);
+ fflush(v4l1_log_file);
+}
diff --git a/v4l2-apps/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/libv4l/libv4l1/v4l1compat.c
new file mode 100644
index 000000000..e4293d2f9
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4l1/v4l1compat.c
@@ -0,0 +1,127 @@
+/*
+# open/close/ioctl/mmap/munmap library call wrapper doing v4l1 api emulation
+# for v4l2 devices
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define _LARGEFILE64_SOURCE 1
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <libv4l1.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+/* Check that open/read/mmap is not a define */
+#if defined open || defined read || defined mmap
+#error open/read/mmap is a prepocessor macro !!
+#endif
+
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
+{
+ int fd;
+
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = v4l1_open(file, oflag, mode);
+
+ va_end(ap);
+ } else
+ fd = v4l1_open(file, oflag);
+
+ return fd;
+}
+
+LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...)
+{
+ int fd;
+
+ if (oflag & O_CREAT)
+ {
+ va_list ap;
+ mode_t mode;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+
+ fd = v4l1_open(file, oflag | O_LARGEFILE, mode);
+
+ va_end(ap);
+ } else
+ fd = v4l1_open(file, oflag | O_LARGEFILE);
+
+ return fd;
+}
+
+LIBV4L_PUBLIC int close(int fd) {
+ return v4l1_close(fd);
+}
+
+LIBV4L_PUBLIC int dup(int fd)
+{
+ return v4l1_dup(fd);
+}
+
+LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...)
+{
+ void *arg;
+ va_list ap;
+
+ va_start (ap, request);
+ arg = va_arg (ap, void *);
+ va_end (ap);
+
+ return v4l1_ioctl (fd, request, arg);
+}
+
+LIBV4L_PUBLIC ssize_t read(int fd, void* buffer, size_t n)
+{
+ return v4l1_read (fd, buffer, n);
+}
+
+LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd,
+ __off_t offset)
+{
+ return v4l1_mmap(start, length, prot, flags, fd, offset);
+}
+
+LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd,
+ __off64_t offset)
+{
+ return v4l1_mmap(start, length, prot, flags, fd, offset);
+}
+
+LIBV4L_PUBLIC int munmap(void *start, size_t length)
+{
+ return v4l1_munmap(start, length);
+}
+