1 /*
2 * next generation[tm] xawtv capture interfaces
3 *
4 * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
5 *
6 */
7
8 #define NG_PRIVATE
9 #include "config.h"
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <pthread.h>
16 #include <dirent.h>
17 #include <fnmatch.h>
18 #include <errno.h>
19 #include <ctype.h>
20 #include <inttypes.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23
24 #include <dlfcn.h>
25 #ifndef RTLD_NOW
26 # define RTLD_NOW RTLD_LAZY
27 #endif
28
29 #include "grab-ng.h"
30
31 int ng_debug = 0;
32 int ng_chromakey = 0x00ff00ff;
33 int ng_jpeg_quality = 75;
34 int ng_ratio_x = 4;
35 int ng_ratio_y = 3;
36
37 char ng_v4l_conf[256] = "v4l-conf";
38
39 /* --------------------------------------------------------------------- */
40
41 const unsigned int ng_vfmt_to_depth[] = {
42 0, /* unused */
43 8, /* RGB8 */
44 8, /* GRAY8 */
45 16, /* RGB15 LE */
46 16, /* RGB16 LE */
47 16, /* RGB15 BE */
48 16, /* RGB16 BE */
49 24, /* BGR24 */
50 32, /* BGR32 */
51 24, /* RGB24 */
52 32, /* RGB32 */
53 16, /* LUT2 */
54 32, /* LUT4 */
55 16, /* YUYV */
56 16, /* YUV422P */
57 12, /* YUV420P */
58 0, /* MJPEG */
59 0, /* JPEG */
60 16, /* UYVY */
61 };
62
63 const char* ng_vfmt_to_desc[] = {
64 "none",
65 "8 bit PseudoColor (dithering)",
66 "8 bit StaticGray",
67 "15 bit TrueColor (LE)",
68 "16 bit TrueColor (LE)",
69 "15 bit TrueColor (BE)",
70 "16 bit TrueColor (BE)",
71 "24 bit TrueColor (LE: bgr)",
72 "32 bit TrueColor (LE: bgr-)",
73 "24 bit TrueColor (BE: rgb)",
74 "32 bit TrueColor (BE: -rgb)",
75 "16 bit TrueColor (lut)",
76 "32 bit TrueColor (lut)",
77 "16 bit YUV 4:2:2 (packed, YUYV)",
78 "16 bit YUV 4:2:2 (planar)",
79 "12 bit YUV 4:2:0 (planar)",
80 "MJPEG (AVI)",
81 "JPEG (JFIF)",
82 "16 bit YUV 4:2:2 (packed, UYVY)",
83 };
84
85 /* --------------------------------------------------------------------- */
86
87 const unsigned int ng_afmt_to_channels[] = {
88 0, 1, 2, 1, 2, 1, 2, 0
89 };
90 const unsigned int ng_afmt_to_bits[] = {
91 0, 8, 8, 16, 16, 16, 16, 0
92 };
93 const char* ng_afmt_to_desc[] = {
94 "none",
95 "8bit mono",
96 "8bit stereo",
97 "16bit mono (LE)",
98 "16bit stereo (LE)",
99 "16bit mono (BE)",
100 "16bit stereo (BE)",
101 "mp3 compressed audio",
102 };
103
104 /* --------------------------------------------------------------------- */
105
106 const char* ng_attr_to_desc[] = {
107 "none",
108 "norm",
109 "input",
110 "volume",
111 "mute",
112 "audio mode",
113 "color",
114 "bright",
115 "hue",
116 "contrast",
117 };
118
119 /* --------------------------------------------------------------------- */
120
121 void ng_init_video_buf(struct ng_video_buf *buf)
122 {
123 memset(buf,0,sizeof(*buf));
124 pthread_mutex_init(&buf->lock,NULL);
125 pthread_cond_init(&buf->cond,NULL);
126 }
127
128 void ng_release_video_buf(struct ng_video_buf *buf)
129 {
130 int release;
131
132 pthread_mutex_lock(&buf->lock);
133 buf->refcount--;
134 release = (buf->refcount == 0);
135 pthread_mutex_unlock(&buf->lock);
136 if (release && NULL != buf->release)
137 buf->release(buf);
138 }
139
140 void ng_wakeup_video_buf(struct ng_video_buf *buf)
141 {
142 pthread_cond_signal(&buf->cond);
143 }
144
145 void ng_waiton_video_buf(struct ng_video_buf *buf)
146 {
147 pthread_mutex_lock(&buf->lock);
148 while (buf->refcount)
149 pthread_cond_wait(&buf->cond, &buf->lock);
150 pthread_mutex_unlock(&buf->lock);
151 }
152
153 static void ng_free_video_buf(struct ng_video_buf *buf)
154 {
155 free(buf->data);
156 free(buf);
157 }
158
159 struct ng_video_buf*
160 ng_malloc_video_buf(struct ng_video_fmt *fmt, int size)
161 {
162 struct ng_video_buf *buf;
163
164 buf = malloc(sizeof(*buf));
165 if (NULL == buf)
166 return NULL;
167 ng_init_video_buf(buf);
168 buf->fmt = *fmt;
169 buf->size = size;
170 buf->data = malloc(size);
171 if (NULL == buf->data) {
172 free(buf);
173 return NULL;
174 }
175 buf->refcount = 1;
176 buf->release = ng_free_video_buf;
177 return buf;
178 }
179
180 /* --------------------------------------------------------------------- */
181
182 struct ng_audio_buf*
183 ng_malloc_audio_buf(struct ng_audio_fmt *fmt, int size)
184 {
185 struct ng_audio_buf *buf;
186
187 buf = malloc(sizeof(*buf)+size);
188 memset(buf,0,sizeof(*buf));
189 buf->fmt = *fmt;
190 buf->size = size;
191 buf->data = (char*)buf + sizeof(*buf);
192 return buf;
193 }
194
195 /* --------------------------------------------------------------------- */
196
197 struct ng_attribute*
198 ng_attr_byid(struct ng_attribute *attrs, int id)
199 {
200 if (NULL == attrs)
201 return NULL;
202 for (;;) {
203 if (NULL == attrs->name)
204 return NULL;
205 if (attrs->id == id)
206 return attrs;
207 attrs++;
208 }
209 }
210
211 struct ng_attribute*
212 ng_attr_byname(struct ng_attribute *attrs, char *name)
213 {
214 if (NULL == attrs)
215 return NULL;
216 for (;;) {
217 if (NULL == attrs->name)
218 return NULL;
219 if (0 == strcasecmp(attrs->name,name))
220 return attrs;
221 attrs++;
222 }
223 }
224
225 const char*
226 ng_attr_getstr(struct ng_attribute *attr, int value)
227 {
228 int i;
229
230 if (NULL == attr)
231 return NULL;
232 if (attr->type != ATTR_TYPE_CHOICE)
233 return NULL;
234
235 for (i = 0; attr->choices[i].str != NULL; i++)
236 if (attr->choices[i].nr == value)
237 return attr->choices[i].str;
238 return NULL;
239 }
240
241 int
242 ng_attr_getint(struct ng_attribute *attr, char *value)
243 {
244 int i,val;
245
246 if (NULL == attr)
247 return -1;
248 if (attr->type != ATTR_TYPE_CHOICE)
249 return -1;
250
251 for (i = 0; attr->choices[i].str != NULL; i++) {
252 if (0 == strcasecmp(attr->choices[i].str,value))
253 return attr->choices[i].nr;
254 }
255
256 if (isdigit(value[0])) {
257 /* Hmm. String not found, but starts with a digit.
258 Check if this is a valid number ... */
259 val = atoi(value);
260 for (i = 0; attr->choices[i].str != NULL; i++)
261 if (val == attr->choices[i].nr)
262 return attr->choices[i].nr;
263
264 }
265 return -1;
266 }
267
268 void
269 ng_attr_listchoices(struct ng_attribute *attr)
270 {
271 int i;
272
273 fprintf(stderr,"valid choices for \"%s\": ",attr->name);
274 for (i = 0; attr->choices[i].str != NULL; i++)
275 fprintf(stderr,"%s\"%s\"",
276 i ? ", " : "",
277 attr->choices[i].str);
278 fprintf(stderr,"\n");
279 }
280
281 int
282 ng_attr_int2percent(struct ng_attribute *attr, int value)
283 {
284 int range,percent;
285
286 range = attr->max - attr->min;
287 percent = (value - attr->min) * 100 / range;
288 if (percent < 0)
289 percent = 0;
290 if (percent > 100)
291 percent = 100;
292 return percent;
293 }
294
295 int
296 ng_attr_percent2int(struct ng_attribute *attr, int percent)
297 {
298 int range,value;
299
300 range = attr->max - attr->min;
301 value = percent * range / 100 + attr->min;
302 if (value < attr->min)
303 value = attr->min;
304 if (value > attr->max)
305 value = attr->max;
306 return value;
307 }
308
309 int
310 ng_attr_parse_int(struct ng_attribute *attr, char *str)
311 {
312 int value,n;
313
314 if (0 == sscanf(str,"%d%n",&value,&n))
315 /* parse error */
316 return attr->defval;
317 if (str[n] == '%')
318 value = ng_attr_percent2int(attr,value);
319 if (value < attr->min)
320 value = attr->min;
321 if (value > attr->max)
322 value = attr->max;
323 return value;
324 }
325
326 /* --------------------------------------------------------------------- */
327
328 void
329 ng_ratio_fixup(int *width, int *height, int *xoff, int *yoff)
330 {
331 int h = *height;
332 int w = *width;
333
334 if (0 == ng_ratio_x || 0 == ng_ratio_y)
335 return;
336 if (w * ng_ratio_y < h * ng_ratio_x) {
337 *height = *width * ng_ratio_y / ng_ratio_x;
338 if (yoff)
339 *yoff += (h-*height)/2;
340 } else if (w * ng_ratio_y > h * ng_ratio_x) {
341 *width = *height * ng_ratio_x / ng_ratio_y;
342 if (yoff)
343 *xoff += (w-*width)/2;
344 }
345 }
346
347 void
348 ng_ratio_fixup2(int *width, int *height, int *xoff, int *yoff,
349 int ratio_x, int ratio_y, int up)
350 {
351 int h = *height;
352 int w = *width;
353
354 if (0 == ratio_x || 0 == ratio_y)
355 return;
356 if ((!up && w * ratio_y < h * ratio_x) ||
357 (up && w * ratio_y > h * ratio_x)) {
358 *height = *width * ratio_y / ratio_x;
359 if (yoff)
360 *yoff += (h-*height)/2;
361 } else if ((!up && w * ratio_y > h * ratio_x) ||
362 (up && w * ratio_y < h * ratio_x)) {
363 *width = *height * ratio_x / ratio_y;
364 if (yoff)
365 *xoff += (w-*width)/2;
366 }
367 }
368
369 /* --------------------------------------------------------------------- */
370
371 LIST_HEAD(ng_conv);
372 LIST_HEAD(ng_aconv);
373 LIST_HEAD(ng_filters);
374 LIST_HEAD(ng_writers);
375 LIST_HEAD(ng_readers);
376 LIST_HEAD(ng_vid_drivers);
377 LIST_HEAD(ng_dsp_drivers);
378 LIST_HEAD(ng_mix_drivers);
379
380 static int ng_check_magic(int magic, char *plugname, char *type)
381 {
382 if (magic != NG_PLUGIN_MAGIC) {
383 fprintf(stderr, "ERROR: plugin magic mismatch [xawtv=%d,%s=%d]\n",
384 NG_PLUGIN_MAGIC,plugname,magic);
385 return -1;
386 }
387 #if 0
388 if (ng_debug)
389 fprintf(stderr,"plugins: %s registered by %s\n",type,plugname);
390 #endif
391 return 0;
392 }
393
394 int
395 ng_conv_register(int magic, char *plugname,
396 struct ng_video_conv *list, int count)
397 {
398 int n;
399
400 if (0 != ng_check_magic(magic,plugname,"video converters"))
401 return -1;
402 for (n = 0; n < count; n++)
403 list_add_tail(&(list[n].list),&ng_conv);
404 return 0;
405 }
406
407 int
408 ng_aconv_register(int magic, char *plugname,
409 struct ng_audio_conv *list, int count)
410 {
411 int n;
412
413 if (0 != ng_check_magic(magic,plugname,"audio converters"))
414 return -1;
415 for (n = 0; n < count; n++)
416 list_add_tail(&(list[n].list),&ng_aconv);
417 return 0;
418 }
419
420 int
421 ng_filter_register(int magic, char *plugname, struct ng_filter *filter)
422 {
423 if (0 != ng_check_magic(magic,plugname,"filter"))
424 return -1;
425 list_add_tail(&filter->list,&ng_filters);
426 return 0;
427 }
428
429 int
430 ng_writer_register(int magic, char *plugname, struct ng_writer *writer)
431 {
432 if (0 != ng_check_magic(magic,plugname,"writer"))
433 return -1;
434 list_add_tail(&writer->list,&ng_writers);
435 return 0;
436 }
437
438 int
439 ng_reader_register(int magic, char *plugname, struct ng_reader *reader)
440 {
441 if (0 != ng_check_magic(magic,plugname,"reader"))
442 return -1;
443 list_add_tail(&reader->list,&ng_readers);
444 return 0;
445 }
446
447 int
448 ng_vid_driver_register(int magic, char *plugname, struct ng_vid_driver *driver)
449 {
450 if (0 != ng_check_magic(magic,plugname,"video drv"))
451 return -1;
452 list_add_tail(&driver->list,&ng_vid_drivers);
453 return 0;
454 }
455
456 int
457 ng_dsp_driver_register(int magic, char *plugname, struct ng_dsp_driver *driver)
458 {
459 if (0 != ng_check_magic(magic,plugname,"dsp drv"))
460 return -1;
461 list_add_tail(&driver->list,&ng_dsp_drivers);
462 return 0;
463 }
464
465 int
466 ng_mix_driver_register(int magic, char *plugname, struct ng_mix_driver *driver)
467 {
468 if (0 != ng_check_magic(magic,plugname,"mixer drv"))
469 return -1;
470 list_add_tail(&driver->list,&ng_mix_drivers);
471 return 0;
472 }
473
474 struct ng_video_conv*
475 ng_conv_find_to(unsigned int out, int *i)
476 {
477 struct list_head *item;
478 struct ng_video_conv *ret;
479 int j = 0;
480
481 list_for_each(item,&ng_conv) {
482 if (j < *i) {
483 j++;
484 continue;
485 }
486 ret = list_entry(item, struct ng_video_conv, list);
487 #if 0
488 fprintf(stderr,"\tconv to: %-28s => %s\n",
489 ng_vfmt_to_desc[ret->fmtid_in],
490 ng_vfmt_to_desc[ret->fmtid_out]);
491 #endif
492 if (ret->fmtid_out == out) {
493 (*i)++;
494 return ret;
495 }
496 (*i)++;
497 j++;
498 }
499 return NULL;
500 }
501
502 struct ng_video_conv*
503 ng_conv_find_from(unsigned int in, int *i)
504 {
505 struct list_head *item;
506 struct ng_video_conv *ret;
507
508 int j = 0;
509
510 list_for_each(item,&ng_conv) {
511 if (j < *i) {
512 j++;
513 continue;
514 }
515 ret = list_entry(item, struct ng_video_conv, list);
516 #if 0
517 fprintf(stderr,"\tconv from: %-28s => %s\n",
518 ng_vfmt_to_desc[ret->fmtid_in],
519 ng_vfmt_to_desc[ret->fmtid_out]);
520 #endif
521 if (ret->fmtid_in == in) {
522 (*i)++;
523 return ret;
524 }
525 }
526 return NULL;
527 }
528
529 struct ng_video_conv*
530 ng_conv_find_match(unsigned int in, unsigned int out)
531 {
532 struct list_head *item;
533 struct ng_video_conv *ret = NULL;
534
535 list_for_each(item,&ng_conv) {
536 ret = list_entry(item, struct ng_video_conv, list);
537 if (ret->fmtid_in == in && ret->fmtid_out == out)
538 return ret;
539 }
540 return NULL;
541 }
542
543 /* --------------------------------------------------------------------- */
544
545 const struct ng_vid_driver*
546 ng_vid_open(char *device, char *driver, struct ng_video_fmt *screen,
547 void *base, void **handle)
548 {
549 struct list_head *item;
550 struct ng_vid_driver *drv;
551
552 #ifdef __linux__
553 if (NULL != screen) {
554 switch (system(ng_v4l_conf)) {
555 case -1: /* can't run */
556 fprintf(stderr,"could'nt start v4l-conf\n");
557 break;
558 case 0: /* ok */
559 break;
560 default: /* non-zero return */
561 fprintf(stderr,"v4l-conf had some trouble, "
562 "trying to continue anyway\n");
563 break;
564 }
565 }
566 #endif
567
568 /* check all grabber drivers */
569 list_for_each(item,&ng_vid_drivers) {
570 drv = list_entry(item, struct ng_vid_driver, list);
571 if (driver && 0 != strcasecmp(driver, drv->name))
572 continue;
573 if (ng_debug)
574 fprintf(stderr,"vid-open: trying: %s... \n", drv->name);
575 if (NULL != (*handle = drv->open(device)))
576 break;
577 if (ng_debug)
578 fprintf(stderr,"vid-open: failed: %s\n",drv->name);
579 }
580 if (item == &ng_vid_drivers)
581 return NULL;
582 if (ng_debug)
583 fprintf(stderr,"vid-open: ok: %s\n",drv->name);
584 if (NULL != screen && drv->capabilities(*handle) & CAN_OVERLAY)
585 drv->setupfb(*handle,screen,base);
586 return drv;
587 }
588
589 const struct ng_dsp_driver*
590 ng_dsp_open(char *device, struct ng_audio_fmt *fmt, int record, void **handle)
591 {
592 struct list_head *item;
593 struct ng_dsp_driver *drv;
594
595 /* check all dsp drivers */
596 list_for_each(item,&ng_dsp_drivers) {
597 drv = list_entry(item, struct ng_dsp_driver, list);
598 if (NULL == drv->name)
599 continue;
600 if (record && NULL == drv->read)
601 continue;
602 if (!record && NULL == drv->write)
603 continue;
604 if (ng_debug)
605 fprintf(stderr,"dsp-open: trying: %s... \n", drv->name);
606 if (NULL != (*handle = drv->open(device,fmt,record)))
607 break;
608 if (ng_debug)
609 fprintf(stderr,"dsp-open: failed: %s\n", drv->name);
610 }
611 if (item == &ng_dsp_drivers)
612 return NULL;
613 if (ng_debug)
614 fprintf(stderr,"dsp-open: ok: %s\n",drv->name);
615 return drv;
616 }
617
618 struct ng_attribute*
619 ng_mix_init(char *device, char *channel)
620 {
621 struct list_head *item;
622 struct ng_mix_driver *drv = NULL;
623 struct ng_attribute *attrs = NULL;
624 void *handle;
625
626 /* check all mixer drivers */
627 list_for_each(item, &ng_mix_drivers) {
628 drv = list_entry(item, struct ng_mix_driver, list);
629 if (ng_debug)
630 fprintf(stderr,"mix-init: trying: %s... \n", drv->name);
631 if (NULL != (handle = drv->open(device))) {
632 if (NULL != (attrs = drv->volctl(handle,channel)))
633 break;
634 drv->close(handle);
635 }
636 if (ng_debug)
637 fprintf(stderr,"mix-init: failed: %s\n",drv->name);
638 }
639 if (ng_debug && NULL != attrs)
640 fprintf(stderr,"mix-init: ok: %s\n",drv->name);
641 return attrs;
642 }
643
644 struct ng_reader* ng_find_reader(char *filename)
645 {
646 struct list_head *item;
647 struct ng_reader *reader;
648 char blk[512];
649 FILE *fp;
650 int m;
651
652 if (NULL == (fp = fopen(filename, "r"))) {
653 fprintf(stderr,"open %s: %s\n",filename,strerror(errno));
654 return NULL;
655 }
656 memset(blk,0,sizeof(blk));
657 fread(blk,1,sizeof(blk),fp);
658 fclose(fp);
659
660 list_for_each(item,&ng_readers) {
661 reader = list_entry(item, struct ng_reader, list);
662 for (m = 0; m < 4 && reader->mlen[m] > 0; m++) {
663 if (0 == memcmp(blk+reader->moff[m],reader->magic[m],
664 reader->mlen[m]))
665 return reader;
666 }
667 }
668 if (ng_debug)
669 fprintf(stderr,"%s: no reader found\n",filename);
670 return NULL;
671 }
672
673 int64_t
674 ng_tofday_to_timestamp(struct timeval *tv)
675 {
676 long long ts;
677
678 ts = tv->tv_sec;
679 ts *= 1000000;
680 ts += tv->tv_usec;
681 ts *= 1000;
682 return ts;
683 }
684
685 int64_t
686 ng_get_timestamp()
687 {
688 struct timeval tv;
689
690 gettimeofday(&tv,NULL);
691 return ng_tofday_to_timestamp(&tv);
692 }
693
694 struct ng_video_buf*
695 ng_filter_single(struct ng_filter *filter, struct ng_video_buf *in)
696 {
697 struct ng_video_buf *out = in;
698 void *handle;
699
700 if (NULL != filter && filter->fmts & (1 << in->fmt.fmtid)) {
701 handle = filter->init(&in->fmt);
702 out = filter->frame(handle,in);
703 filter->fini(handle);
704 }
705 return out;
706 }
707
708 /* --------------------------------------------------------------------- */
709
710 static void clip_dump(char *state, struct OVERLAY_CLIP *oc, int count)
711 {
712 int i;
713
714 fprintf(stderr,"clip: %s - %d clips\n",state,count);
715 for (i = 0; i < count; i++)
716 fprintf(stderr,"clip: %d: %dx%d+%d+%d\n",i,
717 oc[i].x2 - oc[i].x1,
718 oc[i].y2 - oc[i].y1,
719 oc[i].x1, oc[i].y1);
720 }
721
722 static void clip_drop(struct OVERLAY_CLIP *oc, int n, int *count)
723 {
724 (*count)--;
725 memmove(oc+n, oc+n+1, sizeof(struct OVERLAY_CLIP) * (*count-n));
726 }
727
728 void ng_check_clipping(int width, int height, int xadjust, int yadjust,
729 struct OVERLAY_CLIP *oc, int *count)
730 {
731 int i,j;
732
733 if (ng_debug > 1) {
734 fprintf(stderr,"clip: win=%dx%d xa=%d ya=%d\n",
735 width,height,xadjust,yadjust);
736 clip_dump("init",oc,*count);
737 }
738 for (i = 0; i < *count; i++) {
739 /* fixup coordinates */
740 oc[i].x1 += xadjust;
741 oc[i].x2 += xadjust;
742 oc[i].y1 += yadjust;
743 oc[i].y2 += yadjust;
744 }
745 if (ng_debug > 1)
746 clip_dump("fixup adjust",oc,*count);
747
748 for (i = 0; i < *count; i++) {
749 /* fixup borders */
750 if (oc[i].x1 < 0)
751 oc[i].x1 = 0;
752 if (oc[i].x2 < 0)
753 oc[i].x2 = 0;
754 if (oc[i].x1 > width)
755 oc[i].x1 = width;
756 if (oc[i].x2 > width)
757 oc[i].x2 = width;
758 if (oc[i].y1 < 0)
759 oc[i].y1 = 0;
760 if (oc[i].y2 < 0)
761 oc[i].y2 = 0;
762 if (oc[i].y1 > height)
763 oc[i].y1 = height;
764 if (oc[i].y2 > height)
765 oc[i].y2 = height;
766 }
767 if (ng_debug > 1)
768 clip_dump("fixup range",oc,*count);
769
770 /* drop zero-sized clips */
771 for (i = 0; i < *count;) {
772 if (oc[i].x1 == oc[i].x2 || oc[i].y1 == oc[i].y2) {
773 clip_drop(oc,i,count);
774 continue;
775 }
776 i++;
777 }
778 if (ng_debug > 1)
779 clip_dump("zerosize done",oc,*count);
780
781 /* try to merge clips */
782 restart_merge:
783 for (j = *count - 1; j >= 0; j--) {
784 for (i = 0; i < *count; i++) {
785 if (i == j)
786 continue;
787 if (oc[i].x1 == oc[j].x1 &&
788 oc[i].x2 == oc[j].x2 &&
789 oc[i].y1 <= oc[j].y1 &&
790 oc[i].y2 >= oc[j].y1) {
791 if (ng_debug > 1)
792 fprintf(stderr,"clip: merge y %d,%d\n",i,j);
793 if (oc[i].y2 < oc[j].y2)
794 oc[i].y2 = oc[j].y2;
795 clip_drop(oc,j,count);
796 if (ng_debug > 1)
797 clip_dump("merge y done",oc,*count);
798 goto restart_merge;
799 }
800 if (oc[i].y1 == oc[j].y1 &&
801 oc[i].y2 == oc[j].y2 &&
802 oc[i].x1 <= oc[j].x1 &&
803 oc[i].x2 >= oc[j].x1) {
804 if (ng_debug > 1)
805 fprintf(stderr,"clip: merge x %d,%d\n",i,j);
806 if (oc[i].x2 < oc[j].x2)
807 oc[i].x2 = oc[j].x2;
808 clip_drop(oc,j,count);
809 if (ng_debug > 1)
810 clip_dump("merge x done",oc,*count);
811 goto restart_merge;
812 }
813 }
814 }
815 if (ng_debug)
816 clip_dump("final",oc,*count);
817 }
818
819 /* --------------------------------------------------------------------- */
820
821 static int ng_plugins(char *dirname)
822 {
823 struct dirent **list;
824 char filename[1024];
825 void *plugin;
826 void (*initcall)(void);
827 int i,n = 0,l = 0;
828
829 n = scandir(dirname,&list,NULL,alphasort);
830 if (n <= 0)
831 return 0;
832 for (i = 0; i < n; i++) {
833 if (0 != fnmatch("*.so",list[i]->d_name,0))
834 continue;
835 sprintf(filename,"%s/%s",dirname,list[i]->d_name);
836 if (NULL == (plugin = dlopen(filename,RTLD_NOW))) {
837 fprintf(stderr,"dlopen: %s\n",dlerror());
838 continue;
839 }
840 if (NULL == (initcall = dlsym(plugin,"ng_plugin_init"))) {
841 if (NULL == (initcall = dlsym(plugin,"_ng_plugin_init"))) {
842 fprintf(stderr,"dlsym[%s]: %s\n",filename,dlerror());
843 continue;
844 }
845 }
846 initcall();
847 l--;
848 }
849 for (i = 0; i < n; i++)
850 free(list[i]);
851 free(list);
852 return l;
853 }
854
855 void
856 ng_init(void)
857 {
858 static int once=0;
859 int count=0;
860
861 if (once++) {
862 fprintf(stderr,"panic: ng_init called twice\n");
863 exit(1);
864 }
865 ng_device_init();
866 ng_color_packed_init();
867 ng_color_yuv2rgb_init();
868 ng_writefile_init();
869
870 count += ng_plugins(LIBDIR);
871 if (0 == count) {
872 /* nice for development */
873 count += ng_plugins("../libng/plugins");
874 count += ng_plugins("../libng/contrib-plugins");
875 }
876 if (0 == count)
877 fprintf(stderr,"WARNING: no plugins found [%s]\n",LIBDIR);
878 }
879
|
This page was automatically generated by the
LXR engine.
|