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.
|