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