8
#include "connections.h"
10
#include "allowed_input_t.h"
12
#if LIBVNCSERVER_HAVE_LINUX_VIDEODEV_H
13
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
14
#include <sys/ioctl.h>
15
#define CONFIG_VIDEO_V4L1_COMPAT
16
#include <linux/videodev.h>
21
char *v4l_guess(char *str, int *fd);
22
void v4l_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
23
void v4l_pointer_command(int mask, int x, int y, rfbClientPtr client);
25
static int v4l1_val(int pct);
26
static int v4l1_width(int w);
27
static int v4l1_height(int h);
28
static int v4l1_resize(int fd, int w, int h);
29
static void v4l1_setfreq(int fd, unsigned long freq, int verb);
30
static void v4l1_set_input(int fd, int which);
31
static int v4l1_setfmt(int fd, char *fmt);
32
static void apply_settings(char *dev, char *settings, int *fd);
33
static int v4l1_dpct(int old, int d);
34
static void v4l_requery(void);
35
static void v4l_br(int b);
36
static void v4l_hu(int b);
37
static void v4l_co(int b);
38
static void v4l_cn(int b);
39
static void v4l_sz(int b);
40
static void v4l_sta(int sta);
41
static void v4l_inp(int inp);
42
static void v4l_fmt(char *fmt);
43
static int colon_n(char *line);
44
static char *colon_str(char *line);
45
static char *colon_tag(char *line);
46
static void lookup_rgb(char *g_fmt, int *g_b, int *mask_rev);
47
static char *v4l1_lu_palette(unsigned short palette);
48
static unsigned short v4l1_lu_palette_str(char *name, int *bits, int *rev);
49
static char *v4l2_lu_palette(unsigned int palette);
50
static unsigned int v4l2_lu_palette_str(char *name, int *bits, int *rev);
51
static int v4l1_query(int fd, int verbose);
52
static int v4l2_query(int fd, int verbose);
53
static int open_dev(char *dev);
54
static char *guess_via_v4l(char *dev, int *fd);
55
static char *guess_via_v4l_info(char *dev, int *fd);
56
static void parse_str(char *str, char **dev, char **settings, char **atparms);
57
static unsigned long lookup_freqtab(int sta);
58
static unsigned long lookup_freq(int sta);
59
static int lookup_station(unsigned long freq);
60
static void init_freqtab(char *file);
61
static void init_freqs(void);
62
static void init_ntsc_cable(void);
64
#define C_VIDEO_CAPTURE 1
69
static struct video_capability v4l1_capability;
70
static struct video_channel v4l1_channel;
71
static struct video_tuner v4l1_tuner;
72
static struct video_picture v4l1_picture;
73
static struct video_window v4l1_window;
76
static struct v4l2_capability v4l2_capability;
77
static struct v4l2_input v4l2_input;
78
static struct v4l2_tuner v4l2_tuner;
79
static struct v4l2_fmtdesc v4l2_fmtdesc;
80
static struct v4l2_format v4l2_format;
81
/*static struct v4l2_framebuffer v4l2_fbuf; */
82
/*static struct v4l2_queryctrl v4l2_qctrl; */
86
static int v4l1_cap = -1;
87
static int v4l2_cap = -1;
88
#define V4L1_MAX 65535
90
#define CHANNEL_MAX 500
91
static unsigned long ntsc_cable[CHANNEL_MAX];
92
static unsigned long custom_freq[CHANNEL_MAX];
94
static unsigned long last_freq = 0;
95
static int last_channel = 0;
97
static int v4l1_val(int pct) {
99
int val, max = V4L1_MAX;
102
} else if (pct > 100) {
105
val = (pct * max)/100;
109
static int v4l1_width(int w) {
111
int min = v4l1_capability.minwidth;
112
int max = v4l1_capability.maxwidth;
122
static int v4l1_height(int h) {
124
int min = v4l1_capability.minheight;
125
int max = v4l1_capability.maxheight;
136
static int v4l1_resize(int fd, int w, int h) {
140
memset(&v4l1_window, 0, sizeof(v4l1_window));
141
if (ioctl(fd, VIDIOCGWIN, &v4l1_window) == -1) {
145
if (w > 0) w = v4l1_width(w);
147
if (w > 0 && w != (int) v4l1_window.width) {
151
if (h > 0) h = v4l1_height(h);
153
if (h > 0 && h != (int) v4l1_window.height) {
160
ioctl(fd, VIDIOCSWIN, &v4l1_window);
161
if (w > 0) v4l1_window.width = w;
162
if (h > 0) v4l1_window.height = h;
163
fprintf(stderr, "calling V4L_1: VIDIOCSWIN\n");
164
fprintf(stderr, "trying new size %dx%d\n",
165
v4l1_window.width, v4l1_window.height);
166
if (ioctl(fd, VIDIOCSWIN, &v4l1_window) == -1) {
167
perror("ioctl VIDIOCSWIN");
172
if (!fd || !w || !h) {}
177
static void v4l1_setfreq(int fd, unsigned long freq, int verb) {
179
unsigned long f0, f1;
180
f1 = (freq * 16) / 1000;
181
ioctl(fd, VIDIOCGFREQ, &f0);
182
if (verb) fprintf(stderr, "read freq: %d\n", (int) f0);
184
if (ioctl(fd, VIDIOCSFREQ, &f1) == -1) {
185
perror("ioctl VIDIOCSFREQ");
187
ioctl(fd, VIDIOCGFREQ, &f0);
188
if (verb) fprintf(stderr, "read freq: %d\n", (int) f0);
193
if (!fd || !freq || !verb) {}
197
static void v4l1_set_input(int fd, int which) {
200
memset(&v4l1_channel, 0, sizeof(v4l1_channel));
201
v4l1_channel.channel = which;
202
if (ioctl(fd, VIDIOCGCHAN, &v4l1_channel) != -1) {
203
v4l1_channel.channel = which;
204
fprintf(stderr, "setting input channel to %d: %s\n",
205
which, v4l1_channel.name);
206
last_channel = which;
207
ioctl(fd, VIDIOCSCHAN, &v4l1_channel);
211
if (!fd || !which) {}
215
static int v4l1_setfmt(int fd, char *fmt) {
220
fnew = v4l1_lu_palette_str(fmt, &bnew, &rnew);
222
v4l1_picture.depth = bnew;
223
v4l1_picture.palette = fnew;
225
fprintf(stderr, "calling V4L_1: VIDIOCSPICT\n");
226
if (ioctl(fd, VIDIOCSPICT, &v4l1_picture) == -1) {
227
perror("ioctl VIDIOCSPICT");
233
raw_fb_pixfmt = strdup(fmt);
240
static int ignore_all = 0;
242
static void apply_settings(char *dev, char *settings, int *fd) {
244
char *str, *p, *fmt = NULL, *tun = NULL, *inp = NULL;
245
int br = -1, co = -1, cn = -1, hu = -1;
246
int w = -1, h = -1, b = -1;
249
if (! settings || settings[0] == '\0') {
252
str = strdup(settings);
253
p = strtok(str, ",");
255
if (strstr(p, "br=") == p) {
257
if (br >= 0) setcnt++;
258
} else if (strstr(p, "co=") == p) {
260
if (co >= 0) setcnt++;
261
} else if (strstr(p, "cn=") == p) {
263
if (cn >= 0) setcnt++;
264
} else if (strstr(p, "hu=") == p) {
266
if (hu >= 0) setcnt++;
267
} else if (strstr(p, "w=") == p) {
270
} else if (strstr(p, "h=") == p) {
273
} else if (strstr(p, "bpp=") == p) {
276
} else if (strstr(p, "fmt=") == p) {
279
} else if (strstr(p, "tun=") == p) {
282
} else if (strstr(p, "inp=") == p) {
285
} else if (strstr(p, "sta=") == p) {
289
p = strtok(NULL, ",");
301
v4l1_cap = v4l1_query(*fd, 1);
302
v4l2_cap = v4l2_query(*fd, 1);
304
if (v4l1_cap && ! ignore_all) {
305
if (br >= 0) v4l1_picture.brightness = v4l1_val(br);
306
if (hu >= 0) v4l1_picture.hue = v4l1_val(hu);
307
if (co >= 0) v4l1_picture.colour = v4l1_val(co);
308
if (cn >= 0) v4l1_picture.contrast = v4l1_val(cn);
310
fprintf(stderr, "calling V4L_1: VIDIOCSPICT\n");
311
if (ioctl(*fd, VIDIOCSPICT, &v4l1_picture) == -1) {
312
perror("ioctl VIDIOCSPICT");
316
v4l1_setfmt(*fd, fmt);
317
} else if (b > 0 && b != v4l1_picture.depth) {
319
v4l1_setfmt(*fd, "HI240");
320
} else if (b == 16) {
321
v4l1_setfmt(*fd, "RGB565");
322
} else if (b == 24) {
323
v4l1_setfmt(*fd, "RGB24");
324
} else if (b == 32) {
325
v4l1_setfmt(*fd, "RGB32");
329
v4l1_resize(*fd, w, h);
333
if (!strcasecmp(tun, "PAL")) {
334
mode = VIDEO_MODE_PAL;
335
} else if (!strcasecmp(tun, "NTSC")) {
336
mode = VIDEO_MODE_NTSC;
337
} else if (!strcasecmp(tun, "SECAM")) {
338
mode = VIDEO_MODE_SECAM;
339
} else if (!strcasecmp(tun, "AUTO")) {
340
mode = VIDEO_MODE_AUTO;
344
for (i=0; i< v4l1_capability.channels; i++) {
345
memset(&v4l1_channel, 0, sizeof(v4l1_channel));
346
v4l1_channel.channel = i;
347
if (ioctl(*fd, VIDIOCGCHAN, &v4l1_channel) == -1) {
350
if (! v4l1_channel.tuners) {
353
if (v4l1_channel.norm == mode) {
356
v4l1_channel.norm = mode;
357
ioctl(*fd, VIDIOCSCHAN, &v4l1_channel);
367
if (strstr("0123456789", s)) {
370
for (i=0; i< v4l1_capability.channels; i++) {
371
memset(&v4l1_channel, 0, sizeof(v4l1_channel));
372
v4l1_channel.channel = i;
373
if (ioctl(*fd, VIDIOCGCHAN, &v4l1_channel) == -1) {
376
if (!strcmp(v4l1_channel.name, inp)) {
382
v4l1_set_input(*fd, chan);
385
unsigned long freq = lookup_freq(sta);
386
v4l1_setfreq(*fd, freq, 1);
389
v4l1_cap = v4l1_query(*fd, 1);
390
v4l2_cap = v4l2_query(*fd, 1);
392
if (!dev || !settings || !fd) {}
397
static double dval = 0.05;
399
static int v4l1_dpct(int old, int d) {
400
int new, max = V4L1_MAX;
402
/* -1 and 1 are special cases for "small increments" */
404
new = old - (int) (dval * max);
406
new = old + (int) (dval * max);
419
static void v4l_requery(void) {
423
v4l1_cap = v4l1_query(raw_fb_fd, 1);
424
v4l2_cap = v4l2_query(raw_fb_fd, 1);
427
static void v4l_br(int b) {
429
int old = v4l1_picture.brightness;
431
v4l1_picture.brightness = v4l1_dpct(old, b);
432
ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture);
439
static void v4l_hu(int b) {
441
int old = v4l1_picture.hue;
443
v4l1_picture.hue = v4l1_dpct(old, b);
444
ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture);
451
static void v4l_co(int b) {
453
int old = v4l1_picture.colour;
455
v4l1_picture.colour = v4l1_dpct(old, b);
456
ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture);
463
static void v4l_cn(int b) {
465
int old = v4l1_picture.contrast;
467
v4l1_picture.contrast = v4l1_dpct(old, b);
468
ioctl(raw_fb_fd, VIDIOCSPICT, &v4l1_picture);
475
static void v4l_sz(int b) {
477
int w_old = v4l1_window.width;
478
int h_old = v4l1_window.height;
489
w = w_old + (int) (0.15 * w_old);
490
h = h_old + (int) (0.15 * h_old);
491
} else if (b == -1) {
492
w = w_old - (int) (0.15 * w_old);
493
h = h_old - (int) (0.15 * h_old);
498
if (! v4l1_resize(raw_fb_fd, w, h)) {
504
push_black_screen(4);
514
static void v4l_sta(int sta) {
516
unsigned long freq = 0;
517
int cur = lookup_station(last_freq);
520
if (sta == 0 || sta == -1) {
527
freq = lookup_freq(--cur);
532
} else if (sta == 0) {
533
while (cur < CHANNEL_MAX - 1) {
534
freq = lookup_freq(++cur);
540
freq = lookup_freq(sta);
543
fprintf(stderr, "to station %d / %d\n", cur, (int) freq);
544
v4l1_setfreq(raw_fb_fd, freq, 0);
550
static void v4l_inp(int inp) {
554
inp = last_channel + 1;
555
if (inp >= v4l1_capability.channels) {
559
} else if (inp == -2) {
560
inp = last_channel - 1;
562
inp = v4l1_capability.channels - 1;
568
v4l1_set_input(raw_fb_fd, next);
574
static void v4l_fmt(char *fmt) {
575
if (v4l1_setfmt(raw_fb_fd, fmt)) {
584
void v4l_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
585
allowed_input_t input;
596
get_allowed_input(client, &input);
597
if (! input.keystroke) {
601
if (keysym == XK_b) {
603
} else if (keysym == XK_B) {
605
} else if (keysym == XK_h) {
607
} else if (keysym == XK_H) {
609
} else if (keysym == XK_c) {
611
} else if (keysym == XK_C) {
613
} else if (keysym == XK_n) {
615
} else if (keysym == XK_N) {
617
} else if (keysym == XK_s) {
619
} else if (keysym == XK_S) {
621
} else if (keysym == XK_i) {
623
} else if (keysym == XK_I) {
625
} else if (keysym == XK_Up) {
627
} else if (keysym == XK_Down) {
629
} else if (keysym == XK_F1) {
631
} else if (keysym == XK_F2) {
633
} else if (keysym == XK_F3) {
635
} else if (keysym == XK_F4) {
637
} else if (keysym == XK_F5) {
639
} else if (keysym == XK_F6) {
646
void v4l_pointer_command(int mask, int x, int y, rfbClientPtr client) {
647
/* do not forget viewonly perms */
648
if (mask || x || y || client) {}
651
static int colon_n(char *line) {
654
q = strrchr(line, ':');
659
if (sscanf(q, "%d", &n) == 1) {
665
static char *colon_str(char *line) {
667
q = strrchr(line, ':');
672
p = strpbrk(q, " \t\n");
681
static char *colon_tag(char *line) {
683
q = strrchr(line, '[');
698
static void lookup_rgb(char *fmt, int *bits, int *rev) {
701
if (v4l2_lu_palette_str(fmt, &tb, &tr)) {
706
if (v4l1_lu_palette_str(fmt, &tb, &tr)) {
713
static char *v4l1_lu_palette(unsigned short palette) {
716
case VIDEO_PALETTE_GREY: return "GREY";
717
case VIDEO_PALETTE_HI240: return "HI240";
718
case VIDEO_PALETTE_RGB565: return "RGB565";
719
case VIDEO_PALETTE_RGB24: return "RGB24";
720
case VIDEO_PALETTE_RGB32: return "RGB32";
721
case VIDEO_PALETTE_RGB555: return "RGB555";
722
case VIDEO_PALETTE_YUV422: return "YUV422";
723
case VIDEO_PALETTE_YUYV: return "YUYV";
724
case VIDEO_PALETTE_UYVY: return "UYVY";
725
case VIDEO_PALETTE_YUV420: return "YUV420";
726
case VIDEO_PALETTE_YUV411: return "YUV411";
727
case VIDEO_PALETTE_RAW: return "RAW";
728
case VIDEO_PALETTE_YUV422P: return "YUV422P";
729
case VIDEO_PALETTE_YUV411P: return "YUV411P";
730
case VIDEO_PALETTE_YUV420P: return "YUV420P";
731
case VIDEO_PALETTE_YUV410P: return "YUV410P";
733
default: return "unknown";
737
static unsigned short v4l1_lu_palette_str(char *name, int *bits, int *rev) {
740
if (!strcmp(name, "RGB555")) {
742
return VIDEO_PALETTE_RGB555;
743
} else if (!strcmp(name, "RGB565")) {
745
return VIDEO_PALETTE_RGB565;
746
} else if (!strcmp(name, "RGB24")) {
748
return VIDEO_PALETTE_RGB24;
749
} else if (!strcmp(name, "RGB32")) {
751
return VIDEO_PALETTE_RGB32;
752
} else if (!strcmp(name, "HI240")) {
754
return VIDEO_PALETTE_HI240;
755
} else if (!strcmp(name, "GREY")) {
757
return VIDEO_PALETTE_GREY;
760
if (!name || !bits || !rev) {}
765
static char *v4l2_lu_palette(unsigned int fmt) {
767
#if defined(V4L_OK) && HAVE_V4L2
768
case V4L2_PIX_FMT_RGB332: return "RGB332";
769
case V4L2_PIX_FMT_RGB555: return "RGB555";
770
case V4L2_PIX_FMT_RGB565: return "RGB565";
771
case V4L2_PIX_FMT_RGB555X: return "RGB555X";
772
case V4L2_PIX_FMT_RGB565X: return "RGB565X";
773
case V4L2_PIX_FMT_BGR24: return "BGR24";
774
case V4L2_PIX_FMT_RGB24: return "RGB24";
775
case V4L2_PIX_FMT_BGR32: return "BGR32";
776
case V4L2_PIX_FMT_RGB32: return "RGB32";
777
case V4L2_PIX_FMT_GREY: return "GREY";
778
case V4L2_PIX_FMT_YVU410: return "YVU410";
779
case V4L2_PIX_FMT_YVU420: return "YVU420";
780
case V4L2_PIX_FMT_YUYV: return "YUYV";
781
case V4L2_PIX_FMT_UYVY: return "UYVY";
782
case V4L2_PIX_FMT_YUV422P: return "YUV422P";
783
case V4L2_PIX_FMT_YUV411P: return "YUV411P";
784
case V4L2_PIX_FMT_Y41P: return "Y41P";
785
case V4L2_PIX_FMT_NV12: return "NV12";
786
case V4L2_PIX_FMT_NV21: return "NV21";
787
case V4L2_PIX_FMT_YUV410: return "YUV410";
788
case V4L2_PIX_FMT_YUV420: return "YUV420";
789
case V4L2_PIX_FMT_YYUV: return "YYUV";
790
case V4L2_PIX_FMT_HI240: return "HI240";
791
case V4L2_PIX_FMT_MJPEG: return "MJPEG";
792
case V4L2_PIX_FMT_JPEG: return "JPEG";
793
case V4L2_PIX_FMT_DV: return "DV";
794
case V4L2_PIX_FMT_MPEG: return "MPEG";
796
default: return "unknown";
800
static unsigned int v4l2_lu_palette_str(char *name, int *bits, int *rev) {
801
#if defined(V4L_OK) && HAVE_V4L2
802
if (!strcmp(name, "RGB1") || !strcmp(name, "RGB332")) {
805
return V4L2_PIX_FMT_RGB332;
806
} else if (!strcmp(name, "RGBO") || !strcmp(name, "RGB555")) {
809
return V4L2_PIX_FMT_RGB555;
810
} else if (!strcmp(name, "RGBP") || !strcmp(name, "RGB565")) {
813
return V4L2_PIX_FMT_RGB565;
814
} else if (!strcmp(name, "RGBQ") || !strcmp(name, "RGB555X")) {
817
return V4L2_PIX_FMT_RGB555X;
818
} else if (!strcmp(name, "RGBR") || !strcmp(name, "RGB565X")) {
821
return V4L2_PIX_FMT_RGB565X;
822
} else if (!strcmp(name, "BGR3") || !strcmp(name, "BGR24")) {
825
return V4L2_PIX_FMT_BGR24;
826
} else if (!strcmp(name, "RGB3") || !strcmp(name, "RGB24")) {
829
return V4L2_PIX_FMT_RGB24;
830
} else if (!strcmp(name, "BGR4") || !strcmp(name, "BGR32")) {
833
return V4L2_PIX_FMT_BGR32;
834
} else if (!strcmp(name, "RGB4") || !strcmp(name, "RGB32")) {
837
return V4L2_PIX_FMT_RGB32;
838
} else if (!strcmp(name, "GREY")) {
841
return V4L2_PIX_FMT_GREY;
844
if (!name || !bits || !rev) {}
849
static int v4l1_query(int fd, int v) {
853
memset(&v4l1_capability, 0, sizeof(v4l1_capability));
854
memset(&v4l1_channel, 0, sizeof(v4l1_channel));
855
memset(&v4l1_tuner, 0, sizeof(v4l1_tuner));
856
memset(&v4l1_picture, 0, sizeof(v4l1_picture));
857
memset(&v4l1_window, 0, sizeof(v4l1_window));
859
if (v) fprintf(stderr, "\nV4L_1 query:\n");
861
if (ioctl(fd, VIDIOCGCAP, &v4l1_capability) == -1) {
862
perror("ioctl VIDIOCGCAP");
863
fprintf(stderr, "\n");
869
if (v) fprintf(stderr, "v4l-1 capability:\n");
870
if (v) fprintf(stderr, " name: %s\n", v4l1_capability.name);
871
if (v) fprintf(stderr, " channels: %d\n", v4l1_capability.channels);
872
if (v) fprintf(stderr, " audios: %d\n", v4l1_capability.audios);
873
if (v) fprintf(stderr, " maxwidth: %d\n", v4l1_capability.maxwidth);
874
if (v) fprintf(stderr, " maxheight: %d\n", v4l1_capability.maxheight);
875
if (v) fprintf(stderr, " minwidth: %d\n", v4l1_capability.minwidth);
876
if (v) fprintf(stderr, " minheight: %d\n", v4l1_capability.minheight);
878
for (i=0; (int) i < v4l1_capability.channels; i++) {
879
char *type = "unknown";
880
memset(&v4l1_channel, 0, sizeof(v4l1_channel));
881
v4l1_channel.channel = i;
882
if (ioctl(fd, VIDIOCGCHAN, &v4l1_channel) == -1) {
883
perror("ioctl VIDIOCGCHAN");
886
if (v4l1_channel.type == VIDEO_TYPE_TV) {
888
} else if (v4l1_channel.type == VIDEO_TYPE_CAMERA) {
891
if (v) fprintf(stderr, " channel[%d]: %s\ttuners: %d norm: %d type: %d %s\n",
892
i, v4l1_channel.name, v4l1_channel.tuners, v4l1_channel.norm,
893
v4l1_channel.type, type);
896
memset(&v4l1_tuner, 0, sizeof(v4l1_tuner));
897
if (ioctl(fd, VIDIOCGTUNER, &v4l1_tuner) != -1) {
898
char *mode = "unknown";
899
if (v4l1_tuner.mode == VIDEO_MODE_PAL) {
901
} else if (v4l1_tuner.mode == VIDEO_MODE_NTSC) {
903
} else if (v4l1_tuner.mode == VIDEO_MODE_SECAM) {
905
} else if (v4l1_tuner.mode == VIDEO_MODE_AUTO) {
909
if (v) fprintf(stderr, " tuner[%d]: %s\tflags: 0x%x mode: %s\n",
910
v4l1_tuner.tuner, v4l1_tuner.name, v4l1_tuner.flags, mode);
914
if (ioctl(fd, VIDIOCGPICT, &v4l1_picture) == -1) {
915
perror("ioctl VIDIOCGCHAN");
918
if (v) fprintf(stderr, "v4l-1 picture:\n");
919
if (v) fprintf(stderr, " brightness: %d\n", v4l1_picture.brightness);
920
if (v) fprintf(stderr, " hue: %d\n", v4l1_picture.hue);
921
if (v) fprintf(stderr, " colour: %d\n", v4l1_picture.colour);
922
if (v) fprintf(stderr, " contrast: %d\n", v4l1_picture.contrast);
923
if (v) fprintf(stderr, " whiteness: %d\n", v4l1_picture.whiteness);
924
if (v) fprintf(stderr, " depth: %d\n", v4l1_picture.depth);
925
if (v) fprintf(stderr, " palette: %d %s\n", v4l1_picture.palette,
926
v4l1_lu_palette(v4l1_picture.palette));
928
if (ioctl(fd, VIDIOCGWIN, &v4l1_window) == -1) {
929
perror("ioctl VIDIOCGWIN");
930
if (v) fprintf(stderr, "\n");
933
if (v) fprintf(stderr, "v4l-1 window:\n");
934
if (v) fprintf(stderr, " x: %d\n", v4l1_window.x);
935
if (v) fprintf(stderr, " y: %d\n", v4l1_window.y);
936
if (v) fprintf(stderr, " width: %d\n", v4l1_window.width);
937
if (v) fprintf(stderr, " height: %d\n", v4l1_window.height);
938
if (v) fprintf(stderr, " chromakey: %d\n", v4l1_window.chromakey);
939
if (v) fprintf(stderr, "\n");
948
static int v4l2_query(int fd, int v) {
949
#if defined(V4L_OK) && HAVE_V4L2
952
memset(&v4l2_capability, 0, sizeof(v4l2_capability));
953
memset(&v4l2_input, 0, sizeof(v4l2_input));
954
memset(&v4l2_tuner, 0, sizeof(v4l2_tuner));
955
memset(&v4l2_fmtdesc, 0, sizeof(v4l2_fmtdesc));
956
memset(&v4l2_format, 0, sizeof(v4l2_format));
958
if (v) fprintf(stderr, "\nV4L_2 query:\n");
959
#ifdef VIDIOC_QUERYCAP
960
if (ioctl(fd, VIDIOC_QUERYCAP, &v4l2_capability) == -1) {
961
perror("ioctl VIDIOC_QUERYCAP");
962
if (v) fprintf(stderr, "\n");
969
if (v) fprintf(stderr, "v4l-2 capability:\n");
970
if (v) fprintf(stderr, " driver: %s\n", v4l2_capability.driver);
971
if (v) fprintf(stderr, " card: %s\n", v4l2_capability.card);
972
if (v) fprintf(stderr, " bus_info: %s\n", v4l2_capability.bus_info);
973
if (v) fprintf(stderr, " version: %d\n", v4l2_capability.version);
974
if (v) fprintf(stderr, " capabilities: %u\n", v4l2_capability.capabilities);
977
memset(&v4l2_input, 0, sizeof(v4l2_input));
978
v4l2_input.index = i;
979
if (ioctl(fd, VIDIOC_ENUMINPUT, &v4l2_input) == -1) {
982
if (v) fprintf(stderr, " input[%d]: %s\ttype: %d tuner: %d\n",
983
i, v4l2_input.name, v4l2_input.type, v4l2_input.tuner);
985
if (v4l2_capability.capabilities & V4L2_CAP_TUNER) {
987
memset(&v4l2_tuner, 0, sizeof(v4l2_tuner));
988
v4l2_tuner.index = i;
989
if (ioctl(fd, VIDIOC_G_TUNER, &v4l2_tuner) == -1) {
992
if (v) fprintf(stderr, " tuner[%d]: %s\ttype: %d\n",
993
i, v4l2_tuner.name, v4l2_tuner.type);
996
if (v4l2_capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
998
memset(&v4l2_fmtdesc, 0, sizeof(v4l2_fmtdesc));
999
v4l2_fmtdesc.index = i;
1000
v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1002
if (ioctl(fd, VIDIOC_ENUM_FMT, &v4l2_fmtdesc) == -1) {
1005
if (v) fprintf(stderr, " fmtdesc[%d]: %s\ttype: %d"
1006
" pixelformat: %d\n",
1007
i, v4l2_fmtdesc.description, v4l2_fmtdesc.type,
1008
v4l2_fmtdesc.pixelformat);
1010
v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1011
if (ioctl(fd, VIDIOC_G_FMT, &v4l2_format) == -1) {
1012
perror("ioctl VIDIOC_G_FMT");
1014
if (v) fprintf(stderr, " width: %d\n", v4l2_format.fmt.pix.width);
1015
if (v) fprintf(stderr, " height: %d\n", v4l2_format.fmt.pix.height);
1016
if (v) fprintf(stderr, " format: %u %s\n",
1017
v4l2_format.fmt.pix.pixelformat,
1018
v4l2_lu_palette(v4l2_format.fmt.pix.pixelformat));
1026
#endif /* V4L_OK && HAVE_V4L2 */
1030
static int open_dev(char *dev) {
1035
dfd = open(dev, O_RDWR);
1037
rfbLog("failed to rawfb file: %s O_RDWR\n", dev);
1038
rfbLogPerror("open");
1039
dfd = open(dev, O_RDONLY);
1042
rfbLog("failed to rawfb file: %s\n", dev);
1043
rfbLog("failed to rawfb file: %s O_RDONLY\n", dev);
1044
rfbLogPerror("open");
1049
static char *guess_via_v4l(char *dev, int *fd) {
1054
dfd = open_dev(dev);
1062
v4l1_cap = v4l1_query(dfd, 1);
1065
v4l2_cap = v4l2_query(dfd, 1);
1070
int g_w = v4l2_format.fmt.pix.width;
1071
int g_h = v4l2_format.fmt.pix.height;
1074
if (v4l2_format.fmt.pix.pixelformat) {
1075
char *str = v4l2_lu_palette(v4l2_format.fmt.pix.pixelformat);
1076
if (strcmp(str, "unknown")) {
1077
v4l2_lu_palette_str(str, &g_d, &g_rev);
1081
if (g_w > 0 && g_h > 0 && g_d > 0) {
1082
char *atparms = (char *) malloc(200);
1083
char *pal = v4l2_lu_palette(v4l2_format.fmt.pix.pixelformat);
1084
sprintf(atparms, "%dx%dx%d", g_w, g_h, g_d);
1085
if (strstr(pal, "RGB555")) {
1086
strcat(atparms, ":7c00/3e0/1f");
1094
int g_w = v4l1_window.width;
1095
int g_h = v4l1_window.height;
1096
int g_d = v4l1_picture.depth;
1099
char *str = v4l1_lu_palette(v4l1_picture.palette);
1100
if (strcmp(str, "unknown")) {
1101
v4l1_lu_palette_str(str, &g_d, &g_rev);
1104
if (0) fprintf(stderr, "v4l1: %d %d %d\n", g_w, g_h, g_d);
1105
if (g_w > 0 && g_h > 0 && g_d > 0) {
1106
char *atparms = (char *) malloc(200);
1107
char *pal = v4l1_lu_palette(v4l1_picture.palette);
1108
fprintf(stderr, "palette: %s\n", pal);
1109
sprintf(atparms, "%dx%dx%d", g_w, g_h, g_d);
1110
if (strstr(pal, "RGB555")) {
1111
strcat(atparms, ":7c00/3e0/1f");
1127
static char *guess_via_v4l_info(char *dev, int *fd) {
1128
char *atparms, *cmd;
1129
char line[1024], tmp[] = "/tmp/x11vnc-tmp.XXXXXX";
1131
int tmp_fd, len, rc, curr = 0;
1132
int g_w = 0, g_h = 0, g_b = 0, mask_rev = 0;
1138
if (no_external_cmds || !cmd_ok("v4l-info")) {
1139
rfbLog("guess_via_v4l_info: cannot run external "
1140
"command: v4l-info\n");
1144
if (strchr(dev, '\'')) {
1145
rfbLog("guess_via_v4l_info: bad dev string: %s\n", dev);
1149
tmp_fd = mkstemp(tmp);
1154
len = strlen("v4l-info")+1+1+strlen(dev)+1+1+1+1+strlen(tmp)+1;
1155
cmd = (char *) malloc(len);
1156
rfbLog("guess_via_v4l_info running: v4l-info '%s'\n", dev);
1157
sprintf(cmd, "v4l-info '%s' > %s", dev, tmp);
1167
out = fopen(tmp, "r");
1174
while (fgets(line, 1024, out) != NULL) {
1175
char *lb = lblanks(line);
1176
if (strstr(line, "video capture") == line) {
1177
curr = C_VIDEO_CAPTURE;
1178
} else if (strstr(line, "picture") == line) {
1180
} else if (strstr(line, "window") == line) {
1184
if (0) fprintf(stderr, "lb: %s", lb);
1186
if (curr == C_VIDEO_CAPTURE) {
1187
if (strstr(lb, "pixelformat ") == lb) {
1188
fprintf(stderr, "%s", line);
1189
} else if (strstr(lb, "fmt.pix.width ") == lb) {
1191
g_w = colon_n(line);
1193
} else if (strstr(lb, "fmt.pix.height ") == lb) {
1195
g_h = colon_n(line);
1197
} else if (strstr(lb, "fmt.pix.pixelformat ") == lb) {
1199
g_fmt = colon_tag(line);
1202
} else if (curr == C_PICTURE) {
1203
if (strstr(lb, "depth ") == lb) {
1205
g_b = colon_n(line);
1207
} else if (strstr(lb, "palette ") == lb) {
1209
g_fmt = colon_str(line);
1212
} else if (curr == C_WINDOW) {
1213
if (strstr(lb, "width ") == lb) {
1215
g_w = colon_n(line);
1217
} else if (strstr(lb, "height ") == lb) {
1219
g_h = colon_n(line);
1228
rfbLog("could not guess device width.\n");
1231
rfbLog("guessed device width: %d\n", g_w);
1234
rfbLog("could not guess device height.\n");
1237
rfbLog("guessed device height: %d\n", g_h);
1240
rfbLog("guessed pixel fmt: %s\n", g_fmt);
1241
lookup_rgb(g_fmt, &g_b, &mask_rev);
1244
rfbLog("could not guess device bpp.\n");
1247
rfbLog("guessed device bpp: %d\n", g_b);
1249
atparms = (char *) malloc(100);
1250
sprintf(atparms, "%dx%dx%d", g_w, g_h, g_b);
1254
static void parse_str(char *str, char **dev, char **settings, char **atparms) {
1255
char *p, *q, *s = NULL;
1257
q = strchr(str, '@');
1258
if (q && strlen(q+1) > 0) {
1259
/* ends @WxHXB... */
1260
*atparms = strdup(q+1);
1264
q = strchr(str, ':');
1265
if (q && strlen(q+1) > 0) {
1266
/* ends :br=N,w=N... */
1273
/* see if fn=filename */
1274
q = strstr(s, "fn=");
1285
rfbLog("set video device to: '%s'\n", *dev);
1290
s = (char *) malloc(strlen("/dev/") + strlen(str) + 1);
1291
if (strstr(str, "/dev/") == str) {
1292
sprintf(s, "%s", str);
1294
sprintf(s, "/dev/%s", str);
1297
rfbLog("set video device to: '%s'\n", *dev);
1301
char *v4l_guess(char *str, int *fd) {
1302
char *dev = NULL, *settings = NULL, *atparms = NULL;
1304
parse_str(str, &dev, &settings, &atparms);
1313
rfbLog("v4l_guess: could not find device in: %s\n", str);
1318
apply_settings(dev, settings, fd);
1322
/* use user's parameters. */
1323
char *t = (char *) malloc(5+strlen(dev)+1+strlen(atparms)+1);
1324
sprintf(t, "snap:%s@%s", dev, atparms);
1328
/* try to query the device for parameters. */
1329
atparms = guess_via_v4l(dev, fd);
1330
if (atparms == NULL) {
1331
/* try again with v4l-info(1) */
1332
atparms = guess_via_v4l_info(dev, fd);
1335
if (atparms == NULL) {
1343
char *t = (char *) malloc(5+strlen(dev)+1+strlen(atparms)+1);
1344
sprintf(t, "snap:%s@%s", dev, atparms);
1349
static unsigned long lookup_freqtab(int sta) {
1351
if (sta >= CHANNEL_MAX) {
1352
return (unsigned long) sta;
1354
if (sta < 0 || sta >= CHANNEL_MAX) {
1357
return custom_freq[sta];
1360
static unsigned long lookup_freq(int sta) {
1362
return lookup_freqtab(sta);
1364
if (sta >= CHANNEL_MAX) {
1365
return (unsigned long) sta;
1367
if (sta < 1 || sta > 125) {
1370
return ntsc_cable[sta];
1373
static int lookup_station(unsigned long freq) {
1376
for (i = 0; i < CHANNEL_MAX; i++) {
1377
if (0) fprintf(stderr, "%lu %lu\n", freq, custom_freq[i]);
1378
if (freq == custom_freq[i]) {
1383
for (i = 1; i <= 125; i++) {
1384
if (freq == ntsc_cable[i]) {
1392
static void init_freqtab(char *file) {
1393
char *p, *q, *dir, *file2;
1394
char line[1024], inc[1024];
1396
int size = 0, maxn, extra, currn;
1406
q = strrchr(dir, '/');
1413
file2 = (char *) malloc(strlen(dir) + 1024 + 1);
1414
in1 = fopen(file, "r");
1416
rfbLog("error opening freqtab: %s\n", file);
1419
if (v) fprintf(stderr, "loading frequencies from: %s\n", file);
1420
while (fgets(line, 1024, in1) != NULL) {
1423
size += strlen(line);
1425
if (strstr(lb, "#include") == lb &&
1426
sscanf(lb, "#include %s", inc) == 1) {
1431
q = strrchr(s, '"');
1435
sprintf(file2, "%s%s", dir, s);
1436
in2 = fopen(file2, "r");
1438
rfbLog("error opening freqtab include: %s %s\n", line, file2);
1441
if (v) fprintf(stderr, "loading frequencies from: %s\n", file2);
1442
while (fgets(line2, 1024, in2) != NULL) {
1443
size += strlen(line2);
1450
size = 4*(size + 10000);
1452
text = (char *) malloc(size);
1456
in1 = fopen(file, "r");
1458
rfbLog("error opening freqtab: %s\n", file);
1461
while (fgets(line, 1024, in1) != NULL) {
1467
} else if (strstr(lb, "freq")) {
1469
} else if (strstr(lb, "#include") == lb &&
1470
sscanf(lb, "#include %s", inc) == 1) {
1476
q = strrchr(s, '"');
1480
sprintf(file2, "%s%s", dir, s);
1481
in2 = fopen(file2, "r");
1483
rfbLog("error opening freqtab include: %s %s\n", line, file2);
1486
while (fgets(line2, 1024, in2) != NULL) {
1487
lb2 = lblanks(line2);
1488
if (lb2[0] == '[') {
1490
} else if (strstr(lb2, "freq")) {
1493
if ((int) strlen(text) > size/2) {
1499
if ((int) strlen(text) > size/2) {
1505
if (0) fprintf(stderr, "%s", text);
1508
p = strtok(str, "\n");
1519
if (! isdigit((unsigned char) (*q))) {
1520
if (0) fprintf(stderr, "extra: %s\n", p);
1529
if (sscanf(p, "[%d]", &n) == 1) {
1533
if (0) fprintf(stderr, "maxn: %d %d\n", maxn, n);
1538
p = strtok(NULL, "\n");
1543
p = strtok(str, "\n");
1546
if (v) fprintf(stderr, "\nname\tstation\tfreq (KHz)\n");
1550
strncpy(line, p, 100);
1556
if (! isdigit((unsigned char) (*q))) {
1558
currn = maxn + extra;
1566
if (sscanf(p, "[%d]", &n) == 1) {
1571
if (strstr(p, "freq") && (q = strchr(p, '=')) != NULL) {
1574
if (sscanf(q, "%d", &n) == 1) {
1575
if (currn >= 0 && currn < CHANNEL_MAX) {
1576
if (v) fprintf(stderr, "%s\t%d\t%d\n", line, currn, n);
1577
custom_freq[currn] = (unsigned long) n;
1578
if (last_freq == 0) {
1579
last_freq = custom_freq[currn];
1584
p = strtok(NULL, "\n");
1586
if (v) fprintf(stderr, "\n");
1594
static void init_freqs(void) {
1596
for (i=0; i<CHANNEL_MAX; i++) {
1602
last_freq = ntsc_cable[1];
1605
init_freqtab(freqtab);
1609
static void init_ntsc_cable(void) {
1610
ntsc_cable[1] = 73250;
1611
ntsc_cable[2] = 55250;
1612
ntsc_cable[3] = 61250;
1613
ntsc_cable[4] = 67250;
1614
ntsc_cable[5] = 77250;
1615
ntsc_cable[6] = 83250;
1616
ntsc_cable[7] = 175250;
1617
ntsc_cable[8] = 181250;
1618
ntsc_cable[9] = 187250;
1619
ntsc_cable[10] = 193250;
1620
ntsc_cable[11] = 199250;
1621
ntsc_cable[12] = 205250;
1622
ntsc_cable[13] = 211250;
1623
ntsc_cable[14] = 121250;
1624
ntsc_cable[15] = 127250;
1625
ntsc_cable[16] = 133250;
1626
ntsc_cable[17] = 139250;
1627
ntsc_cable[18] = 145250;
1628
ntsc_cable[19] = 151250;
1629
ntsc_cable[20] = 157250;
1630
ntsc_cable[21] = 163250;
1631
ntsc_cable[22] = 169250;
1632
ntsc_cable[23] = 217250;
1633
ntsc_cable[24] = 223250;
1634
ntsc_cable[25] = 229250;
1635
ntsc_cable[26] = 235250;
1636
ntsc_cable[27] = 241250;
1637
ntsc_cable[28] = 247250;
1638
ntsc_cable[29] = 253250;
1639
ntsc_cable[30] = 259250;
1640
ntsc_cable[31] = 265250;
1641
ntsc_cable[32] = 271250;
1642
ntsc_cable[33] = 277250;
1643
ntsc_cable[34] = 283250;
1644
ntsc_cable[35] = 289250;
1645
ntsc_cable[36] = 295250;
1646
ntsc_cable[37] = 301250;
1647
ntsc_cable[38] = 307250;
1648
ntsc_cable[39] = 313250;
1649
ntsc_cable[40] = 319250;
1650
ntsc_cable[41] = 325250;
1651
ntsc_cable[42] = 331250;
1652
ntsc_cable[43] = 337250;
1653
ntsc_cable[44] = 343250;
1654
ntsc_cable[45] = 349250;
1655
ntsc_cable[46] = 355250;
1656
ntsc_cable[47] = 361250;
1657
ntsc_cable[48] = 367250;
1658
ntsc_cable[49] = 373250;
1659
ntsc_cable[50] = 379250;
1660
ntsc_cable[51] = 385250;
1661
ntsc_cable[52] = 391250;
1662
ntsc_cable[53] = 397250;
1663
ntsc_cable[54] = 403250;
1664
ntsc_cable[55] = 409250;
1665
ntsc_cable[56] = 415250;
1666
ntsc_cable[57] = 421250;
1667
ntsc_cable[58] = 427250;
1668
ntsc_cable[59] = 433250;
1669
ntsc_cable[60] = 439250;
1670
ntsc_cable[61] = 445250;
1671
ntsc_cable[62] = 451250;
1672
ntsc_cable[63] = 457250;
1673
ntsc_cable[64] = 463250;
1674
ntsc_cable[65] = 469250;
1675
ntsc_cable[66] = 475250;
1676
ntsc_cable[67] = 481250;
1677
ntsc_cable[68] = 487250;
1678
ntsc_cable[69] = 493250;
1679
ntsc_cable[70] = 499250;
1680
ntsc_cable[71] = 505250;
1681
ntsc_cable[72] = 511250;
1682
ntsc_cable[73] = 517250;
1683
ntsc_cable[74] = 523250;
1684
ntsc_cable[75] = 529250;
1685
ntsc_cable[76] = 535250;
1686
ntsc_cable[77] = 541250;
1687
ntsc_cable[78] = 547250;
1688
ntsc_cable[79] = 553250;
1689
ntsc_cable[80] = 559250;
1690
ntsc_cable[81] = 565250;
1691
ntsc_cable[82] = 571250;
1692
ntsc_cable[83] = 577250;
1693
ntsc_cable[84] = 583250;
1694
ntsc_cable[85] = 589250;
1695
ntsc_cable[86] = 595250;
1696
ntsc_cable[87] = 601250;
1697
ntsc_cable[88] = 607250;
1698
ntsc_cable[89] = 613250;
1699
ntsc_cable[90] = 619250;
1700
ntsc_cable[91] = 625250;
1701
ntsc_cable[92] = 631250;
1702
ntsc_cable[93] = 637250;
1703
ntsc_cable[94] = 643250;
1704
ntsc_cable[95] = 91250;
1705
ntsc_cable[96] = 97250;
1706
ntsc_cable[97] = 103250;
1707
ntsc_cable[98] = 109250;
1708
ntsc_cable[99] = 115250;
1709
ntsc_cable[100] = 649250;
1710
ntsc_cable[101] = 655250;
1711
ntsc_cable[102] = 661250;
1712
ntsc_cable[103] = 667250;
1713
ntsc_cable[104] = 673250;
1714
ntsc_cable[105] = 679250;
1715
ntsc_cable[106] = 685250;
1716
ntsc_cable[107] = 691250;
1717
ntsc_cable[108] = 697250;
1718
ntsc_cable[109] = 703250;
1719
ntsc_cable[110] = 709250;
1720
ntsc_cable[111] = 715250;
1721
ntsc_cable[112] = 721250;
1722
ntsc_cable[113] = 727250;
1723
ntsc_cable[114] = 733250;
1724
ntsc_cable[115] = 739250;
1725
ntsc_cable[116] = 745250;
1726
ntsc_cable[117] = 751250;
1727
ntsc_cable[118] = 757250;
1728
ntsc_cable[119] = 763250;
1729
ntsc_cable[120] = 769250;
1730
ntsc_cable[121] = 775250;
1731
ntsc_cable[122] = 781250;
1732
ntsc_cable[123] = 787250;
1733
ntsc_cable[124] = 793250;
1734
ntsc_cable[125] = 799250;