z4l.c revision 79d5fcd7
1/* 2 * Copyright (c) 2006 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 * 22 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 23 * contributors may be used to endorse or promote products derived from this 24 * software without specific prior written permission. 25 */ 26 27/* prototype Xv interface for lxv4l2 driver */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <sys/time.h> 34#include <sys/fcntl.h> 35#include <sys/mman.h> 36#include <sys/ioctl.h> 37#include <errno.h> 38#include <unistd.h> 39#include <string.h> 40#include <ctype.h> 41#include <stdlib.h> 42 43#include "xf86.h" 44#include <X11/extensions/Xv.h> 45#include "xf86_OSproc.h" 46#include "compiler.h" 47#include "xf86xv.h" 48#include "fourcc.h" 49 50#include "compat-api.h" 51 52#define __s64 __s_64 53typedef long long __s64; 54 55#define __u64 __u_64 56typedef unsigned long long __u64; 57 58#define __user 59#include "linux/videodev2.h" 60 61typedef signed long long s64; 62typedef unsigned long long u64; 63 64int debuglvl = 0; 65 66#define NONBLK_IO 67#undef HAVE_SELECT 68 69#define DEBUG 1 70#ifdef DEBUG 71#define DBLOG(n,s...) do { \ 72 if ( debuglvl >= (n) ) \ 73 xf86Msg(X_INFO, "z4l: " s); \ 74 } while(0) 75#else 76#define DBLOG(n,s...) do {} while(0) 77#endif 78 79#define DEFAULT_COLORKEY 0x010203 80#define DEFAULT_KEYMODE 0 81 82#define MAX_BUFFERS 4 83#define MAX_OVLY_WIDTH 2048 84#define MAX_OVLY_HEIGHT 2048 85 86static char *z4l_dev_paths[] = { 87 "/dev/videox", NULL 88}; 89 90#define ATTR_ENCODING "encoding" 91#define ATTR_ENCODING_ID -1 92#define ATTR_KEYMODE "keymode" 93#define ATTR_KEYMODE_ID -2 94#define ATTR_COLORKEY "colorkey" 95#define ATTR_COLORKEY_ID -3 96#define ATTR_MAX_ID 3 97 98#ifdef XvExtension 99 100static XF86VideoFormatRec Formats[] = { 101 {8, PseudoColor}, 102 {15, TrueColor}, 103 {16, TrueColor}, 104 {24, TrueColor} 105}; 106 107#define NUM_FORMATS (sizeof(Formats)/sizeof(Formats[0])) 108 109#define FOURCC_Y800 0x30303859 110#define XVIMAGE_Y800 \ 111 { \ 112 FOURCC_Y800, \ 113 XvYUV, \ 114 LSBFirst, \ 115 {'Y','8','0','0', \ 116 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \ 117 8, \ 118 XvPacked, \ 119 1, \ 120 0, 0, 0, 0, \ 121 8, 0, 0, \ 122 1, 0, 0, \ 123 1, 0, 0, \ 124 {'Y','8','0','0', \ 125 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}, \ 126 XvTopToBottom \ 127 } 128 129static XF86ImageRec pixfmts[] = { 130 XVIMAGE_UYVY, XVIMAGE_YUY2, 131 XVIMAGE_I420, XVIMAGE_YV12, 132 XVIMAGE_Y800, 133}; 134 135#define NUM_PIXFMTS (sizeof(pixfmts)/sizeof(pixfmts[0])) 136 137typedef struct s_std_data { 138 int inp; 139 v4l2_std_id std; 140 unsigned int fmt; 141} t_std_data; 142 143typedef struct s_ovly_bfrs { 144 void *start; 145 unsigned long offset; 146 size_t length; 147} t_ovly_bfrs; 148 149typedef struct { 150 int fd; 151 int run; 152 int dir; 153 int nbfrs; 154 int bufno; 155 int bufsz; 156 int last; 157 int width, height; 158 int keymode, colorkey; 159 int src_is_set, src_x, src_y, src_w, src_h; 160 int drw_is_set, drw_x, drw_y, drw_w, drw_h; 161 unsigned int pixfmt; 162 char dev_path[32]; 163 t_ovly_bfrs bfrs[MAX_BUFFERS]; 164 XF86VideoAdaptorPtr adpt; 165 XF86VideoEncodingPtr enc; 166 RegionRec clips; 167 int attrIds[1]; 168} Z4lPortPrivRec; 169 170static int z4l_x_offset = 0; 171static int z4l_y_offset = 0; 172static int Z4l_nAdaptors = 0; 173static XF86VideoAdaptorPtr *Z4l_pAdaptors = NULL; 174 175static int 176IoCtl(int fd, unsigned int fn, void *arg, int flag) 177{ 178 int ret; 179 180 errno = 0; 181 ret = ioctl(fd, fn, arg); 182 if (ret != 0 && flag != 0) 183 DBLOG(0, "ioctl(%08x)=%d\n", fn, ret); 184 return ret; 185} 186 187static void 188z4l_ovly_unmap(Z4lPortPrivRec * pPriv) 189{ 190 int i, nbfrs; 191 192 nbfrs = pPriv->nbfrs; 193 for (i = 0; i < nbfrs; ++i) { 194 if (pPriv->bfrs[i].start != NULL) { 195 munmap(pPriv->bfrs[i].start, pPriv->bfrs[i].length); 196 pPriv->bfrs[i].start = NULL; 197 } 198 } 199 pPriv->nbfrs = -1; 200 pPriv->bufsz = -1; 201 pPriv->last = -1; 202} 203 204static void 205z4l_ovly_map(Z4lPortPrivRec * pPriv, int dir) 206{ 207 long offset, bsz; 208 int i, fd; 209 struct v4l2_buffer bfr; 210 struct v4l2_requestbuffers req; 211 int type = dir >= 0 ? 212 V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VIDEO_OVERLAY; 213 if (pPriv->run > 0) { 214 DBLOG(1, "busy\n"); 215 return; 216 } 217 fd = pPriv->fd; 218 memset(&req, 0, sizeof(req)); 219 req.type = type; 220 req.memory = V4L2_MEMORY_MMAP; 221 req.count = MAX_BUFFERS; 222 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) 223 goto xit; 224 pPriv->nbfrs = req.count; 225 if (pPriv->nbfrs <= 0) { 226 DBLOG(1, "no vidmem\n"); 227 return; 228 } 229 memset(&pPriv->bfrs, 0, sizeof(pPriv->bfrs)); 230 231 for (i = 0; i < pPriv->nbfrs; ++i) { 232 memset(&bfr, 0, sizeof(bfr)); 233 bfr.type = type; 234 bfr.index = i; 235 if (ioctl(fd, VIDIOC_QUERYBUF, &bfr) < 0) 236 goto xit; 237 offset = bfr.m.offset; 238 pPriv->bfrs[i].offset = offset; 239 pPriv->bfrs[i].length = bfr.length; 240 bsz = offset + bfr.length; 241 if (pPriv->bufsz < bsz) 242 pPriv->bufsz = bsz; 243 } 244 245 for (i = 0; i < pPriv->nbfrs; ++i) { 246 pPriv->bfrs[i].start = mmap(NULL, bfr.length, PROT_READ | PROT_WRITE, 247 MAP_SHARED, fd, pPriv->bfrs[i].offset); 248 if (pPriv->bfrs[i].start == MAP_FAILED) 249 goto xit; 250 } 251 252 for (i = 0; i < pPriv->nbfrs; ++i) { 253 DBLOG(3, "bfr %d ofs %#lx adr %p sz %lu\n", i, pPriv->bfrs[i].offset, 254 pPriv->bfrs[i].start, (unsigned long) pPriv->bfrs[i].length); 255 memset(pPriv->bfrs[i].start, 0x80, pPriv->bfrs[i].length); 256 } 257 258 pPriv->last = 0; 259 while (pPriv->last < pPriv->nbfrs - 1) { 260 bfr.index = pPriv->last++; 261 bfr.type = type; 262 if (ioctl(fd, VIDIOC_QBUF, &bfr) < 0) 263 goto xit; 264 } 265 return; 266 267 xit: 268 z4l_ovly_unmap(pPriv); 269} 270 271static int 272z4l_ovly_dqbuf(Z4lPortPrivRec * pPriv) 273{ 274 int stat; 275 struct v4l2_buffer bfr; 276 int fd = pPriv->fd; 277 278#ifdef HAVE_SELECT 279 struct timeval tmo; 280 fd_set dqset; 281 282 FD_ZERO(&dqset); 283 FD_SET(pPriv->fd, &dqset); 284 tmo.tv_sec = 0; 285 tmo.tv_usec = 0; 286 if (select(fd + 1, &dqset, NULL, NULL, &tmo) <= 0) 287 return -1; 288#endif 289 memset(&bfr, 0, sizeof(bfr)); 290 bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 291 stat = ioctl(fd, VIDIOC_DQBUF, &bfr); 292 DBLOG(3, "dqbuf %d,%d,%d,%d\n", stat, bfr.index, pPriv->last, errno); 293 294 return stat == 0 ? bfr.index : -1; 295} 296 297static int 298z4l_open_device(Z4lPortPrivRec * pPriv) 299{ 300 int enable; 301 302 if (pPriv->fd < 0) { 303 pPriv->fd = open(&pPriv->dev_path[0], O_RDWR, 0); 304 DBLOG(1, "open(%s)=%d\n", &pPriv->dev_path[0], pPriv->fd); 305 enable = 1; 306#ifdef NONBLK_IO 307 if (IoCtl(pPriv->fd, FIONBIO, &enable, 1) != 0) { 308 DBLOG(1, "open can't enable nonblocking\n"); 309 close(pPriv->fd); 310 pPriv->fd = -1; 311 } 312#endif 313 } 314 return pPriv->fd; 315} 316 317static int 318z4l_close_device(Z4lPortPrivRec * pPriv) 319{ 320 int ret = 0; 321 322 if (pPriv->fd >= 0) { 323 ret = close(pPriv->fd); 324 pPriv->fd = -1; 325 DBLOG(1, "close()=%d\n", ret); 326 } 327 if (pPriv->run > 0) { 328 z4l_ovly_unmap(pPriv); 329 pPriv->run = -1; 330 } 331 332 return ret; 333} 334 335static int 336z4l_ovly_reset(Z4lPortPrivRec * pPriv) 337{ 338 int ret = 0; 339 340 if (pPriv->run > 0) { 341 z4l_close_device(pPriv); 342 ret = z4l_open_device(pPriv); 343 } 344 345 return ret; 346} 347 348static unsigned int 349z4l_fourcc_pixfmt(int fourcc) 350{ 351 unsigned int pixfmt = -1; 352 353 switch (fourcc) { 354 case FOURCC_UYVY: 355 pixfmt = V4L2_PIX_FMT_UYVY; 356 break; 357 case FOURCC_YV12: 358 pixfmt = V4L2_PIX_FMT_YVU420; 359 break; 360 case FOURCC_Y800: 361 case FOURCC_I420: 362 pixfmt = V4L2_PIX_FMT_YUV420; 363 break; 364 case FOURCC_YUY2: 365 pixfmt = V4L2_PIX_FMT_YUYV; 366 break; 367 } 368 369 return pixfmt; 370} 371 372static void 373z4l_ovly_pixfmt(Z4lPortPrivRec * pPriv, unsigned int pixfmt) 374{ 375 struct v4l2_framebuffer fbuf; 376 377 DBLOG(1, "pixfmt %4.4s %4.4s\n", (char *) &pPriv->pixfmt, (char *) &pixfmt); 378 memset(&fbuf, 0, sizeof(fbuf)); 379 IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1); 380 fbuf.fmt.pixelformat = pixfmt; 381 fbuf.base = NULL; 382 IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1); 383 pPriv->pixfmt = pixfmt; 384} 385 386static void 387z4l_ovly_bfr(Z4lPortPrivRec * pPriv, int width, int height) 388{ 389 struct v4l2_format fmt; 390 391 DBLOG(1, "sfmt ovly %dx%d\n", width, height); 392 memset(&fmt, 0, sizeof(fmt)); 393 fmt.type = 0x102; 394 IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1); 395 fmt.fmt.win.field = V4L2_FIELD_NONE; 396 fmt.fmt.win.w.width = pPriv->width = width; 397 fmt.fmt.win.w.height = pPriv->height = height; 398 IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1); 399} 400 401static void 402z4l_ovly_rect(Z4lPortPrivRec * pPriv, 403 int src_x, int src_y, int src_w, int src_h, 404 int drw_x, int drw_y, int drw_w, int drw_h) 405{ 406 int x, dx, w, y, dy, h; 407 struct v4l2_format fmt; 408 409 pPriv->src_x = src_x; 410 pPriv->src_y = src_y; 411 pPriv->src_w = src_w; 412 pPriv->src_h = src_h; 413 pPriv->drw_x = drw_x; 414 pPriv->drw_y = drw_y; 415 pPriv->drw_w = drw_w; 416 pPriv->drw_h = drw_h; 417 418 if ((drw_x -= z4l_x_offset) < 0) { 419 if ((w = pPriv->drw_w) <= 0) 420 w = 1; 421 x = -drw_x; 422 dx = x * pPriv->src_w / w; 423 src_x = pPriv->src_x + dx; 424 src_w = pPriv->src_w - dx; 425 drw_w = pPriv->drw_w - x; 426 drw_x = 0; 427 } 428 429 if ((drw_y -= z4l_y_offset) < 0) { 430 if ((h = pPriv->drw_h) <= 0) 431 h = 1; 432 y = -drw_y; 433 dy = y * pPriv->src_h / h; 434 src_y = pPriv->src_y + dy; 435 src_h = pPriv->src_h - dy; 436 drw_h = pPriv->drw_h - y; 437 drw_y = 0; 438 } 439 440 memset(&fmt, 0, sizeof(fmt)); 441 fmt.type = 0x100; 442 IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1); 443 if (pPriv->src_is_set != 0) { 444 if (src_x != fmt.fmt.win.w.left || src_y != fmt.fmt.win.w.top || 445 src_w != fmt.fmt.win.w.width || src_h != fmt.fmt.win.w.height) 446 pPriv->src_is_set = 0; 447 } 448 if (pPriv->src_is_set == 0) { 449 pPriv->src_is_set = 1; 450 fmt.fmt.win.w.left = src_x; 451 fmt.fmt.win.w.top = src_y; 452 fmt.fmt.win.w.width = src_w; 453 fmt.fmt.win.w.height = src_h; 454 IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1); 455 DBLOG(3, " set src %d,%d %dx%d\n", src_x, src_y, src_w, src_h); 456 } 457 memset(&fmt, 0, sizeof(fmt)); 458 fmt.type = 0x101; 459 IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1); 460 if (pPriv->drw_is_set != 0) { 461 if (drw_x != fmt.fmt.win.w.left || drw_y != fmt.fmt.win.w.top || 462 drw_w != fmt.fmt.win.w.width || drw_h != fmt.fmt.win.w.height) 463 pPriv->drw_is_set = 0; 464 } 465 if (pPriv->drw_is_set == 0) { 466 pPriv->drw_is_set = 1; 467 fmt.fmt.win.w.left = drw_x; 468 fmt.fmt.win.w.top = drw_y; 469 fmt.fmt.win.w.width = drw_w; 470 fmt.fmt.win.w.height = drw_h; 471 IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1); 472 DBLOG(3, " set drw %d,%d %dx%d\n", drw_x, drw_y, drw_w, drw_h); 473 } 474} 475 476static void 477z4l_ovly_pitch(unsigned int pixfmt, int w, int h, int *py_pitch, 478 int *puv_pitch, int *poffset1, int *poffset2, int *psize) 479{ 480 int y_pitch, uv_pitch; 481 int offset1, offset2; 482 int size, is_420; 483 484 switch (pixfmt) { 485 case V4L2_PIX_FMT_YVU420: 486 case V4L2_PIX_FMT_YUV420: 487 is_420 = 1; 488 y_pitch = ((w + 1) / 2) * 2; 489 uv_pitch = (w + 1) / 2; 490 break; 491 default: 492 is_420 = 0; 493 y_pitch = ((w + 1) / 2) * 4; 494 uv_pitch = 0; 495 break; 496 } 497 498 offset1 = y_pitch * h; 499 offset2 = uv_pitch * h; 500 501 if (is_420 != 0) 502 offset2 /= 2; 503 504 size = offset1 + 2 * offset2; 505 *py_pitch = y_pitch; 506 *puv_pitch = uv_pitch; 507 *poffset1 = offset1; 508 *poffset2 = offset2; 509 *psize = size; 510} 511 512static int 513z4l_ovly_set_colorkey(Z4lPortPrivRec * pPriv, int key) 514{ 515 struct v4l2_format fmt; 516 517 memset(&fmt, 0, sizeof(fmt)); 518 fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 519 if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0) 520 return 0; 521 fmt.fmt.win.chromakey = key; 522 if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0) 523 return 0; 524 pPriv->colorkey = key; 525 526 return 1; 527} 528 529static int 530z4l_ovly_get_colorkey(Z4lPortPrivRec * pPriv, int *key) 531{ 532 struct v4l2_format fmt; 533 534 memset(&fmt, 0, sizeof(fmt)); 535 fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 536 if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0) 537 return 0; 538 *key = fmt.fmt.win.chromakey; 539 540 return 1; 541} 542 543static int 544z4l_ovly_set_keymode(Z4lPortPrivRec * pPriv, int enable) 545{ 546 struct v4l2_framebuffer fbuf; 547 548 memset(&fbuf, 0, sizeof(fbuf)); 549 if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0) 550 return 0; 551 552 if (enable != 0) 553 fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY; 554 else 555 fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY; 556 557 fbuf.base = NULL; 558 if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0) 559 return 0; 560 pPriv->keymode = enable; 561 562 return 1; 563} 564 565static int 566z4l_ovly_get_keymode(Z4lPortPrivRec * pPriv, int *enable) 567{ 568 struct v4l2_framebuffer fbuf; 569 570 memset(&fbuf, 0, sizeof(fbuf)); 571 if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0) 572 return 0; 573 *enable = (fbuf.flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0 ? 1 : 0; 574 575 return 1; 576} 577 578static int 579z4l_ovly_set_encoding(Z4lPortPrivRec * pPriv, int id) 580{ 581 int l, n, inp; 582 char *cp; 583 t_std_data *sp; 584 XF86VideoEncodingPtr enc; 585 XF86VideoAdaptorPtr adpt; 586 v4l2_std_id std; 587 struct v4l2_format fmt; 588 struct v4l2_framebuffer fbuf; 589 590 adpt = pPriv->adpt; 591 DBLOG(1, "z4l_ovly_set_encoding(%d)\n", id); 592 if (id < 0 || id >= adpt->nEncodings) 593 return 0; 594 enc = &adpt->pEncodings[id]; 595 cp = &enc->name[0]; 596 n = sizeof(int) - 1; 597 l = strlen(cp) + 1; 598 l = (l + n) & ~n; 599 sp = (t_std_data *) (cp + l); 600 inp = sp->inp; 601 602 DBLOG(1, " nm %s fmt %4.4s inp %d std %llx\n", 603 cp, (char *) &sp->fmt, sp->inp, sp->std); 604 605 if (IoCtl(pPriv->fd, VIDIOC_S_INPUT, &inp, 1) < 0) 606 return 0; 607 608 std = sp->std; 609 if (IoCtl(pPriv->fd, VIDIOC_S_STD, &std, 1) < 0) 610 return 0; 611 612 memset(&fmt, 0, sizeof(fmt)); 613 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 614 if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0) 615 return 0; 616 617 fmt.fmt.pix.pixelformat = sp->fmt; 618 if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0) 619 return 0; 620 memset(&fbuf, 0, sizeof(fbuf)); 621 622 if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0) 623 return 0; 624 625 fbuf.fmt.pixelformat = sp->fmt; 626 fbuf.base = NULL; 627 if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0) 628 return 0; 629 pPriv->pixfmt = sp->fmt; 630 pPriv->enc = enc; 631 pPriv->src_is_set = pPriv->drw_is_set = 0; 632 633 return 1; 634} 635 636static int 637z4l_ovly_get_encoding(Z4lPortPrivRec * pPriv, int *id) 638{ 639 XF86VideoEncodingPtr enc = pPriv->enc; 640 641 *id = enc->id; 642 return 1; 643} 644 645static void 646z4l_ovly_stop(Z4lPortPrivRec * pPriv) 647{ 648 int type, enable, fd; 649 650 if (pPriv->run < 0) 651 return; 652 653 fd = pPriv->fd; 654 if (pPriv->dir > 0) { 655 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 656 ioctl(fd, VIDIOC_STREAMOFF, &type); 657 } 658 659 if (pPriv->dir <= 0) { 660 enable = 0; 661 ioctl(fd, VIDIOC_OVERLAY, &enable); 662 } 663 664 if (pPriv->dir != 0) 665 z4l_ovly_unmap(pPriv); 666 667 pPriv->run = -1; 668 z4l_close_device(pPriv); 669} 670 671static void 672z4l_ovly_start(Z4lPortPrivRec * pPriv, int dir) 673{ 674 int enable; 675 676 if (pPriv->run >= 0) 677 return; 678 679 if ((pPriv->dir = dir) != 0) 680 z4l_ovly_map(pPriv, dir); 681 682 enable = 1; 683 684 if (IoCtl(pPriv->fd, VIDIOC_OVERLAY, &enable, 1) != 0) { 685 z4l_ovly_stop(pPriv); 686 return; 687 } 688 689 pPriv->run = 1; 690} 691 692static int 693z4l_region_equal(RegionPtr ap, RegionPtr bp) 694{ 695 int nboxes; 696 BoxPtr abox, bbox; 697 698 if (ap == NULL && bp == NULL) 699 return 1; 700 if (ap == NULL || bp == NULL) 701 return 0; 702 703 if ((nboxes = REGION_NUM_RECTS(ap)) != REGION_NUM_RECTS(bp) || 704 ap->extents.x1 != bp->extents.x1 || 705 ap->extents.x2 != bp->extents.x2 706 || ap->extents.y1 != bp->extents.y1 || ap->extents.y2 != bp->extents.y2) 707 return 0; 708 709 abox = REGION_RECTS(ap); 710 bbox = REGION_RECTS(bp); 711 712 while (--nboxes >= 0) { 713 if (abox->x1 != bbox->x1 || abox->y1 != bbox->y1 || 714 abox->x2 != bbox->x2 || abox->y2 != bbox->y2) 715 return 0; 716 ++abox; 717 ++bbox; 718 } 719 720 return 1; 721} 722 723static void 724z4l_setup_colorkey(Z4lPortPrivRec * pPriv, ScreenPtr pScrn, RegionPtr clipBoxes) 725{ 726 if (pPriv->run > 0 && pPriv->dir <= 0 && pPriv->keymode != 0 && 727 z4l_region_equal(&pPriv->clips, clipBoxes) == 0) { 728 xf86XVFillKeyHelper(pScrn, pPriv->colorkey, clipBoxes); 729 REGION_COPY(pScrn, &pPriv->clips, clipBoxes); 730 } 731} 732 733static void 734Z4lStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit) 735{ 736 Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data; 737 738 DBLOG(1, "Z4lStopVideo()\n"); 739 740 if (exit != 0) 741 z4l_ovly_stop(pPriv); 742 else 743 pPriv->src_is_set = pPriv->drw_is_set = 0; 744 745 REGION_EMPTY(pScrni->pScreen, &pPriv->clips); 746} 747 748static void 749Z4lQueryBestSize(ScrnInfoPtr pScrni, Bool motion, 750 short vid_w, short vid_h, short drw_w, short drw_h, 751 unsigned int *p_w, unsigned int *p_h, pointer data) 752{ 753 if (drw_w > MAX_OVLY_WIDTH) 754 drw_w = MAX_OVLY_WIDTH; 755 if (drw_h > MAX_OVLY_HEIGHT) 756 drw_h = MAX_OVLY_HEIGHT; 757 758 *p_w = drw_w; 759 *p_h = drw_h; 760 DBLOG(1, "Z4lQueryBestSize(%d, src %dx%d dst %dx%d)\n", motion, vid_w, 761 vid_h, drw_w, drw_h); 762} 763 764static int 765Z4lPutImage(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x, 766 short drw_y, short src_w, short src_h, short drw_w, short drw_h, 767 int id, unsigned char *buf, short width, short height, 768 Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) 769{ 770 int fd, size; 771 int y_pitch, uv_pitch, offset1, offset2; 772 unsigned char *src, *dst; 773 unsigned int pixfmt; 774 struct v4l2_buffer bfr; 775 Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data; 776 777 if (pPriv->run > 0 && pPriv->dir >= 0) 778 return BadMatch; 779 if (pPriv->fd < 0) { 780 z4l_open_device(pPriv); 781 if (pPriv->fd < 0) 782 return BadValue; 783 } 784 785 fd = pPriv->fd; 786 if (pPriv->run < 0) { 787 DBLOG(2, "PutImg id %#x src %d,%d %dx%d drw %d,%d %dx%d bfr %p " 788 "%dx%d data %p\n", id, src_x, src_y, src_w, src_h, drw_x, 789 drw_y, drw_w, drw_h, buf, width, height, data); 790 pPriv->pixfmt = pPriv->height = -1; 791 pPriv->src_is_set = pPriv->drw_is_set = 0; 792 } 793 794 pixfmt = z4l_fourcc_pixfmt(id); 795 if (pixfmt != pPriv->pixfmt) { 796 z4l_ovly_reset(pPriv); 797 z4l_ovly_pixfmt(pPriv, pixfmt); 798 } 799 if (pPriv->width != width || pPriv->height != height) { 800 z4l_ovly_reset(pPriv); 801 z4l_ovly_bfr(pPriv, width, height); 802 } 803 804 if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 || 805 pPriv->src_x != src_x || pPriv->src_y != src_y || 806 pPriv->src_w != src_w || pPriv->src_h != src_h || 807 pPriv->drw_x != drw_x || pPriv->drw_y != drw_y || 808 pPriv->drw_w != drw_w || pPriv->drw_h != drw_h) 809 z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, 810 drw_h); 811 812 if (pPriv->run < 0) { 813 z4l_ovly_start(pPriv, -1); 814 if (pPriv->run < 0) 815 return BadValue; 816 } 817 818 if (pPriv->last < 0 && (pPriv->last = z4l_ovly_dqbuf(pPriv)) < 0) 819 return BadAlloc; 820 821 z4l_ovly_pitch(pixfmt, width, height, &y_pitch, &uv_pitch, 822 &offset1, &offset2, &size); 823 src = buf; 824 dst = (unsigned char *) pPriv->bfrs[pPriv->last].start; 825 DBLOG(3, "cpy %4.4s src %p dst %p yp %d uvp %d o1 %d o2 %d sz %d\n", 826 (char *) &id, src, dst, y_pitch, uv_pitch, offset1, offset2, size); 827 828 if (id == FOURCC_Y800) { 829 memcpy(dst, src, offset1); 830 src += offset1; 831 dst += offset1; 832 memset(dst, 0x80, 2 * offset2); 833 } 834 else 835 memcpy(dst, src, size); 836 837 memset(&bfr, 0, sizeof(bfr)); 838 bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 839 bfr.index = pPriv->last; 840 bfr.timestamp.tv_sec = 0; 841 bfr.timestamp.tv_usec = 0; 842 bfr.flags |= V4L2_BUF_FLAG_TIMECODE; 843 if (IoCtl(fd, VIDIOC_QBUF, &bfr, 1) != 0) 844 return BadAccess; 845 846 pPriv->last = z4l_ovly_dqbuf(pPriv); 847 z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes); 848 849 return Success; 850} 851 852static int 853Z4lQueryImageAttributes(ScrnInfoPtr pScrni, int id, unsigned short *width, 854 unsigned short *height, int *pitches, int *offsets) 855{ 856 int w, h, size; 857 int y_pitch, uv_pitch, offset1, offset2; 858 unsigned int pixfmt = z4l_fourcc_pixfmt(id); 859 860 w = *width; 861 h = *height; 862 if (w > MAX_OVLY_WIDTH) 863 w = MAX_OVLY_WIDTH; 864 if (h > MAX_OVLY_HEIGHT) 865 h = MAX_OVLY_HEIGHT; 866 867 z4l_ovly_pitch(pixfmt, w, h, &y_pitch, &uv_pitch, 868 &offset1, &offset2, &size); 869 870 if (offsets != NULL) 871 offsets[0] = 0; 872 if (pitches != NULL) 873 pitches[0] = y_pitch; 874 875 switch (pixfmt) { 876 case V4L2_PIX_FMT_YVU420: 877 case V4L2_PIX_FMT_YUV420: 878 if (offsets != NULL) { 879 offsets[1] = offset1; 880 offsets[2] = offset1 + offset2; 881 } 882 if (pitches != NULL) 883 pitches[1] = pitches[2] = uv_pitch; 884 h = (h + 1) & ~1; 885 break; 886 } 887 888 w = (w + 1) & ~1; 889 *width = w; 890 *height = h; 891 DBLOG(1, "Z4lQueryImageAttributes(%4.4s) = %d, %dx%d %d/%d %d/%d\n", 892 (char *) &id, size, w, h, y_pitch, uv_pitch, offset1, offset2); 893 894 return size; 895} 896 897static int 898Z4lPutVideo(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x, 899 short drw_y, short src_w, short src_h, short drw_w, short drw_h, 900 RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) 901{ 902 int id; 903 Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data; 904 905 DBLOG(2, "PutVid src %d,%d %dx%d drw %d,%d %dx%d data %p\n", 906 src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, drw_h, data); 907 908 if (z4l_open_device(pPriv) >= 0) { 909 if (pPriv->run < 0) { 910 DBLOG(2, "PutVid start\n"); 911 z4l_ovly_get_encoding(pPriv, &id); 912 z4l_ovly_set_encoding(pPriv, id); 913 } 914 DBLOG(2, "PutVid priv %d,%d %dx%d drw %d,%d %dx%d\n", 915 pPriv->src_x, pPriv->src_y, pPriv->src_w, pPriv->src_h, 916 pPriv->drw_x, pPriv->drw_y, pPriv->drw_w, pPriv->drw_h); 917 if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 || 918 pPriv->src_w != src_w || pPriv->src_h != src_h || 919 pPriv->drw_x != drw_x || pPriv->drw_y != drw_y || 920 pPriv->drw_w != drw_w || pPriv->drw_h != drw_h) 921 z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y, 922 drw_w, drw_h); 923 if (pPriv->run < 0) 924 z4l_ovly_start(pPriv, 0); 925 926 z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes); 927 } 928 929 return Success; 930} 931 932static XF86VideoEncodingPtr 933Z4lNewEncoding(XF86VideoEncodingPtr * encs, int *nencs) 934{ 935 XF86VideoEncodingPtr enc; 936 XF86VideoEncodingPtr tencs = 937 (XF86VideoEncodingPtr) realloc(*encs, sizeof(*tencs) * (*nencs + 1)); 938 939 if (tencs == NULL) 940 return NULL; 941 942 *encs = tencs; 943 enc = &tencs[*nencs]; 944 ++*nencs; 945 memset(enc, 0, sizeof(*enc)); 946 947 return enc; 948} 949 950static void 951Z4lEncodingName(char *ename, int l, char *inp_name, char *std_name, char *fmt) 952{ 953 int i, ch; 954 955 while ((ch = *inp_name++) != 0) { 956 if (isalnum(ch) == 0) 957 continue; 958 if (--l <= 0) 959 goto xit; 960 *ename++ = ch; 961 } 962 963 if (--l <= 0) 964 goto xit; 965 966 *ename++ = '-'; 967 968 while ((ch = *std_name++) != 0) { 969 if (isalnum(ch) == 0) 970 continue; 971 if (--l <= 0) 972 goto xit; 973 *ename++ = ch; 974 } 975 976 if (--l <= 0) 977 goto xit; 978 979 *ename++ = '-'; 980 i = 4; 981 982 while (--i >= 0 && (ch = *fmt++) != 0) { 983 if (isalnum(ch) == 0) 984 continue; 985 if (--l <= 0) 986 goto xit; 987 *ename++ = ch; 988 } 989 990 xit: 991 *ename = 0; 992} 993 994static int 995Z4lAddEncoding(XF86VideoEncodingPtr enc, char *name, int id, int width, 996 int height, int numer, int denom, int inp, v4l2_std_id std, 997 unsigned int fmt) 998{ 999 int l, n; 1000 t_std_data *sp; 1001 char *cp; 1002 1003 n = sizeof(int) - 1; 1004 l = strlen(&name[0]) + 1; 1005 l = (l + n) & ~n; 1006 n = l + sizeof(*sp); 1007 cp = (char *) malloc(n); 1008 1009 if (cp == NULL) 1010 return 0; 1011 1012 sp = (t_std_data *) (cp + l); 1013 enc->id = id; 1014 strcpy(cp, &name[0]); 1015 enc->name = cp; 1016 enc->width = width; 1017 enc->height = height; 1018 enc->rate.numerator = numer; 1019 enc->rate.denominator = denom; 1020 sp->inp = inp; 1021 sp->std = std; 1022 sp->fmt = fmt; 1023 DBLOG(1, "enc %s\n", &name[0]); 1024 1025 return 1; 1026} 1027 1028static XF86ImagePtr 1029Z4lNewImage(XF86ImagePtr * imgs, int *nimgs) 1030{ 1031 XF86ImagePtr img; 1032 XF86ImagePtr timgs = 1033 (XF86ImagePtr) realloc(*imgs, sizeof(*timgs) * (*nimgs + 1)); 1034 1035 if (timgs == NULL) 1036 return NULL; 1037 1038 *imgs = timgs; 1039 img = &timgs[*nimgs]; 1040 ++*nimgs; 1041 memset(img, 0, sizeof(*img)); 1042 1043 return img; 1044} 1045 1046static int 1047Z4lAddImage(XF86ImagePtr img, XF86ImagePtr ip) 1048{ 1049 *img = *ip; 1050 DBLOG(1, "img %4.4s\n", (char *) &img->id); 1051 return 1; 1052} 1053 1054static XF86AttributePtr 1055Z4lNewAttribute(XF86AttributePtr * attrs, int *nattrs) 1056{ 1057 XF86AttributePtr attr; 1058 XF86AttributePtr tattrs = 1059 (XF86AttributePtr) realloc(*attrs, sizeof(*tattrs) * (*nattrs + 1)); 1060 1061 if (tattrs == NULL) 1062 return NULL; 1063 1064 *attrs = tattrs; 1065 attr = &tattrs[*nattrs]; 1066 ++*nattrs; 1067 memset(attr, 0, sizeof(*attr)); 1068 1069 return attr; 1070} 1071 1072static void 1073Z4lAttributeName(char *bp, int l, char *cp) 1074{ 1075 int ch; 1076 char *atomNm = bp; 1077 1078 if (l > 0) { 1079 *bp++ = 'X'; 1080 --l; 1081 } 1082 if (l > 0) { 1083 *bp++ = 'V'; 1084 --l; 1085 } 1086 if (l > 0) { 1087 *bp++ = '_'; 1088 --l; 1089 } 1090 1091 while (l > 0 && (ch = *cp++) != 0) { 1092 if (isalnum(ch) == 0) 1093 continue; 1094 *bp++ = toupper(ch); 1095 } 1096 1097 *bp = 0; 1098 MakeAtom(&atomNm[0], strlen(&atomNm[0]), TRUE); 1099} 1100 1101static int 1102Z4lAddAttribute(XF86AttributePtr attr, char *name, int min, int max, int flags) 1103{ 1104 char *cp = (char *) malloc(strlen((char *) &name[0]) + 1); 1105 1106 if (cp == NULL) 1107 return 0; 1108 1109 attr->name = cp; 1110 strcpy(&attr->name[0], name); 1111 attr->min_value = min; 1112 attr->max_value = max; 1113 attr->flags = flags; 1114 DBLOG(1, "attr %s\n", attr->name); 1115 1116 return 1; 1117} 1118 1119static XF86VideoAdaptorPtr 1120Z4lNewAdaptor(XF86VideoAdaptorPtr ** adpts, int *nadpts, int nattrs) 1121{ 1122 int n; 1123 Z4lPortPrivRec *pPriv; 1124 XF86VideoAdaptorPtr adpt, *tadpts; 1125 1126 tadpts = (XF86VideoAdaptorPtr *) realloc(*adpts, 1127 sizeof(*tadpts) * (*nadpts + 1)); 1128 1129 if (tadpts == NULL) 1130 return NULL; 1131 1132 *adpts = tadpts; 1133 n = sizeof(*adpt) + sizeof(*pPriv) + 1 * sizeof(*adpt->pPortPrivates); 1134 n += (nattrs - 1) * sizeof(pPriv->attrIds[0]); 1135 adpt = (XF86VideoAdaptorPtr) malloc(n); 1136 1137 if (adpt == NULL) 1138 return NULL; 1139 1140 memset(adpt, 0, n); 1141 tadpts[*nadpts] = adpt; 1142 ++*nadpts; 1143 adpt->pPortPrivates = (DevUnion *) &adpt[1]; 1144 pPriv = (Z4lPortPrivRec *) & adpt->pPortPrivates[1]; 1145 adpt->pPortPrivates[0].ptr = (pointer) pPriv; 1146 pPriv->adpt = adpt; 1147 adpt->nPorts = 1; 1148 1149 return adpt; 1150} 1151 1152static int 1153Z4lSetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value, 1154 pointer data) 1155{ 1156 Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data; 1157 XF86VideoAdaptorPtr adpt; 1158 XF86AttributePtr attr; 1159 struct v4l2_control ctrl; 1160 int i, nattrs, attrId, val; 1161 const char *name = NameForAtom(attribute); 1162 int old_fd = pPriv->fd; 1163 1164 DBLOG(1, "Z4lSetPortAttribute(%#lx,%d) '%s'\n", (unsigned long) attribute, 1165 (int) value, name != NULL ? name : "_null_"); 1166 1167 if (name == NULL) 1168 return BadImplementation; 1169 if (old_fd < 0 && z4l_open_device(pPriv) < 0) 1170 return BadAccess; 1171 1172 adpt = pPriv->adpt; 1173 attr = adpt->pAttributes; 1174 nattrs = adpt->nAttributes; 1175 1176 for (i = 0; i < nattrs; ++i, ++attr) 1177 if (strcmp(attr->name, name) == 0) 1178 break; 1179 1180 if (i >= nattrs) 1181 return BadMatch; 1182 1183 attrId = pPriv->attrIds[i]; 1184 val = value; 1185 1186 switch (attrId) { 1187 case ATTR_ENCODING_ID: 1188 z4l_ovly_set_encoding(pPriv, val); 1189 break; 1190 case ATTR_KEYMODE_ID: 1191 z4l_ovly_set_keymode(pPriv, val); 1192 REGION_EMPTY(pScrni->pScreen, &pPriv->clips); 1193 z4l_setup_colorkey(pPriv, pScrni->pScreen, &pPriv->clips); 1194 break; 1195 case ATTR_COLORKEY_ID: 1196 z4l_ovly_set_colorkey(pPriv, val); 1197 break; 1198 default: 1199 memset(&ctrl, 0, sizeof(ctrl)); 1200 ctrl.id = attrId + V4L2_CID_BASE; 1201 ctrl.value = val; 1202 if (IoCtl(pPriv->fd, VIDIOC_S_CTRL, &ctrl, 1) != 0) 1203 return BadMatch; 1204 break; 1205 } 1206 1207 if (old_fd < 0) 1208 z4l_close_device(pPriv); 1209 1210 return Success; 1211} 1212 1213static int 1214Z4lGetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value, 1215 pointer data) 1216{ 1217 Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data; 1218 XF86VideoAdaptorPtr adpt; 1219 XF86AttributePtr attr; 1220 struct v4l2_control ctrl; 1221 int i, nattrs, attrId, val; 1222 const char *name = NameForAtom(attribute); 1223 int old_fd = pPriv->fd; 1224 1225 DBLOG(1, "Z4lGetPortAttribute(%#lx) '%s'\n", 1226 (unsigned long) attribute, name != NULL ? name : "_null_"); 1227 1228 if (name == NULL) 1229 return BadImplementation; 1230 if (old_fd < 0 && z4l_open_device(pPriv) < 0) 1231 return BadAccess; 1232 1233 adpt = pPriv->adpt; 1234 attr = adpt->pAttributes; 1235 nattrs = adpt->nAttributes; 1236 1237 for (i = 0; i < nattrs; ++i, ++attr) 1238 if (strcmp(attr->name, name) == 0) 1239 break; 1240 1241 if (i >= nattrs) 1242 return BadMatch; 1243 1244 attrId = pPriv->attrIds[i]; 1245 val = 0; 1246 1247 switch (attrId) { 1248 case ATTR_ENCODING_ID: 1249 z4l_ovly_get_encoding(pPriv, &val); 1250 *value = val; 1251 break; 1252 case ATTR_KEYMODE_ID: 1253 z4l_ovly_get_keymode(pPriv, &val); 1254 *value = val; 1255 break; 1256 case ATTR_COLORKEY_ID: 1257 z4l_ovly_get_colorkey(pPriv, &val); 1258 break; 1259 default: 1260 memset(&ctrl, 0, sizeof(ctrl)); 1261 ctrl.id = attrId + V4L2_CID_BASE; 1262 if (IoCtl(pPriv->fd, VIDIOC_G_CTRL, &ctrl, 1) != 0) 1263 return BadMatch; 1264 val = ctrl.value; 1265 break; 1266 } 1267 1268 if (old_fd < 0) 1269 z4l_close_device(pPriv); 1270 1271 *value = val; 1272 1273 return Success; 1274} 1275 1276static void (*oldAdjustFrame) (ADJUST_FRAME_ARGS_DECL) = NULL; 1277 1278static void 1279Z4lAdjustFrame(ADJUST_FRAME_ARGS_DECL) 1280{ 1281 SCRN_INFO_PTR(arg); 1282 int i; 1283 XF86VideoAdaptorPtr adpt; 1284 Z4lPortPrivRec *pPriv; 1285 1286 DBLOG(3, "Z4lAdjustFrame(%d,%d)\n", x, y); 1287 z4l_x_offset = x; 1288 z4l_y_offset = y; 1289 oldAdjustFrame(ADJUST_FRAME_ARGS(x, y)); 1290 1291 /* xv adjust does not handle putvideo case */ 1292 for (i = 0; i < Z4l_nAdaptors; ++i) { 1293 adpt = Z4l_pAdaptors[i]; 1294 pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr; 1295 if (pPriv->run > 0) { 1296 pPriv->drw_is_set = 0; 1297 z4l_ovly_rect(pPriv, 1298 pPriv->src_x, pPriv->src_y, pPriv->src_w, 1299 pPriv->src_h, pPriv->drw_x, pPriv->drw_y, 1300 pPriv->drw_w, pPriv->drw_h); 1301 } 1302 } 1303} 1304 1305static int 1306Z4lInit(ScrnInfoPtr pScrni, XF86VideoAdaptorPtr ** adaptors) 1307{ 1308 int i, id, fd, dev, enable, has_video, has_colorkey; 1309 int ctl, cinp, inp, std, fmt, has_image; 1310 int nadpts, nattrs, nencs, cenc, nimgs; 1311 int numer, denom, width, height; 1312 unsigned int pixfmt, cpixfmt, opixfmt; 1313 XF86VideoAdaptorPtr *adpts, adpt; 1314 XF86AttributePtr attrs, attr; 1315 XF86VideoEncodingPtr encs, enc; 1316 XF86ImagePtr ip, img, imgs; 1317 Z4lPortPrivRec *pPriv; 1318 char *dp, *msg; 1319 char enc_name[256], attr_name[256]; 1320 int attrIds[V4L2_CID_LASTP1 - V4L2_CID_BASE + ATTR_MAX_ID]; 1321 struct v4l2_capability capability; 1322 v4l2_std_id cstd_id, std_id; 1323 struct v4l2_standard standard; 1324 struct v4l2_format format, cfmt; 1325 struct v4l2_input input; 1326 struct v4l2_fmtdesc fmtdesc; 1327 struct v4l2_queryctrl queryctrl; 1328 struct v4l2_framebuffer fbuf; 1329 1330 DBLOG(1, "Init\n"); 1331 if (oldAdjustFrame == NULL) { 1332 oldAdjustFrame = pScrni->AdjustFrame; 1333 pScrni->AdjustFrame = Z4lAdjustFrame; 1334 } 1335 1336 fd = -1; 1337 enc = NULL; 1338 encs = NULL; 1339 nencs = 0; 1340 img = NULL; 1341 imgs = NULL; 1342 nimgs = 0; 1343 attr = NULL; 1344 attrs = NULL; 1345 nattrs = 0; 1346 adpt = NULL; 1347 adpts = NULL; 1348 nadpts = 0; 1349 has_video = has_image = has_colorkey = 0; 1350 1351 for (dev = 0; z4l_dev_paths[dev] != NULL; ++dev) { 1352 fd = open(z4l_dev_paths[dev], O_RDWR, 0); 1353 if (fd < 0) 1354 continue; 1355 DBLOG(1, "%s open ok\n", z4l_dev_paths[dev]); 1356 msg = NULL; 1357 enable = 1; 1358 if (IoCtl(fd, VIDIOC_QUERYCAP, &capability, 1) < 0) 1359 msg = "bad querycap"; 1360 else if ((capability.capabilities & V4L2_CAP_VIDEO_OVERLAY) == 0) 1361 msg = "no overlay"; 1362 else if ((capability.capabilities & V4L2_CAP_STREAMING) == 0) 1363 msg = "no streaming"; 1364#ifdef NONBLK_IO 1365 else if (IoCtl(fd, FIONBIO, &enable, 1) != 0) 1366 msg = "can't enable non-blocking io"; 1367#endif 1368 if (msg == NULL) { 1369 memset(&format, 0, sizeof(format)); 1370 format.type = 0x100; 1371 if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) != 0) 1372 msg = "no src/dst ovly fmt"; 1373 } 1374 if (msg != NULL) { 1375 DBLOG(0, "%s %s\n", z4l_dev_paths[dev], msg); 1376 close(fd); 1377 continue; 1378 } 1379 1380 memset(&cfmt, 0, sizeof(cfmt)); 1381 cfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1382 if (IoCtl(fd, VIDIOC_G_FMT, &cfmt, 1) < 0) 1383 goto fail; 1384 if (IoCtl(fd, VIDIOC_G_STD, &cstd_id, 1) < 0) 1385 goto fail; 1386 if (IoCtl(fd, VIDIOC_G_INPUT, &cinp, 1) < 0) 1387 goto fail; 1388 cpixfmt = cfmt.fmt.pix.pixelformat; 1389 cenc = 0; 1390 for (inp = 0;; ++inp) { 1391 memset(&input, 0, sizeof(input)); 1392 input.index = inp; 1393 if (IoCtl(fd, VIDIOC_ENUMINPUT, &input, 0) < 0) 1394 break; 1395 id = inp; 1396 if (IoCtl(fd, VIDIOC_S_INPUT, &id, 1) < 0) 1397 goto fail; 1398 for (std = 0;; ++std) { 1399 memset(&standard, 0, sizeof(standard)); 1400 standard.index = std; 1401 if (IoCtl(fd, VIDIOC_ENUMSTD, &standard, 0) < 0) 1402 break; 1403 std_id = standard.id; 1404 denom = standard.frameperiod.denominator; 1405 numer = standard.frameperiod.numerator; 1406 if (IoCtl(fd, VIDIOC_S_STD, &std_id, 1) < 0) 1407 continue; 1408 memset(&format, 0, sizeof(format)); 1409 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1410 if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) < 0) 1411 continue; 1412 width = format.fmt.pix.width; 1413 height = format.fmt.pix.height; 1414 for (fmt = 0;; ++fmt) { 1415 memset(&fmtdesc, 0, sizeof(fmtdesc)); 1416 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1417 fmtdesc.index = fmt; 1418 if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0) 1419 break; 1420 pixfmt = fmtdesc.pixelformat; 1421 ip = &pixfmts[0]; 1422 for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0; 1423 ++ip) 1424 if (z4l_fourcc_pixfmt(ip->id) == pixfmt) 1425 break; 1426 1427 if (i >= 0) { 1428 id = nencs; 1429 has_video = 1; 1430 if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL) 1431 goto fail; 1432 Z4lEncodingName(&enc_name[0], sizeof(enc_name), 1433 (char *) &input.name[0], 1434 (char *) &standard.name[0], 1435 (char *) &pixfmt); 1436 if (Z4lAddEncoding 1437 (enc, &enc_name[0], id, width, height, denom, numer, 1438 inp, std_id, pixfmt) == 0) 1439 goto fail; 1440 if (std_id == cstd_id && inp == cinp 1441 && pixfmt == cpixfmt) 1442 cenc = id; 1443 } 1444 } 1445 } 1446 } 1447 1448 if (IoCtl(fd, VIDIOC_S_INPUT, &cinp, 1) < 0) 1449 goto fail; 1450 if (IoCtl(fd, VIDIOC_S_STD, &cstd_id, 1) < 0) 1451 goto fail; 1452 if (IoCtl(fd, VIDIOC_S_FMT, &cfmt, 1) < 0) 1453 goto fail; 1454 1455 if (encs == NULL) { 1456 DBLOG(0, "no encodings\n"); 1457 goto fail; 1458 } 1459 1460 for (fmt = 0;; ++fmt) { 1461 memset(&fmtdesc, 0, sizeof(fmtdesc)); 1462 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 1463 fmtdesc.index = fmt; 1464 if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0) 1465 break; 1466 pixfmt = fmtdesc.pixelformat; 1467 ip = &pixfmts[0]; 1468 for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0; ++ip) 1469 if (z4l_fourcc_pixfmt(ip->id) == pixfmt) 1470 break; 1471 1472 if (i >= 0) { 1473 has_image = 1; 1474 if ((img = Z4lNewImage(&imgs, &nimgs)) == NULL) 1475 goto fail; 1476 if (Z4lAddImage(img, ip) == 0) 1477 goto fail; 1478 } 1479 } 1480 1481 if (nimgs > 0) { 1482 id = nencs; 1483 if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL) 1484 goto fail; 1485 if (Z4lAddEncoding(enc, "XV_IMAGE", id, MAX_OVLY_WIDTH, 1486 MAX_OVLY_HEIGHT, 0, 0, 0, 0, pixfmt) == 0) 1487 goto fail; 1488 } 1489 1490 ctl = 0; 1491 for (ctl = 0; ctl < (V4L2_CID_LASTP1 - V4L2_CID_BASE); ++ctl) { 1492 memset(&queryctrl, 0, sizeof(queryctrl)); 1493 queryctrl.id = V4L2_CID_BASE + ctl; 1494 if (IoCtl(fd, VIDIOC_QUERYCTRL, &queryctrl, 0) < 0) 1495 continue; 1496 if (queryctrl.type != V4L2_CTRL_TYPE_INTEGER && 1497 queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN) 1498 continue; 1499 attrIds[nattrs] = ctl; 1500 if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL) 1501 goto fail; 1502 Z4lAttributeName(&attr_name[0], sizeof(attr_name), 1503 (char *) &queryctrl.name[0]); 1504 if (Z4lAddAttribute(attr, &attr_name[0], 1505 queryctrl.minimum, queryctrl.maximum, 1506 XvSettable | XvGettable) == 0) 1507 goto fail; 1508 } 1509 attrIds[nattrs] = ATTR_ENCODING_ID; 1510 if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL) 1511 goto fail; 1512 Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_ENCODING); 1513 if (Z4lAddAttribute(attr, &attr_name[0], 0, nencs - 1, 1514 XvSettable | XvGettable) == 0) 1515 goto fail; 1516 memset(&fbuf, 0, sizeof(fbuf)); 1517 if (IoCtl(fd, VIDIOC_G_FBUF, &fbuf, 1) < 0) 1518 goto fail; 1519 opixfmt = fbuf.fmt.pixelformat; 1520 1521 if ((fbuf.capability & V4L2_FBUF_CAP_CHROMAKEY) != 0) { 1522 attrIds[nattrs] = ATTR_KEYMODE_ID; 1523 if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL) 1524 goto fail; 1525 Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_KEYMODE); 1526 if (Z4lAddAttribute(attr, &attr_name[0], 0, 1, 1527 XvSettable | XvGettable) == 0) 1528 goto fail; 1529 attrIds[nattrs] = ATTR_COLORKEY_ID; 1530 if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL) 1531 goto fail; 1532 Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_COLORKEY); 1533 if (Z4lAddAttribute(attr, &attr_name[0], 0, 0xffffff, 1534 XvSettable | XvGettable) == 0) 1535 goto fail; 1536 has_colorkey = 1; 1537 } 1538 1539 dp = malloc(strlen((char *) &capability.card[0]) + 1); 1540 if (dp == NULL) 1541 goto fail; 1542 strcpy(dp, (char *) &capability.card[0]); 1543 if ((adpt = Z4lNewAdaptor(&adpts, &nadpts, nattrs)) == NULL) 1544 goto fail; 1545 adpt->type = XvWindowMask | XvInputMask; 1546 if (has_video != 0) 1547 adpt->type |= XvVideoMask; 1548 if (has_image != 0) 1549 adpt->type |= XvImageMask; 1550 adpt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 1551 adpt->name = dp; 1552 adpt->type = XvInputMask | XvWindowMask | XvVideoMask | XvImageMask; 1553 adpt->pEncodings = encs; 1554 adpt->nEncodings = nencs; 1555 adpt->pFormats = &Formats[0]; 1556 adpt->nFormats = sizeof(Formats) / sizeof(Formats[0]); 1557 adpt->pAttributes = attrs; 1558 adpt->nAttributes = nattrs; 1559 attrs = NULL; 1560 nattrs = 0; 1561 adpt->pImages = imgs; 1562 adpt->nImages = nimgs; 1563 imgs = NULL; 1564 nimgs = 0; 1565 adpt->PutVideo = Z4lPutVideo; 1566 adpt->StopVideo = Z4lStopVideo; 1567 adpt->SetPortAttribute = Z4lSetPortAttribute; 1568 adpt->GetPortAttribute = Z4lGetPortAttribute; 1569 adpt->QueryBestSize = Z4lQueryBestSize; 1570 adpt->PutImage = Z4lPutImage; 1571 adpt->QueryImageAttributes = Z4lQueryImageAttributes; 1572 pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr; 1573 pPriv->fd = fd; 1574 pPriv->run = -1; 1575 pPriv->dir = 0; 1576 pPriv->nbfrs = -1; 1577 pPriv->bufsz = -1; 1578 pPriv->last = -1; 1579 pPriv->pixfmt = opixfmt; 1580#if defined(REGION_NULL) 1581 REGION_NULL(pScrni->pScreen, &pPriv->clips); 1582#else 1583 REGION_INIT(pScrni->pScreen, &pPriv->clips, NullBox, 0); 1584#endif 1585 strncpy(&pPriv->dev_path[0], z4l_dev_paths[dev], 1586 sizeof(pPriv->dev_path)); 1587 pPriv->enc = &encs[cenc]; 1588 for (i = 0; i < adpt->nAttributes; ++i) 1589 pPriv->attrIds[i] = attrIds[i]; 1590 DBLOG(1, "adpt %s\n", dp); 1591 if (has_colorkey != 0) { 1592 z4l_ovly_set_colorkey(pPriv, DEFAULT_COLORKEY); 1593 z4l_ovly_set_keymode(pPriv, DEFAULT_KEYMODE); 1594 } 1595 close(fd); 1596 pPriv->fd = -1; 1597 adpt = NULL; 1598 cenc = 0; 1599 encs = NULL; 1600 nencs = 0; 1601 } 1602 1603 DBLOG(0, "init done, %d device(s) found\n", nadpts); 1604 Z4l_nAdaptors = nadpts; 1605 Z4l_pAdaptors = adpts; 1606 *adaptors = adpts; 1607 1608 return nadpts; 1609 1610 fail: 1611 if (attrs != NULL) { 1612 for (i = 0; i < nattrs; ++i) 1613 if (attrs[i].name != NULL) 1614 free(attrs[i].name); 1615 free(attrs); 1616 } 1617 1618 if (encs != NULL) { 1619 for (i = 0; i < nencs; ++i) { 1620 if (encs[i].name != NULL) 1621 free(encs[i].name); 1622 } 1623 free(encs); 1624 } 1625 1626 if (imgs != NULL) 1627 free(imgs); 1628 1629 if (adpts != NULL) { 1630 for (i = 0; i < nadpts; ++i) { 1631 if ((adpt = adpts[i]) != NULL) { 1632 if (adpt->name != NULL) 1633 free(adpt->name); 1634 if ((attrs = adpt->pAttributes) != NULL) { 1635 for (i = 0; i < adpt->nAttributes; ++i) 1636 if (attrs[i].name != NULL) 1637 free(attrs[i].name); 1638 free(attrs); 1639 } 1640 if ((encs = adpt->pEncodings) != NULL) { 1641 for (i = 0; i < adpt->nEncodings; ++i, ++enc) 1642 if (encs[i].name != NULL) 1643 free(encs[i].name); 1644 free(encs); 1645 } 1646 if ((imgs = adpt->pImages) != NULL) 1647 free(imgs); 1648 free(adpt); 1649 } 1650 } 1651 free(adpts); 1652 } 1653 1654 if (fd >= 0) 1655 close(fd); 1656 1657 return 0; 1658} 1659 1660static Bool 1661Z4lProbe(DriverPtr drv, int flags) 1662{ 1663 DBLOG(1, "Probe\n"); 1664 if (flags & PROBE_DETECT) 1665 return TRUE; 1666 1667 xf86XVRegisterGenericAdaptorDriver(Z4lInit); 1668 drv->refCount++; 1669 1670 return TRUE; 1671} 1672 1673static const OptionInfoRec * 1674Z4lAvailableOptions(int chipid, int busid) 1675{ 1676 return NULL; 1677} 1678 1679static void 1680Z4lIdentify(int flags) 1681{ 1682 xf86Msg(X_INFO, "z4l driver for Video4Linux\n"); 1683} 1684 1685_X_EXPORT DriverRec Z4l = { 1686 40001, 1687 "z4l", 1688 Z4lIdentify, 1689 Z4lProbe, 1690 Z4lAvailableOptions, 1691 NULL, 1692 0 1693}; 1694 1695#ifdef XFree86LOADER 1696 1697static MODULESETUPPROTO(z4lSetup); 1698 1699static XF86ModuleVersionInfo z4lVersionRec = { 1700 "ztv", 1701 MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, 1702 XORG_VERSION_CURRENT, 0, 0, 1, 1703 ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_NONE, 1704 {0, 0, 0, 0} 1705}; 1706 1707_X_EXPORT XF86ModuleData ztvModuleData = { &z4lVersionRec, z4lSetup, NULL }; 1708 1709static pointer 1710z4lSetup(pointer module, pointer opts, int *errmaj, int *errmin) 1711{ 1712 static Bool setupDone = FALSE; 1713 1714 if (setupDone != FALSE) { 1715 if (errmaj != NULL) 1716 *errmaj = LDR_ONCEONLY; 1717 return NULL; 1718 } 1719 1720 setupDone = TRUE; 1721 xf86AddDriver(&Z4l, module, 0); 1722 return (pointer) 1; 1723} 1724 1725#endif 1726#endif /* !XvExtension */ 1727