1 /*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5 This file is part of x11vnc.
6
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables. You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL". If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so. If you do not wish to do
30 so, 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
58 char *v4l_guess(char *str, int *fd);
59 void v4l_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
60 void v4l_pointer_command(int mask, int x, int y, rfbClientPtr client);
61
62 static int v4l1_val(int pct);
63 static int v4l1_width(int w);
64 static int v4l1_height(int h);
65 static int v4l1_resize(int fd, int w, int h);
66 static void v4l1_setfreq(int fd, unsigned long freq, int verb);
67 static void v4l1_set_input(int fd, int which);
68 static int v4l1_setfmt(int fd, char *fmt);
69 static void apply_settings(char *dev, char *settings, int *fd);
70 static int v4l1_dpct(int old, int d);
71 static void v4l_requery(void);
72 static void v4l_br(int b);
73 static void v4l_hu(int b);
74 static void v4l_co(int b);
75 static void v4l_cn(int b);
76 static void v4l_sz(int b);
77 static void v4l_sta(int sta);
78 static void v4l_inp(int inp);
79 static void v4l_fmt(char *fmt);
80 static int colon_n(char *line);
81 static char *colon_str(char *line);
82 static char *colon_tag(char *line);
83 static void lookup_rgb(char *g_fmt, int *g_b, int *mask_rev);
84 static char *v4l1_lu_palette(unsigned short palette);
85 static unsigned short v4l1_lu_palette_str(char *name, int *bits, int *rev);
86 static char *v4l2_lu_palette(unsigned int palette);
87 static unsigned int v4l2_lu_palette_str(char *name, int *bits, int *rev);
88 static int v4l1_query(int fd, int verbose);
89 static int v4l2_query(int fd, int verbose);
90 static int open_dev(char *dev);
91 static char *guess_via_v4l(char *dev, int *fd);
92 static char *guess_via_v4l_info(char *dev, int *fd);
93 static void parse_str(char *str, char **dev, char **settings, char **atparms);
94 static unsigned long lookup_freqtab(int sta);
95 static unsigned long lookup_freq(int sta);
96 static int lookup_station(unsigned long freq);
97 static void init_freqtab(char *file);
98 static void init_freqs(void);
99 static 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
106 static struct video_capability v4l1_capability;
107 static struct video_channel v4l1_channel;
108 static struct video_tuner v4l1_tuner;
109 static struct video_picture v4l1_picture;
110 static struct video_window v4l1_window;
111
112 #if HAVE_V4L2
113 static struct v4l2_capability v4l2_capability;
114 static struct v4l2_input v4l2_input;
115 static struct v4l2_tuner v4l2_tuner;
116 static struct v4l2_fmtdesc v4l2_fmtdesc;
117 static struct v4l2_format v4l2_format;
118 /*static struct v4l2_framebuffer v4l2_fbuf; */
119 /*static struct v4l2_queryctrl v4l2_qctrl; */
120 #endif
121 #endif
122
123 static int v4l1_cap = -1;
124 static int v4l2_cap = -1;
125 #define V4L1_MAX 65535
126
127 #define CHANNEL_MAX 500
128 static unsigned long ntsc_cable[CHANNEL_MAX];
129 static unsigned long custom_freq[CHANNEL_MAX];
130
131 static unsigned long last_freq = 0;
132 static int last_channel = 0;
133
v4l1_val(int pct)134 static 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 }
v4l1_width(int w)146 static 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 }
v4l1_height(int h)159 static 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
v4l1_resize(int fd,int w,int h)173 static 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
v4l1_setfreq(int fd,unsigned long freq,int verb)214 static 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
v4l1_set_input(int fd,int which)234 static 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
v4l1_setfmt(int fd,char * fmt)252 static 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
277 static int ignore_all = 0;
278
apply_settings(char * dev,char * settings,int * fd)279 static 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
434 static double dval = 0.05;
435
v4l1_dpct(int old,int d)436 static 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
v4l_requery(void)456 static 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
v4l_br(int b)464 static 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
v4l_hu(int b)476 static 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
v4l_co(int b)488 static 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
v4l_cn(int b)500 static 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
v4l_sz(int b)512 static 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
v4l_sta(int sta)551 static 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
v4l_inp(int inp)587 static 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
v4l_fmt(char * fmt)611 static 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
v4l_key_command(rfbBool down,rfbKeySym keysym,rfbClientPtr client)621 void 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
v4l_pointer_command(int mask,int x,int y,rfbClientPtr client)683 void 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
colon_n(char * line)688 static 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
colon_str(char * line)702 static 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
colon_tag(char * line)718 static 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
lookup_rgb(char * fmt,int * bits,int * rev)735 static 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
v4l1_lu_palette(unsigned short palette)750 static 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
v4l1_lu_palette_str(char * name,int * bits,int * rev)774 static 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
v4l2_lu_palette(unsigned int fmt)802 static 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
v4l2_lu_palette_str(char * name,int * bits,int * rev)837 static 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
v4l1_query(int fd,int v)886 static 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 }
v4l2_query(int fd,int v)985 static 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
open_dev(char * dev)1067 static 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
guess_via_v4l(char * dev,int * fd)1086 static 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 }
1141 if (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
guess_via_v4l_info(char * dev,int * fd)1164 static 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
1221 if (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
parse_str(char * str,char ** dev,char ** settings,char ** atparms)1291 static 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
v4l_guess(char * str,int * fd)1350 char *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
lookup_freqtab(int sta)1398 static 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
lookup_freq(int sta)1409 static 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
lookup_station(unsigned long freq)1422 static int lookup_station(unsigned long freq) {
1423 int i;
1424 if (freqtab) {
1425 for (i = 0; i < CHANNEL_MAX; i++) {
1426 if (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
init_freqtab(char * file)1441 static 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
init_freqs(void)1643 static 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
init_ntsc_cable(void)1658 static 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