diff options
Diffstat (limited to 'src/z4l.c')
-rw-r--r-- | src/z4l.c | 1754 |
1 files changed, 1754 insertions, 0 deletions
diff --git a/src/z4l.c b/src/z4l.c new file mode 100644 index 0000000..ae08c3e --- /dev/null +++ b/src/z4l.c @@ -0,0 +1,1754 @@ +/* + * 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 */ + +#include <sys/time.h> +#include <sys/fcntl.h> +#include <asm/ioctl.h> +#include <asm/ioctls.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.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; + +#include "linux/videodev.h" +#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) +{ + 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) +{ + 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) xrealloc(*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 *)xalloc(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) xrealloc(*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) xrealloc(*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 *)xalloc(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 *) xrealloc(*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) xalloc(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; + 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; + 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 = xalloc(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); + xfree(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"); +} + +DriverRec Z4l = { + 40001, + "z4l", + Z4lIdentify, + Z4lProbe, + Z4lAvailableOptions, + NULL, + 0 +}; + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(z4lSetup); + +static XF86ModuleVersionInfo z4lVersRec = { + "z4l", + MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, + XF86_VERSION_CURRENT, 0, 0, 1, + ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_NONE, + {0, 0, 0, 0} +}; + +XF86ModuleData z4lModuleData = { &z4lVersRec, 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 */ |