1/* 2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> 3 All rights reserved. 4 5This file is part of x11vnc. 6 7x11vnc is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or (at 10your option) any later version. 11 12x11vnc is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with x11vnc; if not, write to the Free Software 19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 20or see <http://www.gnu.org/licenses/>. 21 22In addition, as a special exception, Karl J. Runge 23gives permission to link the code of its release of x11vnc with the 24OpenSSL project's "OpenSSL" library (or with modified versions of it 25that use the same license as the "OpenSSL" library), and distribute 26the linked executables. You must obey the GNU General Public License 27in all respects for all of the code used other than "OpenSSL". If you 28modify this file, you may extend this exception to your version of the 29file, but you are not obligated to do so. If you do not wish to do 30so, delete this exception statement from your version. 31*/ 32 33/* -- v4l.c -- */ 34 35#include "x11vnc.h" 36#include "cleanup.h" 37#include "scan.h" 38#include "xinerama.h" 39#include "screen.h" 40#include "connections.h" 41#include "keyboard.h" 42#include "allowed_input_t.h" 43 44#if LIBVNCSERVER_HAVE_LINUX_VIDEODEV_H 45#if LIBVNCSERVER_HAVE_SYS_IOCTL_H 46#include <sys/ioctl.h> 47#define CONFIG_VIDEO_V4L1_COMPAT 48#include <linux/videodev.h> 49#ifdef __LINUX_VIDEODEV2_H 50# ifndef HAVE_V4L2 51# define HAVE_V4L2 1 52# endif 53#endif 54#define V4L_OK 55#endif 56#endif 57 58char *v4l_guess(char *str, int *fd); 59void v4l_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client); 60void v4l_pointer_command(int mask, int x, int y, rfbClientPtr client); 61 62static int v4l1_val(int pct); 63static int v4l1_width(int w); 64static int v4l1_height(int h); 65static int v4l1_resize(int fd, int w, int h); 66static void v4l1_setfreq(int fd, unsigned long freq, int verb); 67static void v4l1_set_input(int fd, int which); 68static int v4l1_setfmt(int fd, char *fmt); 69static void apply_settings(char *dev, char *settings, int *fd); 70static int v4l1_dpct(int old, int d); 71static void v4l_requery(void); 72static void v4l_br(int b); 73static void v4l_hu(int b); 74static void v4l_co(int b); 75static void v4l_cn(int b); 76static void v4l_sz(int b); 77static void v4l_sta(int sta); 78static void v4l_inp(int inp); 79static void v4l_fmt(char *fmt); 80static int colon_n(char *line); 81static char *colon_str(char *line); 82static char *colon_tag(char *line); 83static void lookup_rgb(char *g_fmt, int *g_b, int *mask_rev); 84static char *v4l1_lu_palette(unsigned short palette); 85static unsigned short v4l1_lu_palette_str(char *name, int *bits, int *rev); 86static char *v4l2_lu_palette(unsigned int palette); 87static unsigned int v4l2_lu_palette_str(char *name, int *bits, int *rev); 88static int v4l1_query(int fd, int verbose); 89static int v4l2_query(int fd, int verbose); 90static int open_dev(char *dev); 91static char *guess_via_v4l(char *dev, int *fd); 92static char *guess_via_v4l_info(char *dev, int *fd); 93static void parse_str(char *str, char **dev, char **settings, char **atparms); 94static unsigned long lookup_freqtab(int sta); 95static unsigned long lookup_freq(int sta); 96static int lookup_station(unsigned long freq); 97static void init_freqtab(char *file); 98static void init_freqs(void); 99static void init_ntsc_cable(void); 100 101#define C_VIDEO_CAPTURE 1 102#define C_PICTURE 2 103#define C_WINDOW 3 104 105#ifdef V4L_OK 106static struct video_capability v4l1_capability; 107static struct video_channel v4l1_channel; 108static struct video_tuner v4l1_tuner; 109static struct video_picture v4l1_picture; 110static struct video_window v4l1_window; 111 112#if HAVE_V4L2 113static struct v4l2_capability v4l2_capability; 114static struct v4l2_input v4l2_input; 115static struct v4l2_tuner v4l2_tuner; 116static struct v4l2_fmtdesc v4l2_fmtdesc; 117static struct v4l2_format v4l2_format; 118/*static struct v4l2_framebuffer v4l2_fbuf; */ 119/*static struct v4l2_queryctrl v4l2_qctrl; */ 120#endif 121#endif 122 123static int v4l1_cap = -1; 124static int v4l2_cap = -1; 125#define V4L1_MAX 65535 126 127#define CHANNEL_MAX 500 128static unsigned long ntsc_cable[CHANNEL_MAX]; 129static unsigned long custom_freq[CHANNEL_MAX]; 130 131static unsigned long last_freq = 0; 132static int last_channel = 0; 133 134static int v4l1_val(int pct) { 135 /* pct is % */ 136 int val, max = V4L1_MAX; 137 if (pct < 0) { 138 return 0; 139 } else if (pct > 100) { 140 return max; 141 } 142 val = (pct * max)/100; 143 144 return val; 145} 146static int v4l1_width(int w) { 147#ifdef V4L_OK 148 int min = v4l1_capability.minwidth; 149 int max = v4l1_capability.maxwidth; 150 if (w < min) { 151 w = min; 152 } 153 if (w > max) { 154 w = max; 155 } 156#endif 157 return w; 158} 159static int v4l1_height(int h) { 160#ifdef V4L_OK 161 int min = v4l1_capability.minheight; 162 int max = v4l1_capability.maxheight; 163 if (h < min) { 164 h = min; 165 } 166 if (h > max) { 167 h = max; 168 } 169#endif 170 return h; 171} 172 173static int v4l1_resize(int fd, int w, int h) { 174#ifdef V4L_OK 175 int dowin = 0; 176 177 memset(&v4l1_window, 0, sizeof(v4l1_window)); 178 if (ioctl(fd, VIDIOCGWIN, &v4l1_window) == -1) { 179 return 0; 180 } 181 182 if (w > 0) w = v4l1_width(w); 183 184 if (w > 0 && w != (int) v4l1_window.width) { 185 dowin = 1; 186 } 187 188 if (h > 0) h = v4l1_height(h); 189 190 if (h > 0 && h != (int) v4l1_window.height) { 191 dowin = 1; 192 } 193 194 if (dowin) { 195 v4l1_window.x = 0; 196 v4l1_window.y = 0; 197 ioctl(fd, VIDIOCSWIN, &v4l1_window); 198 if (w > 0) v4l1_window.width = w; 199 if (h > 0) v4l1_window.height = h; 200 fprintf(stderr, "calling V4L_1: VIDIOCSWIN\n"); 201 fprintf(stderr, "trying new size %dx%d\n", 202 v4l1_window.width, v4l1_window.height); 203 if (ioctl(fd, VIDIOCSWIN, &v4l1_window) == -1) { 204 perror("ioctl VIDIOCSWIN"); 205 return 0; 206 } 207 } 208#else 209 if (!fd || !w || !h) {} 210#endif 211 return 1; 212} 213 214static void v4l1_setfreq(int fd, unsigned long freq, int verb) { 215#ifdef V4L_OK 216 unsigned long f0, f1; 217 f1 = (freq * 16) / 1000; 218 ioctl(fd, VIDIOCGFREQ, &f0); 219 if (verb) fprintf(stderr, "read freq: %d\n", (int) f0); 220 if (freq > 0) { 221 if (ioctl(fd, VIDIOCSFREQ, &f1) == -1) { 222 perror("ioctl VIDIOCSFREQ"); 223 } else { 224 ioctl(fd, VIDIOCGFREQ, &f0); 225 if (verb) fprintf(stderr, "read freq: %d\n", (int) f0); 226 last_freq = freq; 227 } 228 } 229#else 230 if (!fd || !freq || !verb) {} 231#endif 232} 233 234static void v4l1_set_input(int fd, int which) { 235#ifdef V4L_OK 236 if (which != -1) { 237 memset(&v4l1_channel, 0, sizeof(v4l1_channel)); 238 v4l1_channel.channel = which; 239 if (ioctl(fd, VIDIOCGCHAN, &v4l1_channel) != -1) { 240 v4l1_channel.channel = which; 241 fprintf(stderr, "setting input channel to %d: %s\n", 242 which, v4l1_channel.name); 243 last_channel = which; 244 ioctl(fd, VIDIOCSCHAN, &v4l1_channel); 245 } 246 } 247#else 248 if (!fd || !which) {} 249#endif 250} 251 252static int v4l1_setfmt(int fd, char *fmt) { 253#ifdef V4L_OK 254 unsigned short fnew; 255 int bnew, rnew; 256 257 fnew = v4l1_lu_palette_str(fmt, &bnew, &rnew); 258 if (fnew) { 259 v4l1_picture.depth = bnew; 260 v4l1_picture.palette = fnew; 261 } 262 fprintf(stderr, "calling V4L_1: VIDIOCSPICT\n"); 263 if (ioctl(fd, VIDIOCSPICT, &v4l1_picture) == -1) { 264 perror("ioctl VIDIOCSPICT"); 265 return 0; 266 } 267 if (raw_fb_pixfmt) { 268 free(raw_fb_pixfmt); 269 } 270 raw_fb_pixfmt = strdup(fmt); 271#else 272 if (!fd || !fmt) {} 273#endif 274 return 1; 275} 276 277static int ignore_all = 0; 278 279static void apply_settings(char *dev, char *settings, int *fd) { 280#ifdef V4L_OK 281 char *str, *p, *fmt = NULL, *tun = NULL, *inp = NULL; 282 int br = -1, co = -1, cn = -1, hu = -1; 283 int w = -1, h = -1, b = -1; 284 int sta = -1; 285 int setcnt = 0; 286 if (! settings || settings[0] == '\0') { 287 return; 288 } 289 str = strdup(settings); 290 p = strtok(str, ","); 291 while (p) { 292 if (strstr(p, "br=") == p) { 293 br = atoi(p+3); 294 if (br >= 0) setcnt++; 295 } else if (strstr(p, "co=") == p) { 296 co = atoi(p+3); 297 if (co >= 0) setcnt++; 298 } else if (strstr(p, "cn=") == p) { 299 cn = atoi(p+3); 300 if (cn >= 0) setcnt++; 301 } else if (strstr(p, "hu=") == p) { 302 hu = atoi(p+3); 303 if (hu >= 0) setcnt++; 304 } else if (strstr(p, "w=") == p) { 305 w = atoi(p+2); 306 if (w > 0) setcnt++; 307 } else if (strstr(p, "h=") == p) { 308 h = atoi(p+2); 309 if (h > 0) setcnt++; 310 } else if (strstr(p, "bpp=") == p) { 311 b = atoi(p+4); 312 if (b > 0) setcnt++; 313 } else if (strstr(p, "fmt=") == p) { 314 fmt = strdup(p+4); 315 setcnt++; 316 } else if (strstr(p, "tun=") == p) { 317 tun = strdup(p+4); 318 setcnt++; 319 } else if (strstr(p, "inp=") == p) { 320 inp = strdup(p+4); 321 setcnt++; 322 } else if (strstr(p, "sta=") == p) { 323 sta = atoi(p+4); 324 setcnt++; 325 } 326 p = strtok(NULL, ","); 327 } 328 free(str); 329 if (! setcnt) { 330 return; 331 } 332 if (*fd < 0) { 333 *fd = open_dev(dev); 334 } 335 if (*fd < 0) { 336 return; 337 } 338 v4l1_cap = v4l1_query(*fd, 1); 339 v4l2_cap = v4l2_query(*fd, 1); 340 341 if (v4l1_cap && ! ignore_all) { 342 if (br >= 0) v4l1_picture.brightness = v4l1_val(br); 343 if (hu >= 0) v4l1_picture.hue = v4l1_val(hu); 344 if (co >= 0) v4l1_picture.colour = v4l1_val(co); 345 if (cn >= 0) v4l1_picture.contrast = v4l1_val(cn); 346 347 fprintf(stderr, "calling V4L_1: VIDIOCSPICT\n"); 348 if (ioctl(*fd, VIDIOCSPICT, &v4l1_picture) == -1) { 349 perror("ioctl VIDIOCSPICT"); 350 } 351 352 if (fmt) { 353 v4l1_setfmt(*fd, fmt); 354 } else if (b > 0 && b != v4l1_picture.depth) { 355 if (b == 8) { 356 v4l1_setfmt(*fd, "HI240"); 357 } else if (b == 16) { 358 v4l1_setfmt(*fd, "RGB565"); 359 } else if (b == 24) { 360 v4l1_setfmt(*fd, "RGB24"); 361 } else if (b == 32) { 362 v4l1_setfmt(*fd, "RGB32"); 363 } 364 } 365 366 v4l1_resize(*fd, w, h); 367 368 if (tun) { 369 int mode = -1; 370 if (!strcasecmp(tun, "PAL")) { 371 mode = VIDEO_MODE_PAL; 372 } else if (!strcasecmp(tun, "NTSC")) { 373 mode = VIDEO_MODE_NTSC; 374 } else if (!strcasecmp(tun, "SECAM")) { 375 mode = VIDEO_MODE_SECAM; 376 } else if (!strcasecmp(tun, "AUTO")) { 377 mode = VIDEO_MODE_AUTO; 378 } 379 if (mode != -1) { 380 int i; 381 for (i=0; i< v4l1_capability.channels; i++) { 382 memset(&v4l1_channel, 0, sizeof(v4l1_channel)); 383 v4l1_channel.channel = i; 384 if (ioctl(*fd, VIDIOCGCHAN, &v4l1_channel) == -1) { 385 continue; 386 } 387 if (! v4l1_channel.tuners) { 388 continue; 389 } 390 if (v4l1_channel.norm == mode) { 391 continue; 392 } 393 v4l1_channel.norm = mode; 394 ioctl(*fd, VIDIOCSCHAN, &v4l1_channel); 395 } 396 } 397 } 398 if (inp) { 399 char s[2]; 400 int i, chan = -1; 401 402 s[0] = inp[0]; 403 s[1] = '\0'; 404 if (strstr("0123456789", s)) { 405 chan = atoi(inp); 406 } else { 407 for (i=0; i< v4l1_capability.channels; i++) { 408 memset(&v4l1_channel, 0, sizeof(v4l1_channel)); 409 v4l1_channel.channel = i; 410 if (ioctl(*fd, VIDIOCGCHAN, &v4l1_channel) == -1) { 411 continue; 412 } 413 if (!strcmp(v4l1_channel.name, inp)) { 414 chan = i; 415 break; 416 } 417 } 418 } 419 v4l1_set_input(*fd, chan); 420 } 421 if (sta >= 0) { 422 unsigned long freq = lookup_freq(sta); 423 v4l1_setfreq(*fd, freq, 1); 424 } 425 } 426 v4l1_cap = v4l1_query(*fd, 1); 427 v4l2_cap = v4l2_query(*fd, 1); 428#else 429 if (!dev || !settings || !fd) {} 430 return; 431#endif 432} 433 434static double dval = 0.05; 435 436static int v4l1_dpct(int old, int d) { 437 int newval, max = V4L1_MAX; 438 439 /* -1 and 1 are special cases for "small increments" */ 440 if (d == -1) { 441 newval = old - (int) (dval * max); 442 } else if (d == 1) { 443 newval = old + (int) (dval * max); 444 } else { 445 newval = (d * max)/100; 446 } 447 if (newval < 0) { 448 newval = 0; 449 } 450 if (newval > max) { 451 newval = max; 452 } 453 return newval; 454} 455 456static void v4l_requery(void) { 457 if (raw_fb_fd < 0) { 458 return; 459 } 460 v4l1_cap = v4l1_query(raw_fb_fd, 1); 461 v4l2_cap = v4l2_query(raw_fb_fd, 1); 462} 463 464static void v4l_br(int b) { 465#ifdef V4L_OK 466 int old = v4l1_picture.brightness; 467 468 v4l1_picture.brightness = v4l1_dpct(old, b); 469 ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture); 470 v4l_requery(); 471#else 472 if (!b) {} 473#endif 474} 475 476static void v4l_hu(int b) { 477#ifdef V4L_OK 478 int old = v4l1_picture.hue; 479 480 v4l1_picture.hue = v4l1_dpct(old, b); 481 ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture); 482 v4l_requery(); 483#else 484 if (!b) {} 485#endif 486} 487 488static void v4l_co(int b) { 489#ifdef V4L_OK 490 int old = v4l1_picture.colour; 491 492 v4l1_picture.colour = v4l1_dpct(old, b); 493 ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture); 494 v4l_requery(); 495#else 496 if (!b) {} 497#endif 498} 499 500static void v4l_cn(int b) { 501#ifdef V4L_OK 502 int old = v4l1_picture.contrast; 503 504 v4l1_picture.contrast = v4l1_dpct(old, b); 505 ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture); 506 v4l_requery(); 507#else 508 if (!b) {} 509#endif 510} 511 512static void v4l_sz(int b) { 513#ifdef V4L_OK 514 int w_old = v4l1_window.width; 515 int h_old = v4l1_window.height; 516 int w, h; 517 518 if (w_old == 0) { 519 w_old = 160; 520 } 521 if (h_old == 0) { 522 h_old = 120; 523 } 524 525 if (b == 1) { 526 w = w_old + (int) (0.15 * w_old); 527 h = h_old + (int) (0.15 * h_old); 528 } else if (b == -1) { 529 w = w_old - (int) (0.15 * w_old); 530 h = h_old - (int) (0.15 * h_old); 531 } else { 532 return; 533 } 534 535 if (! v4l1_resize(raw_fb_fd, w, h)) { 536 return; 537 } 538 539 v4l_requery(); 540 541 push_black_screen(4); 542 543 ignore_all = 1; 544 do_new_fb(1); 545 ignore_all = 0; 546#else 547 if (!b) {} 548#endif 549} 550 551static void v4l_sta(int sta) { 552#ifdef V4L_OK 553 unsigned long freq = 0; 554 int cur = lookup_station(last_freq); 555 556 if (! last_freq) { 557 if (sta == 0 || sta == -1) { 558 sta = 11; 559 } 560 } 561 562 if (sta == -1) { 563 while (cur > 0) { 564 freq = lookup_freq(--cur); 565 if (freq) { 566 break; 567 } 568 } 569 } else if (sta == 0) { 570 while (cur < CHANNEL_MAX - 1) { 571 freq = lookup_freq(++cur); 572 if (freq) { 573 break; 574 } 575 } 576 } else { 577 freq = lookup_freq(sta); 578 cur = sta; 579 } 580 fprintf(stderr, "to station %d / %d\n", cur, (int) freq); 581 v4l1_setfreq(raw_fb_fd, freq, 0); 582#else 583 if (!sta) {} 584#endif 585} 586 587static void v4l_inp(int inp) { 588#ifdef V4L_OK 589 int next = -1; 590 if (inp == -1) { 591 inp = last_channel + 1; 592 if (inp >= v4l1_capability.channels) { 593 inp = 0; 594 } 595 next = inp; 596 } else if (inp == -2) { 597 inp = last_channel - 1; 598 if (inp < 0) { 599 inp = v4l1_capability.channels - 1; 600 } 601 next = inp; 602 } else { 603 next = inp; 604 } 605 v4l1_set_input(raw_fb_fd, next); 606#else 607 if (!inp) {} 608#endif 609} 610 611static void v4l_fmt(char *fmt) { 612 if (v4l1_setfmt(raw_fb_fd, fmt)) { 613 v4l_requery(); 614 615 ignore_all = 1; 616 do_new_fb(1); 617 ignore_all = 0; 618 } 619} 620 621void v4l_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { 622 allowed_input_t input; 623 624 if (raw_fb_fd < 0) { 625 return; 626 } 627 if (! down) { 628 return; 629 } 630 if (view_only) { 631 return; 632 } 633 get_allowed_input(client, &input); 634 if (! input.keystroke) { 635 return; 636 } 637 638 if (keysym == XK_b) { 639 v4l_br(-1); 640 } else if (keysym == XK_B) { 641 v4l_br(+1); 642 } else if (keysym == XK_h) { 643 v4l_hu(-1); 644 } else if (keysym == XK_H) { 645 v4l_hu(+1); 646 } else if (keysym == XK_c) { 647 v4l_co(-1); 648 } else if (keysym == XK_C) { 649 v4l_co(+1); 650 } else if (keysym == XK_n) { 651 v4l_cn(-1); 652 } else if (keysym == XK_N) { 653 v4l_cn(+1); 654 } else if (keysym == XK_s) { 655 v4l_sz(-1); 656 } else if (keysym == XK_S) { 657 v4l_sz(+1); 658 } else if (keysym == XK_i) { 659 v4l_inp(-1); 660 } else if (keysym == XK_I) { 661 v4l_inp(-2); 662 } else if (keysym == XK_Up) { 663 v4l_sta(+0); 664 } else if (keysym == XK_Down) { 665 v4l_sta(-1); 666 } else if (keysym == XK_F1) { 667 v4l_fmt("HI240"); 668 } else if (keysym == XK_F2) { 669 v4l_fmt("RGB565"); 670 } else if (keysym == XK_F3) { 671 v4l_fmt("RGB24"); 672 } else if (keysym == XK_F4) { 673 v4l_fmt("RGB32"); 674 } else if (keysym == XK_F5) { 675 v4l_fmt("RGB555"); 676 } else if (keysym == XK_F6) { 677 v4l_fmt("GREY"); 678 } 679 if (client) {} 680} 681 682 683void v4l_pointer_command(int mask, int x, int y, rfbClientPtr client) { 684 /* do not forget viewonly perms */ 685 if (mask || x || y || client) {} 686} 687 688static int colon_n(char *line) { 689 char *q; 690 int n; 691 q = strrchr(line, ':'); 692 if (! q) { 693 return 0; 694 } 695 q = lblanks(q+1); 696 if (sscanf(q, "%d", &n) == 1) { 697 return n; 698 } 699 return 0; 700} 701 702static char *colon_str(char *line) { 703 char *q, *p, *t; 704 q = strrchr(line, ':'); 705 if (! q) { 706 return strdup(""); 707 } 708 q = lblanks(q+1); 709 p = strpbrk(q, " \t\n"); 710 if (p) { 711 *p = '\0'; 712 } 713 t = strdup(q); 714 *p = '\n'; 715 return t; 716} 717 718static char *colon_tag(char *line) { 719 char *q, *p, *t; 720 q = strrchr(line, '['); 721 if (! q) { 722 return strdup(""); 723 } 724 q++; 725 p = strrchr(q, ']'); 726 if (! p) { 727 return strdup(""); 728 } 729 *p = '\0'; 730 t = strdup(q); 731 *p = ']'; 732 return t; 733} 734 735static void lookup_rgb(char *fmt, int *bits, int *rev) { 736 int tb, tr; 737 738 if (v4l2_lu_palette_str(fmt, &tb, &tr)) { 739 *bits = tb; 740 *rev = tr; 741 return; 742 } 743 if (v4l1_lu_palette_str(fmt, &tb, &tr)) { 744 *bits = tb; 745 *rev = tr; 746 return; 747 } 748} 749 750static char *v4l1_lu_palette(unsigned short palette) { 751 switch(palette) { 752#ifdef V4L_OK 753 case VIDEO_PALETTE_GREY: return "GREY"; 754 case VIDEO_PALETTE_HI240: return "HI240"; 755 case VIDEO_PALETTE_RGB565: return "RGB565"; 756 case VIDEO_PALETTE_RGB24: return "RGB24"; 757 case VIDEO_PALETTE_RGB32: return "RGB32"; 758 case VIDEO_PALETTE_RGB555: return "RGB555"; 759 case VIDEO_PALETTE_YUV422: return "YUV422"; 760 case VIDEO_PALETTE_YUYV: return "YUYV"; 761 case VIDEO_PALETTE_UYVY: return "UYVY"; 762 case VIDEO_PALETTE_YUV420: return "YUV420"; 763 case VIDEO_PALETTE_YUV411: return "YUV411"; 764 case VIDEO_PALETTE_RAW: return "RAW"; 765 case VIDEO_PALETTE_YUV422P: return "YUV422P"; 766 case VIDEO_PALETTE_YUV411P: return "YUV411P"; 767 case VIDEO_PALETTE_YUV420P: return "YUV420P"; 768 case VIDEO_PALETTE_YUV410P: return "YUV410P"; 769#endif 770 default: return "unknown"; 771 } 772} 773 774static unsigned short v4l1_lu_palette_str(char *name, int *bits, int *rev) { 775#ifdef V4L_OK 776 *rev = 0; 777 if (!strcmp(name, "RGB555")) { 778 *bits = 16; 779 return VIDEO_PALETTE_RGB555; 780 } else if (!strcmp(name, "RGB565")) { 781 *bits = 16; 782 return VIDEO_PALETTE_RGB565; 783 } else if (!strcmp(name, "RGB24")) { 784 *bits = 24; 785 return VIDEO_PALETTE_RGB24; 786 } else if (!strcmp(name, "RGB32")) { 787 *bits = 32; 788 return VIDEO_PALETTE_RGB32; 789 } else if (!strcmp(name, "HI240")) { 790 *bits = 8; 791 return VIDEO_PALETTE_HI240; 792 } else if (!strcmp(name, "GREY")) { 793 *bits = 8; 794 return VIDEO_PALETTE_GREY; 795 } 796#else 797 if (!name || !bits || !rev) {} 798#endif 799 return 0; 800} 801 802static char *v4l2_lu_palette(unsigned int fmt) { 803 switch(fmt) { 804#if defined(V4L_OK) && HAVE_V4L2 805 case V4L2_PIX_FMT_RGB332: return "RGB332"; 806 case V4L2_PIX_FMT_RGB555: return "RGB555"; 807 case V4L2_PIX_FMT_RGB565: return "RGB565"; 808 case V4L2_PIX_FMT_RGB555X: return "RGB555X"; 809 case V4L2_PIX_FMT_RGB565X: return "RGB565X"; 810 case V4L2_PIX_FMT_BGR24: return "BGR24"; 811 case V4L2_PIX_FMT_RGB24: return "RGB24"; 812 case V4L2_PIX_FMT_BGR32: return "BGR32"; 813 case V4L2_PIX_FMT_RGB32: return "RGB32"; 814 case V4L2_PIX_FMT_GREY: return "GREY"; 815 case V4L2_PIX_FMT_YVU410: return "YVU410"; 816 case V4L2_PIX_FMT_YVU420: return "YVU420"; 817 case V4L2_PIX_FMT_YUYV: return "YUYV"; 818 case V4L2_PIX_FMT_UYVY: return "UYVY"; 819 case V4L2_PIX_FMT_YUV422P: return "YUV422P"; 820 case V4L2_PIX_FMT_YUV411P: return "YUV411P"; 821 case V4L2_PIX_FMT_Y41P: return "Y41P"; 822 case V4L2_PIX_FMT_NV12: return "NV12"; 823 case V4L2_PIX_FMT_NV21: return "NV21"; 824 case V4L2_PIX_FMT_YUV410: return "YUV410"; 825 case V4L2_PIX_FMT_YUV420: return "YUV420"; 826 case V4L2_PIX_FMT_YYUV: return "YYUV"; 827 case V4L2_PIX_FMT_HI240: return "HI240"; 828 case V4L2_PIX_FMT_MJPEG: return "MJPEG"; 829 case V4L2_PIX_FMT_JPEG: return "JPEG"; 830 case V4L2_PIX_FMT_DV: return "DV"; 831 case V4L2_PIX_FMT_MPEG: return "MPEG"; 832#endif 833 default: return "unknown"; 834 } 835} 836 837static unsigned int v4l2_lu_palette_str(char *name, int *bits, int *rev) { 838#if defined(V4L_OK) && HAVE_V4L2 839 if (!strcmp(name, "RGB1") || !strcmp(name, "RGB332")) { 840 *bits = 8; 841 *rev = 0; 842 return V4L2_PIX_FMT_RGB332; 843 } else if (!strcmp(name, "RGBO") || !strcmp(name, "RGB555")) { 844 *bits = 16; 845 *rev = 0; 846 return V4L2_PIX_FMT_RGB555; 847 } else if (!strcmp(name, "RGBP") || !strcmp(name, "RGB565")) { 848 *bits = 16; 849 *rev = 0; 850 return V4L2_PIX_FMT_RGB565; 851 } else if (!strcmp(name, "RGBQ") || !strcmp(name, "RGB555X")) { 852 *bits = 16; 853 *rev = 1; 854 return V4L2_PIX_FMT_RGB555X; 855 } else if (!strcmp(name, "RGBR") || !strcmp(name, "RGB565X")) { 856 *bits = 16; 857 *rev = 1; 858 return V4L2_PIX_FMT_RGB565X; 859 } else if (!strcmp(name, "BGR3") || !strcmp(name, "BGR24")) { 860 *bits = 24; 861 *rev = 1; 862 return V4L2_PIX_FMT_BGR24; 863 } else if (!strcmp(name, "RGB3") || !strcmp(name, "RGB24")) { 864 *bits = 24; 865 *rev = 0; 866 return V4L2_PIX_FMT_RGB24; 867 } else if (!strcmp(name, "BGR4") || !strcmp(name, "BGR32")) { 868 *bits = 32; 869 *rev = 1; 870 return V4L2_PIX_FMT_BGR32; 871 } else if (!strcmp(name, "RGB4") || !strcmp(name, "RGB32")) { 872 *bits = 32; 873 *rev = 0; 874 return V4L2_PIX_FMT_RGB32; 875 } else if (!strcmp(name, "GREY")) { 876 *bits = 8; 877 *rev = 0; 878 return V4L2_PIX_FMT_GREY; 879 } 880#else 881 if (!name || !bits || !rev) {} 882#endif 883 return 0; 884} 885 886static int v4l1_query(int fd, int v) { 887#ifdef V4L_OK 888 unsigned int i; 889 890 memset(&v4l1_capability, 0, sizeof(v4l1_capability)); 891 memset(&v4l1_channel, 0, sizeof(v4l1_channel)); 892 memset(&v4l1_tuner, 0, sizeof(v4l1_tuner)); 893 memset(&v4l1_picture, 0, sizeof(v4l1_picture)); 894 memset(&v4l1_window, 0, sizeof(v4l1_window)); 895 896 if (v) fprintf(stderr, "\nV4L_1 query:\n"); 897#ifdef VIDIOCGCAP 898 if (ioctl(fd, VIDIOCGCAP, &v4l1_capability) == -1) { 899 perror("ioctl VIDIOCGCAP"); 900 fprintf(stderr, "\n"); 901 return 0; 902 } 903#else 904 return 0; 905#endif 906 if (v) fprintf(stderr, "v4l-1 capability:\n"); 907 if (v) fprintf(stderr, " name: %s\n", v4l1_capability.name); 908 if (v) fprintf(stderr, " channels: %d\n", v4l1_capability.channels); 909 if (v) fprintf(stderr, " audios: %d\n", v4l1_capability.audios); 910 if (v) fprintf(stderr, " maxwidth: %d\n", v4l1_capability.maxwidth); 911 if (v) fprintf(stderr, " maxheight: %d\n", v4l1_capability.maxheight); 912 if (v) fprintf(stderr, " minwidth: %d\n", v4l1_capability.minwidth); 913 if (v) fprintf(stderr, " minheight: %d\n", v4l1_capability.minheight); 914 915 for (i=0; (int) i < v4l1_capability.channels; i++) { 916 char *type = "unknown"; 917 memset(&v4l1_channel, 0, sizeof(v4l1_channel)); 918 v4l1_channel.channel = i; 919 if (ioctl(fd, VIDIOCGCHAN, &v4l1_channel) == -1) { 920 perror("ioctl VIDIOCGCHAN"); 921 continue; 922 } 923 if (v4l1_channel.type == VIDEO_TYPE_TV) { 924 type = "TV"; 925 } else if (v4l1_channel.type == VIDEO_TYPE_CAMERA) { 926 type = "CAMERA"; 927 } 928 if (v) fprintf(stderr, " channel[%d]: %s\ttuners: %d norm: %d type: %d %s\n", 929 i, v4l1_channel.name, v4l1_channel.tuners, v4l1_channel.norm, 930 v4l1_channel.type, type); 931 } 932 933 memset(&v4l1_tuner, 0, sizeof(v4l1_tuner)); 934 if (ioctl(fd, VIDIOCGTUNER, &v4l1_tuner) != -1) { 935 char *mode = "unknown"; 936 if (v4l1_tuner.mode == VIDEO_MODE_PAL) { 937 mode = "PAL"; 938 } else if (v4l1_tuner.mode == VIDEO_MODE_NTSC) { 939 mode = "NTSC"; 940 } else if (v4l1_tuner.mode == VIDEO_MODE_SECAM) { 941 mode = "SECAM"; 942 } else if (v4l1_tuner.mode == VIDEO_MODE_AUTO) { 943 mode = "AUTO"; 944 } 945 946 if (v) fprintf(stderr, " tuner[%d]: %s\tflags: 0x%x mode: %s\n", 947 v4l1_tuner.tuner, v4l1_tuner.name, v4l1_tuner.flags, mode); 948 949 } 950 951 if (ioctl(fd, VIDIOCGPICT, &v4l1_picture) == -1) { 952 perror("ioctl VIDIOCGCHAN"); 953 return 0; 954 } 955 if (v) fprintf(stderr, "v4l-1 picture:\n"); 956 if (v) fprintf(stderr, " brightness: %d\n", v4l1_picture.brightness); 957 if (v) fprintf(stderr, " hue: %d\n", v4l1_picture.hue); 958 if (v) fprintf(stderr, " colour: %d\n", v4l1_picture.colour); 959 if (v) fprintf(stderr, " contrast: %d\n", v4l1_picture.contrast); 960 if (v) fprintf(stderr, " whiteness: %d\n", v4l1_picture.whiteness); 961 if (v) fprintf(stderr, " depth: %d\n", v4l1_picture.depth); 962 if (v) fprintf(stderr, " palette: %d %s\n", v4l1_picture.palette, 963 v4l1_lu_palette(v4l1_picture.palette)); 964 965 if (ioctl(fd, VIDIOCGWIN, &v4l1_window) == -1) { 966 perror("ioctl VIDIOCGWIN"); 967 if (v) fprintf(stderr, "\n"); 968 return 0; 969 } 970 if (v) fprintf(stderr, "v4l-1 window:\n"); 971 if (v) fprintf(stderr, " x: %d\n", v4l1_window.x); 972 if (v) fprintf(stderr, " y: %d\n", v4l1_window.y); 973 if (v) fprintf(stderr, " width: %d\n", v4l1_window.width); 974 if (v) fprintf(stderr, " height: %d\n", v4l1_window.height); 975 if (v) fprintf(stderr, " chromakey: %d\n", v4l1_window.chromakey); 976 if (v) fprintf(stderr, "\n"); 977 978 return 1; 979#else 980 if (!fd || !v) {} 981 return 0; 982#endif /* V4L_OK */ 983 984} 985static int v4l2_query(int fd, int v) { 986#if defined(V4L_OK) && HAVE_V4L2 987 unsigned int i; 988 989 memset(&v4l2_capability, 0, sizeof(v4l2_capability)); 990 memset(&v4l2_input, 0, sizeof(v4l2_input)); 991 memset(&v4l2_tuner, 0, sizeof(v4l2_tuner)); 992 memset(&v4l2_fmtdesc, 0, sizeof(v4l2_fmtdesc)); 993 memset(&v4l2_format, 0, sizeof(v4l2_format)); 994 995 if (v) fprintf(stderr, "\nV4L_2 query:\n"); 996#ifdef VIDIOC_QUERYCAP 997 if (ioctl(fd, VIDIOC_QUERYCAP, &v4l2_capability) == -1) { 998 perror("ioctl VIDIOC_QUERYCAP"); 999 if (v) fprintf(stderr, "\n"); 1000 return 0; 1001 } 1002#else 1003 return 0; 1004#endif 1005 1006 if (v) fprintf(stderr, "v4l-2 capability:\n"); 1007 if (v) fprintf(stderr, " driver: %s\n", v4l2_capability.driver); 1008 if (v) fprintf(stderr, " card: %s\n", v4l2_capability.card); 1009 if (v) fprintf(stderr, " bus_info: %s\n", v4l2_capability.bus_info); 1010 if (v) fprintf(stderr, " version: %d\n", v4l2_capability.version); 1011 if (v) fprintf(stderr, " capabilities: %u\n", v4l2_capability.capabilities); 1012 1013 for (i=0; ; i++) { 1014 memset(&v4l2_input, 0, sizeof(v4l2_input)); 1015 v4l2_input.index = i; 1016 if (ioctl(fd, VIDIOC_ENUMINPUT, &v4l2_input) == -1) { 1017 break; 1018 } 1019 if (v) fprintf(stderr, " input[%d]: %s\ttype: %d tuner: %d\n", 1020 i, v4l2_input.name, v4l2_input.type, v4l2_input.tuner); 1021 } 1022 if (v4l2_capability.capabilities & V4L2_CAP_TUNER) { 1023 for (i=0; ; i++) { 1024 memset(&v4l2_tuner, 0, sizeof(v4l2_tuner)); 1025 v4l2_tuner.index = i; 1026 if (ioctl(fd, VIDIOC_G_TUNER, &v4l2_tuner) == -1) { 1027 break; 1028 } 1029 if (v) fprintf(stderr, " tuner[%d]: %s\ttype: %d\n", 1030 i, v4l2_tuner.name, v4l2_tuner.type); 1031 } 1032 } 1033 if (v4l2_capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) { 1034 for (i=0; ; i++) { 1035 memset(&v4l2_fmtdesc, 0, sizeof(v4l2_fmtdesc)); 1036 v4l2_fmtdesc.index = i; 1037 v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1038 1039 if (ioctl(fd, VIDIOC_ENUM_FMT, &v4l2_fmtdesc) == -1) { 1040 break; 1041 } 1042 if (v) fprintf(stderr, " fmtdesc[%d]: %s\ttype: %d" 1043 " pixelformat: %d\n", 1044 i, v4l2_fmtdesc.description, v4l2_fmtdesc.type, 1045 v4l2_fmtdesc.pixelformat); 1046 } 1047 v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1048 if (ioctl(fd, VIDIOC_G_FMT, &v4l2_format) == -1) { 1049 perror("ioctl VIDIOC_G_FMT"); 1050 } else { 1051 if (v) fprintf(stderr, " width: %d\n", v4l2_format.fmt.pix.width); 1052 if (v) fprintf(stderr, " height: %d\n", v4l2_format.fmt.pix.height); 1053 if (v) fprintf(stderr, " format: %u %s\n", 1054 v4l2_format.fmt.pix.pixelformat, 1055 v4l2_lu_palette(v4l2_format.fmt.pix.pixelformat)); 1056 } 1057 } 1058 1059 return 1; 1060#else 1061 if (!fd || !v) {} 1062 return 0; 1063#endif /* V4L_OK && HAVE_V4L2 */ 1064 1065} 1066 1067static int open_dev(char *dev) { 1068 int dfd = -1; 1069 if (! dev) { 1070 return dfd; 1071 } 1072 dfd = open(dev, O_RDWR); 1073 if (dfd < 0) { 1074 rfbLog("failed to rawfb file: %s O_RDWR\n", dev); 1075 rfbLogPerror("open"); 1076 dfd = open(dev, O_RDONLY); 1077 } 1078 if (dfd < 0) { 1079 rfbLog("failed to rawfb file: %s\n", dev); 1080 rfbLog("failed to rawfb file: %s O_RDONLY\n", dev); 1081 rfbLogPerror("open"); 1082 } 1083 return dfd; 1084} 1085 1086static char *guess_via_v4l(char *dev, int *fd) { 1087#ifdef V4L_OK 1088 int dfd; 1089 1090 if (*fd < 0) { 1091 dfd = open_dev(dev); 1092 *fd = dfd; 1093 } 1094 dfd = *fd; 1095 if (dfd < 0) { 1096 return NULL; 1097 } 1098 if (v4l1_cap < 0) { 1099 v4l1_cap = v4l1_query(dfd, 1); 1100 } 1101 if (v4l2_cap < 0) { 1102 v4l2_cap = v4l2_query(dfd, 1); 1103 } 1104 1105 if (v4l2_cap) { 1106#if HAVE_V4L2 1107 int g_w = v4l2_format.fmt.pix.width; 1108 int g_h = v4l2_format.fmt.pix.height; 1109 int g_d = 0, g_rev; 1110 1111 if (v4l2_format.fmt.pix.pixelformat) { 1112 char *str = v4l2_lu_palette(v4l2_format.fmt.pix.pixelformat); 1113 if (strcmp(str, "unknown")) { 1114 v4l2_lu_palette_str(str, &g_d, &g_rev); 1115 } 1116 } 1117 1118 if (g_w > 0 && g_h > 0 && g_d > 0) { 1119 char *atparms = (char *) malloc(200); 1120 char *pal = v4l2_lu_palette(v4l2_format.fmt.pix.pixelformat); 1121 sprintf(atparms, "%dx%dx%d", g_w, g_h, g_d); 1122 if (strstr(pal, "RGB555")) { 1123 strcat(atparms, ":7c00/3e0/1f"); 1124 } 1125 *fd = dfd; 1126 return atparms; 1127 } 1128#endif 1129 } 1130 if (v4l1_cap) { 1131 int g_w = v4l1_window.width; 1132 int g_h = v4l1_window.height; 1133 int g_d = v4l1_picture.depth; 1134 int g_rev; 1135 if (g_d == 0) { 1136 char *str = v4l1_lu_palette(v4l1_picture.palette); 1137 if (strcmp(str, "unknown")) { 1138 v4l1_lu_palette_str(str, &g_d, &g_rev); 1139 } 1140 } 1141if (0) fprintf(stderr, "v4l1: %d %d %d\n", g_w, g_h, g_d); 1142 if (g_w > 0 && g_h > 0 && g_d > 0) { 1143 char *atparms = (char *) malloc(200); 1144 char *pal = v4l1_lu_palette(v4l1_picture.palette); 1145 fprintf(stderr, "palette: %s\n", pal); 1146 sprintf(atparms, "%dx%dx%d", g_w, g_h, g_d); 1147 if (strstr(pal, "RGB555")) { 1148 strcat(atparms, ":7c00/3e0/1f"); 1149 } 1150 *fd = dfd; 1151 return atparms; 1152 } 1153 } 1154 1155 /* failure */ 1156 close(dfd); 1157 return NULL; 1158#else 1159 if (!dev || !fd) {} 1160 return NULL; 1161#endif 1162} 1163 1164static char *guess_via_v4l_info(char *dev, int *fd) { 1165 char *atparms, *cmd; 1166 char line[1024], tmp[] = "/tmp/x11vnc-tmp.XXXXXX"; 1167 FILE *out; 1168 int tmp_fd, len, rc, curr = 0; 1169 int g_w = 0, g_h = 0, g_b = 0, mask_rev = 0; 1170 char *g_fmt = NULL; 1171 1172 if (*fd) {} 1173 1174 /* v4l-info */ 1175 if (no_external_cmds || !cmd_ok("v4l-info")) { 1176 rfbLog("guess_via_v4l_info: cannot run external " 1177 "command: v4l-info\n"); 1178 return NULL; 1179 } 1180 1181 if (strchr(dev, '\'')) { 1182 rfbLog("guess_via_v4l_info: bad dev string: %s\n", dev); 1183 return NULL; 1184 } 1185 1186 tmp_fd = mkstemp(tmp); 1187 if (tmp_fd < 0) { 1188 return NULL; 1189 } 1190 1191 len = strlen("v4l-info")+1+1+strlen(dev)+1+1+1+1+strlen(tmp)+1; 1192 cmd = (char *) malloc(len); 1193 rfbLog("guess_via_v4l_info running: v4l-info '%s'\n", dev); 1194 sprintf(cmd, "v4l-info '%s' > %s", dev, tmp); 1195 1196 close(tmp_fd); 1197 close_exec_fds(); 1198 rc = system(cmd); 1199 if (rc != 0) { 1200 unlink(tmp); 1201 return NULL; 1202 } 1203 1204 out = fopen(tmp, "r"); 1205 if (out == NULL) { 1206 unlink(tmp); 1207 return NULL; 1208 } 1209 1210 curr = 0; 1211 while (fgets(line, 1024, out) != NULL) { 1212 char *lb = lblanks(line); 1213 if (strstr(line, "video capture") == line) { 1214 curr = C_VIDEO_CAPTURE; 1215 } else if (strstr(line, "picture") == line) { 1216 curr = C_PICTURE; 1217 } else if (strstr(line, "window") == line) { 1218 curr = C_WINDOW; 1219 } 1220 1221if (0) fprintf(stderr, "lb: %s", lb); 1222 1223 if (curr == C_VIDEO_CAPTURE) { 1224 if (strstr(lb, "pixelformat ") == lb) { 1225 fprintf(stderr, "%s", line); 1226 } else if (strstr(lb, "fmt.pix.width ") == lb) { 1227 if (! g_w) { 1228 g_w = colon_n(line); 1229 } 1230 } else if (strstr(lb, "fmt.pix.height ") == lb) { 1231 if (! g_h) { 1232 g_h = colon_n(line); 1233 } 1234 } else if (strstr(lb, "fmt.pix.pixelformat ") == lb) { 1235 if (! g_fmt) { 1236 g_fmt = colon_tag(line); 1237 } 1238 } 1239 } else if (curr == C_PICTURE) { 1240 if (strstr(lb, "depth ") == lb) { 1241 if (! g_b) { 1242 g_b = colon_n(line); 1243 } 1244 } else if (strstr(lb, "palette ") == lb) { 1245 if (! g_fmt) { 1246 g_fmt = colon_str(line); 1247 } 1248 } 1249 } else if (curr == C_WINDOW) { 1250 if (strstr(lb, "width ") == lb) { 1251 if (! g_w) { 1252 g_w = colon_n(line); 1253 } 1254 } else if (strstr(lb, "height ") == lb) { 1255 if (! g_h) { 1256 g_h = colon_n(line); 1257 } 1258 } 1259 } 1260 } 1261 fclose(out); 1262 unlink(tmp); 1263 1264 if (! g_w) { 1265 rfbLog("could not guess device width.\n"); 1266 return NULL; 1267 } 1268 rfbLog("guessed device width: %d\n", g_w); 1269 1270 if (! g_h) { 1271 rfbLog("could not guess device height.\n"); 1272 return NULL; 1273 } 1274 rfbLog("guessed device height: %d\n", g_h); 1275 1276 if (g_fmt) { 1277 rfbLog("guessed pixel fmt: %s\n", g_fmt); 1278 lookup_rgb(g_fmt, &g_b, &mask_rev); 1279 } 1280 if (! g_b) { 1281 rfbLog("could not guess device bpp.\n"); 1282 return NULL; 1283 } 1284 rfbLog("guessed device bpp: %d\n", g_b); 1285 1286 atparms = (char *) malloc(100); 1287 sprintf(atparms, "%dx%dx%d", g_w, g_h, g_b); 1288 return atparms; 1289} 1290 1291static void parse_str(char *str, char **dev, char **settings, char **atparms) { 1292 char *p, *q, *s = NULL; 1293 1294 q = strchr(str, '@'); 1295 if (q && strlen(q+1) > 0) { 1296 /* ends @WxHXB... */ 1297 *atparms = strdup(q+1); 1298 *q = '\0'; 1299 } 1300 1301 q = strchr(str, ':'); 1302 if (q && strlen(q+1) > 0) { 1303 /* ends :br=N,w=N... */ 1304 s = strdup(q+1); 1305 *settings = s; 1306 *q = '\0'; 1307 } 1308 1309 if (s != NULL) { 1310 /* see if fn=filename */ 1311 q = strstr(s, "fn="); 1312 if (q) { 1313 q += strlen("fn="); 1314 p = strchr(q, ','); 1315 if (p) { 1316 *p = '\0'; 1317 *dev = strdup(q); 1318 *p = ','; 1319 } else { 1320 *dev = strdup(q); 1321 } 1322 rfbLog("set video device to: '%s'\n", *dev); 1323 } 1324 } 1325 1326 if (*dev == NULL) { 1327 struct stat sbuf; 1328 s = (char *) malloc(strlen("/dev/") + strlen(str) + 2); 1329 if (strstr(str, "/dev/") == str) { 1330 sprintf(s, "%s", str); 1331 } else { 1332 sprintf(s, "/dev/%s", str); 1333 } 1334 rfbLog("Checking existence of '%s'\n", s); 1335 if (stat(s, &sbuf) != 0) { 1336 rfbLogPerror("stat"); 1337 strcat(s, "0"); 1338 rfbLog("switching to '%s'\n", s); 1339 } 1340 if (stat(s, &sbuf) != 0) { 1341 rfbLogPerror("stat"); 1342 rfbLog("You will need to specify the video device more explicity.\n"); 1343 } 1344 1345 *dev = s; 1346 rfbLog("set video device to: '%s'\n", *dev); 1347 } 1348} 1349 1350char *v4l_guess(char *str, int *fd) { 1351 char *dev = NULL, *settings = NULL, *atparms = NULL; 1352 1353 parse_str(str, &dev, &settings, &atparms); 1354 1355 init_freqs(); 1356 1357 v4l1_cap = -1; 1358 v4l2_cap = -1; 1359 *fd = -1; 1360 1361 if (dev == NULL) { 1362 rfbLog("v4l_guess: could not find device in: %s\n", str); 1363 return NULL; 1364 } 1365 1366 if (settings) { 1367 apply_settings(dev, settings, fd); 1368 } 1369 1370 if (atparms) { 1371 /* use user's parameters. */ 1372 char *t = (char *) malloc(5+strlen(dev)+1+strlen(atparms)+1); 1373 sprintf(t, "snap:%s@%s", dev, atparms); 1374 return t; 1375 } 1376 1377 /* try to query the device for parameters. */ 1378 atparms = guess_via_v4l(dev, fd); 1379 if (atparms == NULL) { 1380 /* try again with v4l-info(1) */ 1381 atparms = guess_via_v4l_info(dev, fd); 1382 } 1383 1384 if (atparms == NULL) { 1385 /* bad news */ 1386 if (*fd >= 0) { 1387 close(*fd); 1388 } 1389 *fd = -1; 1390 return NULL; 1391 } else { 1392 char *t = (char *) malloc(5+strlen(dev)+1+strlen(atparms)+1); 1393 sprintf(t, "snap:%s@%s", dev, atparms); 1394 return t; 1395 } 1396} 1397 1398static unsigned long lookup_freqtab(int sta) { 1399 1400 if (sta >= CHANNEL_MAX) { 1401 return (unsigned long) sta; 1402 } 1403 if (sta < 0 || sta >= CHANNEL_MAX) { 1404 return 0; 1405 } 1406 return custom_freq[sta]; 1407} 1408 1409static unsigned long lookup_freq(int sta) { 1410 if (freqtab) { 1411 return lookup_freqtab(sta); 1412 } 1413 if (sta >= CHANNEL_MAX) { 1414 return (unsigned long) sta; 1415 } 1416 if (sta < 1 || sta > 125) { 1417 return 0; 1418 } 1419 return ntsc_cable[sta]; 1420} 1421 1422static int lookup_station(unsigned long freq) { 1423 int i; 1424 if (freqtab) { 1425 for (i = 0; i < CHANNEL_MAX; i++) { 1426if (0) fprintf(stderr, "%lu %lu\n", freq, custom_freq[i]); 1427 if (freq == custom_freq[i]) { 1428 return i; 1429 } 1430 } 1431 } else { 1432 for (i = 1; i <= 125; i++) { 1433 if (freq == ntsc_cable[i]) { 1434 return i; 1435 } 1436 } 1437 } 1438 return 0; 1439} 1440 1441static void init_freqtab(char *file) { 1442 char *p, *q, *dir, *file2; 1443 char line[1024], inc[1024]; 1444 char *text, *str; 1445 int size = 0, maxn, extra, currn; 1446 FILE *in1, *in2; 1447 static int v = 1; 1448 if (quiet) { 1449 v = 0; 1450 } 1451 1452 /* YUCK */ 1453 1454 dir = strdup(file); 1455 q = strrchr(dir, '/'); 1456 if (q) { 1457 *(q+1) = '\0'; 1458 } else { 1459 free(dir); 1460 dir = strdup("./"); 1461 } 1462 file2 = (char *) malloc(strlen(dir) + 1024 + 1); 1463 in1 = fopen(file, "r"); 1464 if (in1 == NULL) { 1465 rfbLog("error opening freqtab: %s\n", file); 1466 clean_up_exit(1); 1467 } 1468 if (v) fprintf(stderr, "loading frequencies from: %s\n", file); 1469 while (fgets(line, 1024, in1) != NULL) { 1470 char *lb; 1471 char line2[1024]; 1472 size += strlen(line); 1473 lb = lblanks(line); 1474 if (strstr(lb, "#include") == lb && 1475 sscanf(lb, "#include %s", inc) == 1) { 1476 char *q, *s = inc; 1477 if (s[0] == '"') { 1478 s++; 1479 } 1480 q = strrchr(s, '"'); 1481 if (q) { 1482 *q = '\0'; 1483 } 1484 sprintf(file2, "%s%s", dir, s); 1485 in2 = fopen(file2, "r"); 1486 if (in2 == NULL) { 1487 rfbLog("error opening freqtab include: %s %s\n", line, file2); 1488 clean_up_exit(1); 1489 } 1490 if (v) fprintf(stderr, "loading frequencies from: %s\n", file2); 1491 while (fgets(line2, 1024, in2) != NULL) { 1492 size += strlen(line2); 1493 } 1494 fclose(in2); 1495 } 1496 } 1497 fclose(in1); 1498 1499 size = 4*(size + 10000); 1500 1501 text = (char *) malloc(size); 1502 1503 text[0] = '\0'; 1504 1505 in1 = fopen(file, "r"); 1506 if (in1 == NULL) { 1507 rfbLog("error opening freqtab: %s\n", file); 1508 clean_up_exit(1); 1509 } 1510 while (fgets(line, 1024, in1) != NULL) { 1511 char *lb; 1512 char line2[1024]; 1513 lb = lblanks(line); 1514 if (lb[0] == '[') { 1515 strcat(text, lb); 1516 } else if (strstr(lb, "freq")) { 1517 strcat(text, lb); 1518 } else if (strstr(lb, "#include") == lb && 1519 sscanf(lb, "#include %s", inc) == 1) { 1520 char *lb2; 1521 char *q, *s = inc; 1522 if (s[0] == '"') { 1523 s++; 1524 } 1525 q = strrchr(s, '"'); 1526 if (q) { 1527 *q = '\0'; 1528 } 1529 sprintf(file2, "%s%s", dir, s); 1530 in2 = fopen(file2, "r"); 1531 if (in2 == NULL) { 1532 rfbLog("error opening freqtab include: %s %s\n", line, file2); 1533 clean_up_exit(1); 1534 } 1535 while (fgets(line2, 1024, in2) != NULL) { 1536 lb2 = lblanks(line2); 1537 if (lb2[0] == '[') { 1538 strcat(text, lb2); 1539 } else if (strstr(lb2, "freq")) { 1540 strcat(text, lb2); 1541 } 1542 if ((int) strlen(text) > size/2) { 1543 break; 1544 } 1545 } 1546 fclose(in2); 1547 } 1548 if ((int) strlen(text) > size/2) { 1549 break; 1550 } 1551 } 1552 fclose(in1); 1553 1554 if (0) fprintf(stderr, "%s", text); 1555 1556 str = strdup(text); 1557 p = strtok(str, "\n"); 1558 maxn = -1; 1559 extra = 0; 1560 while (p) { 1561 if (p[0] == '[') { 1562 int ok = 1; 1563 q = p+1; 1564 while (*q) { 1565 if (*q == ']') { 1566 break; 1567 } 1568 if (! isdigit((unsigned char) (*q))) { 1569 if (0) fprintf(stderr, "extra: %s\n", p); 1570 extra++; 1571 ok = 0; 1572 break; 1573 } 1574 q++; 1575 } 1576 if (ok) { 1577 int n; 1578 if (sscanf(p, "[%d]", &n) == 1) { 1579 if (n > maxn) { 1580 maxn = n; 1581 } 1582 if (0) fprintf(stderr, "maxn: %d %d\n", maxn, n); 1583 } 1584 } 1585 1586 } 1587 p = strtok(NULL, "\n"); 1588 } 1589 free(str); 1590 1591 str = strdup(text); 1592 p = strtok(str, "\n"); 1593 extra = 0; 1594 currn = 0; 1595 if (v) fprintf(stderr, "\nname\tstation\tfreq (KHz)\n"); 1596 while (p) { 1597 if (p[0] == '[') { 1598 int ok = 1; 1599 strncpy(line, p, 100); 1600 q = p+1; 1601 while (*q) { 1602 if (*q == ']') { 1603 break; 1604 } 1605 if (! isdigit((unsigned char) (*q))) { 1606 extra++; 1607 currn = maxn + extra; 1608 ok = 0; 1609 break; 1610 } 1611 q++; 1612 } 1613 if (ok) { 1614 int n; 1615 if (sscanf(p, "[%d]", &n) == 1) { 1616 currn = n; 1617 } 1618 } 1619 } 1620 if (strstr(p, "freq") && (q = strchr(p, '=')) != NULL) { 1621 int n; 1622 q = lblanks(q+1); 1623 if (sscanf(q, "%d", &n) == 1) { 1624 if (currn >= 0 && currn < CHANNEL_MAX) { 1625 if (v) fprintf(stderr, "%s\t%d\t%d\n", line, currn, n); 1626 custom_freq[currn] = (unsigned long) n; 1627 if (last_freq == 0) { 1628 last_freq = custom_freq[currn]; 1629 } 1630 } 1631 } 1632 } 1633 p = strtok(NULL, "\n"); 1634 } 1635 if (v) fprintf(stderr, "\n"); 1636 v = 0; 1637 free(str); 1638 free(text); 1639 free(dir); 1640 free(file2); 1641} 1642 1643static void init_freqs(void) { 1644 int i; 1645 for (i=0; i<CHANNEL_MAX; i++) { 1646 ntsc_cable[i] = 0; 1647 custom_freq[i] = 0; 1648 } 1649 1650 init_ntsc_cable(); 1651 last_freq = ntsc_cable[1]; 1652 1653 if (freqtab) { 1654 init_freqtab(freqtab); 1655 } 1656} 1657 1658static void init_ntsc_cable(void) { 1659 ntsc_cable[1] = 73250; 1660 ntsc_cable[2] = 55250; 1661 ntsc_cable[3] = 61250; 1662 ntsc_cable[4] = 67250; 1663 ntsc_cable[5] = 77250; 1664 ntsc_cable[6] = 83250; 1665 ntsc_cable[7] = 175250; 1666 ntsc_cable[8] = 181250; 1667 ntsc_cable[9] = 187250; 1668 ntsc_cable[10] = 193250; 1669 ntsc_cable[11] = 199250; 1670 ntsc_cable[12] = 205250; 1671 ntsc_cable[13] = 211250; 1672 ntsc_cable[14] = 121250; 1673 ntsc_cable[15] = 127250; 1674 ntsc_cable[16] = 133250; 1675 ntsc_cable[17] = 139250; 1676 ntsc_cable[18] = 145250; 1677 ntsc_cable[19] = 151250; 1678 ntsc_cable[20] = 157250; 1679 ntsc_cable[21] = 163250; 1680 ntsc_cable[22] = 169250; 1681 ntsc_cable[23] = 217250; 1682 ntsc_cable[24] = 223250; 1683 ntsc_cable[25] = 229250; 1684 ntsc_cable[26] = 235250; 1685 ntsc_cable[27] = 241250; 1686 ntsc_cable[28] = 247250; 1687 ntsc_cable[29] = 253250; 1688 ntsc_cable[30] = 259250; 1689 ntsc_cable[31] = 265250; 1690 ntsc_cable[32] = 271250; 1691 ntsc_cable[33] = 277250; 1692 ntsc_cable[34] = 283250; 1693 ntsc_cable[35] = 289250; 1694 ntsc_cable[36] = 295250; 1695 ntsc_cable[37] = 301250; 1696 ntsc_cable[38] = 307250; 1697 ntsc_cable[39] = 313250; 1698 ntsc_cable[40] = 319250; 1699 ntsc_cable[41] = 325250; 1700 ntsc_cable[42] = 331250; 1701 ntsc_cable[43] = 337250; 1702 ntsc_cable[44] = 343250; 1703 ntsc_cable[45] = 349250; 1704 ntsc_cable[46] = 355250; 1705 ntsc_cable[47] = 361250; 1706 ntsc_cable[48] = 367250; 1707 ntsc_cable[49] = 373250; 1708 ntsc_cable[50] = 379250; 1709 ntsc_cable[51] = 385250; 1710 ntsc_cable[52] = 391250; 1711 ntsc_cable[53] = 397250; 1712 ntsc_cable[54] = 403250; 1713 ntsc_cable[55] = 409250; 1714 ntsc_cable[56] = 415250; 1715 ntsc_cable[57] = 421250; 1716 ntsc_cable[58] = 427250; 1717 ntsc_cable[59] = 433250; 1718 ntsc_cable[60] = 439250; 1719 ntsc_cable[61] = 445250; 1720 ntsc_cable[62] = 451250; 1721 ntsc_cable[63] = 457250; 1722 ntsc_cable[64] = 463250; 1723 ntsc_cable[65] = 469250; 1724 ntsc_cable[66] = 475250; 1725 ntsc_cable[67] = 481250; 1726 ntsc_cable[68] = 487250; 1727 ntsc_cable[69] = 493250; 1728 ntsc_cable[70] = 499250; 1729 ntsc_cable[71] = 505250; 1730 ntsc_cable[72] = 511250; 1731 ntsc_cable[73] = 517250; 1732 ntsc_cable[74] = 523250; 1733 ntsc_cable[75] = 529250; 1734 ntsc_cable[76] = 535250; 1735 ntsc_cable[77] = 541250; 1736 ntsc_cable[78] = 547250; 1737 ntsc_cable[79] = 553250; 1738 ntsc_cable[80] = 559250; 1739 ntsc_cable[81] = 565250; 1740 ntsc_cable[82] = 571250; 1741 ntsc_cable[83] = 577250; 1742 ntsc_cable[84] = 583250; 1743 ntsc_cable[85] = 589250; 1744 ntsc_cable[86] = 595250; 1745 ntsc_cable[87] = 601250; 1746 ntsc_cable[88] = 607250; 1747 ntsc_cable[89] = 613250; 1748 ntsc_cable[90] = 619250; 1749 ntsc_cable[91] = 625250; 1750 ntsc_cable[92] = 631250; 1751 ntsc_cable[93] = 637250; 1752 ntsc_cable[94] = 643250; 1753 ntsc_cable[95] = 91250; 1754 ntsc_cable[96] = 97250; 1755 ntsc_cable[97] = 103250; 1756 ntsc_cable[98] = 109250; 1757 ntsc_cable[99] = 115250; 1758 ntsc_cable[100] = 649250; 1759 ntsc_cable[101] = 655250; 1760 ntsc_cable[102] = 661250; 1761 ntsc_cable[103] = 667250; 1762 ntsc_cable[104] = 673250; 1763 ntsc_cable[105] = 679250; 1764 ntsc_cable[106] = 685250; 1765 ntsc_cable[107] = 691250; 1766 ntsc_cable[108] = 697250; 1767 ntsc_cable[109] = 703250; 1768 ntsc_cable[110] = 709250; 1769 ntsc_cable[111] = 715250; 1770 ntsc_cable[112] = 721250; 1771 ntsc_cable[113] = 727250; 1772 ntsc_cable[114] = 733250; 1773 ntsc_cable[115] = 739250; 1774 ntsc_cable[116] = 745250; 1775 ntsc_cable[117] = 751250; 1776 ntsc_cable[118] = 757250; 1777 ntsc_cable[119] = 763250; 1778 ntsc_cable[120] = 769250; 1779 ntsc_cable[121] = 775250; 1780 ntsc_cable[122] = 781250; 1781 ntsc_cable[123] = 787250; 1782 ntsc_cable[124] = 793250; 1783 ntsc_cable[125] = 799250; 1784} 1785 1786