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