Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * (c) 1998-2002 Gerd Knorr
  3  *
  4  *    capture a image, compress as jpeg and upload to the webserver
  5  *    using the ftp utility or ssh
  6  *
  7  */
  8 
  9 #include <stdio.h>
 10 #include <stdlib.h>
 11 #include <string.h>
 12 #include <unistd.h>
 13 #include <errno.h>
 14 #include <fcntl.h>
 15 #include <limits.h>
 16 #include <pthread.h>
 17 #include <math.h>
 18 #include <sys/time.h>
 19 #include <sys/mman.h>
 20 #include <sys/ioctl.h>
 21 #include <sys/stat.h>
 22 
 23 #include "grab-ng.h"
 24 #include "jpeglib.h"
 25 #include "ftp.h"
 26 #include "parseconfig.h"
 27 #include "list.h"
 28 
 29 const char *HTMLSTART = {
 30 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
 31 "<HTML>\n\n"
 32 "<HEAD>\n"
 33 "<TITLE>Webcam</TITLE>\n"
 34 "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"60\">\n"
 35 "<META HTTP-EQUIV=\"Expires\" CONTENT=\"\">\n"
 36 "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">\n"
 37 "<META HTTP-EQUIV=\"Cache-Control\" content=\"no-cache\">\n"
 38 "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n"
 39 "</HEAD>\n\n" "<BODY BGCOLOR=\"#ffffff\">\n\n"
 40 };
 41 const char *HTMLEND = {
 42         "\n</BODY>\n\n" "</HTML>\n"
 43 };
 44 const char *HTMLIMAGE = {
 45         "<IMG VSPACE=5 SRC=\"%%webcam.jpg%%\">\n"
 46 };
 47 
 48 /* ---------------------------------------------------------------------- */
 49 /* configuration                                                          */
 50 
 51 int daemonize = 0;
 52 char *archive = NULL;
 53 char *tmpdir;
 54 struct list_head connections;
 55 struct list_head plugin_list;
 56 struct plugin_s
 57 {
 58         struct ng_filter *filter;
 59         struct list_head list;
 60 };
 61 
 62 char *grab_text = "webcam %Y-%m-%d %H:%M:%S";   /* strftime */
 63 char *grab_infofile = NULL;
 64 int grab_width = 320;
 65 int grab_height = 240;
 66 int grab_delay = 3;
 67 int grab_wait = 0;
 68 int grab_rotate = 0;
 69 int grab_top = 0;
 70 int grab_left = 0;
 71 int grab_bottom = -1;
 72 int grab_right = -1;
 73 int grab_quality = 75;
 74 int grab_trigger = 0;
 75 char *grab_trigger_area = "0%,0%,100%,100%";
 76 int grab_trigger_average = 0;
 77 int grab_trigger_delay = 0;
 78 int grab_times = -1;
 79 int grab_fg_r = 255;
 80 int grab_fg_g = 255;
 81 int grab_fg_b = 255;
 82 int grab_bg_r = -1;
 83 int grab_bg_g = -1;
 84 int grab_bg_b = -1;
 85 char *grab_input = NULL;
 86 char *grab_norm = NULL;
 87 
 88 /* ---------------------------------------------------------------------- */
 89 /* jpeg stuff                                                             */
 90 
 91 static int
 92 write_file (int fd, char *data, int width, int height)
 93 {
 94         struct jpeg_compress_struct cinfo;
 95         struct jpeg_error_mgr jerr;
 96         FILE *fp;
 97         int i;
 98         unsigned char *line;
 99 
100         fp = fdopen (fd, "w");
101         cinfo.err = jpeg_std_error (&jerr);
102         jpeg_create_compress (&cinfo);
103         jpeg_stdio_dest (&cinfo, fp);
104         cinfo.image_width = width;
105         cinfo.image_height = height;
106         cinfo.input_components = 3;
107         cinfo.in_color_space = JCS_RGB;
108         jpeg_set_defaults (&cinfo);
109         jpeg_set_quality (&cinfo, grab_quality, TRUE);
110         jpeg_start_compress (&cinfo, TRUE);
111 
112         for (i = 0, line = data; i < height; i++, line += width * 3)
113                 jpeg_write_scanlines (&cinfo, &line, 1);
114 
115         jpeg_finish_compress (&(cinfo));
116         jpeg_destroy_compress (&(cinfo));
117         fclose (fp);
118 
119         return 0;
120 }
121 
122 /* ---------------------------------------------------------------------- */
123 /* image transfer                                                         */
124 
125 struct xfer_ops;
126 
127 struct xfer_state
128 {
129         char *name;
130         struct list_head list;
131 
132         /* xfer options */
133         char *host;
134         char *user;
135         char *pass;
136         char *dir;
137         char *file;
138         char *tmpfile;
139         int debug;
140         int keepjpegs;
141         int currentCount;
142         char *htmlfile;
143         char *custom_htmlfile;
144 
145         /* ftp options */
146         int passive, autologin;
147 
148         /* function pointers + private date */
149         struct xfer_ops *ops;
150         void *data;
151 };
152 
153 struct xfer_ops
154 {
155         int (*open) (struct xfer_state *);
156         void (*info) (struct xfer_state *);
157         int (*xfer) (struct xfer_state *, char *image, int width, int height);
158         void (*close) (struct xfer_state *);
159 };
160 
161 static int
162 ftp_open (struct xfer_state *s)
163 {
164         s->data = ftp_init (s->name, s->autologin, s->passive, s->debug);
165         ftp_connect (s->data, s->host, s->user, s->pass, s->dir);
166         return 0;
167 }
168 
169 static void
170 ftp_info (struct xfer_state *s)
171 {
172         fprintf (stderr, "ftp config [%s]:\n  %s@%s:%s\n  %s => %s\n",
173                                          s->name, s->user, s->host, s->dir, s->tmpfile, s->file);
174 }
175 
176 static int
177 ftp_xfer (struct xfer_state *s, char *image, int width, int height)
178 {
179         char filename[1024];
180         int fh;
181 
182         sprintf (filename, "%s/webcamXXXXXX", tmpdir);
183         if (-1 == (fh = mkstemp (filename)))
184         {
185                 perror ("mkstemp");
186                 exit (1);
187         }
188         write_file (fh, image, width, height);
189 
190         if (!ftp_stillconnected (s->data))
191                 ftp_connect (s->data, s->host, s->user, s->pass, s->dir);
192 
193         char ftpfilename[1024];
194         strcpy (ftpfilename, s->file);
195 
196         if (s->keepjpegs > 1)
197         {
198                 //tack a number to the file. ..before the extension
199                 char *extpos, *ext = NULL;
200                 if ((extpos = strrchr (ftpfilename, '.')))
201                 {
202                         ext = strdup (extpos);
203                         *(extpos) = '\0';
204                 }
205 
206                 sprintf (ftpfilename, "%s%02i", ftpfilename, s->currentCount);
207                 if (ext)
208                 {
209                         strcat (ftpfilename, ext);
210                         free (ext);
211                 }
212 
213         }
214 
215         ftp_upload (s->data, filename, ftpfilename, s->tmpfile);
216 
217         unlink (filename);
218 
219         return 0;
220 }
221 
222 static void
223 ftp_close (struct xfer_state *s)
224 {
225         ftp_fini (s->data);
226 }
227 
228 static struct xfer_ops ftp_ops = {
229         open:ftp_open,
230         info:ftp_info,
231         xfer:ftp_xfer,
232         close:ftp_close,
233 };
234 
235 static int
236 ssh_open (struct xfer_state *s)
237 {
238         s->data =
239                 malloc (strlen (s->user) + strlen (s->host) + strlen (s->tmpfile) * 2 +
240                                                 strlen (s->dir) + strlen (s->file) + 32);
241         sprintf (s->data, "ssh %s@%s \"cat >%s && mv %s %s/%s\"", s->user, s->host,
242                                          s->tmpfile, s->tmpfile, s->dir, s->file);
243         return 0;
244 }
245 
246 static void
247 ssh_info (struct xfer_state *s)
248 {
249         fprintf (stderr, "ssh config [%s]:\n  %s@%s:%s\n  %s => %s\n",
250                                          s->name, s->user, s->host, s->dir, s->tmpfile, s->file);
251 }
252 
253 static int
254 ssh_xfer (struct xfer_state *s, char *image, int width, int height)
255 {
256         char filename[1024];
257         char *cmd = s->data;
258         unsigned char buf[4096];
259         FILE *sshp, *imgdata;
260         int len, fh;
261 
262         sprintf (filename, "%s/webcamXXXXXX", tmpdir);
263         if (-1 == (fh = mkstemp (filename)))
264         {
265                 perror ("mkstemp");
266                 exit (1);
267         }
268         write_file (fh, image, width, height);
269 
270         if ((sshp = popen (cmd, "w")) == NULL)
271         {
272                 perror ("popen");
273                 exit (1);
274         }
275         if ((imgdata = fopen (filename, "rb")) == NULL)
276         {
277                 perror ("fopen");
278                 exit (1);
279         }
280         for (;;)
281         {
282                 len = fread (buf, 1, sizeof (buf), imgdata);
283                 if (len <= 0)
284                         break;
285                 fwrite (buf, 1, len, sshp);
286         }
287         fclose (imgdata);
288         pclose (sshp);
289 
290         unlink (filename);
291         return 0;
292 }
293 
294 static void
295 ssh_close (struct xfer_state *s)
296 {
297         char *cmd = s->data;
298         free (cmd);
299 }
300 
301 static struct xfer_ops ssh_ops = {
302         open:ssh_open,
303         info:ssh_info,
304         xfer:ssh_xfer,
305         close:ssh_close,
306 };
307 
308 static int
309 local_open (struct xfer_state *s)
310 {
311         char *t;
312 
313         if (s->dir != NULL && s->dir[0] != '\0')
314         {
315                 t = malloc (strlen (s->tmpfile) + strlen (s->dir) + 2);
316                 sprintf (t, "%s/%s", s->dir, s->tmpfile);
317                 s->tmpfile = t;
318 
319                 t = malloc (strlen (s->file) + strlen (s->dir) + 2);
320                 sprintf (t, "%s/%s", s->dir, s->file);
321                 s->file = t;
322         }
323         return 0;
324 }
325 
326 static void
327 local_info (struct xfer_state *s)
328 {
329         fprintf (stderr, "write config [%s]:\n  local transfer %s => %s\n",
330                                          s->name, s->tmpfile, s->file);
331 }
332 
333 static int
334 local_xfer (struct xfer_state *s, char *image, int width, int height)
335 {
336         int fh;
337 
338         if (-1 == (fh = open (s->tmpfile, O_CREAT | O_WRONLY | O_TRUNC, 0666)))
339         {
340                 fprintf (stderr, "open %s: %s\n", s->tmpfile, strerror (errno));
341                 exit (1);
342         }
343         write_file (fh, image, width, height);
344         if (rename (s->tmpfile, s->file))
345         {
346                 fprintf (stderr, "can't move %s -> %s\n", s->tmpfile, s->file);
347                 exit (1);
348         }
349         return 0;
350 }
351 
352 static void
353 local_close (struct xfer_state *s)
354 {
355         /* nothing */
356 }
357 
358 static struct xfer_ops local_ops = {
359         open:local_open,
360         info:local_info,
361         xfer:local_xfer,
362         close:local_close,
363 };
364 
365 /* ---------------------------------------------------------------------- */
366 /* capture stuff                                                          */
367 
368 static struct ng_video_buf *ng_buf;
369 const struct ng_vid_driver *drv;
370 void *h_drv;
371 struct ng_video_fmt fmt, gfmt;
372 struct ng_video_conv *conv;
373 struct ng_filter filter;
374 void *hconv;
375 
376 static void
377 grab_init (void)
378 {
379         struct ng_attribute *attr;
380         int val, i;
381 
382         drv = ng_vid_open (ng_dev.video, NULL, NULL, 0, &h_drv);
383         if (NULL == drv)
384         {
385                 fprintf (stderr, "no grabber device available\n");
386                 exit (1);
387         }
388         if (!(drv->capabilities (h_drv) & CAN_CAPTURE))
389         {
390                 fprintf (stderr, "device does'nt support capture\n");
391                 exit (1);
392         }
393 
394         if (grab_input)
395         {
396                 attr = ng_attr_byid (drv->list_attrs (h_drv), ATTR_ID_INPUT);
397                 val = ng_attr_getint (attr, grab_input);
398                 if (-1 == val)
399                 {
400                         fprintf (stderr, "invalid input: %s\n", grab_input);
401                         exit (1);
402                 }
403                 attr->write (attr, val);
404         }
405         if (grab_norm)
406         {
407                 attr = ng_attr_byid (drv->list_attrs (h_drv), ATTR_ID_NORM);
408                 val = ng_attr_getint (attr, grab_norm);
409                 if (-1 == val)
410                 {
411                         fprintf (stderr, "invalid norm: %s\n", grab_norm);
412                         exit (1);
413                 }
414                 attr->write (attr, val);
415         }
416 
417         /* try native */
418         fmt.fmtid = VIDEO_RGB24;
419         fmt.width = grab_width;
420         fmt.height = grab_height;
421         if (0 == drv->setformat (h_drv, &fmt))
422                 return;
423 
424         /* check all available conversion functions */
425         fmt.bytesperline = fmt.width * ng_vfmt_to_depth[fmt.fmtid] / 8;
426         for (i = 0;;)
427         {
428                 conv = ng_conv_find_to (fmt.fmtid, &i);
429                 if (NULL == conv)
430                         break;
431                 gfmt = fmt;
432                 gfmt.fmtid = conv->fmtid_in;
433                 gfmt.bytesperline = 0;
434                 if (0 == drv->setformat (h_drv, &gfmt))
435                 {
436                         fmt.width = gfmt.width;
437                         fmt.height = gfmt.height;
438                         hconv = conv->init (&fmt, conv->priv);
439                         return;
440                 }
441         }
442         fprintf (stderr, "can't get rgb24 data\n");
443         exit (1);
444 }
445 
446 static unsigned char *
447 grab_one (int *width, int *height, struct ng_video_buf **buf)
448 {
449         struct ng_video_buf *ng_cap;
450 
451         if (NULL != *buf)
452                 ng_release_video_buf (*buf);
453         if (NULL == (ng_cap = drv->getimage (h_drv)))
454         {
455                 fprintf (stderr, "capturing image failed\n");
456                 exit (1);
457         }
458 
459         if (NULL != conv)
460         {
461                 *buf = ng_malloc_video_buf (&fmt, 3 * fmt.width * fmt.height);
462                 conv->frame (hconv, *buf, ng_cap);
463                 (*buf)->info = ng_cap->info;
464                 ng_release_video_buf (ng_cap);
465         }
466         else
467         {
468                 *buf = ng_cap;
469         }
470 
471         *width = (*buf)->fmt.width;
472         *height = (*buf)->fmt.height;
473 
474         return (*buf)->data;
475 }
476 
477 /* ---------------------------------------------------------------------- */
478 
479 #define MSG_MAXLEN   256
480 
481 #define CHAR_HEIGHT  11
482 #define CHAR_WIDTH   6
483 #define CHAR_START   4
484 #include "font-6x11.h"
485 
486 static char *
487 get_message (void)
488 {
489         static char buffer[MSG_MAXLEN + 1];
490         FILE *fp;
491         char *p;
492 
493         if (NULL == grab_infofile)
494                 return grab_text;
495 
496         if (NULL == (fp = fopen (grab_infofile, "r")))
497         {
498                 fprintf (stderr, "open %s: %s\n", grab_infofile, strerror (errno));
499                 return grab_text;
500         }
501 
502         fgets (buffer, MSG_MAXLEN, fp);
503         fclose (fp);
504         if (NULL != (p = strchr (buffer, '\n')))
505                 *p = '\0';
506 
507         return buffer;
508 }
509 
510 static void
511 add_text (char *image, int width, int height)
512 {
513         time_t t;
514         struct tm *tm;
515         char line[MSG_MAXLEN + 1], *ptr;
516         int i, x, y, f, len;
517 
518         time (&t);
519         tm = localtime (&t);
520         len = strftime (line, MSG_MAXLEN, get_message (), tm);
521         fprintf (stderr, "%s\n", line);
522 
523         for (y = 0; y < CHAR_HEIGHT; y++)
524         {
525                 ptr = image + 3 * width * (height - CHAR_HEIGHT - 2 + y) + 12;
526                 for (x = 0; x < len; x++)
527                 {
528                         f = fontdata[line[x] * CHAR_HEIGHT + y];
529                         for (i = CHAR_WIDTH - 1; i >= 0; i--)
530                         {
531                                 if (f & (CHAR_START << i))
532                                 {
533                                         ptr[0] = grab_fg_r;
534                                         ptr[1] = grab_fg_g;
535                                         ptr[2] = grab_fg_b;
536                                 }
537                                 else if (grab_bg_r != -1)
538                                 {
539                                         ptr[0] = grab_bg_r;
540                                         ptr[1] = grab_bg_g;
541                                         ptr[2] = grab_bg_b;
542                                 }
543                                 ptr += 3;
544                         }
545                 }
546         }
547 }
548 
549 /* ---------------------------------------------------------------------- */
550 /* Frederic Helin <Frederic.Helin@inrialpes.fr> - 15/07/2002              */
551 /* Correction fonction of stereographic radial distortion                 */
552 
553 int grab_dist_on = 0;
554 int grab_dist_k = 700;
555 int grab_dist_cx = -1;
556 int grab_dist_cy = -1;
557 int grab_dist_zoom = 50;
558 int grab_dist_sensorw = 640;
559 int grab_dist_sensorh = 480;
560 
561 static unsigned char *
562 correct_distor (unsigned char *in, int width, int height,
563                                                                 int grab_zoom, int grap_k, int cx, int cy,
564                                                                 int grab_sensorw, int grab_sensorh)
565 {
566         static unsigned char *corrimg = NULL;
567 
568         int i, j, di, dj;
569         float dr, cr, ca, sensor_w, sensor_h, sx, zoom, k;
570 
571         sensor_w = grab_dist_sensorw / 100.0;
572         sensor_h = grab_dist_sensorh / 100.0;
573         zoom = grab_zoom / 100.0;
574         k = grap_k / 100.0;
575 
576         if (corrimg == NULL && (corrimg = malloc (width * height * 3)) == NULL)
577         {
578                 fprintf (stderr, "out of memory\n");
579                 exit (1);
580         }
581 
582         sensor_w = 6.4;
583         sensor_h = 4.8;
584 
585         // calc ratio x/y
586         sx = width * sensor_h / (height * sensor_w);
587 
588         // calc new value of k in the coordonates systeme of computer
589         k = k * height / sensor_h;
590 
591         // Clear image
592         for (i = 0; i < height * width * 3; i++)
593                 corrimg[i] = 255;
594 
595         for (j = 0; j < height; j++)
596         {
597                 for (i = 0; i < width; i++)
598                 {
599 
600                         // compute radial distortion / parameters of center of image 
601                         cr = sqrt ((i - cx) / sx * (i - cx) / sx + (j - cy) * (j - cy));
602                         ca = atan (cr / k / zoom);
603                         dr = k * tan (ca / 2);
604 
605                         if (i == cx && j == cy)
606                         {
607                                 di = cx;
608                                 dj = cy;
609                         }
610                         else
611                         {
612                                 di = (i - cx) * dr / cr + cx;
613                                 dj = (j - cy) * dr / cr + cy;
614                         }
615 
616                         if (dj < height && di < width && di >= 0 && dj >= 0 &&
617                                         j < height && i < width && i >= 0 && j >= 0)
618                         {
619                                 corrimg[3 * (j * width + i)] = in[3 * (dj * width + di)];
620                                 corrimg[3 * (j * width + i) + 1] = in[3 * (dj * width + di) + 1];
621                                 corrimg[3 * (j * width + i) + 2] = in[3 * (dj * width + di) + 2];
622                         }
623                 }
624         }
625         return corrimg;
626 }
627 
628 /* ---------------------------------------------------------------------- */
629 
630 /*static unsigned int
631 compare_images(unsigned char *last, unsigned char *current,
632                int width, int height)
633 {
634         unsigned char *p1 = last;
635         unsigned char *p2 = current;
636         int avg, diff, max, i = width*height*3;
637 
638         for (max = 0, avg = 0; --i; p1++,p2++)
639         {
640                 //diff = (*p1 < *p2) ? (*p2 - *p1) : (*p1 - *p2);
641                 diff = abs(*p1 - *p2);
642                 avg += diff;
643                 if (diff > max)
644                         max = diff;
645         }
646 
647         avg = avg / width / height;
648         fprintf(stderr,"compare: max=%d,avg=%d\n",max,avg);
649 
650         // return max
651         return max;
652 }*/
653 
654 static unsigned int
655 compare_images (unsigned char *last, unsigned char *current,
656                                                                 int offsetx, int offsety, int iwidth, int iheight,
657                                                                 int imagewidth)
658 {
659         unsigned char *p1 = last;
660         unsigned char *p2 = current;
661         unsigned int p;
662         int x, y, diff, max = 0;
663         unsigned int avg = 0;
664 
665         offsety *= 3;
666         offsetx *= 3;
667         iheight *= 3;
668         iwidth *= 3;
669 
670         for (y = offsety; y < offsety + iheight; y += 3)
671         {
672                 p = imagewidth * y;
673 
674                 for (x = offsetx; x < offsetx + iwidth; x++)
675                 {
676                         p1 = last + p + x;
677                         p2 = current + p + x;
678 
679                         diff = abs (*p1 - *p2);
680                         avg += diff;
681                         if (diff > max)
682                                 max = diff;
683                 }
684         }
685 
686         avg = 3 * avg / iwidth / iheight;
687         fprintf (stderr, "compare: max=%d,avg=%d\n", max, avg);
688 
689         // return max and average
690         return (max << 8) | avg;
691 }
692 
693 /*int max2 = 0;
694 static unsigned int
695 compare_images(unsigned char *saved, unsigned char *last, unsigned char *current, int width, int height)
696 {
697     unsigned char *p1 = last;
698     unsigned char *p2 = current;
699     unsigned char *p3 = saved;
700     int avg, diff, max, i = width*height*3;
701     int avg2, diff2;
702 
703     for (max = 0, avg = 0, max2=0,avg2=0; --i; p1++,p2++,p3++)
704     {
705                         diff = abs(*p1 - *p2);
706                         avg += diff;
707                         if (diff > max)
708                                 max = diff;
709 
710                         diff2 = abs(*p3 - *p2);
711                         avg2 += diff2;
712                         if (diff2 > max2)
713                                 max2 = diff2;
714                         
715     }
716 
717     avg = avg / width / height;
718     avg2 = avg2 / width / height;
719     fprintf(stderr,"compare: max=%d,%d,avg=%d,%d\n",max,max2,avg,avg2);
720 
721  
722     return max;
723 }*/
724 
725 static unsigned char *
726 rotate_image (unsigned char *in, int *wp, int *hp, int rot,
727                                                         int top, int left, int bottom, int right)
728 {
729         static unsigned char *rotimg = NULL;
730 
731         int i, j;
732 
733         int w = *wp;
734         int ow = (right - left);
735         int oh = (bottom - top);
736 
737         if (rotimg == NULL && (rotimg = malloc (ow * oh * 3)) == NULL)
738         {
739                 fprintf (stderr, "out of memory\n");
740                 exit (1);
741         }
742 
743         switch (rot)
744         {
745         default:
746         case 0:
747                 for (j = 0; j < oh; j++)
748                 {
749                         int ir = (j + top) * w + left;
750                         int or = j * ow;
751                         for (i = 0; i < ow; i++)
752                         {
753                                 rotimg[3 * (or + i)] = in[3 * (ir + i)];
754                                 rotimg[3 * (or + i) + 1] = in[3 * (ir + i) + 1];
755                                 rotimg[3 * (or + i) + 2] = in[3 * (ir + i) + 2];
756                         }
757                 }
758                 *wp = ow;
759                 *hp = oh;
760                 break;
761         case 1:
762                 for (i = 0; i < ow; i++)
763                 {
764                         int rr = (ow - 1 - i) * oh;
765                         int ic = i + left;
766                         for (j = 0; j < oh; j++)
767                         {
768                                 rotimg[3 * (rr + j)] = in[3 * ((j + top) * w + ic)];
769                                 rotimg[3 * (rr + j) + 1] = in[3 * ((j + top) * w + ic) + 1];
770                                 rotimg[3 * (rr + j) + 2] = in[3 * ((j + top) * w + ic) + 2];
771                         }
772                 }
773                 *wp = oh;
774                 *hp = ow;
775                 break;
776         case 2:
777                 for (j = 0; j < oh; j++)
778                 {
779                         int ir = (j + top) * w;
780                         for (i = 0; i < ow; i++)
781                         {
782                                 rotimg[3 * ((oh - 1 - j) * ow + (ow - 1 - i))] =
783                                         in[3 * (ir + i + left)];
784                                 rotimg[3 * ((oh - 1 - j) * ow + (ow - 1 - i)) + 1] =
785                                         in[3 * (ir + i + left) + 1];
786                                 rotimg[3 * ((oh - 1 - j) * ow + (ow - 1 - i)) + 2] =
787                                         in[3 * (ir + i + left) + 2];
788                         }
789                 }
790                 *wp = ow;
791                 *hp = oh;
792                 break;
793         case 3:
794                 for (i = 0; i < ow; i++)
795                 {
796                         int rr = i * oh;
797                         int ic = i + left;
798                         rr += oh - 1;
799                         for (j = 0; j < oh; j++)
800                         {
801                                 rotimg[3 * (rr - j)] = in[3 * ((j + top) * w + ic)];
802                                 rotimg[3 * (rr - j) + 1] = in[3 * ((j + top) * w + ic) + 1];
803                                 rotimg[3 * (rr - j) + 2] = in[3 * ((j + top) * w + ic) + 2];
804                         }
805                 }
806                 *wp = oh;
807                 *hp = ow;
808                 break;
809         }
810 
811         return rotimg;
812 }
813 
814 //-----------------------------------------------------
815 // T.Mohan - 28 July 2002
816 // # strnsub() is based on source by Erik Bachmann and
817 // # was released to public domain on 27 Oct 1995.
818 //-----------------------------------------------------
819 
820 static char *
821 strnsub (char *pszString, char *pszPattern, char *pszReplacement,
822                                  int iMaxLength, int bOnce)
823 {
824         char *pszSubstring, *pszTmpSubstring, *pszlast, *pszTempReplacement;
825         int iPatternLength, iReplacementLength;
826 
827         pszSubstring = pszString;
828         pszTmpSubstring = NULL;
829         iPatternLength = strlen (pszPattern);
830         pszlast = NULL;
831 
832         if (!strcmp (pszPattern, pszReplacement))
833                 return NULL;                                                            // Pattern == replacement: loop
834 
835         while ((pszSubstring = strstr (pszSubstring, pszPattern)))
836         {
837                 iReplacementLength = strlen (pszReplacement);
838                 pszTempReplacement = pszReplacement;
839 
840                 if ((strlen (pszString) + (iReplacementLength - iPatternLength)) >
841                                 iMaxLength)
842                         break;                                                                          // Not enough space for replacement
843 
844                 if (pszTmpSubstring == NULL)    //allocate some memory only once
845                 {
846                         if ((pszTmpSubstring =
847                                          (char *) calloc (iMaxLength, sizeof (char))) == NULL)
848                                 return NULL;                                            // oops, not enough memory?
849                 }
850 
851                 strcpy (pszTmpSubstring, pszSubstring + iPatternLength);
852 
853                 while (iReplacementLength--)
854                 {                                                                                                               // Copy replacement
855                         *pszSubstring++ = *pszTempReplacement++;
856                 }
857 
858                 strcpy (pszSubstring, pszTmpSubstring);
859 
860                 pszlast = pszSubstring - iPatternLength;
861 
862                 if (bOnce)
863                         break;                                                                          //just change one
864 
865         }
866 
867         if (pszTmpSubstring)
868                 free (pszTmpSubstring);
869 
870         return pszlast;
871 
872 }
873 
874 //-----------------------------------------------------
875 // T.Mohan - 28 July 2002
876 //-----------------------------------------------------
877 static int
878 ftp_upload_htmlfile (struct xfer_state *s)
879 {
880 
881 #define MAXLINELEN 1024
882 
883         FILE *filecustom, *filewrite;
884         int filetemp;
885         char line[MAXLINELEN];
886         char tmpfname[1024];
887         char jpegnumbered[1024], jpegfilename[1024];
888         char pattern[20], pattern_newest[20];
889         char *pszFound;
890 
891         strcpy (pattern, "%%webcam.jpg%%");     //replace with numbered .jpg's
892         strcpy (pattern_newest, "%%newest.jpg%%");      //replace with newest .jpg
893         pszFound = NULL;
894         filecustom = filewrite = NULL;
895 
896         //open the custom html file if requested
897         if (s->custom_htmlfile)
898         {
899                 if ((filecustom = fopen (s->custom_htmlfile, "r")) == NULL)
900                 {
901                         perror (s->htmlfile);
902                         return 1;
903                 }
904         }
905 
906         //create a temporary file
907         sprintf (tmpfname, "%s/webcamhtmlXXXXXX", tmpdir);
908 
909         if (-1 == (filetemp = mkstemp (tmpfname)))
910         {
911                 perror ("mkstemp create");
912                 fclose (filecustom);
913                 return 1;
914         }
915 
916         if ((filewrite = fdopen (filetemp, "w")) == NULL)
917         {
918                 perror ("htmlfile open for write");
919                 fclose (filecustom);
920                 unlink (tmpfname);
921                 return 1;
922         }
923 
924         if (s->keepjpegs > 1)                                   //format the filename
925         {
926                 strcpy (jpegfilename, s->file);
927                 char *extpos, *ext = NULL;
928 
929                 if ((extpos = strrchr (jpegfilename, '.')))
930                 {
931                         ext = strdup (extpos);
932                         *(extpos) = '\0';
933                 }
934 
935                 //end up with something like 'webcam%02i.jpg'
936                 sprintf (jpegfilename, "%s%%02i", jpegfilename);
937 
938                 if (ext)                                                                                //tack on the extension if there is one
939                 {
940                         strcat (jpegfilename, ext);
941                         free (ext);
942                 }
943         }
944         else
945         {
946                 strcpy (jpegnumbered, s->file);
947         }
948 
949         //find pattern and replace with approriate filename in custom html file
950         int count = s->currentCount;
951         if (filecustom)
952         {
953                 int actualcount = 0;
954 
955                 while (fgets (line, sizeof (line), filecustom) != NULL)
956                 {
957                         if (s->keepjpegs > 1)
958                                 sprintf (jpegnumbered, jpegfilename, count);
959 
960                         //replace patterns in entire line with the numbered jpeg
961                         if (strnsub (line, pattern, jpegnumbered, MAXLINELEN, FALSE))
962                         {
963                                 if (--count < 1)
964                                         count = s->keepjpegs;
965 
966                                 actualcount++;
967                         }
968 
969                         //replace tag for %%newest.jpg%%
970                         if (s->keepjpegs > 1)
971                                 sprintf (jpegnumbered, jpegfilename, s->currentCount);
972 
973                         strnsub (line, pattern_newest, jpegnumbered, MAXLINELEN, FALSE);
974 
975                         //write line
976                         fputs (line, filewrite);
977                 }
978 
979                 if ((s->keepjpegs > 1) && (actualcount != s->keepjpegs))
980                         fprintf (stderr,
981                                                          "\n*** Warning: Found %i patterns, but keepjpegs = %i\n\n",
982                                                          actualcount, s->keepjpegs);
983         }
984         else
985         {
986                 fputs (HTMLSTART, filewrite);
987 
988                 int i = s->keepjpegs;
989                 while (i--)
990                 {
991                         strcpy (line, HTMLIMAGE);
992 
993                         if (s->keepjpegs > 1)
994                                 sprintf (jpegnumbered, jpegfilename, count);
995 
996                         if (strnsub (line, pattern, jpegnumbered, MAXLINELEN, TRUE))
997                         {
998                                 if (--count < 1)
999                                         count = s->keepjpegs;
1000                         }
1001 
1002                         //replace tag for %%newest.jpg%%
1003                         //sprintf(jpegnumbered,jpegfilename,s->currentCount);
1004                         //strnsub(line, pattern_newest, jpegnumbered, MAXLINELEN, FALSE);
1005 
1006                         fputs (line, filewrite);
1007                 }
1008 
1009                 fputs (HTMLEND, filewrite);
1010         }
1011 
1012         if (filecustom)
1013                 fclose (filecustom);
1014         if (filewrite)
1015                 fclose (filewrite);
1016 
1017         //upload the html file
1018         sprintf (jpegfilename, "%s%s", s->tmpfile, ".html");
1019         fprintf (stderr, "%s,%s,%s\n", tmpfname, s->htmlfile, jpegfilename);
1020         ftp_upload (s->data, tmpfname, s->htmlfile, jpegfilename);
1021 
1022         unlink (tmpfname);
1023 
1024         return 0;
1025 }
1026 
1027 static void
1028 parse_trigger_area (char *pszTriggerArea, int *ixoffset, int *iyoffset,
1029                                                                                 int *width, int *height)
1030 {
1031         if (!ixoffset || !iyoffset || !width || !height)
1032                 return;
1033         if (!pszTriggerArea)
1034                 pszTriggerArea = "0%,0%,100%,100%";
1035 
1036         char *str, *perc, *tmpStr;
1037         int count = -1, ta[4], err = 0;
1038 
1039         tmpStr = strdup (pszTriggerArea);
1040         str = strtok (tmpStr, ",");
1041 
1042         while (str && (++count < 4))
1043         {
1044                 if ((perc = strstr (str, "%")))
1045                         *perc = '\0';
1046 
1047                 if (perc)
1048                         ta[count] = atoi (str) * ((count % 2) ? *height : *width) / 100;
1049                 else
1050                         ta[count] = atoi (str);
1051 
1052                 str = strtok (NULL, ",");
1053         }
1054 
1055         free (tmpStr);
1056 
1057         //some foolproofing...
1058         if ((ta[0] < 0) || (ta[0] > *width))
1059         {
1060                 ta[0] = 0;
1061                 err = 1;
1062         }
1063         if ((ta[1] < 0) || (ta[1] > *height))
1064         {
1065                 ta[1] = 0;
1066                 err = 1;
1067         }
1068         if ((ta[2] < 0) || (ta[2] > *width))
1069         {
1070                 ta[2] = *width;
1071                 err = 1;
1072         }
1073         if ((ta[3] < 0) || (ta[3] > *height))
1074         {
1075                 ta[3] = *height;
1076                 err = 1;
1077         }
1078         if (ta[0] >= ta[2])
1079         {
1080                 ta[2] = *width;
1081                 err = 1;
1082         }
1083         if (ta[1] >= ta[3])
1084         {
1085                 ta[3] = *height;
1086                 err = 1;
1087         }
1088         if (ta[2] <= ta[0])
1089         {
1090                 ta[0] = 0;
1091                 err = 1;
1092         }
1093         if (ta[3] <= ta[1])
1094         {
1095                 ta[1] = 0;
1096                 err = 1;
1097         }
1098 
1099         if (err)
1100                 fprintf (stderr, "\n*** Invalid trigger area was fixed.\n\n");
1101 
1102         *ixoffset = ta[0];
1103         *iyoffset = ta[1];
1104         *width = ta[2] - ta[0];
1105         *height = ta[3] - ta[1];
1106 }
1107 
1108 static void
1109 draw_trigger_area (unsigned char *image, int offsetx, int offsety,
1110                                                                          int iTriggerwidth, int iTriggerheight, int iImageWidth)
1111 {
1112         unsigned char *p;
1113         int x, y;
1114 
1115         offsety *= 3;
1116         offsetx *= 3;
1117         iTriggerheight *= 3;
1118         iTriggerwidth *= 3;
1119 
1120         for (y = offsety; y < offsety + iTriggerheight; y += 3)
1121         {
1122                 p = image + iImageWidth * y;
1123 
1124                 for (x = offsetx; x < offsetx + iTriggerwidth; x++)
1125                 {
1126                         //trigger area is drawn inverted
1127                         *(p + x) = 255 - *(p + x);
1128                 }
1129         }
1130 
1131 }
1132 
1133 static char *
1134 trim (char *p)
1135 {
1136         while ((*p == ' '))
1137                 p++;
1138         while ((p[strlen (p) - 1]) == ' ')
1139                 p[strlen (p) - 1] = '\0';
1140 
1141         return p;
1142 }
1143 
1144 static struct ng_filter *
1145 get_plugin (char *name)
1146 {
1147         int i;
1148 
1149         for (i = 0; NULL != ng_filters[i]; i++)
1150                 if (!strcmp (ng_filters[i]->name, name))
1151                         return ng_filters[i];
1152 
1153         return NULL;
1154 }
1155 
1156 static void
1157 parse_plugins (void)
1158 {
1159         char *name, *attributes, *str;
1160         int count = 0;
1161         struct ng_filter *plugin;
1162         struct plugin_s *currfilter = NULL;
1163 
1164         INIT_LIST_HEAD (&plugin_list);
1165 
1166         if ((str = cfg_get_str ("plugins", "names")) == NULL)
1167                 return;
1168 
1169         while ((name = strtok (str, ",")))
1170         {
1171                 str = NULL;
1172 
1173                 //remove asterix for spaces
1174                 strnsub (name, "*", " ", strlen (name), FALSE);
1175                 name = trim (name);
1176 
1177                 //plugin actually exists?
1178                 if ((plugin = get_plugin (name)) == NULL)
1179                 {
1180                         fprintf (stderr, "plugin: [%s] not found.\n", name);
1181                         continue;
1182                 }
1183 
1184                 currfilter = malloc (sizeof (*currfilter));
1185                 memset (currfilter, 0, sizeof (*currfilter));
1186                 currfilter->filter = plugin;
1187                 list_add_tail (&currfilter->list, &plugin_list);
1188 
1189                 fprintf (stderr, "plugin: [%s] found.\n", name);
1190 
1191                 count++;
1192         }
1193 
1194         //parse the attributes
1195         struct list_head *item;
1196         name = NULL;
1197         list_for_each (item, &plugin_list)
1198         {
1199                 struct plugin_s *currfilter = NULL;
1200 
1201                 currfilter = list_entry (item, struct plugin_s, list);
1202 
1203                 if (name)
1204                         free (name);
1205                 name = strdup (currfilter->filter->name);
1206                 //replace spaces in the name with asterix
1207                 strnsub (name, " ", "*", strlen (name), FALSE);
1208                 attributes = cfg_get_str ("plugins", name);
1209                 //remove asterix for spaces
1210                 strnsub (name, "*", " ", strlen (name), FALSE);
1211 
1212                 //parse the attributes
1213                 if (!attributes)
1214                 {
1215                         if (currfilter->filter->attrs)
1216                                 fprintf (stderr, "plugin: [%s] Using default attributes.\n", name);
1217                         continue;
1218                 }
1219 
1220                 char *attr = attributes;
1221                 char attrname[64], attrvalue[192];
1222                 struct ng_attribute *nga = NULL;
1223                 while ((attributes = strtok (attr, ",")))
1224                 {
1225                         attr = NULL;
1226                         if (sscanf (attributes, " %63[^=] = %191[^\n]", attrname, attrvalue) !=
1227                                         2)
1228                                 fprintf (stderr, "plugin: [%s] Parse error for attribute %s\n", name,
1229                                                                  attrname);
1230 
1231                         trim (attrname);
1232 
1233                         if (currfilter->filter->attrs == NULL)
1234                         {
1235                                 fprintf (stderr, "plugin: [%s] has no attributes to set.\n", name);
1236                                 break;
1237                         }
1238 
1239                         if (!(nga = ng_attr_byname (currfilter->filter->attrs, attrname)))
1240                         {
1241                                 fprintf (stderr, "plugin: [%s] Unkown attribute: %s\n", name,
1242                                                                  attrname);
1243                         }
1244                         else
1245                         {
1246                                 nga->write (nga, atoi (attrvalue));
1247                                 fprintf (stderr, "plugin: [%s] Wrote attribute: %s, value: %s\n",
1248                                                                  name, attrname, attrvalue);
1249                         }
1250 
1251                 }
1252 
1253         }
1254 
1255         if (name)
1256                 free (name);
1257 
1258         if (count)
1259                 fprintf (stderr, "plugin: Using %d plugin%s.\n", count,
1260                                                  (count == 1) ? "" : "s");
1261 
1262 
1263 }
1264 
1265 /* ---------------------------------------------------------------------- */
1266 
1267 int
1268 main (int argc, char *argv[])
1269 {
1270         unsigned char *image, *val, *gimg, *lastimg = NULL;
1271         int width, height, i, fh;
1272         char filename[1024];
1273         char **sections;
1274         struct list_head *item;
1275         struct xfer_state *s = NULL;
1276         int iTrigX, iTrigY, iTrigWidth, iTrigHeight;
1277         struct plugin_s *currfilter;
1278 
1279         /* read config */
1280         if (argc > 1)
1281         {
1282                 strcpy (filename, argv[1]);
1283         }
1284         else
1285         {
1286                 sprintf (filename, "%s/%s", getenv ("HOME"), ".webcamrc");
1287         }
1288 
1289         fprintf (stderr, "reading config file: %s\n", filename);
1290         cfg_parse_file (filename);
1291         ng_init ();
1292 
1293         //setup the plugins
1294         parse_plugins ();
1295 
1296         if (NULL != (val = cfg_get_str ("grab", "device")))
1297                 ng_dev.video = val;
1298         if (NULL != (val = cfg_get_str ("grab", "text")))
1299                 grab_text = val;
1300         if (NULL != (val = cfg_get_str ("grab", "infofile")))
1301                 grab_infofile = val;
1302         if (NULL != (val = cfg_get_str ("grab", "input")))
1303                 grab_input = val;
1304         if (NULL != (val = cfg_get_str ("grab", "norm")))
1305                 grab_norm = val;
1306         if (-1 != (i = cfg_get_int ("grab", "width")))
1307                 grab_width = i;
1308         if (-1 != (i = cfg_get_int ("grab", "height")))
1309                 grab_height = i;
1310         if (-1 != (i = cfg_get_int ("grab", "delay")))
1311                 grab_delay = i;
1312         if (-1 != (i = cfg_get_int ("grab", "wait")))
1313                 grab_wait = i;
1314         if (-1 != (i = cfg_get_int ("grab", "rotate")))
1315                 grab_rotate = i;
1316         if (-1 != (i = cfg_get_int ("grab", "top")))
1317                 grab_top = i;
1318         if (-1 != (i = cfg_get_int ("grab", "left")))
1319                 grab_left = i;
1320         grab_bottom = cfg_get_int ("grab", "bottom");
1321         grab_right = cfg_get_int ("grab", "right");
1322         if (-1 != (i = cfg_get_int ("grab", "quality")))
1323                 grab_quality = i;
1324         if (-1 != (i = cfg_get_int ("grab", "trigger")))
1325                 grab_trigger = i;
1326         if (NULL != (val = cfg_get_str ("grab", "trigger_area")))
1327                 grab_trigger_area = val;
1328         if (-1 != (i = cfg_get_int ("grab", "trigger_average")))
1329                 grab_trigger_average = i;
1330         if (-1 != (i = cfg_get_int ("grab", "trigger_delay")))
1331                 grab_trigger_delay = i;
1332         if (-1 != (i = cfg_get_int ("grab", "once")))
1333                 if (i)
1334                         grab_times = 1;
1335         if (-1 != (i = cfg_get_int ("grab", "times")))
1336                 grab_times = i;
1337         if (NULL != (val = cfg_get_str ("grab", "archive")))
1338                 archive = val;
1339 
1340         if (-1 != (i = cfg_get_int ("grab", "fg_red")))
1341                 if (i >= 0 && i <= 255)
1342                         grab_fg_r = i;
1343         if (-1 != (i = cfg_get_int ("grab", "fg_green")))
1344                 if (i >= 0 && i <= 255)
1345                         grab_fg_g = i;
1346         if (-1 != (i = cfg_get_int ("grab", "fg_blue")))
1347                 if (i >= 0 && i <= 255)
1348                         grab_fg_b = i;
1349         if (-1 != (i = cfg_get_int ("grab", "bg_red")))
1350                 if (i >= 0 && i <= 255)
1351                         grab_bg_r = i;
1352         if (-1 != (i = cfg_get_int ("grab", "bg_green")))
1353                 if (i >= 0 && i <= 255)
1354                         grab_bg_g = i;
1355         if (-1 != (i = cfg_get_int ("grab", "bg_blue")))
1356                 if (i >= 0 && i <= 255)
1357                         grab_bg_b = i;
1358 
1359         if (-1 != (i = cfg_get_int ("grab", "distor")))
1360                 grab_dist_on = i;
1361         if (-1 != (i = cfg_get_int ("grab", "distor_k")))
1362                 grab_dist_k = i;
1363         if (-1 != (i = cfg_get_int ("grab", "distor_cx")))
1364                 grab_dist_cx = i;
1365         if (-1 != (i = cfg_get_int ("grab", "distor_cy")))
1366                 grab_dist_cy = i;
1367         if (-1 != (i = cfg_get_int ("grab", "distor_zoom")))
1368                 grab_dist_zoom = i;
1369         if (-1 != (i = cfg_get_int ("grab", "distor_sensorw")))
1370                 grab_dist_sensorw = i;
1371         if (-1 != (i = cfg_get_int ("grab", "distor_sensorh")))
1372                 grab_dist_sensorh = i;
1373 
1374         if (grab_top < 0)
1375                 grab_top = 0;
1376         if (grab_left < 0)
1377                 grab_left = 0;
1378         if (grab_bottom > grab_height)
1379                 grab_bottom = grab_height;
1380         if (grab_right > grab_width)
1381                 grab_right = grab_width;
1382         if (grab_bottom < 0)
1383                 grab_bottom = grab_height;
1384         if (grab_right < 0)
1385                 grab_right = grab_width;
1386         if (grab_top >= grab_bottom)
1387                 grab_top = 0;
1388         if (grab_left >= grab_right)
1389                 grab_left = 0;
1390 
1391         if (grab_dist_k < 1 || grab_dist_k > 10000)
1392                 grab_dist_k = 700;
1393         if (grab_dist_cx < 0 || grab_dist_cx > grab_width)
1394                 grab_dist_cx = grab_width / 2;
1395         if (grab_dist_cy < 0 || grab_dist_cy > grab_height)
1396                 grab_dist_cy = grab_height / 2;
1397         if (grab_dist_zoom < 1 || grab_dist_zoom > 1000)
1398                 grab_dist_zoom = 100;
1399         if (grab_dist_sensorw < 1 || grab_dist_sensorw > 9999)
1400                 grab_dist_sensorw = 640;
1401         if (grab_dist_sensorh < 1 || grab_dist_sensorh > 9999)
1402                 grab_dist_sensorh = 480;
1403 
1404         INIT_LIST_HEAD (&connections);
1405         for (sections = cfg_list_sections (); *sections != NULL; sections++)
1406         {
1407                 if ((0 == strcasecmp (*sections, "grab"))
1408                                 || (0 == strcasecmp (*sections, "plugins")))
1409                         continue;
1410 
1411                 /* init + set defaults */
1412                 s = malloc (sizeof (*s));
1413                 memset (s, 0, sizeof (*s));
1414                 s->name = *sections;
1415                 s->host = "www";
1416                 s->user = "webcam";
1417                 s->pass = "xxxxxx";
1418                 s->dir = "public_html/images";
1419                 s->file = "webcam.jpeg";
1420                 s->tmpfile = "uploading.jpeg";
1421                 s->passive = 1;
1422                 s->autologin = 0;
1423                 s->ops = &ftp_ops;
1424                 s->keepjpegs = 1;                                               //number of jpeg files to rotate through. 0 & 1 are synonymous
1425                 s->htmlfile = NULL;
1426                 s->custom_htmlfile = NULL;
1427                 s->currentCount = 0;
1428 
1429                 /* from config */
1430                 if (NULL != (val = cfg_get_str (*sections, "host")))
1431                         s->host = val;
1432                 if (NULL != (val = cfg_get_str (*sections, "user")))
1433                         s->user = val;
1434                 if (NULL != (val = cfg_get_str (*sections, "pass")))
1435                         s->pass = val;
1436                 if (NULL != (val = cfg_get_str (*sections, "dir")))
1437                         s->dir = val;
1438                 if (NULL != (val = cfg_get_str (*sections, "file")))
1439                         s->file = val;
1440                 if (NULL != (val = cfg_get_str (*sections, "tmp")))
1441                         s->tmpfile = val;
1442                 if (-1 != (i = cfg_get_int (*sections, "passive")))
1443                         s->passive = i;
1444                 if (-1 != (i = cfg_get_int (*sections, "auto")))
1445                         s->autologin = i;
1446                 if (-1 != (i = cfg_get_int (*sections, "debug")))
1447                         s->debug = i;
1448                 if (-1 != (i = cfg_get_int (*sections, "local")))
1449                         if (i)
1450                                 s->ops = &local_ops;
1451                 if (-1 != (i = cfg_get_int (*sections, "ssh")))
1452                         if (i)
1453                                 s->ops = &ssh_ops;
1454                 if (-1 != (i = cfg_get_int (*sections, "keepjpegs")))
1455                         s->keepjpegs = (i < 1) ? 1 : i;
1456                 if (NULL != (val = cfg_get_str (*sections, "htmlfile")))
1457                         s->htmlfile = val;
1458                 if (NULL != (val = cfg_get_str (*sections, "custom_htmlfile")))
1459                         s->custom_htmlfile = val;
1460 
1461                 /* all done */
1462                 list_add_tail (&s->list, &connections);
1463         }
1464 
1465         /* init everything */
1466         grab_init ();
1467         sleep (grab_wait);
1468         tmpdir = (NULL != getenv ("TMPDIR")) ? getenv ("TMPDIR") : "/tmp";
1469         list_for_each (item, &connections)
1470         {
1471                 s = list_entry (item, struct xfer_state, list);
1472                 s->ops->open (s);
1473         }
1474 
1475         /* print config */
1476         fprintf (stderr, "video4linux webcam v1.5 - (c) 1998-2002 Gerd Knorr\n");
1477         fprintf (stderr, "grabber config:\n  size %dx%d [%s]\n",
1478                                          fmt.width, fmt.height, ng_vfmt_to_desc[gfmt.fmtid]);
1479         fprintf (stderr, "  input %s, norm %s, jpeg quality %d\n",
1480                                          grab_input, grab_norm, grab_quality);
1481         fprintf (stderr, "  rotate=%d, top=%d, left=%d, bottom=%d, right=%d\n",
1482                                          grab_rotate, grab_top, grab_left, grab_bottom, grab_right);
1483         list_for_each (item, &connections)
1484         {
1485                 s = list_entry (item, struct xfer_state, list);
1486                 s->ops->info (s);
1487         }
1488 
1489         /* run as daemon - detach from terminal */
1490         if (daemonize)
1491         {
1492                 switch (fork ())
1493                 {
1494                 case -1:
1495                         perror ("fork");
1496                         exit (1);
1497                 case 0:
1498                         close (0);
1499                         close (1);
1500                         close (2);
1501                         setsid ();
1502                         break;
1503                 default:
1504                         exit (0);
1505                 }
1506         }
1507 
1508 
1509         /* main loop */
1510         for (;;)
1511         {
1512                 /* grab a new one */
1513                 gimg = grab_one (&width, &height, &ng_buf);
1514 
1515                 if (grab_top != 0 || grab_left != 0 ||
1516                                 grab_right != width || grab_bottom != height)
1517                 {                                                                                                               //don't call rotate_image() if nothing to do
1518                         gimg = rotate_image (gimg, &width, &height, grab_rotate,
1519                                                                                                          grab_top, grab_left, grab_bottom, grab_right);
1520                 }
1521 
1522                 if (grab_dist_on)
1523                 {
1524                         gimg = correct_distor (gimg, width, height,
1525                                                                                                                  grab_dist_zoom, grab_dist_k,
1526                                                                                                                  grab_dist_cx, grab_dist_cy,
1527                                                                                                                  grab_dist_sensorw, grab_dist_sensorh);
1528                 }
1529 
1530                 image = gimg;
1531 
1532                 if (grab_trigger)
1533                 {
1534                         /* look if it has changed */
1535                         if (NULL != lastimg)
1536                         {
1537                                 i = compare_images (lastimg, image, iTrigX, iTrigY, iTrigWidth,
1538                                                                                                                 iTrigHeight, width);
1539 
1540                                 if (grab_trigger_average)
1541                                         i = i & 0xFF;
1542                                 else
1543                                         i = i >> 8;
1544 
1545                                 if (i < grab_trigger)
1546                                 {
1547                                         if (grab_trigger_delay)
1548                                                 usleep (grab_trigger_delay * 1000);
1549 
1550                                         continue;
1551                                 }
1552 
1553                         }
1554                         else
1555                         {
1556                                 lastimg = malloc (width * height * 3);
1557 
1558                                 iTrigWidth = width;
1559                                 iTrigHeight = height;
1560                                 fprintf (stderr, "width: %d,height:%d\n", width, height);
1561                                 parse_trigger_area (grab_trigger_area, &iTrigX, &iTrigY, &iTrigWidth,
1562                                                                                                                 &iTrigHeight);
1563                         }
1564 
1565                         memcpy (lastimg, image, width * height * 3);
1566 
1567                         //draw inverted trigger area if debug > 1
1568                         if (s->debug > 1)
1569                                 draw_trigger_area (image, iTrigX, iTrigY, iTrigWidth, iTrigHeight,
1570                                                                                                          width);
1571 
1572                 }
1573 
1574                 if (!list_empty (&plugin_list))
1575                 {
1576                         //if we're using plugins ng_buf will have to be valid
1577                         // to pass to the filters.
1578                         //assign the current image to ng_buf and make sure fmt is
1579                         // valid due to possible size change in rotate_image()
1580                         if (!conv && !ng_buf)
1581                                 ng_buf = ng_malloc_video_buf (&fmt, 3 * fmt.width * fmt.height);
1582 
1583                         ng_buf->fmt.width = width;
1584                         ng_buf->fmt.height = height;
1585                         ng_buf->fmt.bytesperline = width * (ng_vfmt_to_depth[fmt.fmtid] / 8);
1586                         ng_buf->size = ng_buf->fmt.bytesperline * height;
1587                         memcpy (ng_buf->data, image, ng_buf->size);
1588 
1589                         //call the plugins....
1590                         list_for_each (item, &plugin_list)
1591                         {
1592                                 currfilter = list_entry (item, struct plugin_s, list);
1593                                 ng_buf = ng_filter_single (currfilter->filter, ng_buf);
1594                                 image = ng_buf->data;
1595                         }
1596 
1597                 }
1598 
1599                 /* ok, label it and upload */
1600                 add_text (image, width, height);
1601 
1602                 list_for_each (item, &connections)
1603                 {
1604                         s = list_entry (item, struct xfer_state, list);
1605 
1606                         if (++s->currentCount > s->keepjpegs)
1607                                 s->currentCount = 1;
1608 
1609                         s->ops->xfer (s, image, width, height);
1610 
1611                         if (s->htmlfile)                                        // || s->custom_htmlfile)
1612                                 ftp_upload_htmlfile (s);
1613                 }
1614 
1615                 if (archive)
1616                 {
1617                         time_t t;
1618                         struct tm *tm;
1619 
1620                         time (&t);
1621                         tm = localtime (&t);
1622                         strftime (filename, sizeof (filename) - 1, archive, tm);
1623                         if (-1 == (fh = open (filename, O_CREAT | O_WRONLY | O_TRUNC, 0666)))
1624                         {
1625                                 fprintf (stderr, "open %s: %s\n", filename, strerror (errno));
1626                                 exit (1);
1627                         }
1628                         write_file (fh, image, width, height);
1629                 }
1630 
1631                 if (-1 != grab_times && --grab_times == 0)
1632                 {
1633                         fprintf (stderr, "grab \"times\" reached 0\n");
1634                         break;
1635                 }
1636                 if (grab_delay > 0)
1637                 {
1638                         fprintf (stderr, "delay for %d seconds...\n", grab_delay);
1639                         sleep (grab_delay);
1640                 }
1641         }
1642 
1643         list_for_each (item, &connections)
1644         {
1645                 s = list_entry (item, struct xfer_state, list);
1646                 s->ops->close (s);
1647         }
1648 
1649         return 0;
1650 }
1651 
  This page was automatically generated by the LXR engine.