OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / w3cam / w3cam.c
1 /*
2  * w3cam.c
3  *
4  * Copyright (C) 1998 - 2001 Rasca, Berlin
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <errno.h>
26 #ifdef USE_SYSLOG
27 #include <syslog.h>
28 #endif
29 #if defined __GLIBC__ && __GLIBC__ >= 2
30 #include <libgen.h>     /* basename */
31 #endif
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <sys/mman.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <linux/types.h>
39 #include <linux/videodev.h>
40 #ifdef HAVE_LIBZ
41 #include <zlib.h>
42 #endif
43 #ifdef HAVE_LIBPNG
44 #include <png.h>
45 #endif
46 #ifdef HAVE_LIBJPEG
47 #include <jpeglib.h>
48 #endif
49 #ifdef HAVE_LIBTTF
50 #include <freetype.h>
51 #endif
52 #include "w3cam.h"
53 #include "cgi.h"
54 #include "v4l.h"
55
56 /*
57  * some default values, change these to fit your needs
58  * most of these could be changed at runtime with config file
59  */
60 #define FMT_DEFAULT             FMT_JPEG        /* FMT_PPM, FMT_JPEG, FMT_PNG */
61 #define QUALITY_DEFAULT 65                      /* JPEG default quality */
62
63 #define WIDTH_DEFAULT   240                     /* default width and height of the image */
64 #define HEIGHT_DEFAULT  180
65
66 #define MODE_DEFAULT    MODE_PLAIN      /* MODE_GUI or MODE_PLAIN */
67 #define USEC_DEFAULT    20000           /* wait microseconds before capturing */
68 #define REFRESH_DEFAULT OFF                     /* don't use refreshing */
69 #define MIN_REFRESH             0.0                     /* min refresh time, compile time option */
70 #define FREQLIST_DEFAULT "878;9076;9844;9460"   /* default frequenzies */
71 #define MAX_TRY_OPEN    20                      /* may be the device is locked, so try max*/
72 /* end of default values
73  * *********************
74  */
75
76
77 /*
78  */
79 void
80 usage (char *pname, int width, int height, int color, int quality, int usec)
81 {
82         cgi_response (http_bad_request, "text/html");
83         printf (
84         "<title>w3cam - help</title><pre>W3Cam, Version %s\n\n"
85         "Usage: %s<?parameters>\n"
86         "CGI parameters (GET or POST):\n"
87         " help                                    show this page\n"
88         " size=#x#                                geometry of picture "
89                 "[default = %dx%d]\n"
90         " color={0|1}                             color or grey mode "
91                 "[default = %d]\n"
92         " input={tv|composite|composite2|s-video} define input source\n"
93         " quality={1-100}                         jpeg quality "
94                 "[default = %d]\n"
95         " format={ppm|png|jpeg}                   output format\n"
96         " freq=#                                  define frequenzy for TV\n"
97         " usleep=#                                sleep # micro secs before cap. "
98                 "[default = %d]\n"
99         " mode=[gui|html]                         build a page with panel or plain html\n"
100         " refresh=#.#                             time in sec to refresh gui\n"
101         " norm={pal|ntsc|secam}                   tv norm\n"
102         " bgr={1|0}                               swap RGB to BGR (default: no)\n",
103         VERSION, basename(pname), width, height, color, quality, usec);
104         printf (
105         "\nCompiled in features:\n");
106 #ifdef HAVE_LIBPNG
107         printf (" PNG file format\n");
108 #endif
109 #ifdef HAVE_LIBJPEG
110         printf (" JPEG file format\n");
111 #endif
112 #ifdef HAVE_LIBTTF
113         printf ( " TTF/TimeStamp\n");
114 #endif
115 #ifdef USE_SYSLOG
116         printf ( " SYSLOG support\n");
117 #endif
118         exit (0);
119 }
120
121 /*
122  */
123 void
124 log (char *info)
125 {
126 #ifdef USE_SYSLOG
127         syslog (LOG_USER, "%s\n", info);
128 #else
129         fprintf (stderr, "%s\n", info);
130 #endif
131 }
132
133 /*
134  */
135 void
136 log2 (char *s1, char *s2)
137 {
138 #ifdef USE_SYSLOG
139         syslog (LOG_USER, "%s %s\n", s1, s2);
140 #else
141         fprintf (stderr, "%s %s\n", s1, s2);
142 #endif
143 }
144
145 /*
146  * parse comma seperated frequency list
147  */
148 char **
149 parse_list (char *freqs)
150 {
151         char **flist = NULL;
152         char *p = freqs, *end = NULL;
153         int num = 0, i, len;
154
155         if (!freqs)
156                 return (NULL);
157         while ((p = strchr(p, ';')) != NULL) {
158                 p++;
159                 num++;
160         }
161         num++;
162         flist = malloc ((num + 1) * sizeof (char *));
163         flist[num] = NULL;
164         p = freqs;
165         for (i = 0; i < num; i++) {
166                 if (i == (num-1)) {
167                         /* last element */
168                         len = strlen (p);
169                 } else {
170                         end = strchr(p, ';');
171                         len = end - p;
172                 }
173                 flist[i] = malloc (len+1);
174                 strncpy (flist[i], p, len);
175                 p = end+1;
176         }
177         return (flist);
178 }
179
180 /*
181  * read rgb image from v4l device
182  * return: new allocated buffer
183  */
184 unsigned char *
185 get_image (int dev, int width, int height, int input, int usec,
186                         unsigned long freq, int palette)
187 {
188         struct video_mbuf vid_buf;
189         struct video_mmap vid_mmap;
190         char *map;
191         unsigned char *buff;
192         int size, len, bpp;
193         register int i;
194
195         if (input == IN_TV) {
196                 if (freq > 0) {
197                         if (ioctl (dev, VIDIOCSFREQ, &freq) == -1)
198                                 log2 ("ioctl (VIDIOCSREQ):", strerror(errno));
199                 }
200         }
201
202         /* it seems some cards need a little bit time to come in
203                 sync with the new settings */
204         if (usec)
205                 usleep (usec);
206
207         if (palette != VIDEO_PALETTE_GREY) {
208                 /* RGB or YUV */
209                 size = width * height * 3;
210                 bpp = 3;
211         } else {
212                 size = width * height * 1;
213                 bpp = 1;
214         }
215         vid_mmap.format = palette;
216
217         if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) {
218                 /* do a normal read()
219                  */
220                 struct video_window vid_win;
221
222                 if (ioctl (dev, VIDIOCGWIN, &vid_win) != -1) {
223                         vid_win.width  = width;
224                         vid_win.height = height;
225                         if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) {
226                                 log2 ("ioctl(VIDIOCSWIN):", strerror(errno));
227                                 return (NULL);
228                         }
229                 }
230                 map = malloc (size);
231                 if (!map)
232                         return (NULL);
233                 
234                 len = read (dev, map, size);
235                 if (len <= 0) {
236                         free (map);
237                         return NULL;
238                 }
239                 if (palette == VIDEO_PALETTE_YUV420P) {
240                         char *convmap;
241             convmap = malloc ( width * height * bpp );
242             v4l_yuv420p2rgb (convmap, map, width, height, bpp * 8);
243             memcpy (map, convmap, (size_t) width * height * bpp);
244             free (convmap);
245         } else if (palette == VIDEO_PALETTE_YUV422P) {
246                         char *convmap;
247             convmap = malloc ( width * height * bpp );
248             v4l_yuv422p2rgb (convmap, map, width, height, bpp * 8);
249             memcpy (map, convmap, (size_t) width * height * bpp);
250             free (convmap);
251                 }
252                 return (map);
253         }
254
255         map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED,dev,0);
256         if ((unsigned char *)-1 == (unsigned char *)map) {
257                 log2 ("mmap():", strerror(errno));
258                 return (NULL);
259         }
260         vid_mmap.frame = 0;
261         vid_mmap.width = width;
262         vid_mmap.height =height;
263         if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) {
264                 log2 ("ioctl(VIDIOCMCAPTURE):", strerror(errno));
265                 munmap (map, vid_buf.size);
266                 return (NULL);
267         }
268         if (ioctl (dev, VIDIOCSYNC, &vid_mmap.frame) == -1) {
269                 log2 ("ioctl(VIDIOCSYNC):", strerror(errno));
270                 munmap (map, vid_buf.size);
271                 return (NULL);
272         }
273         buff = (unsigned char *) malloc (size);
274         if (buff) {
275                 if (palette == VIDEO_PALETTE_YUV420P) {
276                         v4l_yuv420p2rgb (buff, map, width, height, 24);
277         } else if (palette == VIDEO_PALETTE_YUV422P) {
278             v4l_yuv422p2rgb (buff, map, width, height, 24);
279                 } else {
280                         for (i = 0; i < size; i++)
281                                 buff[i] = map[i];
282                 }
283         } else {
284                 perror ("malloc()");
285         }
286         munmap (map, vid_buf.size);
287         return (buff);
288 }
289
290 /*
291  */
292 void
293 put_image_jpeg (char *image, int width, int height, int quality, int color)
294 {
295 #ifdef HAVE_LIBJPEG
296         register int x, y, line_width;
297         JSAMPROW row_ptr[1];
298         struct jpeg_compress_struct cjpeg;
299         struct jpeg_error_mgr jerr;
300         char *line = NULL;
301
302         if (color) {
303                 line_width = width * 3;
304                 line = malloc (line_width);
305                 if (!line)
306                         return;
307         } else {
308                 line_width = width;
309         }
310         cjpeg.err = jpeg_std_error(&jerr);
311         jpeg_create_compress (&cjpeg);
312         cjpeg.image_width = width;
313         cjpeg.image_height= height;
314         if (color) {
315                 cjpeg.input_components = 3;
316                 cjpeg.in_color_space = JCS_RGB;
317         } else {
318                 cjpeg.input_components = 1;
319                 cjpeg.in_color_space = JCS_GRAYSCALE;
320         }
321         jpeg_set_defaults (&cjpeg);
322
323         jpeg_simple_progression (&cjpeg);
324         jpeg_set_quality (&cjpeg, quality, TRUE);
325         cjpeg.dct_method = JDCT_FASTEST;
326         jpeg_stdio_dest (&cjpeg, stdout);
327
328         jpeg_start_compress (&cjpeg, TRUE);
329
330         if (color) {
331                 row_ptr[0] = line;
332                 for ( y = 0; y < height; y++) {
333                         for (x = 0; x < line_width; x += 3) {
334                                 line[x]   = image[x+2];
335                                 line[x+1] = image[x+1];
336                                 line[x+2] = image[x];
337                         }
338                         image += line_width;
339                         jpeg_write_scanlines (&cjpeg, row_ptr, 1);
340                 }
341                 free (line);
342         } else {
343                 for ( y = 0; y < height; y++) {
344                         row_ptr[0] = image;
345                         jpeg_write_scanlines (&cjpeg, row_ptr, 1);
346                         image += line_width;
347                 }
348         }
349         jpeg_finish_compress (&cjpeg);
350         jpeg_destroy_compress (&cjpeg);
351 #endif
352 }
353
354 /*
355  * write png image to stdout
356  */
357 void
358 put_image_png (char *image, int width, int height, int color)
359 {
360 #ifdef HAVE_LIBPNG
361         register int y;
362         register char *p;
363         png_infop info_ptr;
364         png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
365                                                 NULL, NULL, NULL);
366         if (!png_ptr)
367                 return;
368         info_ptr = png_create_info_struct (png_ptr);
369         if (!info_ptr)
370                 return;
371
372         png_init_io (png_ptr, stdout);
373         if (color) {
374                 png_set_IHDR (png_ptr, info_ptr, width, height,
375                                         8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
376                                         PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
377                 png_set_bgr (png_ptr);
378         } else {
379                 png_set_IHDR (png_ptr, info_ptr, width, height,
380                                         8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
381                                         PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
382         }
383         png_write_info (png_ptr, info_ptr);
384         p = image;
385         if (color) {
386                 width *= 3;
387                 for (y = 0; y < height; y++) {
388                         png_write_row (png_ptr, p);
389                         p += width;
390                 }
391         } else {
392                 for (y = 0; y < height; y++) {
393                         png_write_row (png_ptr, p);
394                         p += width;
395                 }
396         }
397         png_write_end (png_ptr, info_ptr);
398         png_destroy_write_struct (&png_ptr, &info_ptr);
399 #endif
400 }
401
402 /*
403  * write ppm image to stdout
404  */
405 void
406 put_image_ppm (char *image, int width, int height)
407 {
408         int x, y, ls=0;
409         unsigned char *p = (unsigned char *)image;
410         printf ("P3\n%d %d\n%d\n", width, height, 255);
411         for (x = 0; x < width; x++) {
412                 for (y = 0; y < height; y++) {
413                         printf ("%03d %03d %03d  ", p[2], p[1], p[0]);
414                         p += 3;
415                         if (ls++ > 4) {
416                                 printf ("\n");
417                                 ls = 0;
418                         }
419                 }
420         }
421 }
422
423 /*
424  */
425 const char *
426 palette2string (int palette) {
427         if (palette == VIDEO_PALETTE_RGB24)
428                 return "rgb24";
429         if (palette == VIDEO_PALETTE_YUV420P)
430                 return "yuv420p";
431         if (palette == VIDEO_PALETTE_YUV422P)
432                 return "yuv422p";
433         if (palette == VIDEO_PALETTE_GREY)
434                 return "grey";
435         return "color";
436 }
437
438 /*
439  * create a plain html page
440  */
441 void
442 make_html (int width, int height, int color, int input, int fmt, int quality,
443                         float refresh, int us, int norm, int freq, char **freqs, int pal,
444                         int swapRGB)
445 {
446         cgi_response (http_ok, "text/html");
447         /* cgi_refresh (refresh, NULL); */
448         cgi_html_start ("W3Cam");
449         printf ("<DIV class=image><IMG width=%d height=%d src=\"%s?"
450                 "size=%dx%d&color=%s&id=%d&refresh=%1.2f&usleep=%d&freq=%d"
451                 "&mode=plain",
452                 width, height,
453                 cgi_script_name(),
454                 width, height, palette2string(pal),(int)time(NULL), refresh, us, freq);
455         if (input != INPUT_DEFAULT)
456                 printf ("&input=%s", input == IN_TV? "tv" :
457                                         input == IN_COMP1 ? "composite" :
458                                         input == IN_COMP2? "composite2" : "s-video");
459         if (norm != OFF)
460                 printf ("&norm=%s", norm == NORM_PAL ? "pal":
461                                         norm == NORM_NTSC ? "ntsc" : "secam");
462         if (fmt != FMT_DEFAULT)
463                 printf ("&format=%s", fmt == FMT_PNG? "png":
464                                         fmt == FMT_JPEG? "jpeg": "ppm");
465         if (quality)
466                 printf ("&quality=%d", quality);
467         if (swapRGB)
468                 printf ("&bgr=1");
469         printf ("\"></DIV>\n");
470 }
471
472
473 /*
474  * create a html page with panel
475  */
476 void
477 make_gui (int width, int height, int color, int input, int fmt, int quality,
478                         float refresh, int us, int norm, int freq, char **freqs, int pal,
479                         int swapRGB)
480 {
481         make_html (width, height, color, input, fmt, quality,
482                         refresh, us, norm, freq, freqs, pal, swapRGB);
483
484         printf ("<P><DIV class=panel><FORM>\n");
485         printf ("<INPUT type=hidden name=width value=%d>", width);
486         printf ("<INPUT type=hidden name=height value=%d>\n", height);
487         printf ("<INPUT type=hidden name=mode value=gui>");
488         printf ("<INPUT type=hidden name=quality value=%d>\n", quality);
489         printf ("<INPUT type=hidden name=usleep value=%d>\n", us);
490
491         printf ("Input:<SELECT name=input>\n");
492         printf ("<option%s value='-1'>Default</option>",
493                                 input == INPUT_DEFAULT? " selected":"");
494         printf ("<option%s>TV</option>",
495                                 input == IN_TV? " selected":"");
496         printf ("<option%s>Composite</option>",
497                                 input == IN_COMP1 ? " selected":"");
498         printf ("<option%s>Composite2</option>",
499                                 input == IN_COMP2? " selected":"");
500         printf ("<option%s>S-Video</option></SELECT>\n",
501                                 input == IN_SVIDEO? " selected":"");
502
503         if ((norm != OFF) && (input == IN_TV)) {
504                 printf ("Norm:<SELECT name=norm>\n");
505                 printf ("<option%s>PAL</option>",   norm == NORM_PAL ? " selected":"");
506                 printf ("<option%s>NTSC</option>",  norm == NORM_NTSC? " selected":"");
507                 printf ("<option%s>SECAM</option>", norm == NORM_SECAM?" selected":"");
508                 printf ("<option>off</option>");        /* hide gui entry */
509                 printf ("</SELECT>\n");
510         }
511         if (freqs && (input == IN_TV)) {
512                 int f;
513                 printf ("Freq:<SELECT name=freq>\n");
514                 printf ("<option value=0>default</option>\n");
515                 while (*freqs) {
516                         f = atoi(*freqs);
517                         printf ("<option%s>%d</option>",  freq == f ? " selected": "", f);
518                         freqs++;
519                 }
520                 printf ("</SELECT>\n");
521         }
522
523         printf ("Format:<SELECT name=format>\n");
524         printf ("<option%s>PPM", fmt == FMT_PPM? " selected":"");
525         printf ("<option%s>PNG", fmt == FMT_PNG? " selected":"");
526         printf ("<option%s>JPEG</SELECT>\n", fmt == FMT_JPEG? " selected":"");
527
528         printf ("Size:<SELECT name=size>\n");
529         printf ("<option%s>80x60\n", width == 80  ? " selected": "");
530         printf ("<option%s>160x120", width == 160 ? " selected": "");
531         printf ("<option%s>240x180", width == 240 ? " selected": "");
532         printf ("<option%s>320x240", width == 320 ? " selected": "");
533         printf ("<option%s>400x300", width == 400 ? " selected": "");
534         printf ("<option%s>480x360", width == 480 ? " selected": "");
535         printf ("<option%s>640x480", width == 640 ? " selected": "");
536         printf ("<option%s>720x540", width == 720 ? " selected": "");
537         printf ("<option%s>768x576</SELECT>\n", width == 768 ? " selected": "");
538
539         printf ("Refresh (sec.):<SELECT name=refresh>\n");
540         printf ("<OPTION value=\"-1\">off\n");
541         printf ("<OPTION>0.0<OPTION>0.1<OPTION>0.5<OPTION>1.0<OPTION>2.0\n");
542         printf ("<OPTION>3.0<OPTION>4.0<OPTION>5.0\n");
543         printf ("<OPTION>10<OPTION>20<OPTION>40<OPTION>80\n");
544         if (refresh != OFF)
545                 printf ("<option selected>%1.2f</SELECT>\n", refresh);
546         else
547                 printf ("</SELECT>\n");
548
549         printf ("<P><input type=submit value=Update></FORM></DIV><P>\n");
550         cgi_html_end ("<HR><DIV class=footer>w3cam, &copy; rasca</DIV>");
551 }
552
553 /*
554  */
555 void
556 on_signal (int signum)
557 {
558         exit (0);
559 }
560
561
562 #ifdef HAVE_LIBTTF
563 #include "font.c"
564 #endif
565
566 /*
567  * main()
568  */
569 int
570 main (int argc, char *argv[])
571 {
572         int width = WIDTH_DEFAULT, height = HEIGHT_DEFAULT, dev = -1;
573         char *val = NULL, **form = NULL, *image;
574         char *boundary = "--w3cam-ns-boundary--may-not-work-with-ie--";
575         char *freqlist = FREQLIST_DEFAULT;
576         char **freqs = NULL;
577         char *device = VIDEO_DEV;
578         int max_try = MAX_TRY_OPEN;     /* we try 20 times (5 sec) to open the device */
579         int quality = QUALITY_DEFAULT;  /* default jpeg quality setting */
580         int input = INPUT_DEFAULT;
581         int norm  = NORM_DEFAULT;
582         int mode = MODE_DEFAULT;
583         int color = TRUE;
584         int swapRGB = FALSE;
585         int palette = VIDEO_PALETTE_RGB24;
586         float refresh = REFRESH_DEFAULT;
587         float min_refresh = MIN_REFRESH;
588         int format = FMT_DEFAULT;
589         int usec = USEC_DEFAULT;
590         int freq = 0;
591         int protected = 0;
592         char *mime = NULL;
593 #ifdef HAVE_LIBTTF
594         char *font = NULL;
595         char *timestamp = NULL;
596         int font_size = 12;
597 #define TS_MAX 128
598         /* timestamp string */
599         char ts_buff[TS_MAX+1];
600         int ts_len;
601         int border = 2;
602         int blend = 60;
603         int align = 1;
604         time_t t;
605         struct tm *tm;
606         TT_Engine engine;
607         TT_Face face;
608         TT_Face_Properties properties;
609         TT_Instance instance;
610         TT_Glyph *glyphs = NULL;
611         TT_Raster_Map bit;
612         TT_Raster_Map sbit;
613 #endif
614
615 #ifdef USE_SYSLOG
616         openlog (argv[0], LOG_PID, LOG_USER);
617 #endif
618         cgi_init (argv[0]);
619         if (signal (SIGTERM, on_signal) == SIG_ERR) {
620                 log ("couldn't register handler for SIGTERM");
621         }
622         if (signal (SIGPIPE, on_signal) == SIG_ERR) {
623                 log ("couldn't register handler for SIGPIPE");
624         }
625         /* check some values from the config file
626          */
627         val = cgi_cfg_value ("width");
628         if (val) width = atoi (val);
629         val = cgi_cfg_value ("height");
630         if (val) height = atoi (val);
631         val = cgi_cfg_value ("color");
632         if (val) {
633                 if (strcasecmp (val, "yuv420p") == 0) {
634                         color = 1;
635                         palette = VIDEO_PALETTE_YUV420P;
636                 } else if (strcasecmp (val, "yuv422p") == 0) {
637                         color = 1;
638                         palette = VIDEO_PALETTE_YUV422P;
639                 } else if (*val == '0' || *val == 'g') {
640                         color = 0;
641                         palette = VIDEO_PALETTE_GREY;
642                 } else {
643                         color = 1;
644                 }
645         }
646         val = cgi_cfg_value ("refresh");
647         if (val) refresh = atof (val);
648         val = cgi_cfg_value ("norm");
649         if (val) norm = atoi (val);
650         val = cgi_cfg_value ("input");
651         if (val) input = atoi (val);
652         val = cgi_cfg_value ("format");
653         if (val) format = atoi (val);
654         val = cgi_cfg_value ("quality");
655         if (val) quality = atoi (val);
656         val = cgi_cfg_value ("mode");
657         if (val) mode = atoi (val);
658         val = cgi_cfg_value ("usleep");
659         if (val) usec = atoi (val);
660         val = cgi_cfg_value ("freq");
661         if (val) freq = atoi (val);
662         val = cgi_cfg_value ("freqlist");
663         if (val) freqlist = val;
664         val = cgi_cfg_value ("protected");
665         if (val) protected = atoi (val);
666         val = cgi_cfg_value ("device");
667         if (val) device = val;
668         val = cgi_cfg_value ("bgr");
669         if (val) swapRGB = atoi (val);
670 #ifdef HAVE_LIBTTF
671         val = cgi_cfg_value ("font");
672         if (val) font = val;
673         val = cgi_cfg_value ("font_size");
674         if (val) font_size = atoi (val);
675         val = cgi_cfg_value ("timestamp");
676         if (val) timestamp = val;
677         val = cgi_cfg_value ("timestamp_border");
678         if (val) border = atoi (val);
679         val = cgi_cfg_value ("timestamp_blend");
680         if (val) blend = atoi (val);
681         val = cgi_cfg_value ("timestamp_align");
682         if (val) align = atoi (val);
683 #endif
684
685         /* parse the form, if there is any
686          */
687         if (!protected)
688                 form = cgi_parse_form ();
689
690         if (form && !protected) {
691                 val = cgi_form_value ("help");
692                 if (val) {
693                         usage (argv[0], width, height, color, quality, usec);
694                 }
695                 val = cgi_form_value ("size");
696                 if (val) {
697                         sscanf (val, "%dx%d", &width, &height);
698                 }
699                 val = cgi_form_value ("color");
700                 if (val) {
701                         if (strcasecmp (val, "yuv420p") == 0) {
702                                 color = 1;
703                                 palette = VIDEO_PALETTE_YUV420P;
704                         } else if (strcasecmp (val, "yuv422p") == 0) {
705                                 color = 1;
706                                 palette = VIDEO_PALETTE_YUV422P;
707                         } else if (*val == '0' || *val == 'g') {
708                                 color = 0;
709                                 palette = VIDEO_PALETTE_GREY;
710                         } else {
711                                 color = 1;
712                                 palette = VIDEO_PALETTE_RGB24;
713                         }
714                 }
715                 val = cgi_form_value ("format");
716                 if (val) {
717                         if ((strcasecmp ("ppm", val) == 0) && color) {
718                                 format = FMT_PPM;
719                         } else if (strcasecmp ("png", val) == 0) {
720                                 format = FMT_PNG;
721                         } else if (strcasecmp ("jpeg", val) == 0) {
722                                 format = FMT_JPEG;
723                         }
724                 }
725                 val = cgi_form_value ("refresh");
726                 if (val) refresh = atof (val);
727                 val = cgi_form_value ("quality");
728                 if (val) quality = atoi (val);
729                 val = cgi_form_value ("usleep");
730                 if (val) usec = atoi (val);
731                 val = cgi_form_value ("freq");
732                 if (val) freq = atoi (val);
733
734                 val = cgi_form_value ("mode");
735                 if (val) {
736                         if (strcmp ("gui", val) == 0)
737                                 mode = MODE_GUI;
738                         else if (strcmp ("html", val) == 0)
739                                 mode = MODE_HTML;
740                         else
741                                 mode = MODE_PLAIN;
742                 }
743                 val = cgi_form_value ("input");
744                 if (val) {
745                         if (strcasecmp ("tv", val) == 0) {
746                                 input = IN_TV;
747                         } else if (strcasecmp ("composite", val) == 0) {
748                                 input = IN_COMP1;
749                         } else if (strcasecmp ("composite2", val) ==0) {
750                                 input = IN_COMP2;
751                         } else if (strcasecmp ("s-video", val) == 0) {
752                                 input = IN_SVIDEO;
753                         } else {
754                                 input = INPUT_DEFAULT;
755                         }
756                 }
757                 val = cgi_form_value ("norm");
758                 if (val) {
759                         if (strcasecmp ("pal", val) == 0) {
760                                 norm = NORM_PAL;
761                         } else if (strcasecmp ("ntsc", val) == 0) {
762                                 norm = NORM_NTSC;
763                         } else if (strcasecmp ("secam", val) == 0) {
764                                 norm = NORM_SECAM;
765                         } else {
766                                 norm = OFF;
767                         }
768                 }
769                 val = cgi_form_value ("bgr");
770                 if (val) {
771                         /* check for yes,true,1 */
772                         if ((*val == '1') || (*val == 't') || (*val == 'y')) {
773                                 swapRGB = 1;
774                         } else {
775                                 swapRGB = 0;
776                         }
777                 }
778         }
779
780         if ((refresh > OFF) && (refresh < min_refresh))
781                 refresh = min_refresh;
782         if (!*freqlist)
783                 freqlist = NULL;
784
785         if (mode == MODE_GUI) {
786                 freqs = parse_list (freqlist);
787                 make_gui (width, height, color, input, format, quality, refresh, usec,
788                                         norm,freq, freqs, palette, swapRGB);
789                 return (0);
790         }
791         if (mode == MODE_HTML) {
792                 freqs = parse_list (freqlist);
793                 make_html (width, height, color, input, format, quality, refresh, usec,
794                                         norm,freq, freqs, palette, swapRGB);
795                 return (0);
796         }
797         switch (format) {
798                 case FMT_PPM:
799                         mime = "image/ppm";
800                         break;
801                 case FMT_JPEG:
802                         mime = "image/jpeg";
803                         break;
804                 case FMT_PNG:
805                         mime = "image/png";
806                         break;
807                 default:
808                         log ("unknown image format..!?");
809                         break;
810         }
811 #ifdef HAVE_LIBTTF
812         if (font && timestamp) {
813                 if (TT_Init_FreeType (&engine)) {
814                         font = NULL;
815                         goto no_time_stamp;
816                 }
817                 if (Face_Open (font, engine, &face, &properties, &instance, font_size)){
818                         TT_Done_FreeType (engine);
819                         font = NULL;
820                         goto no_time_stamp;
821                 }
822         }
823 no_time_stamp:
824 #endif
825         if (!color) {
826                 palette = VIDEO_PALETTE_GREY;
827         }
828         /* open the video4linux device */
829 again:
830         while (max_try) {
831                 dev = open (device, O_RDWR);
832                 if (dev == -1) {
833                         log2 (device, strerror(errno));
834                         if (!--max_try) {
835                                 cgi_response (http_ok, "text/plain");
836                                 printf ("Can't open device %s: %s\n",device,strerror(errno));
837                                 exit (0);
838                         }
839                         /* sleep 1/4 second */
840                         usleep (250000);
841                 } else {
842                         max_try = MAX_TRY_OPEN; /* we may need it in a loop later .. */
843                         break;
844                 }
845         }
846         if (v4l_mute_sound (dev) == -1) {
847                 perror ("mute sound");
848         }
849         if (v4l_set_input (dev, input, norm) == -1) {
850                 return 1;
851         }
852         if (v4l_check_size (dev, &width, &height) == -1) {
853                 return 1;
854         }
855         /* if (v4l_check_palette (dev, &palette) == -1) {
856                 return 1;
857         } */
858 again_without_open:
859         image = get_image (dev, width, height, input, usec,freq, palette);
860         if (image) {
861                 if (swapRGB && (palette == VIDEO_PALETTE_RGB24)) {
862                         int x,y;
863                         unsigned char *p, pt;
864                         p = image;
865                         for (y = 0; y < height; y++) {
866                                 for (x = 0; x < width; x++) {
867                                         pt = *p;
868                                         *p = *(p+2);
869                                         *(p+2) = pt;
870                                         p += 3;
871                                 }
872                         }
873                 }
874                 if (refresh != 0.0) {
875                         close (dev);
876                 }
877                 if (refresh != OFF) {
878                         cgi_multipart (boundary);
879                         printf ("Content-Type: %s\n\n", mime);
880                 } else {
881                         cgi_response (http_ok, mime);
882                 }
883 #ifdef HAVE_LIBTTF
884         if (font && timestamp) {
885                 time (&t);
886                 tm = localtime (&t);
887                 ts_buff[TS_MAX] = '\0';
888                 strftime (ts_buff, TS_MAX, timestamp, tm);
889                 ts_len = strlen (ts_buff);
890
891                 glyphs = Glyphs_Load (face, &properties, instance, ts_buff, ts_len);
892                 Raster_Init(face, &properties,instance,ts_buff,ts_len, border, glyphs, &bit);
893                 Raster_Small_Init (&sbit, &instance);
894                 Render_String (glyphs, ts_buff, ts_len, &bit, &sbit, border);
895                 if (bit.bitmap) {
896                         int x, y, psize, i, x_off, y_off;
897                         unsigned char *p;
898
899                         if (color)
900                                 psize = 3;
901                         else
902                                 psize = 1;
903
904                         switch (align) {
905                                 case 1:
906                                         x_off = (width - bit.width) * psize;
907                                         y_off = 0;
908                                         break;
909                                 case 2:
910                                         x_off = 0;
911                                         y_off = height - bit.rows;
912                                         break;
913                                 case 3:
914                                         x_off = (width - bit.width) * psize;
915                                         y_off = height - bit.rows;
916                                         break;
917                                 default:
918                                         x_off = y_off = 0;
919                                         break;
920                         }
921
922                         for (y = 0; y < bit.rows; y++) {
923                                 p = image + (y + y_off) * (width * psize) + x_off;
924                                 for (x = 0; x < bit.width; x++) {
925                                         switch (((unsigned char *)bit.bitmap)
926                                                                 [((bit.rows-y-1)*bit.cols)+x]) {
927                                                 case 0:
928                                                         for (i = 0; i < psize; i++) {
929                                                                 *p = (255 * blend + *p * (100 - blend))/100;
930                                                                 p++;
931                                                         }
932                                                         break;
933                                                 case 1:
934                                                         for (i = 0; i < psize; i++) {
935                                                                 *p = (220 * blend + *p * (100 - blend))/100;
936                                                                 p++;
937                                                         }
938                                                         break;
939                                                 case 2:
940                                                         for (i = 0; i < psize; i++) {
941                                                                 *p = (162 * blend + *p * (100 - blend))/100;
942                                                                 p++;
943                                                         }
944                                                         break;
945                                                 case 3:
946                                                         for (i = 0; i < psize; i++) {
947                                                                 *p = (64 * blend + *p * (100 - blend))/100;
948                                                                 p++;
949                                                         }
950                                                         break;
951                                                 default:
952                                                         for (i = 0; i < psize; i++) {
953                                                                 *p = (0 * blend + *p * (100 - blend))/100;
954                                                                 p++;
955                                                         }
956                                                         break;
957                                         }
958                                 }
959                         }
960                 }
961                 Raster_Done (&sbit);
962                 Raster_Done (&bit);
963                 Glyphs_Done (glyphs);
964                 glyphs = NULL;
965         }
966 #endif
967                 switch (format) {
968                         case FMT_PPM:
969                                 put_image_ppm (image, width, height);
970                                 printf ("\n%s\n", boundary);
971                                 break;
972                         case FMT_PNG:
973                                 put_image_png (image, width, height, color);
974                                 printf ("\n%s\n", boundary);
975                                 break;
976                         case FMT_JPEG:
977                                 put_image_jpeg (image, width, height, quality, color);
978                                 printf ("\n%s\n", boundary);
979                                 break;
980                         default:
981                                 /* should never be reached */
982                                 printf ("Unknown format (%d)\n", format);
983                                 printf ("\n%s\n", boundary);
984                                 break;
985                 }
986                 free (image);
987                 if (refresh == 0.0) {
988                         fflush (stdout);
989                         /* wait ? */
990                         goto again_without_open;
991                 }
992                 if (refresh != OFF) {
993                         fflush (stdout);
994                         usleep ((int)(refresh * 1000000));
995                         goto again;
996                 }
997         } else {
998                 cgi_response (http_ok, "text/plain");
999                 printf ("Error: Can't get image\n");
1000                 close (dev);
1001         }
1002 #ifdef HAVE_LIBTTF
1003         if (font && timestamp) {
1004                 Face_Done (instance, face);
1005                 TT_Done_FreeType (engine);
1006         }
1007 #endif
1008         return (0);
1009 }
1010