summaryrefslogtreecommitdiff
path: root/ztv/z4l.c
diff options
context:
space:
mode:
Diffstat (limited to 'ztv/z4l.c')
-rw-r--r--ztv/z4l.c1761
1 files changed, 1761 insertions, 0 deletions
diff --git a/ztv/z4l.c b/ztv/z4l.c
new file mode 100644
index 0000000..d44ff73
--- /dev/null
+++ b/ztv/z4l.c
@@ -0,0 +1,1761 @@
+/*
+ * Copyright (c) 2006 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ */
+
+/* prototype Xv interface for lxv4l2 driver */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "xf86.h"
+#include <X11/extensions/Xv.h>
+#include "xf86_OSproc.h"
+#include "compiler.h"
+#include "xf86xv.h"
+#include "fourcc.h"
+
+#include <linux/types.h>
+
+#define __s64 __s_64
+typedef long long __s64;
+
+#define __u64 __u_64
+typedef unsigned long long __u64;
+
+#define __user
+#include "linux/videodev2.h"
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+int debuglvl = 0;
+
+#define NONBLK_IO
+#undef HAVE_SELECT
+
+#define DEBUG 1
+#ifdef DEBUG
+#define DBLOG(n,s...) do { \
+ if ( debuglvl >= (n) ) \
+ xf86Msg(X_INFO, "z4l: " s); \
+ } while(0)
+#else
+#define DBLOG(n,s...) do {} while(0)
+#endif
+
+#define DEFAULT_COLORKEY 0x010203
+#define DEFAULT_KEYMODE 0
+
+#define MAX_BUFFERS 4
+#define MAX_OVLY_WIDTH 2048
+#define MAX_OVLY_HEIGHT 2048
+
+static char *z4l_dev_paths[] = {
+ "/dev/videox", NULL
+};
+
+#define ATTR_ENCODING "encoding"
+#define ATTR_ENCODING_ID -1
+#define ATTR_KEYMODE "keymode"
+#define ATTR_KEYMODE_ID -2
+#define ATTR_COLORKEY "colorkey"
+#define ATTR_COLORKEY_ID -3
+#define ATTR_MAX_ID 3
+
+#ifdef XvExtension
+
+static XF86VideoFormatRec Formats[] = {
+ {8, PseudoColor},
+ {15, TrueColor},
+ {16, TrueColor},
+ {24, TrueColor}
+};
+
+#define NUM_FORMATS (sizeof(Formats)/sizeof(Formats[0]))
+
+#define FOURCC_Y800 0x30303859
+#define XVIMAGE_Y800 \
+ { \
+ FOURCC_Y800, \
+ XvYUV, \
+ LSBFirst, \
+ {'Y','8','0','0', \
+ 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
+ 8, \
+ XvPacked, \
+ 1, \
+ 0, 0, 0, 0, \
+ 8, 0, 0, \
+ 1, 0, 0, \
+ 1, 0, 0, \
+ {'Y','8','0','0', \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
+ XvTopToBottom \
+ }
+
+static XF86ImageRec pixfmts[] = {
+ XVIMAGE_UYVY, XVIMAGE_YUY2,
+ XVIMAGE_I420, XVIMAGE_YV12,
+ XVIMAGE_Y800,
+};
+
+#define NUM_PIXFMTS (sizeof(pixfmts)/sizeof(pixfmts[0]))
+
+typedef struct s_std_data
+{
+ int inp;
+ v4l2_std_id std;
+ unsigned int fmt;
+} t_std_data;
+
+typedef struct s_ovly_bfrs
+{
+ void *start;
+ unsigned long offset;
+ size_t length;
+} t_ovly_bfrs;
+
+typedef struct
+{
+ int fd;
+ int run;
+ int dir;
+ int nbfrs;
+ int bufno;
+ int bufsz;
+ int last;
+ int width, height;
+ int keymode, colorkey;
+ int src_is_set, src_x, src_y, src_w, src_h;
+ int drw_is_set, drw_x, drw_y, drw_w, drw_h;
+ unsigned int pixfmt;
+ char dev_path[32];
+ t_ovly_bfrs bfrs[MAX_BUFFERS];
+ XF86VideoAdaptorPtr adpt;
+ XF86VideoEncodingPtr enc;
+ RegionRec clips;
+ int attrIds[1];
+} Z4lPortPrivRec;
+
+static int z4l_x_offset = 0;
+static int z4l_y_offset = 0;
+static int Z4l_nAdaptors = 0;
+static XF86VideoAdaptorPtr *Z4l_pAdaptors = NULL;
+
+static int
+IoCtl(int fd, unsigned int fn, void *arg, int flag)
+{
+ int ret;
+
+ errno = 0;
+ ret = ioctl(fd, fn, arg);
+ if (ret != 0 && flag != 0)
+ DBLOG(0, "ioctl(%08x)=%d\n", fn, ret);
+ return ret;
+}
+
+static void
+z4l_ovly_unmap(Z4lPortPrivRec * pPriv)
+{
+#ifdef LINUX_2_6
+ int i, nbfrs;
+
+ nbfrs = pPriv->nbfrs;
+ for (i = 0; i < nbfrs; ++i) {
+ if (pPriv->bfrs[i].start != NULL) {
+ munmap(pPriv->bfrs[i].start, pPriv->bfrs[i].length);
+ pPriv->bfrs[i].start = NULL;
+ }
+ }
+#else
+ if (pPriv->bfrs[0].start != NULL) {
+ munmap((void *)pPriv->bfrs[0].start, pPriv->bufsz);
+ pPriv->bfrs[0].start = NULL;
+ }
+#endif
+ pPriv->nbfrs = -1;
+ pPriv->bufsz = -1;
+ pPriv->last = -1;
+}
+
+static void
+z4l_ovly_map(Z4lPortPrivRec * pPriv, int dir)
+{
+ long offset, bsz;
+ int i, fd;
+ struct v4l2_buffer bfr;
+ struct v4l2_requestbuffers req;
+ int type = dir >= 0 ?
+ V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ if (pPriv->run > 0) {
+ DBLOG(1, "busy\n");
+ return;
+ }
+ fd = pPriv->fd;
+ memset(&req, 0, sizeof(req));
+ req.type = type;
+ req.memory = V4L2_MEMORY_MMAP;
+ req.count = MAX_BUFFERS;
+ if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
+ goto xit;
+ pPriv->nbfrs = req.count;
+ if (pPriv->nbfrs <= 0) {
+ DBLOG(1, "no vidmem\n");
+ return;
+ }
+ memset(&pPriv->bfrs, 0, sizeof(pPriv->bfrs));
+
+ for (i = 0; i < pPriv->nbfrs; ++i) {
+ memset(&bfr, 0, sizeof(bfr));
+ bfr.type = type;
+ bfr.index = i;
+ if (ioctl(fd, VIDIOC_QUERYBUF, &bfr) < 0)
+ goto xit;
+ offset = bfr.m.offset;
+ pPriv->bfrs[i].offset = offset;
+ pPriv->bfrs[i].length = bfr.length;
+ bsz = offset + bfr.length;
+ if (pPriv->bufsz < bsz)
+ pPriv->bufsz = bsz;
+ }
+
+#ifdef LINUX_2_6
+ for (i = 0; i < pPriv->nbfrs; ++i) {
+ pPriv->bfrs[i].start = mmap(NULL, bfr.length, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, pPriv->bfrs[i].offset);
+ if (pPriv->bfrs[i].start == MAP_FAILED)
+ goto xit;
+ }
+#else
+ pPriv->bfrs[0].offset = 0;
+ pPriv->bfrs[0].start =
+ mmap(NULL, pPriv->bufsz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (pPriv->bfrs[0].start == MAP_FAILED) {
+ pPriv->bfrs[0].start = NULL;
+ goto xit;
+ }
+
+ offset = (unsigned long)pPriv->bfrs[0].start;
+ for (i = 1; i < pPriv->nbfrs; ++i)
+ pPriv->bfrs[i].start = (void *)(offset + pPriv->bfrs[i].offset);
+#endif
+
+ for (i = 0; i < pPriv->nbfrs; ++i) {
+ DBLOG(3, "bfr %d ofs %#lx adr %p sz %lu\n", i, pPriv->bfrs[i].offset,
+ pPriv->bfrs[i].start, (unsigned long)pPriv->bfrs[i].length);
+ memset(pPriv->bfrs[i].start, 0x80, pPriv->bfrs[i].length);
+ }
+
+ pPriv->last = 0;
+ while (pPriv->last < pPriv->nbfrs - 1) {
+ bfr.index = pPriv->last++;
+ bfr.type = type;
+ if (ioctl(fd, VIDIOC_QBUF, &bfr) < 0)
+ goto xit;
+ }
+ return;
+
+ xit:
+ z4l_ovly_unmap(pPriv);
+}
+
+static int
+z4l_ovly_dqbuf(Z4lPortPrivRec * pPriv)
+{
+ int stat;
+ struct v4l2_buffer bfr;
+ int fd = pPriv->fd;
+
+#ifdef HAVE_SELECT
+ struct timeval tmo;
+ fd_set dqset;
+
+ FD_ZERO(&dqset);
+ FD_SET(pPriv->fd, &dqset);
+ tmo.tv_sec = 0;
+ tmo.tv_usec = 0;
+ if (select(fd + 1, &dqset, NULL, NULL, &tmo) <= 0)
+ return -1;
+#endif
+ memset(&bfr, 0, sizeof(bfr));
+ bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ stat = ioctl(fd, VIDIOC_DQBUF, &bfr);
+ DBLOG(3, "dqbuf %d,%d,%d,%d\n", stat, bfr.index, pPriv->last, errno);
+
+ return stat == 0 ? bfr.index : -1;
+}
+
+static int
+z4l_open_device(Z4lPortPrivRec * pPriv)
+{
+ int enable;
+
+ if (pPriv->fd < 0) {
+ pPriv->fd = open(&pPriv->dev_path[0], O_RDWR, 0);
+ DBLOG(1, "open(%s)=%d\n", &pPriv->dev_path[0], pPriv->fd);
+ enable = 1;
+#ifdef NONBLK_IO
+ if (IoCtl(pPriv->fd, FIONBIO, &enable, 1) != 0) {
+ DBLOG(1, "open cant enable nonblocking\n");
+ close(pPriv->fd);
+ pPriv->fd = -1;
+ }
+#endif
+ }
+ return pPriv->fd;
+}
+
+static int
+z4l_close_device(Z4lPortPrivRec * pPriv)
+{
+ int ret = 0;
+
+ if (pPriv->fd >= 0) {
+ ret = close(pPriv->fd);
+ pPriv->fd = -1;
+ DBLOG(1, "close()=%d\n", ret);
+ }
+ if (pPriv->run > 0) {
+ z4l_ovly_unmap(pPriv);
+ pPriv->run = -1;
+ }
+
+ return ret;
+}
+
+static int
+z4l_ovly_reset(Z4lPortPrivRec * pPriv)
+{
+ int ret = 0;
+
+ if (pPriv->run > 0) {
+ z4l_close_device(pPriv);
+ ret = z4l_open_device(pPriv);
+ }
+
+ return ret;
+}
+
+static unsigned int
+z4l_fourcc_pixfmt(int fourcc)
+{
+ unsigned int pixfmt = -1;
+
+ switch (fourcc) {
+ case FOURCC_UYVY:
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ break;
+ case FOURCC_YV12:
+ pixfmt = V4L2_PIX_FMT_YVU420;
+ break;
+ case FOURCC_Y800:
+ case FOURCC_I420:
+ pixfmt = V4L2_PIX_FMT_YUV420;
+ break;
+ case FOURCC_YUY2:
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ break;
+ }
+
+ return pixfmt;
+}
+static void
+z4l_ovly_pixfmt(Z4lPortPrivRec * pPriv, unsigned int pixfmt)
+{
+ struct v4l2_framebuffer fbuf;
+
+ DBLOG(1, "pixfmt %4.4s %4.4s\n", (char *)&pPriv->pixfmt, (char *)&pixfmt);
+ memset(&fbuf, 0, sizeof(fbuf));
+ IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1);
+ fbuf.fmt.pixelformat = pixfmt;
+ fbuf.base = NULL;
+ IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1);
+ pPriv->pixfmt = pixfmt;
+}
+
+static void
+z4l_ovly_bfr(Z4lPortPrivRec * pPriv, int width, int height)
+{
+ struct v4l2_format fmt;
+
+ DBLOG(1, "sfmt ovly %dx%d\n", width, height);
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = 0x102;
+ IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
+ fmt.fmt.win.field = V4L2_FIELD_NONE;
+ fmt.fmt.win.w.width = pPriv->width = width;
+ fmt.fmt.win.w.height = pPriv->height = height;
+ IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
+}
+
+static void
+z4l_ovly_rect(Z4lPortPrivRec * pPriv,
+ int src_x, int src_y, int src_w, int src_h,
+ int drw_x, int drw_y, int drw_w, int drw_h)
+{
+ int x, dx, w, y, dy, h;
+ struct v4l2_format fmt;
+
+ pPriv->src_x = src_x;
+ pPriv->src_y = src_y;
+ pPriv->src_w = src_w;
+ pPriv->src_h = src_h;
+ pPriv->drw_x = drw_x;
+ pPriv->drw_y = drw_y;
+ pPriv->drw_w = drw_w;
+ pPriv->drw_h = drw_h;
+
+ if ((drw_x -= z4l_x_offset) < 0) {
+ if ((w = pPriv->drw_w) <= 0)
+ w = 1;
+ x = -drw_x;
+ dx = x * pPriv->src_w / w;
+ src_x = pPriv->src_x + dx;
+ src_w = pPriv->src_w - dx;
+ drw_w = pPriv->drw_w - x;
+ drw_x = 0;
+ }
+
+ if ((drw_y -= z4l_y_offset) < 0) {
+ if ((h = pPriv->drw_h) <= 0)
+ h = 1;
+ y = -drw_y;
+ dy = y * pPriv->src_h / h;
+ src_y = pPriv->src_y + dy;
+ src_h = pPriv->src_h - dy;
+ drw_h = pPriv->drw_h - y;
+ drw_y = 0;
+ }
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = 0x100;
+ IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
+ if (pPriv->src_is_set != 0) {
+ if (src_x != fmt.fmt.win.w.left || src_y != fmt.fmt.win.w.top ||
+ src_w != fmt.fmt.win.w.width || src_h != fmt.fmt.win.w.height)
+ pPriv->src_is_set = 0;
+ }
+ if (pPriv->src_is_set == 0) {
+ pPriv->src_is_set = 1;
+ fmt.fmt.win.w.left = src_x;
+ fmt.fmt.win.w.top = src_y;
+ fmt.fmt.win.w.width = src_w;
+ fmt.fmt.win.w.height = src_h;
+ IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
+ DBLOG(3, " set src %d,%d %dx%d\n", src_x, src_y, src_w, src_h);
+ }
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = 0x101;
+ IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
+ if (pPriv->drw_is_set != 0) {
+ if (drw_x != fmt.fmt.win.w.left || drw_y != fmt.fmt.win.w.top ||
+ drw_w != fmt.fmt.win.w.width || drw_h != fmt.fmt.win.w.height)
+ pPriv->drw_is_set = 0;
+ }
+ if (pPriv->drw_is_set == 0) {
+ pPriv->drw_is_set = 1;
+ fmt.fmt.win.w.left = drw_x;
+ fmt.fmt.win.w.top = drw_y;
+ fmt.fmt.win.w.width = drw_w;
+ fmt.fmt.win.w.height = drw_h;
+ IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
+ DBLOG(3, " set drw %d,%d %dx%d\n", drw_x, drw_y, drw_w, drw_h);
+ }
+}
+
+static void
+z4l_ovly_pitch(unsigned int pixfmt, int w, int h, int *py_pitch,
+ int *puv_pitch, int *poffset1, int *poffset2, int *psize)
+{
+ int y_pitch, uv_pitch;
+ int offset1, offset2;
+ int size, is_420;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV420:
+ is_420 = 1;
+ y_pitch = ((w + 1) / 2) * 2;
+ uv_pitch = (w + 1) / 2;
+ break;
+ default:
+ is_420 = 0;
+ y_pitch = ((w + 1) / 2) * 4;
+ uv_pitch = 0;
+ break;
+ }
+
+ offset1 = y_pitch * h;
+ offset2 = uv_pitch * h;
+
+ if (is_420 != 0)
+ offset2 /= 2;
+
+ size = offset1 + 2 * offset2;
+ *py_pitch = y_pitch;
+ *puv_pitch = uv_pitch;
+ *poffset1 = offset1;
+ *poffset2 = offset2;
+ *psize = size;
+}
+
+static int
+z4l_ovly_set_colorkey(Z4lPortPrivRec * pPriv, int key)
+{
+ struct v4l2_format fmt;
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
+ return 0;
+ fmt.fmt.win.chromakey = key;
+ if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0)
+ return 0;
+ pPriv->colorkey = key;
+
+ return 1;
+}
+
+static int
+z4l_ovly_get_colorkey(Z4lPortPrivRec * pPriv, int *key)
+{
+ struct v4l2_format fmt;
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
+ return 0;
+ *key = fmt.fmt.win.chromakey;
+
+ return 1;
+}
+
+static int
+z4l_ovly_set_keymode(Z4lPortPrivRec * pPriv, int enable)
+{
+ struct v4l2_framebuffer fbuf;
+
+ memset(&fbuf, 0, sizeof(fbuf));
+ if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
+ return 0;
+
+ if (enable != 0)
+ fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ else
+ fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
+
+ fbuf.base = NULL;
+ if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0)
+ return 0;
+ pPriv->keymode = enable;
+
+ return 1;
+}
+
+static int
+z4l_ovly_get_keymode(Z4lPortPrivRec * pPriv, int *enable)
+{
+ struct v4l2_framebuffer fbuf;
+
+ memset(&fbuf, 0, sizeof(fbuf));
+ if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
+ return 0;
+ *enable = (fbuf.flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0 ? 1 : 0;
+
+ return 1;
+}
+
+static int
+z4l_ovly_set_encoding(Z4lPortPrivRec * pPriv, int id)
+{
+ int l, n, inp;
+ char *cp;
+ t_std_data *sp;
+ XF86VideoEncodingPtr enc;
+ XF86VideoAdaptorPtr adpt;
+ v4l2_std_id std;
+ struct v4l2_format fmt;
+ struct v4l2_framebuffer fbuf;
+
+ adpt = pPriv->adpt;
+ DBLOG(1, "z4l_ovly_set_encoding(%d)\n", id);
+ if (id < 0 || id >= adpt->nEncodings)
+ return 0;
+ enc = &adpt->pEncodings[id];
+ cp = &enc->name[0];
+ n = sizeof(int) - 1;
+ l = strlen(cp) + 1;
+ l = (l + n) & ~n;
+ sp = (t_std_data *) (cp + l);
+ inp = sp->inp;
+
+ DBLOG(1, " nm %s fmt %4.4s inp %d std %llx\n",
+ cp, (char *)&sp->fmt, sp->inp, sp->std);
+
+ if (IoCtl(pPriv->fd, VIDIOC_S_INPUT, &inp, 1) < 0)
+ return 0;
+
+ std = sp->std;
+ if (IoCtl(pPriv->fd, VIDIOC_S_STD, &std, 1) < 0)
+ return 0;
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
+ return 0;
+
+ fmt.fmt.pix.pixelformat = sp->fmt;
+ if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0)
+ return 0;
+ memset(&fbuf, 0, sizeof(fbuf));
+
+ if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
+ return 0;
+
+ fbuf.fmt.pixelformat = sp->fmt;
+ fbuf.base = NULL;
+ if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0)
+ return 0;
+ pPriv->pixfmt = sp->fmt;
+ pPriv->enc = enc;
+ pPriv->src_is_set = pPriv->drw_is_set = 0;
+
+ return 1;
+}
+
+static int
+z4l_ovly_get_encoding(Z4lPortPrivRec * pPriv, int *id)
+{
+ XF86VideoEncodingPtr enc = pPriv->enc;
+
+ *id = enc->id;
+ return 1;
+}
+
+static void
+z4l_ovly_stop(Z4lPortPrivRec * pPriv)
+{
+ int type, enable, fd;
+
+ if (pPriv->run < 0)
+ return;
+
+ fd = pPriv->fd;
+ if (pPriv->dir > 0) {
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ioctl(fd, VIDIOC_STREAMOFF, &type);
+ }
+
+ if (pPriv->dir <= 0) {
+ enable = 0;
+ ioctl(fd, VIDIOC_OVERLAY, &enable);
+ }
+
+ if (pPriv->dir != 0)
+ z4l_ovly_unmap(pPriv);
+
+ pPriv->run = -1;
+ z4l_close_device(pPriv);
+}
+
+static void
+z4l_ovly_start(Z4lPortPrivRec * pPriv, int dir)
+{
+ int enable;
+
+ if (pPriv->run >= 0)
+ return;
+
+ if ((pPriv->dir = dir) != 0)
+ z4l_ovly_map(pPriv, dir);
+
+ enable = 1;
+
+ if (IoCtl(pPriv->fd, VIDIOC_OVERLAY, &enable, 1) != 0) {
+ z4l_ovly_stop(pPriv);
+ return;
+ }
+
+ pPriv->run = 1;
+}
+
+static int
+z4l_region_equal(RegionPtr ap, RegionPtr bp)
+{
+ int nboxes;
+ BoxPtr abox, bbox;
+
+ if (ap == NULL && bp == NULL)
+ return 1;
+ if (ap == NULL || bp == NULL)
+ return 0;
+
+ if ((nboxes = REGION_NUM_RECTS(ap)) != REGION_NUM_RECTS(bp) ||
+ ap->extents.x1 != bp->extents.x1 ||
+ ap->extents.x2 != bp->extents.x2
+ || ap->extents.y1 != bp->extents.y1
+ || ap->extents.y2 != bp->extents.y2)
+ return 0;
+
+ abox = REGION_RECTS(ap);
+ bbox = REGION_RECTS(bp);
+
+ while (--nboxes >= 0) {
+ if (abox->x1 != bbox->x1 || abox->y1 != bbox->y1 ||
+ abox->x2 != bbox->x2 || abox->y2 != bbox->y2)
+ return 0;
+ ++abox;
+ ++bbox;
+ }
+
+ return 1;
+}
+
+static void
+z4l_setup_colorkey(Z4lPortPrivRec * pPriv, ScreenPtr pScrn,
+ RegionPtr clipBoxes)
+{
+ if (pPriv->run > 0 && pPriv->dir <= 0 && pPriv->keymode != 0 &&
+ z4l_region_equal(&pPriv->clips, clipBoxes) == 0) {
+ xf86XVFillKeyHelper(pScrn, pPriv->colorkey, clipBoxes);
+ REGION_COPY(pScrn, &pPriv->clips, clipBoxes);
+ }
+}
+
+static void
+Z4lStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
+{
+ Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
+
+ DBLOG(1, "Z4lStopVideo()\n");
+
+ if (exit != 0)
+ z4l_ovly_stop(pPriv);
+ else
+ pPriv->src_is_set = pPriv->drw_is_set = 0;
+
+ REGION_EMPTY(pScrni->pScreen, &pPriv->clips);
+}
+
+static void
+Z4lQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
+ short vid_w, short vid_h, short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h, pointer data)
+{
+ if (drw_w > MAX_OVLY_WIDTH)
+ drw_w = MAX_OVLY_WIDTH;
+ if (drw_h > MAX_OVLY_HEIGHT)
+ drw_h = MAX_OVLY_HEIGHT;
+
+ *p_w = drw_w;
+ *p_h = drw_h;
+ DBLOG(1, "Z4lQueryBestSize(%d, src %dx%d dst %dx%d)\n", motion, vid_w,
+ vid_h, drw_w, drw_h);
+}
+
+static int
+Z4lPutImage(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x,
+ short drw_y, short src_w, short src_h, short drw_w, short drw_h,
+ int id, unsigned char *buf, short width, short height,
+ Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
+{
+ int fd, size;
+ int y_pitch, uv_pitch, offset1, offset2;
+ unsigned char *src, *dst;
+ unsigned int pixfmt;
+ struct v4l2_buffer bfr;
+ Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
+
+ if (pPriv->run > 0 && pPriv->dir >= 0)
+ return BadMatch;
+ if (pPriv->fd < 0) {
+ z4l_open_device(pPriv);
+ if (pPriv->fd < 0)
+ return BadValue;
+ }
+
+ fd = pPriv->fd;
+ if (pPriv->run < 0) {
+ DBLOG(2, "PutImg id %#x src %d,%d %dx%d drw %d,%d %dx%d bfr %p "
+ "%dx%d data %p\n", id, src_x, src_y, src_w, src_h, drw_x,
+ drw_y, drw_w, drw_h, buf, width, height, data);
+ pPriv->pixfmt = pPriv->height = -1;
+ pPriv->src_is_set = pPriv->drw_is_set = 0;
+ }
+
+ pixfmt = z4l_fourcc_pixfmt(id);
+ if (pixfmt != pPriv->pixfmt) {
+ z4l_ovly_reset(pPriv);
+ z4l_ovly_pixfmt(pPriv, pixfmt);
+ }
+ if (pPriv->width != width || pPriv->height != height) {
+ z4l_ovly_reset(pPriv);
+ z4l_ovly_bfr(pPriv, width, height);
+ }
+
+ if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 ||
+ pPriv->src_x != src_x || pPriv->src_y != src_y ||
+ pPriv->src_w != src_w || pPriv->src_h != src_h ||
+ pPriv->drw_x != drw_x || pPriv->drw_y != drw_y ||
+ pPriv->drw_w != drw_w || pPriv->drw_h != drw_h)
+ z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w,
+ drw_h);
+
+ if (pPriv->run < 0) {
+ z4l_ovly_start(pPriv, -1);
+ if (pPriv->run < 0)
+ return BadValue;
+ }
+
+ if (pPriv->last < 0 && (pPriv->last = z4l_ovly_dqbuf(pPriv)) < 0)
+ return BadAlloc;
+
+ z4l_ovly_pitch(pixfmt, width, height, &y_pitch, &uv_pitch,
+ &offset1, &offset2, &size);
+ src = buf;
+ dst = (unsigned char *)pPriv->bfrs[pPriv->last].start;
+ DBLOG(3, "cpy %4.4s src %p dst %p yp %d uvp %d o1 %d o2 %d sz %d\n",
+ (char *)&id, src, dst, y_pitch, uv_pitch, offset1, offset2, size);
+
+ if (id == FOURCC_Y800) {
+ memcpy(dst, src, offset1);
+ src += offset1;
+ dst += offset1;
+ memset(dst, 0x80, 2 * offset2);
+ } else
+ memcpy(dst, src, size);
+
+ memset(&bfr, 0, sizeof(bfr));
+ bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ bfr.index = pPriv->last;
+ bfr.timestamp.tv_sec = 0;
+ bfr.timestamp.tv_usec = 0;
+ bfr.flags |= V4L2_BUF_FLAG_TIMECODE;
+ if (IoCtl(fd, VIDIOC_QBUF, &bfr, 1) != 0)
+ return BadAccess;
+
+ pPriv->last = z4l_ovly_dqbuf(pPriv);
+ z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes);
+
+ return Success;
+}
+
+static int
+Z4lQueryImageAttributes(ScrnInfoPtr pScrni, int id, unsigned short *width,
+ unsigned short *height, int *pitches, int *offsets)
+{
+ int w, h, size;
+ int y_pitch, uv_pitch, offset1, offset2;
+ unsigned int pixfmt = z4l_fourcc_pixfmt(id);
+
+ w = *width;
+ h = *height;
+ if (w > MAX_OVLY_WIDTH)
+ w = MAX_OVLY_WIDTH;
+ if (h > MAX_OVLY_HEIGHT)
+ h = MAX_OVLY_HEIGHT;
+
+ z4l_ovly_pitch(pixfmt, w, h, &y_pitch, &uv_pitch,
+ &offset1, &offset2, &size);
+
+ if (offsets != NULL)
+ offsets[0] = 0;
+ if (pitches != NULL)
+ pitches[0] = y_pitch;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV420:
+ if (offsets != NULL) {
+ offsets[1] = offset1;
+ offsets[2] = offset1 + offset2;
+ }
+ if (pitches != NULL)
+ pitches[1] = pitches[2] = uv_pitch;
+ h = (h + 1) & ~1;
+ break;
+ }
+
+ w = (w + 1) & ~1;
+ *width = w;
+ *height = h;
+ DBLOG(1, "Z4lQueryImageAttributes(%4.4s) = %d, %dx%d %d/%d %d/%d\n",
+ (char *)&id, size, w, h, y_pitch, uv_pitch, offset1, offset2);
+
+ return size;
+}
+
+static int
+Z4lPutVideo(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x,
+ short drw_y, short src_w, short src_h, short drw_w, short drw_h,
+ RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
+{
+ int id;
+ Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
+
+ DBLOG(2, "PutVid src %d,%d %dx%d drw %d,%d %dx%d data %p\n",
+ src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, drw_h, data);
+
+ if (z4l_open_device(pPriv) >= 0) {
+ if (pPriv->run < 0) {
+ DBLOG(2, "PutVid start\n");
+ z4l_ovly_get_encoding(pPriv, &id);
+ z4l_ovly_set_encoding(pPriv, id);
+ }
+ DBLOG(2, "PutVid priv %d,%d %dx%d drw %d,%d %dx%d\n",
+ pPriv->src_x, pPriv->src_y, pPriv->src_w, pPriv->src_h,
+ pPriv->drw_x, pPriv->drw_y, pPriv->drw_w, pPriv->drw_h);
+ if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 ||
+ pPriv->src_w != src_w || pPriv->src_h != src_h ||
+ pPriv->drw_x != drw_x || pPriv->drw_y != drw_y ||
+ pPriv->drw_w != drw_w || pPriv->drw_h != drw_h)
+ z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y,
+ drw_w, drw_h);
+ if (pPriv->run < 0)
+ z4l_ovly_start(pPriv, 0);
+
+ z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes);
+ }
+
+ return Success;
+}
+
+static XF86VideoEncodingPtr
+Z4lNewEncoding(XF86VideoEncodingPtr * encs, int *nencs)
+{
+ XF86VideoEncodingPtr enc;
+ XF86VideoEncodingPtr tencs =
+ (XF86VideoEncodingPtr) realloc(*encs, sizeof(*tencs) * (*nencs + 1));
+
+ if (tencs == NULL)
+ return NULL;
+
+ *encs = tencs;
+ enc = &tencs[*nencs];
+ ++*nencs;
+ memset(enc, 0, sizeof(*enc));
+
+ return enc;
+}
+
+static void
+Z4lEncodingName(char *ename, int l, char *inp_name, char *std_name, char *fmt)
+{
+ int i, ch;
+
+ while ((ch = *inp_name++) != 0) {
+ if (isalnum(ch) == 0)
+ continue;
+ if (--l <= 0)
+ goto xit;
+ *ename++ = ch;
+ }
+
+ if (--l <= 0)
+ goto xit;
+
+ *ename++ = '-';
+
+ while ((ch = *std_name++) != 0) {
+ if (isalnum(ch) == 0)
+ continue;
+ if (--l <= 0)
+ goto xit;
+ *ename++ = ch;
+ }
+
+ if (--l <= 0)
+ goto xit;
+
+ *ename++ = '-';
+ i = 4;
+
+ while (--i >= 0 && (ch = *fmt++) != 0) {
+ if (isalnum(ch) == 0)
+ continue;
+ if (--l <= 0)
+ goto xit;
+ *ename++ = ch;
+ }
+
+ xit:
+ *ename = 0;
+}
+
+static int
+Z4lAddEncoding(XF86VideoEncodingPtr enc, char *name, int id, int width,
+ int height, int numer, int denom, int inp, v4l2_std_id std,
+ unsigned int fmt)
+{
+ int l, n;
+ t_std_data *sp;
+ char *cp;
+ n = sizeof(int) - 1;
+ l = strlen(&name[0]) + 1;
+ l = (l + n) & ~n;
+ n = l + sizeof(*sp);
+ cp = (char *)malloc(n);
+
+ if (cp == NULL)
+ return 0;
+
+ sp = (t_std_data *) (cp + l);
+ enc->id = id;
+ strcpy(cp, &name[0]);
+ enc->name = cp;
+ enc->width = width;
+ enc->height = height;
+ enc->rate.numerator = numer;
+ enc->rate.denominator = denom;
+ sp->inp = inp;
+ sp->std = std;
+ sp->fmt = fmt;
+ DBLOG(1, "enc %s\n", &name[0]);
+
+ return 1;
+}
+
+static XF86ImagePtr
+Z4lNewImage(XF86ImagePtr * imgs, int *nimgs)
+{
+ XF86ImagePtr img;
+ XF86ImagePtr timgs =
+ (XF86ImagePtr) realloc(*imgs, sizeof(*timgs) * (*nimgs + 1));
+
+ if (timgs == NULL)
+ return NULL;
+
+ *imgs = timgs;
+ img = &timgs[*nimgs];
+ ++*nimgs;
+ memset(img, 0, sizeof(*img));
+
+ return img;
+}
+
+static int
+Z4lAddImage(XF86ImagePtr img, XF86ImagePtr ip)
+{
+ *img = *ip;
+ DBLOG(1, "img %4.4s\n", (char *)&img->id);
+ return 1;
+}
+
+static XF86AttributePtr
+Z4lNewAttribute(XF86AttributePtr * attrs, int *nattrs)
+{
+ XF86AttributePtr attr;
+ XF86AttributePtr tattrs =
+ (XF86AttributePtr) realloc(*attrs, sizeof(*tattrs) * (*nattrs + 1));
+
+ if (tattrs == NULL)
+ return NULL;
+
+ *attrs = tattrs;
+ attr = &tattrs[*nattrs];
+ ++*nattrs;
+ memset(attr, 0, sizeof(*attr));
+
+ return attr;
+}
+
+static void
+Z4lAttributeName(char *bp, int l, char *cp)
+{
+ int ch;
+ char *atomNm = bp;
+
+ if (l > 0) {
+ *bp++ = 'X';
+ --l;
+ }
+ if (l > 0) {
+ *bp++ = 'V';
+ --l;
+ }
+ if (l > 0) {
+ *bp++ = '_';
+ --l;
+ }
+
+ while (l > 0 && (ch = *cp++) != 0) {
+ if (isalnum(ch) == 0)
+ continue;
+ *bp++ = toupper(ch);
+ }
+
+ *bp = 0;
+ MakeAtom(&atomNm[0], strlen(&atomNm[0]), TRUE);
+}
+
+static int
+Z4lAddAttribute(XF86AttributePtr attr, char *name,
+ int min, int max, int flags)
+{
+ char *cp = (char *)malloc(strlen((char *)&name[0]) + 1);
+
+ if (cp == NULL)
+ return 0;
+
+ attr->name = cp;
+ strcpy(&attr->name[0], name);
+ attr->min_value = min;
+ attr->max_value = max;
+ attr->flags = flags;
+ DBLOG(1, "attr %s\n", attr->name);
+
+ return 1;
+}
+
+static XF86VideoAdaptorPtr
+Z4lNewAdaptor(XF86VideoAdaptorPtr ** adpts, int *nadpts, int nattrs)
+{
+ int n;
+ Z4lPortPrivRec *pPriv;
+ XF86VideoAdaptorPtr adpt, *tadpts;
+
+ tadpts = (XF86VideoAdaptorPtr *) realloc(*adpts,
+ sizeof(*tadpts) * (*nadpts + 1));
+
+ if (tadpts == NULL)
+ return NULL;
+
+ *adpts = tadpts;
+ n = sizeof(*adpt) + sizeof(*pPriv) + 1 * sizeof(*adpt->pPortPrivates);
+ n += (nattrs - 1) * sizeof(pPriv->attrIds[0]);
+ adpt = (XF86VideoAdaptorPtr) malloc(n);
+
+ if (adpt == NULL)
+ return NULL;
+
+ memset(adpt, 0, n);
+ tadpts[*nadpts] = adpt;
+ ++*nadpts;
+ adpt->pPortPrivates = (DevUnion *) & adpt[1];
+ pPriv = (Z4lPortPrivRec *) & adpt->pPortPrivates[1];
+ adpt->pPortPrivates[0].ptr = (pointer) pPriv;
+ pPriv->adpt = adpt;
+ adpt->nPorts = 1;
+
+ return adpt;
+}
+
+static int
+Z4lSetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value,
+ pointer data)
+{
+ Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
+ XF86VideoAdaptorPtr adpt;
+ XF86AttributePtr attr;
+ struct v4l2_control ctrl;
+ int i, nattrs, attrId, val;
+ const char *name = NameForAtom(attribute);
+ int old_fd = pPriv->fd;
+
+ DBLOG(1, "Z4lSetPortAttribute(%#lx,%d) '%s'\n", (unsigned long)attribute,
+ (int)value, name != NULL ? name : "_null_");
+
+ if (name == NULL)
+ return BadImplementation;
+ if (old_fd < 0 && z4l_open_device(pPriv) < 0)
+ return BadAccess;
+
+ adpt = pPriv->adpt;
+ attr = adpt->pAttributes;
+ nattrs = adpt->nAttributes;
+
+ for (i = 0; i < nattrs; ++i, ++attr)
+ if (strcmp(attr->name, name) == 0)
+ break;
+
+ if (i >= nattrs)
+ return BadMatch;
+
+ attrId = pPriv->attrIds[i];
+ val = value;
+
+ switch (attrId) {
+ case ATTR_ENCODING_ID:
+ z4l_ovly_set_encoding(pPriv, val);
+ break;
+ case ATTR_KEYMODE_ID:
+ z4l_ovly_set_keymode(pPriv, val);
+ REGION_EMPTY(pScrni->pScreen, &pPriv->clips);
+ z4l_setup_colorkey(pPriv, pScrni->pScreen, &pPriv->clips);
+ break;
+ case ATTR_COLORKEY_ID:
+ z4l_ovly_set_colorkey(pPriv, val);
+ break;
+ default:
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = attrId + V4L2_CID_BASE;
+ ctrl.value = val;
+ if (IoCtl(pPriv->fd, VIDIOC_S_CTRL, &ctrl, 1) != 0)
+ return BadMatch;
+ break;
+ }
+
+ if (old_fd < 0)
+ z4l_close_device(pPriv);
+
+ return Success;
+}
+
+static int
+Z4lGetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value,
+ pointer data)
+{
+ Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
+ XF86VideoAdaptorPtr adpt;
+ XF86AttributePtr attr;
+ struct v4l2_control ctrl;
+ int i, nattrs, attrId, val;
+ const char *name = NameForAtom(attribute);
+ int old_fd = pPriv->fd;
+
+ DBLOG(1, "Z4lGetPortAttribute(%#lx) '%s'\n",
+ (unsigned long)attribute, name != NULL ? name : "_null_");
+
+ if (name == NULL)
+ return BadImplementation;
+ if (old_fd < 0 && z4l_open_device(pPriv) < 0)
+ return BadAccess;
+
+ adpt = pPriv->adpt;
+ attr = adpt->pAttributes;
+ nattrs = adpt->nAttributes;
+
+ for (i = 0; i < nattrs; ++i, ++attr)
+ if (strcmp(attr->name, name) == 0)
+ break;
+
+ if (i >= nattrs)
+ return BadMatch;
+
+ attrId = pPriv->attrIds[i];
+ val = 0;
+
+ switch (attrId) {
+ case ATTR_ENCODING_ID:
+ z4l_ovly_get_encoding(pPriv, &val);
+ *value = val;
+ break;
+ case ATTR_KEYMODE_ID:
+ z4l_ovly_get_keymode(pPriv, &val);
+ *value = val;
+ break;
+ case ATTR_COLORKEY_ID:
+ z4l_ovly_get_colorkey(pPriv, &val);
+ break;
+ default:
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = attrId + V4L2_CID_BASE;
+ if (IoCtl(pPriv->fd, VIDIOC_G_CTRL, &ctrl, 1) != 0)
+ return BadMatch;
+ val = ctrl.value;
+ break;
+ }
+
+ if (old_fd < 0)
+ z4l_close_device(pPriv);
+
+ *value = val;
+
+ return Success;
+}
+
+static void (*oldAdjustFrame) (int scrnIndex, int x, int y, int flags) = NULL;
+
+static void
+Z4lAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ int i;
+ XF86VideoAdaptorPtr adpt;
+ Z4lPortPrivRec *pPriv;
+
+ DBLOG(3, "Z4lAdjustFrame(%d,%d,%d)\n", x, y, flags);
+ z4l_x_offset = x;
+ z4l_y_offset = y;
+ oldAdjustFrame(scrnIndex, x, y, flags);
+
+ /* xv adjust does not handle putvideo case */
+ for (i = 0; i < Z4l_nAdaptors; ++i) {
+ adpt = Z4l_pAdaptors[i];
+ pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr;
+ if (pPriv->run > 0) {
+ pPriv->drw_is_set = 0;
+ z4l_ovly_rect(pPriv,
+ pPriv->src_x, pPriv->src_y, pPriv->src_w, pPriv->src_h,
+ pPriv->drw_x, pPriv->drw_y, pPriv->drw_w, pPriv->drw_h);
+ }
+ }
+}
+
+static int
+Z4lInit(ScrnInfoPtr pScrni, XF86VideoAdaptorPtr ** adaptors)
+{
+ int i, id, fd, dev, enable, has_video, has_colorkey;
+ int ctl, cinp, inp, std, fmt, has_image;
+ int nadpts, nattrs, nencs, cenc, nimgs;
+ int numer, denom, width, height;
+ unsigned int pixfmt, cpixfmt, opixfmt;
+ XF86VideoAdaptorPtr *adpts, adpt;
+ XF86AttributePtr attrs, attr;
+ XF86VideoEncodingPtr encs, enc;
+ XF86ImagePtr ip, img, imgs;
+ Z4lPortPrivRec *pPriv;
+ char *dp, *msg;
+ char enc_name[256], attr_name[256];
+ int attrIds[V4L2_CID_LASTP1 - V4L2_CID_BASE + ATTR_MAX_ID];
+ struct v4l2_capability capability;
+ v4l2_std_id cstd_id, std_id;
+ struct v4l2_standard standard;
+ struct v4l2_format format, cfmt;
+ struct v4l2_input input;
+ struct v4l2_fmtdesc fmtdesc;
+ struct v4l2_queryctrl queryctrl;
+ struct v4l2_framebuffer fbuf;
+
+ DBLOG(1, "Init\n");
+ if (oldAdjustFrame == NULL) {
+ oldAdjustFrame = pScrni->AdjustFrame;
+ pScrni->AdjustFrame = Z4lAdjustFrame;
+ }
+
+ fd = -1;
+ enc = NULL;
+ encs = NULL;
+ nencs = 0;
+ img = NULL;
+ imgs = NULL;
+ nimgs = 0;
+ attr = NULL;
+ attrs = NULL;
+ nattrs = 0;
+ adpt = NULL;
+ adpts = NULL;
+ nadpts = 0;
+ has_video = has_image = has_colorkey = 0;
+
+ for (dev = 0; z4l_dev_paths[dev] != NULL; ++dev) {
+ fd = open(z4l_dev_paths[dev], O_RDWR, 0);
+ if (fd < 0)
+ continue;
+ DBLOG(1, "%s open ok\n", z4l_dev_paths[dev]);
+ msg = NULL;
+ enable = 1;
+ if (IoCtl(fd, VIDIOC_QUERYCAP, &capability, 1) < 0)
+ msg = "bad querycap";
+ else if ((capability.capabilities & V4L2_CAP_VIDEO_OVERLAY) == 0)
+ msg = "no overlay";
+ else if ((capability.capabilities & V4L2_CAP_STREAMING) == 0)
+ msg = "no streaming";
+#ifdef NONBLK_IO
+ else if (IoCtl(fd, FIONBIO, &enable, 1) != 0)
+ msg = "cant enable non-blocking io";
+#endif
+ if (msg == NULL) {
+ memset(&format, 0, sizeof(format));
+ format.type = 0x100;
+ if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) != 0)
+ msg = "no src/dst ovly fmt";
+ }
+ if (msg != NULL) {
+ DBLOG(0, "%s %s\n", z4l_dev_paths[dev], msg);
+ close(fd);
+ continue;
+ }
+
+ memset(&cfmt, 0, sizeof(cfmt));
+ cfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (IoCtl(fd, VIDIOC_G_FMT, &cfmt, 1) < 0)
+ goto fail;
+ if (IoCtl(fd, VIDIOC_G_STD, &cstd_id, 1) < 0)
+ goto fail;
+ if (IoCtl(fd, VIDIOC_G_INPUT, &cinp, 1) < 0)
+ goto fail;
+ cpixfmt = cfmt.fmt.pix.pixelformat;
+ cenc = 0;
+ for (inp = 0;; ++inp) {
+ memset(&input, 0, sizeof(input));
+ input.index = inp;
+ if (IoCtl(fd, VIDIOC_ENUMINPUT, &input, 0) < 0)
+ break;
+ id = inp;
+ if (IoCtl(fd, VIDIOC_S_INPUT, &id, 1) < 0)
+ goto fail;
+ for (std = 0;; ++std) {
+ memset(&standard, 0, sizeof(standard));
+ standard.index = std;
+ if (IoCtl(fd, VIDIOC_ENUMSTD, &standard, 0) < 0)
+ break;
+ std_id = standard.id;
+ denom = standard.frameperiod.denominator;
+ numer = standard.frameperiod.numerator;
+ if (IoCtl(fd, VIDIOC_S_STD, &std_id, 1) < 0)
+ continue;
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) < 0)
+ continue;
+ width = format.fmt.pix.width;
+ height = format.fmt.pix.height;
+ for (fmt = 0;; ++fmt) {
+ memset(&fmtdesc, 0, sizeof(fmtdesc));
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmtdesc.index = fmt;
+ if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0)
+ break;
+ pixfmt = fmtdesc.pixelformat;
+ ip = &pixfmts[0];
+ for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0;
+ ++ip)
+ if (z4l_fourcc_pixfmt(ip->id) == pixfmt)
+ break;
+
+ if (i >= 0) {
+ id = nencs;
+ has_video = 1;
+ if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL)
+ goto fail;
+ Z4lEncodingName(&enc_name[0], sizeof(enc_name),
+ (char *)&input.name[0],
+ (char *)&standard.name[0], (char *)&pixfmt);
+ if (Z4lAddEncoding(enc, &enc_name[0], id, width,
+ height, denom, numer, inp, std_id,
+ pixfmt) == 0)
+ goto fail;
+ if (std_id == cstd_id && inp == cinp
+ && pixfmt == cpixfmt)
+ cenc = id;
+ }
+ }
+ }
+ }
+
+ if (IoCtl(fd, VIDIOC_S_INPUT, &cinp, 1) < 0)
+ goto fail;
+ if (IoCtl(fd, VIDIOC_S_STD, &cstd_id, 1) < 0)
+ goto fail;
+ if (IoCtl(fd, VIDIOC_S_FMT, &cfmt, 1) < 0)
+ goto fail;
+
+ if (encs == NULL) {
+ DBLOG(0, "no encodings\n");
+ goto fail;
+ }
+
+ for (fmt = 0;; ++fmt) {
+ memset(&fmtdesc, 0, sizeof(fmtdesc));
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ fmtdesc.index = fmt;
+ if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0)
+ break;
+ pixfmt = fmtdesc.pixelformat;
+ ip = &pixfmts[0];
+ for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0; ++ip)
+ if (z4l_fourcc_pixfmt(ip->id) == pixfmt)
+ break;
+
+ if (i >= 0) {
+ has_image = 1;
+ if ((img = Z4lNewImage(&imgs, &nimgs)) == NULL)
+ goto fail;
+ if (Z4lAddImage(img, ip) == 0)
+ goto fail;
+ }
+ }
+
+ if (nimgs > 0) {
+ id = nencs;
+ if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL)
+ goto fail;
+ if (Z4lAddEncoding(enc, "XV_IMAGE", id, MAX_OVLY_WIDTH,
+ MAX_OVLY_HEIGHT, 0, 0, 0, 0, pixfmt) == 0)
+ goto fail;
+ }
+
+ ctl = 0;
+ for (ctl = 0; ctl < (V4L2_CID_LASTP1 - V4L2_CID_BASE); ++ctl) {
+ memset(&queryctrl, 0, sizeof(queryctrl));
+ queryctrl.id = V4L2_CID_BASE + ctl;
+ if (IoCtl(fd, VIDIOC_QUERYCTRL, &queryctrl, 0) < 0)
+ continue;
+ if (queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
+ queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN)
+ continue;
+ attrIds[nattrs] = ctl;
+ if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
+ goto fail;
+ Z4lAttributeName(&attr_name[0], sizeof(attr_name),
+ (char *)&queryctrl.name[0]);
+ if (Z4lAddAttribute(attr, &attr_name[0],
+ queryctrl.minimum, queryctrl.maximum,
+ XvSettable | XvGettable) == 0)
+ goto fail;
+ }
+ attrIds[nattrs] = ATTR_ENCODING_ID;
+ if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
+ goto fail;
+ Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_ENCODING);
+ if (Z4lAddAttribute(attr, &attr_name[0], 0, nencs - 1,
+ XvSettable | XvGettable) == 0)
+ goto fail;
+ memset(&fbuf, 0, sizeof(fbuf));
+ if (IoCtl(fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
+ goto fail;
+ opixfmt = fbuf.fmt.pixelformat;
+
+ if ((fbuf.capability & V4L2_FBUF_CAP_CHROMAKEY) != 0) {
+ attrIds[nattrs] = ATTR_KEYMODE_ID;
+ if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
+ goto fail;
+ Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_KEYMODE);
+ if (Z4lAddAttribute(attr, &attr_name[0], 0, 1,
+ XvSettable | XvGettable) == 0)
+ goto fail;
+ attrIds[nattrs] = ATTR_COLORKEY_ID;
+ if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
+ goto fail;
+ Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_COLORKEY);
+ if (Z4lAddAttribute(attr, &attr_name[0], 0, 0xffffff,
+ XvSettable | XvGettable) == 0)
+ goto fail;
+ has_colorkey = 1;
+ }
+
+ dp = malloc(strlen((char *)&capability.card[0]) + 1);
+ if (dp == NULL)
+ goto fail;
+ strcpy(dp, (char *)&capability.card[0]);
+ if ((adpt = Z4lNewAdaptor(&adpts, &nadpts, nattrs)) == NULL)
+ goto fail;
+ adpt->type = XvWindowMask | XvInputMask;
+ if (has_video != 0)
+ adpt->type |= XvVideoMask;
+ if (has_image != 0)
+ adpt->type |= XvImageMask;
+ adpt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ adpt->name = dp;
+ adpt->type = XvInputMask | XvWindowMask | XvVideoMask | XvImageMask;
+ adpt->pEncodings = encs;
+ adpt->nEncodings = nencs;
+ adpt->pFormats = &Formats[0];
+ adpt->nFormats = sizeof(Formats) / sizeof(Formats[0]);
+ adpt->pAttributes = attrs;
+ adpt->nAttributes = nattrs;
+ attrs = NULL;
+ nattrs = 0;
+ adpt->pImages = imgs;
+ adpt->nImages = nimgs;
+ imgs = NULL;
+ nimgs = 0;
+ adpt->PutVideo = Z4lPutVideo;
+ adpt->StopVideo = Z4lStopVideo;
+ adpt->SetPortAttribute = Z4lSetPortAttribute;
+ adpt->GetPortAttribute = Z4lGetPortAttribute;
+ adpt->QueryBestSize = Z4lQueryBestSize;
+ adpt->PutImage = Z4lPutImage;
+ adpt->QueryImageAttributes = Z4lQueryImageAttributes;
+ pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr;
+ pPriv->fd = fd;
+ pPriv->run = -1;
+ pPriv->dir = 0;
+ pPriv->nbfrs = -1;
+ pPriv->bufsz = -1;
+ pPriv->last = -1;
+ pPriv->pixfmt = opixfmt;
+#if defined(REGION_NULL)
+ REGION_NULL(pScrni->pScreen, &pPriv->clips);
+#else
+ REGION_INIT(pScrni->pScreen, &pPriv->clips, NullBox, 0);
+#endif
+ strncpy(&pPriv->dev_path[0], z4l_dev_paths[dev],
+ sizeof(pPriv->dev_path));
+ pPriv->enc = &encs[cenc];
+ for (i = 0; i < adpt->nAttributes; ++i)
+ pPriv->attrIds[i] = attrIds[i];
+ DBLOG(1, "adpt %s\n", dp);
+ if (has_colorkey != 0) {
+ z4l_ovly_set_colorkey(pPriv, DEFAULT_COLORKEY);
+ z4l_ovly_set_keymode(pPriv, DEFAULT_KEYMODE);
+ }
+ close(fd);
+ pPriv->fd = -1;
+ adpt = NULL;
+ cenc = 0;
+ encs = NULL;
+ nencs = 0;
+ }
+
+ DBLOG(0, "init done, %d device(s) found\n", nadpts);
+ Z4l_nAdaptors = nadpts;
+ Z4l_pAdaptors = adpts;
+ *adaptors = adpts;
+
+ return nadpts;
+
+ fail:
+ if (attrs != NULL) {
+ for (i = 0; i < nattrs; ++i)
+ if (attrs[i].name != NULL)
+ free(attrs[i].name);
+ free(attrs);
+ }
+
+ if (encs != NULL) {
+ for (i = 0; i < nencs; ++i) {
+ if (encs[i].name != NULL)
+ free(encs[i].name);
+ }
+ free(encs);
+ }
+
+ if (imgs != NULL)
+ free(imgs);
+
+ if (adpts != NULL) {
+ for (i = 0; i < nadpts; ++i) {
+ if ((adpt = adpts[i]) != NULL) {
+ if (adpt->name != NULL)
+ free(adpt->name);
+ if ((attrs = adpt->pAttributes) != NULL) {
+ for (i = 0; i < adpt->nAttributes; ++i)
+ if (attrs[i].name != NULL)
+ free(attrs[i].name);
+ free(attrs);
+ }
+ if ((encs = adpt->pEncodings) != NULL) {
+ for (i = 0; i < adpt->nEncodings; ++i, ++enc)
+ if (encs[i].name != NULL)
+ free(encs[i].name);
+ free(encs);
+ }
+ if ((imgs = adpt->pImages) != NULL)
+ free(imgs);
+ free(adpt);
+ }
+ }
+ free(adpts);
+ }
+
+ if (fd >= 0)
+ close(fd);
+
+ return 0;
+}
+
+static Bool
+Z4lProbe(DriverPtr drv, int flags)
+{
+ DBLOG(1, "Probe\n");
+ if (flags & PROBE_DETECT)
+ return TRUE;
+
+ xf86XVRegisterGenericAdaptorDriver(Z4lInit);
+ drv->refCount++;
+
+ return TRUE;
+}
+
+static const OptionInfoRec *
+Z4lAvailableOptions(int chipid, int busid)
+{
+ return NULL;
+}
+
+static void
+Z4lIdentify(int flags)
+{
+ xf86Msg(X_INFO, "z4l driver for Video4Linux\n");
+}
+
+_X_EXPORT DriverRec Z4l = {
+ 40001,
+ "z4l",
+ Z4lIdentify,
+ Z4lProbe,
+ Z4lAvailableOptions,
+ NULL,
+ 0
+};
+
+#ifdef XFree86LOADER
+
+static MODULESETUPPROTO(z4lSetup);
+
+static XF86ModuleVersionInfo z4lVersionRec = {
+ "ztv",
+ MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2,
+ XORG_VERSION_CURRENT, 0, 0, 1,
+ ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_NONE,
+ {0, 0, 0, 0}
+};
+
+_X_EXPORT XF86ModuleData ztvModuleData = { &z4lVersionRec, z4lSetup, NULL };
+
+static pointer
+z4lSetup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+ const char *osname;
+ static Bool setupDone = FALSE;
+
+ if (setupDone != FALSE) {
+ if (errmaj != NULL)
+ *errmaj = LDR_ONCEONLY;
+ return NULL;
+ }
+
+ setupDone = TRUE;
+ LoaderGetOS(&osname, NULL, NULL, NULL);
+
+ if (osname == NULL || strcmp(osname, "linux") != 0) {
+ if (errmaj)
+ *errmaj = LDR_BADOS;
+ if (errmin)
+ *errmin = 0;
+
+ return NULL;
+ }
+
+ xf86AddDriver(&Z4l, module, 0);
+
+ return (pointer) 1;
+}
+
+#endif
+#endif /* !XvExtension */