ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Video-Capture-V4l/V4l/V4l.xs
Revision: 1.5
Committed: Sun Jun 13 16:05:17 2004 UTC (19 years, 11 months ago) by root
Branch: MAIN
CVS Tags: rel-0_9, rel-0_902, HEAD
Changes since 1.4: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include <sys/types.h>
6 #include <sys/time.h>
7 #include <unistd.h>
8 #include <sys/mman.h>
9
10 #include <string.h>
11 #include <pthread.h>
12 #include <linux/videodev.h>
13
14 #define NEED_newCONSTSUB
15 #include "../gppport.h"
16
17 #ifndef pTHX_
18 #define pTHX_
19 #endif
20
21 #define XSRETURN_bool(bool) if (bool) XSRETURN_YES; else XSRETURN_NO;
22
23 #define VBI_BPF (2048*32)
24
25 typedef struct video_capability *Video__Capture__V4l__Capability;
26 typedef struct video_channel *Video__Capture__V4l__Channel;
27 typedef struct video_audio *Video__Capture__V4l__Audio;
28 typedef struct video_picture *Video__Capture__V4l__Picture;
29 typedef struct video_tuner *Video__Capture__V4l__Tuner;
30
31 static void
32 attach_struct (SV *sv, size_t bytes)
33 {
34 void *ptr;
35
36 sv = SvRV (sv);
37 Newz (0, ptr, bytes, void*);
38
39 sv_magic (sv, 0, '~', 0, bytes);
40 mg_find(sv, '~')->mg_ptr = ptr;
41 }
42
43 static SV *
44 new_struct (SV *sv, size_t bytes, const char *pkg)
45 {
46 SV *rv = newRV_noinc (sv);
47 attach_struct (rv, bytes);
48 return sv_bless (rv, gv_stashpv ((char *)pkg, TRUE));
49 }
50
51 static void *
52 old_struct (SV *sv, const char *name)
53 {
54 /* TODO: check name */
55 return mg_find (SvRV(sv), '~')->mg_ptr;
56 }
57
58 static int
59 framesize (unsigned int format, unsigned int pixels)
60 {
61 if (format==VIDEO_PALETTE_RGB565) return pixels*2;
62 if (format==VIDEO_PALETTE_RGB24) return pixels*3;
63 if (format==VIDEO_PALETTE_RGB555) return pixels*2;
64 if (format==VIDEO_PALETTE_HI240) return pixels*1;
65 if (format==VIDEO_PALETTE_GREY) return pixels*1;
66 if (format==VIDEO_PALETTE_RGB32) return pixels*4;
67 if (format==VIDEO_PALETTE_UYVY) return pixels*2;
68 if (format==VIDEO_PALETTE_YUYV) return pixels*2;
69 /* everything below is very probably WRONG */
70 if (format==VIDEO_PALETTE_YUV410P) return pixels*2;
71 if (format==VIDEO_PALETTE_YUV411) return pixels*2;
72 if (format==VIDEO_PALETTE_YUV411P) return pixels*2;
73 if (format==VIDEO_PALETTE_YUV420) return pixels*3/2;
74 if (format==VIDEO_PALETTE_YUV420P) return pixels*3/2;
75 if (format==VIDEO_PALETTE_YUV422) return pixels*2;
76 if (format==VIDEO_PALETTE_YUV422P) return pixels*2;
77 if (format==VIDEO_PALETTE_PLANAR) return pixels*2;
78 if (format==VIDEO_PALETTE_RAW) return pixels*8;
79 return 0;
80 }
81
82 struct private {
83 int fd;
84 unsigned char *mmap_base;
85 struct video_mbuf vm;
86 };
87
88 static int
89 private_free (pTHX_ SV *obj, MAGIC *mg)
90 {
91 struct private *p = (struct private *)mg->mg_ptr;
92 munmap (p->mmap_base, p->vm.size);
93 return 0;
94 }
95
96 static MGVTBL vtbl_private = {0, 0, 0, 0, private_free};
97
98 static struct private *
99 find_private (SV *sv)
100 {
101 HV *hv = (HV*)SvRV(sv);
102 MAGIC *mg = mg_find ((SV*)hv, '~');
103
104 if (!mg)
105 {
106 struct private p;
107 p.fd = SvIV (*hv_fetch (hv, "fd", 2, 0));
108 if (ioctl (p.fd, VIDIOCGMBUF, &p.vm) == 0)
109 {
110 p.mmap_base = (unsigned char *)mmap (0, p.vm.size, PROT_READ|PROT_WRITE, MAP_SHARED, p.fd, 0);
111 if (p.mmap_base)
112 {
113 sv_magic ((SV*)hv, 0, '~', (char*)&p, sizeof p);
114 mg = mg_find ((SV*)hv, '~');
115 mg->mg_virtual = &vtbl_private;
116 }
117 }
118 }
119
120 return (struct private *) (mg ? mg->mg_ptr : 0);
121 }
122
123 typedef unsigned char u8;
124 typedef unsigned int UI;
125
126 #define get_field(field) (*hv_fetch ((HV*)SvRV (self), #field, strlen(#field), 0))
127
128 /* only one thread currently */
129 typedef struct vbi_frame {
130 struct vbi_frame *next;
131 int size;
132 char data[VBI_BPF];
133 } vbi_frame;
134 static vbi_frame *vbi_head, *vbi_tail,
135 *vbi_free;
136 static int vbi_fd;
137 static UI vbi_max;
138 static pthread_t vbi_snatcher;
139 static pthread_mutex_t vbi_lock = PTHREAD_MUTEX_INITIALIZER;
140 static pthread_cond_t vbi_cond = PTHREAD_COND_INITIALIZER;
141
142 static void *
143 vbi_snatcher_thread (void *arg)
144 {
145 /* try to become a realtime process. */
146 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
147 {
148 struct sched_param sp;
149
150 sp.sched_priority = (sched_get_priority_max (SCHED_FIFO)
151 + sched_get_priority_min (SCHED_FIFO)) / 2 - 1;
152 pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp);
153 }
154 #endif
155 for(;;)
156 {
157 vbi_frame *next;
158
159 pthread_mutex_lock (&vbi_lock);
160 if (vbi_free)
161 {
162 next = vbi_free;
163 vbi_free = vbi_free->next;
164 pthread_mutex_unlock (&vbi_lock);
165
166 next->next = 0;
167 next->size = read (vbi_fd, next->data, VBI_BPF);
168
169 pthread_mutex_lock (&vbi_lock);
170
171 if (vbi_tail)
172 vbi_tail->next = next;
173 else
174 vbi_head = vbi_tail = next;
175
176 vbi_tail = next;
177 vbi_max--;
178
179 pthread_cond_signal (&vbi_cond);
180 pthread_mutex_unlock (&vbi_lock);
181 }
182 else
183 {
184 static struct timespec to = { 0, 1000000000 / 70 }; /* skip almost a frame */
185
186 pthread_mutex_unlock (&vbi_lock);
187 pthread_testcancel ();
188 nanosleep (&to, 0);
189 }
190 }
191 }
192
193 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l::VBI
194
195 PROTOTYPES: ENABLE
196
197 SV *
198 field(self)
199 SV * self
200 CODE:
201 int fd = SvIV(get_field(fd));
202
203 if (vbi_fd == fd)
204 {
205 vbi_frame *next;
206
207 pthread_mutex_lock (&vbi_lock);
208 while (!vbi_head)
209 pthread_cond_wait (&vbi_cond, &vbi_lock);
210
211 RETVAL = newSVpvn (vbi_head->data, vbi_head->size);
212
213 vbi_max++;
214 next = vbi_head->next;
215
216 vbi_head->next = vbi_free;
217 vbi_free = vbi_head;
218
219 vbi_head = next;
220
221 if (!next)
222 vbi_tail = vbi_head;
223
224 pthread_mutex_unlock (&vbi_lock);
225 }
226 else
227 {
228 int len;
229
230 RETVAL = newSVpvn ("", 0);
231 SvGROW (RETVAL, VBI_BPF);
232 len = read (fd, SvPV_nolen (RETVAL), VBI_BPF);
233 SvCUR_set (RETVAL, len);
234 }
235
236 OUTPUT:
237 RETVAL
238
239 void
240 backlog(self,backlog)
241 SV * self
242 unsigned int backlog
243 CODE:
244 {
245 while (vbi_max != backlog)
246 {
247 vbi_frame *f;
248
249 pthread_mutex_lock (&vbi_lock);
250
251 if (vbi_max < backlog)
252 {
253 f = malloc (sizeof (vbi_frame));
254 f->next = vbi_free;
255 vbi_free = f;
256 vbi_max++;
257 }
258 else
259 {
260 if (vbi_free)
261 {
262 f = vbi_free;
263 vbi_free = vbi_free->next;
264 free (f);
265 vbi_max--;
266 }
267 }
268
269 pthread_mutex_unlock (&vbi_lock);
270 }
271
272 if (backlog)
273 {
274 if (!vbi_fd)
275 {
276 vbi_fd = SvIV(get_field(fd));
277 pthread_create (&vbi_snatcher, 0, vbi_snatcher_thread, 0);
278 }
279 }
280 else
281 {
282 if (vbi_fd)
283 {
284 pthread_cancel (vbi_snatcher);
285 pthread_join (vbi_snatcher, 0);
286 vbi_fd = 0;
287 }
288
289 /* no locking necessary, in theory */
290 while (vbi_head)
291 {
292 vbi_frame *next = vbi_head->next;
293
294 free (vbi_head);
295 vbi_head = next;
296 }
297
298 vbi_tail = 0;
299 }
300 }
301
302 int
303 queued(self)
304 CODE:
305 if (vbi_fd)
306 {
307 /* FIXME: lock/unlock */
308 pthread_mutex_lock (&vbi_lock);
309 RETVAL = !!vbi_head;
310 pthread_mutex_unlock (&vbi_lock);
311 }
312 else
313 RETVAL = 1;
314 OUTPUT:
315 RETVAL
316
317 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l
318
319 SV *
320 capture(sv,frame,width,height,format = VIDEO_PALETTE_RGB24)
321 SV *sv
322 unsigned int frame
323 unsigned int width
324 unsigned int height
325 unsigned int format
326 CODE:
327 {
328 struct private *p;
329 if ((p = find_private (sv)))
330 {
331 struct video_mmap vm;
332 vm.frame = frame;
333 vm.height = height;
334 vm.width = width;
335 vm.format = format;
336 if (ioctl (p->fd, VIDIOCMCAPTURE, &vm) == 0)
337 {
338 SV *fr = newSV (0);
339 SvUPGRADE (fr, SVt_PV);
340 SvREADONLY_on (fr);
341 SvPVX (fr) = p->mmap_base + p->vm.offsets[frame];
342 SvCUR_set (fr, framesize (format, width*height));
343 SvLEN_set (fr, 0);
344 SvPOK_only (fr);
345 RETVAL = fr;
346 }
347 else
348 XSRETURN_EMPTY;
349 }
350 else
351 XSRETURN_EMPTY;
352 }
353 OUTPUT:
354 RETVAL
355
356 void
357 sync(sv,frame)
358 SV *sv
359 int frame
360 PPCODE:
361 {
362 struct private *p;
363 if ((p = find_private (sv))
364 && ioctl (p->fd, VIDIOCSYNC, &frame) == 0)
365 XSRETURN_YES;
366 else
367 XSRETURN_EMPTY;
368 }
369
370 unsigned long
371 _freq (fd,fr)
372 int fd
373 unsigned long fr
374 CODE:
375 if (items > 1)
376 {
377 fr = ((fr<<4)+499)/1000;
378 ioctl (fd, VIDIOCSFREQ, &fr);
379 }
380 if (GIMME_V != G_VOID)
381 {
382 if (ioctl (fd, VIDIOCGFREQ, &fr) == 0)
383 RETVAL = (fr*1000+7)>>4;
384 else
385 XSRETURN_EMPTY;
386 }
387 else
388 XSRETURN (0);
389 OUTPUT:
390 RETVAL
391
392
393 SV *
394 _capabilities_new(fd)
395 int fd
396 CODE:
397 RETVAL = new_struct (newSViv (fd), sizeof (struct video_capability), "Video::Capture::V4l::Capability");
398 OUTPUT:
399 RETVAL
400
401 SV *
402 _channel_new(fd)
403 int fd
404 CODE:
405 RETVAL = new_struct (newSViv (fd), sizeof (struct video_channel), "Video::Capture::V4l::Channel");
406 OUTPUT:
407 RETVAL
408
409 SV *
410 _tuner_new(fd)
411 int fd
412 CODE:
413 RETVAL = new_struct (newSViv (fd), sizeof (struct video_tuner), "Video::Capture::V4l::Tuner");
414 OUTPUT:
415 RETVAL
416
417 SV *
418 _audio_new(fd)
419 int fd
420 CODE:
421 RETVAL = new_struct (newSViv (fd), sizeof (struct video_audio), "Video::Capture::V4l::Audio");
422 OUTPUT:
423 RETVAL
424
425 SV *
426 _picture_new(fd)
427 int fd
428 CODE:
429 RETVAL = new_struct (newSViv (fd), sizeof (struct video_picture), "Video::Capture::V4l::Picture");
430 OUTPUT:
431 RETVAL
432
433 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l::Capability
434
435 void
436 get(sv)
437 SV * sv
438 CODE:
439 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCGCAP, old_struct (sv, "Video::Capture::V4l::Capability")) == 0);
440
441 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l::Channel
442
443 void
444 get(sv)
445 SV * sv
446 CODE:
447 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCGCHAN, old_struct (sv, "Video::Capture::V4l::Channel")) == 0);
448
449 void
450 set(sv)
451 SV * sv
452 CODE:
453 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCSCHAN, old_struct (sv, "Video::Capture::V4l::Channel")) == 0);
454
455 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l::Tuner
456
457 void
458 get(sv)
459 SV * sv
460 CODE:
461 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCGTUNER, old_struct (sv, "Video::Capture::V4l::Tuner")) == 0);
462
463 void
464 set(sv)
465 SV * sv
466 CODE:
467 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCSTUNER, old_struct (sv, "Video::Capture::V4l::Tuner")) == 0);
468
469 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l::Audio
470
471 void
472 get(sv)
473 SV * sv
474 CODE:
475 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCGAUDIO, old_struct (sv, "Video::Capture::V4l::Audio")) == 0);
476
477 void
478 set(sv)
479 SV * sv
480 CODE:
481 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCSAUDIO, old_struct (sv, "Video::Capture::V4l::Audio")) == 0);
482
483 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l::Picture
484
485 void
486 get(sv)
487 SV * sv
488 CODE:
489 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCGPICT, old_struct (sv, "Video::Capture::V4l::Picture")) == 0);
490
491 void
492 set(sv)
493 SV * sv
494 CODE:
495 XSRETURN_bool (ioctl (SvIV (SvRV (sv)), VIDIOCSPICT, old_struct (sv, "Video::Capture::V4l::Picture")) == 0);
496
497 # accessors/mutators
498 INCLUDE: ./genacc |
499
500 MODULE = Video::Capture::V4l PACKAGE = Video::Capture::V4l
501
502 PROTOTYPES: ENABLE
503
504 BOOT:
505 {
506 HV *stash = gv_stashpvn("Video::Capture::V4l", 19, TRUE);
507
508 newCONSTSUB(stash,"AUDIO_BASS", newSViv(VIDEO_AUDIO_BASS));
509 newCONSTSUB(stash,"AUDIO_MUTABLE", newSViv(VIDEO_AUDIO_MUTABLE));
510 newCONSTSUB(stash,"AUDIO_MUTE", newSViv(VIDEO_AUDIO_MUTE));
511 newCONSTSUB(stash,"AUDIO_TREBLE", newSViv(VIDEO_AUDIO_TREBLE));
512 newCONSTSUB(stash,"AUDIO_VOLUME", newSViv(VIDEO_AUDIO_VOLUME));
513 newCONSTSUB(stash,"CAPTURE_EVEN", newSViv(VIDEO_CAPTURE_EVEN));
514 newCONSTSUB(stash,"CAPTURE_ODD", newSViv(VIDEO_CAPTURE_ODD));
515 newCONSTSUB(stash,"MAX_FRAME", newSViv(VIDEO_MAX_FRAME));
516 newCONSTSUB(stash,"MODE_AUTO", newSViv(VIDEO_MODE_AUTO));
517 newCONSTSUB(stash,"MODE_NTSC", newSViv(VIDEO_MODE_NTSC));
518 newCONSTSUB(stash,"MODE_PAL", newSViv(VIDEO_MODE_PAL));
519 newCONSTSUB(stash,"MODE_SECAM", newSViv(VIDEO_MODE_SECAM));
520 newCONSTSUB(stash,"PALETTE_COMPONENT", newSViv(VIDEO_PALETTE_COMPONENT));
521 newCONSTSUB(stash,"PALETTE_GREY", newSViv(VIDEO_PALETTE_GREY));
522 newCONSTSUB(stash,"PALETTE_HI240", newSViv(VIDEO_PALETTE_HI240));
523 newCONSTSUB(stash,"PALETTE_PLANAR", newSViv(VIDEO_PALETTE_PLANAR));
524 newCONSTSUB(stash,"PALETTE_RAW", newSViv(VIDEO_PALETTE_RAW));
525 newCONSTSUB(stash,"PALETTE_RGB24", newSViv(VIDEO_PALETTE_RGB24));
526 newCONSTSUB(stash,"PALETTE_RGB32", newSViv(VIDEO_PALETTE_RGB32));
527 newCONSTSUB(stash,"PALETTE_RGB555", newSViv(VIDEO_PALETTE_RGB555));
528 newCONSTSUB(stash,"PALETTE_RGB565", newSViv(VIDEO_PALETTE_RGB565));
529 newCONSTSUB(stash,"PALETTE_UYVY", newSViv(VIDEO_PALETTE_UYVY));
530 newCONSTSUB(stash,"PALETTE_YUV410P", newSViv(VIDEO_PALETTE_YUV410P));
531 newCONSTSUB(stash,"PALETTE_YUV411", newSViv(VIDEO_PALETTE_YUV411));
532 newCONSTSUB(stash,"PALETTE_YUV411P", newSViv(VIDEO_PALETTE_YUV411P));
533 newCONSTSUB(stash,"PALETTE_YUV420", newSViv(VIDEO_PALETTE_YUV420));
534 newCONSTSUB(stash,"PALETTE_YUV420P", newSViv(VIDEO_PALETTE_YUV420P));
535 newCONSTSUB(stash,"PALETTE_YUV422", newSViv(VIDEO_PALETTE_YUV422));
536 newCONSTSUB(stash,"PALETTE_YUV422P", newSViv(VIDEO_PALETTE_YUV422P));
537 newCONSTSUB(stash,"PALETTE_YUYV", newSViv(VIDEO_PALETTE_YUYV));
538 newCONSTSUB(stash,"SOUND_LANG1", newSViv(VIDEO_SOUND_LANG1));
539 newCONSTSUB(stash,"SOUND_LANG2", newSViv(VIDEO_SOUND_LANG2));
540 newCONSTSUB(stash,"SOUND_MONO", newSViv(VIDEO_SOUND_MONO));
541 newCONSTSUB(stash,"SOUND_STEREO", newSViv(VIDEO_SOUND_STEREO));
542 newCONSTSUB(stash,"TUNER_LOW", newSViv(VIDEO_TUNER_LOW));
543 newCONSTSUB(stash,"TUNER_MBS_ON", newSViv(VIDEO_TUNER_MBS_ON));
544 newCONSTSUB(stash,"TUNER_NORM", newSViv(VIDEO_TUNER_NORM));
545 newCONSTSUB(stash,"TUNER_NTSC", newSViv(VIDEO_TUNER_NTSC));
546 newCONSTSUB(stash,"TUNER_PAL", newSViv(VIDEO_TUNER_PAL));
547 newCONSTSUB(stash,"TUNER_RDS_ON", newSViv(VIDEO_TUNER_RDS_ON));
548 newCONSTSUB(stash,"TUNER_SECAM", newSViv(VIDEO_TUNER_SECAM));
549 newCONSTSUB(stash,"TUNER_STEREO_ON", newSViv(VIDEO_TUNER_STEREO_ON));
550 newCONSTSUB(stash,"TYPE_CAMERA", newSViv(VIDEO_TYPE_CAMERA));
551 newCONSTSUB(stash,"TYPE_TV", newSViv(VIDEO_TYPE_TV));
552 newCONSTSUB(stash,"VC_AUDIO", newSViv(VIDEO_VC_AUDIO));
553 newCONSTSUB(stash,"VC_TUNER", newSViv(VIDEO_VC_TUNER));
554 newCONSTSUB(stash,"TYPE_CAPTURE", newSViv(VID_TYPE_CAPTURE));
555 newCONSTSUB(stash,"TYPE_CHROMAKEY", newSViv(VID_TYPE_CHROMAKEY));
556 newCONSTSUB(stash,"TYPE_CLIPPING", newSViv(VID_TYPE_CLIPPING));
557 newCONSTSUB(stash,"TYPE_FRAMERAM", newSViv(VID_TYPE_FRAMERAM));
558 newCONSTSUB(stash,"TYPE_MONOCHROME", newSViv(VID_TYPE_MONOCHROME));
559 newCONSTSUB(stash,"TYPE_OVERLAY", newSViv(VID_TYPE_OVERLAY));
560 newCONSTSUB(stash,"TYPE_SCALES", newSViv(VID_TYPE_SCALES));
561 newCONSTSUB(stash,"TYPE_SUBCAPTURE", newSViv(VID_TYPE_SUBCAPTURE));
562 newCONSTSUB(stash,"TYPE_TELETEXT", newSViv(VID_TYPE_TELETEXT));
563 newCONSTSUB(stash,"TYPE_TUNER", newSViv(VID_TYPE_TUNER));
564 }
565
566 void
567 bgr2rgb(fr)
568 SV * fr
569 CODE:
570 {
571 u8 *data, *end;
572
573 end = SvEND (fr);
574
575 for (data = SvPV_nolen (fr); data < end; data += 3)
576 {
577 data[0] ^= data[2];
578 data[2] ^= data[0];
579 data[0] ^= data[2];
580 }
581 }
582 OUTPUT:
583 fr
584
585 SV *
586 reduce2(fr,w)
587 SV * fr
588 UI w
589 CODE:
590 {
591 u8 *src, *dst, *end;
592
593 src = SvPV_nolen (fr);
594 dst = SvPV_nolen (fr);
595
596 w *= 3;
597
598 do
599 {
600 end = src + w;
601 do
602 {
603 dst[1] = ((UI)src[0] + (UI)src[3]) >> 1; src++;
604 dst[2] = ((UI)src[0] + (UI)src[3]) >> 1; src++;
605 dst[0] = ((UI)src[0] + (UI)src[3]) >> 1; src++;
606 src += 3;
607 dst += 3;
608 }
609 while (src < end);
610 src = end + w;
611 }
612 while (src < (u8*)SvEND (fr));
613
614 SvCUR_set (fr, dst - (u8*)SvPV_nolen (fr));
615 }
616 OUTPUT:
617 fr
618
619 void
620 normalize(fr)
621 SV * fr
622 CODE:
623 {
624 u8 mfr = 255, max = 0;
625 u8 *src, *dst, *end;
626
627 end = SvEND (fr);
628 dst = SvPV_nolen (fr);
629
630 for (src = SvPV_nolen (fr); src < end; src++)
631 {
632 if (*src > max) max = *src;
633 if (*src < mfr) mfr = *src;
634 }
635
636 if (max != mfr)
637 for (src = SvPV_nolen (fr); src < end; )
638 *dst++ = ((UI)*src++ - mfr) * 255 / (max-mfr);
639 }
640 OUTPUT:
641 fr
642
643 void
644 findmin(db,fr,start=0,count=0)
645 SV * db
646 SV * fr
647 UI start
648 UI count
649 PPCODE:
650 {
651 UI diff, min = -1;
652 int mindata, data;
653 u8 *src, *dst, *end, *efr;
654 UI datasize = SvCUR (fr);
655 UI framesize = datasize + sizeof(int);
656
657 src = SvPV_nolen (db) + start * framesize;
658 if (src < (u8*)SvPV_nolen (db) || src > (u8*)SvEND (db))
659 src = SvPV_nolen (db);
660
661 end = src + count * framesize;
662 if (end <= src || end > (u8*)SvEND (db))
663 end = SvEND (db);
664
665 do
666 {
667 data = *((int *)src); src += sizeof (int);
668
669 dst = SvPV_nolen (fr);
670 efr = src + datasize;
671 diff = 0;
672
673 do
674 {
675 int dif = (int)*src++ - (int)*dst++;
676 diff += dif*dif;
677 }
678 while (src < efr);
679
680 if (min > diff)
681 {
682 min = diff;
683 mindata = data;
684 }
685 }
686 while (src < end);
687
688 EXTEND (sp, 2);
689 PUSHs (sv_2mortal (newSViv (mindata)));
690 PUSHs (sv_2mortal (newSViv ((min << 8) / SvCUR (fr))));
691 }
692
693 void
694 linreg(array)
695 SV * array
696 PPCODE:
697 {
698 AV *xy = (AV*) SvRV (array);
699 I32 i;
700 I32 n = (av_len (xy)+1)>>1;
701 double x_ = 0, y_ = 0;
702 double sxy = 0, sxx = 0, syy = 0;
703
704 for (i=0; i<n; i++)
705 {
706 x_ += SvNV(*av_fetch(xy, i*2 ,1));
707 y_ += SvNV(*av_fetch(xy, i*2+1,1));
708 }
709
710 x_ /= n;
711 y_ /= n;
712
713 for (i=0; i<n; i++)
714 {
715 double x = SvNV(*av_fetch(xy, i*2 ,1));
716 double y = SvNV(*av_fetch(xy, i*2+1,1));
717
718 sxy += (x-x_)*(y-y_);
719 sxx += (x-x_)*(x-x_);
720 syy += (y-y_)*(y-y_);
721 }
722
723 {
724 double rxy2 = sxy*sxy / (sxx*syy);
725 double b = sxy / sxx;
726 double a = y_ - b*x_;
727 double r2 = (n-1)/(n-2)*syy*(1-rxy2);
728
729 EXTEND (sp, 3);
730 PUSHs (sv_2mortal (newSVnv (a )));
731 PUSHs (sv_2mortal (newSVnv (b )));
732 PUSHs (sv_2mortal (newSVnv (r2)));
733 }
734 }
735
736 void
737 linreg1(array)
738 SV * array
739 PPCODE:
740 {
741 AV *xy = (AV*) SvRV (array);
742 I32 i;
743 I32 n = (av_len (xy)+1)>>1;
744 double c = 0;
745 double c2 = 0;
746
747 for (i=0; i<n; i++)
748 {
749 double d = SvNV(*av_fetch(xy, i*2-1,1)) - SvNV(*av_fetch(xy, i*2,1));
750 c += d;
751 }
752
753 c /= n;
754
755 for (i=0; i<n; i++)
756 {
757 double d = c + SvNV(*av_fetch(xy, i*2,1)) - SvNV(*av_fetch(xy, i*2-1,1));
758 c2 += d*d;
759 }
760
761 c2 /= n;
762
763 EXTEND (sp, 3);
764 PUSHs (sv_2mortal (newSVnv (c)));
765 PUSHs (sv_2mortal (newSVnv (1)));
766 PUSHs (sv_2mortal (newSVnv (c2)));
767 }
768