popcount and hamming distance functions, with tests!
[sparrow.git] / sparrow.c
blob9451484777911d9e12639a4ade4fc717b83f2889
1 /* Copyright (C) <2010> Douglas Bagnall <douglas@halo.gen.nz>
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 02111-1307, USA.
19 #include "sparrow.h"
20 #include "gstsparrow.h"
22 #include <string.h>
23 #include <math.h>
25 /* static functions (via `make cproto`) */
26 static void change_state(GstSparrow *sparrow, sparrow_state state);
27 static __inline__ gint mask_to_shift(guint32 mask);
28 static guint32 get_mask(GstStructure *s, char *mask_name);
29 static void init_debug(GstSparrow *sparrow);
30 static void rng_init(GstSparrow *sparrow, guint32 seed);
31 static void simple_negation(guint8 *bytes, guint size);
32 static void gamma_negation(GstSparrow *sparrow, guint8 *in, guint8 *out);
33 static void calibrate_new_pattern(GstSparrow *sparrow);
34 static __inline__ void init_one_square(GstSparrow *sparrow, sparrow_shape_t *shape);
35 static void calibrate_init_squares(GstSparrow *sparrow);
36 static void add_random_signal(GstSparrow *sparrow, guint8 *out);
37 static void calibrate_init_lines(GstSparrow *sparrow);
38 static __inline__ void horizontal_line(GstSparrow *sparrow, guint8 *out, guint32 y);
39 static __inline__ void vertical_line(GstSparrow *sparrow, guint8 *out, guint32 x);
40 static __inline__ void rectangle(GstSparrow *sparrow, guint8 *out, sparrow_shape_t *shape);
41 static void draw_shapes(GstSparrow *sparrow, guint8 *out);
42 static __inline__ void record_calibration(GstSparrow *sparrow, gint32 offset, guint32 signal);
43 static __inline__ int find_lag(GstSparrow *sparrow);
44 static __inline__ void debug_calibration_histogram(GstSparrow *sparrow);
45 static void debug_frame(GstSparrow *sparrow, guint8 *data, guint32 width, guint32 height);
46 static void ppm_dump(sparrow_format *rgb, guint8 *data, guint32 width, guint32 height, char *name);
47 static int cycle_pattern(GstSparrow *sparrow, int repeat);
48 static void see_grid(GstSparrow *sparrow, guint8 *in);
49 static void find_grid(GstSparrow *sparrow, guint8 *in, guint8 *out);
50 static void find_self(GstSparrow *sparrow, guint8 *in, guint8 *out);
51 static void extract_caps(sparrow_format *im, GstCaps *caps);
52 static __inline__ IplImage *init_ipl_image(sparrow_format *dim);
56 #ifdef HAVE_LIBOIL
57 #include <liboil/liboil.h>
58 #include <liboil/liboilcpu.h>
59 #include <liboil/liboilfunction.h>
60 #endif
63 static inline gint
64 mask_to_shift(guint32 mask){
65 /*mask is big-endian, so these numbers are reversed */
66 switch(mask){
67 case 0x000000ff:
68 return 24;
69 case 0x0000ff00:
70 return 16;
71 case 0x00ff0000:
72 return 8;
73 case 0xff000000:
74 return 0;
76 GST_WARNING("mask not byte aligned: %x\n", mask);
77 return 0;
80 static guint32 get_mask(GstStructure *s, char *mask_name){
81 gint32 mask;
82 int res = gst_structure_get_int(s, mask_name, &mask);
83 if (!res){
84 GST_WARNING("No mask for '%s' !\n", mask_name);
86 return (guint32)mask;
91 static void
92 init_debug(GstSparrow *sparrow){
93 if (!sparrow->debug_frame){
94 sparrow->debug_frame = malloc_aligned_or_die(MAX(sparrow->in.size, sparrow->out.size));
98 /*RNG code */
100 /*seed with -1 for automatic seed choice */
101 static void rng_init(GstSparrow *sparrow, guint32 seed){
102 GST_DEBUG("in RNG init\n");
103 if (seed == (guint32)-1){
104 /* XXX should really use /dev/urandom */
105 seed = rand();
106 GST_DEBUG("Real seed %u\n", seed);
108 if (seed == 0)
109 seed = 12345;
111 dsfmt_init_gen_rand(sparrow->dsfmt, seed);
112 dsfmt_gen_rand_all(sparrow->dsfmt);
113 GST_DEBUG("RNG seeded with %u\n", seed);
116 /* here we go */
118 UNUSED
119 static void
120 simple_negation(guint8 * bytes, guint size){
121 guint i;
122 guint32 * data = (guint32 *)bytes;
123 //could use sse for superspeed
124 for (i = 0; i < size / 4; i++){
125 data[i] = ~data[i];
129 static void
130 gamma_negation(GstSparrow *sparrow, guint8 *in, guint8 *out){
131 //guint i;
132 //XXX could try oil_tablelookup_u8
133 //for (i = 0; i < size; i++){
134 // out[i] = sparrow_rgb_gamma_full_range_REVERSE[in[i]];
135 // }
138 static void calibrate_new_pattern(GstSparrow *sparrow){
139 int i;
140 sparrow->calibrate.index = CALIBRATE_PATTERN_L;
141 sparrow->calibrate.wait = 0;
142 for (i = 0; i < CALIBRATE_PATTERN_L; i+=2){
143 sparrow->calibrate.pattern[i] = RANDINT(sparrow, CALIBRATE_OFF_MIN_T, CALIBRATE_OFF_MAX_T);
144 sparrow->calibrate.pattern[i + 1] = RANDINT(sparrow, CALIBRATE_ON_MIN_T, CALIBRATE_ON_MAX_T);
146 GST_DEBUG("New Pattern: wait %u, index %u\n", sparrow->calibrate.wait, sparrow->calibrate.index);
149 static inline void
150 init_one_square(GstSparrow *sparrow, sparrow_shape_t* shape){
151 shape->shape = RECTANGLE;
152 shape->w = CALIBRATE_SELF_SIZE;
153 shape->h = CALIBRATE_SELF_SIZE;
154 shape->x = RANDINT(sparrow, sparrow->out.width / 8,
155 sparrow->out.width * 7 / 8 - shape->w);
156 shape->y = RANDINT(sparrow, sparrow->out.height / 8,
157 sparrow->out.height * 7 / 8 - shape->h);
160 static void calibrate_init_squares(GstSparrow *sparrow){
161 int i;
162 for (i = 0; i < MAX_CALIBRATE_SHAPES; i++){
163 init_one_square(sparrow, &(sparrow->shapes[i]));
168 static void add_random_signal(GstSparrow *sparrow, guint8 *out){
169 int i;
170 static sparrow_shape_t shapes[MAX_CALIBRATE_SHAPES];
171 static int been_here = 0;
172 static int countdown = 0;
173 static int on = 0;
174 if (! been_here){
175 for (i = 0; i < MAX_CALIBRATE_SHAPES; i++){
176 init_one_square(sparrow, &shapes[i]);
178 been_here = 1;
180 if (! countdown){
181 on = ! on;
182 countdown = on ? RANDINT(sparrow, CALIBRATE_ON_MIN_T, CALIBRATE_ON_MAX_T) :
183 RANDINT(sparrow, CALIBRATE_ON_MIN_T, CALIBRATE_ON_MAX_T);
185 if (on){
186 for (i = 0; i < MAX_CALIBRATE_SHAPES; i++){
187 rectangle(sparrow, out, &shapes[i]);
190 countdown--;
194 static void calibrate_init_lines(GstSparrow *sparrow){
195 int i;
196 sparrow_shape_t* shape = sparrow->shapes;
197 for (i = 0; i < MAX_CALIBRATE_SHAPES; i++){
198 shape[i].w = 1;
199 shape[i].h = 1;
200 shape[i].x = 0;
201 shape[i].y = 0;
202 shape[i].shape = NO_SHAPE;
204 /* shape[0] will be set to vertical or horizontal in due course */
209 /* in a noisy world, try to find the spot you control by stoping and watching
210 for a while.
213 static inline void
214 horizontal_line(GstSparrow *sparrow, guint8 *out, guint32 y){
215 guint stride = sparrow->out.width * PIXSIZE;
216 guint8 *line = out + y * stride;
217 memset(line, 255, stride);
220 static inline void
221 vertical_line(GstSparrow *sparrow, guint8 *out, guint32 x){
222 guint y;
223 guint32 *p = (guint32 *)out;
224 p += x;
225 for(y = 0; y < (guint)(sparrow->out.height); y++){
226 *p = -1;
227 p += sparrow->out.width;
231 static inline void
232 rectangle(GstSparrow *sparrow, guint8 *out, sparrow_shape_t *shape){
233 guint y;
234 guint stride = sparrow->out.width * PIXSIZE;
235 guint8 *line = out + shape->y * stride + shape->x * PIXSIZE;
236 for(y = 0; y < (guint)shape->h; y++){
237 memset(line, 255, shape->w * PIXSIZE);
238 line += stride;
244 static void draw_shapes(GstSparrow *sparrow, guint8 *out){
245 int i;
246 sparrow_shape_t *shape;
247 for (i = 0; i < MAX_CALIBRATE_SHAPES; i++){
248 shape = sparrow->shapes + i;
249 switch (shape->shape){
250 case NO_SHAPE:
251 goto done; /* an empty one ends the list */
252 case VERTICAL_LINE:
253 vertical_line(sparrow, out, shape->x);
254 break;
255 case HORIZONTAL_LINE:
256 horizontal_line(sparrow, out, shape->x);
257 break;
258 case RECTANGLE:
259 rectangle(sparrow, out, shape);
260 break;
261 case FULLSCREEN:
262 memset(out, 255, sparrow->out.size);
263 break;
266 done:
267 return;
271 static inline void
272 record_calibration(GstSparrow *sparrow, gint32 offset, guint32 signal){
273 guint16 *t = sparrow->lag_table[offset].lag;
274 guint32 r = sparrow->lag_record;
275 if (signal > CALIBRATE_SIGNAL_THRESHOLD){
276 sparrow->lag_table[offset].hits++;
277 while(r){
278 if(r & 1){
279 *t += 4;
281 r >>= 1;
282 t++;
285 else{
286 while(r){
287 if((r & 1) && *t){
288 *t -= 1;
290 r >>= 1;
291 t++;
296 static inline void
297 colour_coded_pixel(guint32* pixel, guint32 weight, guint32 lag){
298 if (weight){
299 guint32 c = lag_false_colour[lag];
300 if (weight <= 3){
301 c >>= 2;
302 c &= 0x3f3f3f3f;
304 if (weight <= 6){
305 c >>= 1;
306 c &= 0x7f7f7f7f;
308 *pixel = c;
312 /*return 1 if a reasonably likely lag has been found */
314 static inline int
315 find_lag(GstSparrow *sparrow){
316 int res = 0;
317 guint i, j;
318 guint votes[MAX_CALIBRATION_LAG] = {0};
319 guint32 *frame = (guint32 *)sparrow->debug_frame;
320 //GST_DEBUG("sparrow->debug is %d\n", sparrow->debug);
322 if (sparrow->calibrate.transitions >= CALIBRATION_START_LAG_SEARCH){
323 guint expected_hits_min = sparrow->calibrate.transitions / 2;
324 guint expected_hits_max = sparrow->calibrate.transitions + 1;
326 if (sparrow->debug){
327 memset(frame, 0, sparrow->in.size);
329 for (i = 0; i < sparrow->in.pixcount; i++){
330 lag_times_t *lt = &(sparrow->lag_table[i]);
331 if (lt->hits > CALIBRATION_MIN_HITS){
332 guint32 sum = 0;
333 guint16 peak = 0;
334 int offset = 0;
335 guint32 centre;
336 guint32 confidence;
337 for(j = 0; j < MAX_CALIBRATION_LAG; j++){
338 guint16 v = lt->lag[j];
339 sum += v;
340 if (v > peak){
341 peak = v;
342 offset = j;
345 /* Heuristic for confidence:
346 one point for each of:
347 * the peak is twice average
348 * the peak is 4/3 average
349 * the number of hits is close to the number of transitions
351 There of course is a proper way, but it might be slower.
353 //XXX perhaps adjust centre according to neighbours, using sub-frame values (fixed point)
354 centre = offset;
355 guint32 peak2 = peak * MAX_CALIBRATION_LAG; //scale to make sum equivalant to mean
356 confidence = ((peak2 * 7 >= sum * 8) +
357 (peak2 * 6 >= sum * 8) +
358 (peak2 * 5 >= sum * 8) +
359 (peak2 * 4 >= sum * 8));
360 if (lt->hits > expected_hits_min &&
361 lt->hits < expected_hits_max){
362 confidence *= 4;
363 //GST_DEBUG("hits %u, transitions %u\n", lt->hits, sparrow->calibrate.transitions);
365 confidence *= lt->hits;
366 votes[offset] += confidence;
367 if (sparrow->debug){
368 colour_coded_pixel(&frame[i], confidence, offset);
373 /* find votes */
374 guint max_vote;
375 guint offset;
376 guint total;
377 for (j = 0; j < MAX_CALIBRATION_LAG; j++){
378 total += votes[j];
379 if (votes[j] > max_vote){
380 max_vote = votes[j];
381 offset = j;
384 if ((max_vote + (total >> 2)) > total){
385 GST_DEBUG("80%% majority for %u: %u out of %u\n", offset, max_vote, total);
386 res = 1;
387 sparrow->lag = offset;
389 if (total){
390 /*draw a histogram on the screen*/
391 guint8 *row = sparrow->debug_frame;
392 for (j = 0; j < MAX_CALIBRATION_LAG; j++){
393 row += sparrow->in.width * PIXSIZE;
394 memset(row, 255, votes[j] * sparrow->in.width * (PIXSIZE) / total);
398 if (sparrow->debug){
399 debug_frame(sparrow, sparrow->debug_frame, sparrow->in.width, sparrow->in.height);
401 return res;
404 static inline void
405 debug_calibration_histogram(GstSparrow *sparrow){
406 int pixels = sparrow->in.pixcount;
407 guint32 *frame = (guint32 *)sparrow->debug_frame;
408 memcpy(sparrow->debug_frame, sparrow->in_frame, sparrow->in.size);
409 int i, j;
410 static guint32 high_peak = 0;
411 static guint32 high_pix = 0;
412 static guint32 high_offset = 0;
413 for (i = 0; i < pixels; i++){
414 guint16 peak = 0;
415 int offset = 0;
416 if (sparrow->lag_table[i].hits > CALIBRATION_MIN_HITS){
417 for(j = 0; j < MAX_CALIBRATION_LAG; j++){
418 if (sparrow->lag_table[i].lag[j] > peak){
419 peak = sparrow->lag_table[i].lag[j];
420 offset = j;
423 if (peak > high_peak){
424 high_peak = peak;
425 high_pix = i;
426 high_offset = offset;
430 if (high_peak){
431 /*draw a histogram on the screen*/
432 guint8 *row = sparrow->debug_frame;
433 for (j = 0; j < MAX_CALIBRATION_LAG; j++){
434 row += sparrow->in.width * PIXSIZE;
435 memset(row, 255, sparrow->lag_table[high_pix].lag[j] * sparrow->in.width * (PIXSIZE / 2) / high_peak);
438 /*flicker most peaky pixel */
439 if (sparrow->frame_count & 4){
440 frame[high_pix] = (guint32)-1 & (sparrow->in.rmask);
442 else {
443 frame[high_pix] = 0;
446 debug_frame(sparrow, sparrow->debug_frame, sparrow->in.width, sparrow->in.height);
451 #define PPM_FILENAME_TEMPLATE "/tmp/sparrow_%05d.pgm"
452 #define PPM_FILENAME_LENGTH (sizeof(PPM_FILENAME_TEMPLATE) + 10)
454 static void
455 debug_frame(GstSparrow *sparrow, guint8 *data, guint32 width, guint32 height){
456 #if SPARROW_PPM_DEBUG
457 char name[PPM_FILENAME_LENGTH];
458 int res = snprintf(name, PPM_FILENAME_LENGTH, PPM_FILENAME_TEMPLATE, sparrow->frame_count);
459 if (res > 0){
460 ppm_dump(&(sparrow->in), data, width, height, name);
462 #endif
467 static void
468 ppm_dump(sparrow_format *rgb, guint8 *data, guint32 width, guint32 height, char *name)
470 guint i;
471 FILE *fh = fopen(name, "w");
472 guint32 size = width * height;
473 fprintf(fh, "P6\n%u %u\n255\n", width, height);
474 /* 4 cases: xBGR xRGB BGRx RGBx
475 need to convert to 24bit R G B
476 XX maybe could optimise some cases?
478 guint32 *p = (guint32 *)data;
479 for (i = 0; i < size; i++){
480 putc((*p >> rgb->rshift) & 255, fh);
481 putc((*p >> rgb->gshift) & 255, fh);
482 putc((*p >> rgb->bshift) & 255, fh);
483 p++;
485 fflush(fh);
486 fclose(fh);
489 static inline void
490 abs_diff(GstSparrow *sparrow, guint8 *a, guint8 *b, guint8 *target){
491 sparrow->in_ipl[0]->imageData = (char*) a;
492 sparrow->in_ipl[1]->imageData = (char*) b;
493 sparrow->in_ipl[2]->imageData = (char*) target;
494 cvAbsDiff(sparrow->in_ipl[0], sparrow->in_ipl[1], sparrow->in_ipl[2]);
499 /*compare the frame to the new one. regions of change should indicate the
500 square is about.
502 static inline int
503 calibrate_find_square(GstSparrow *sparrow, guint8 *in){
504 //GST_DEBUG("finding square\n");
505 int res = 0;
506 if(sparrow->prev_frame){
507 abs_diff(sparrow, in, sparrow->prev_frame, sparrow->work_frame);
509 guint32 i;
510 //pix_t *changes = (pix_t *)sparrow->work_frame;
511 for (i = 0; i < sparrow->in.pixcount; i++){
512 guint32 signal = sparrow->work_frame[i * PIXSIZE + 2];//possibly R, G, or B, but never A
513 record_calibration(sparrow, i, signal);
516 res = find_lag(sparrow);
517 if (res){
518 GST_DEBUG("lag is set at %u! after %u cycles\n", sparrow->lag, sparrow->frame_count);
521 return res;
524 static int cycle_pattern(GstSparrow *sparrow, int repeat){
525 if (sparrow->calibrate.wait == 0){
526 if(sparrow->calibrate.index == 0){
527 //pattern has run out
528 if (repeat){
529 sparrow->calibrate.index = CALIBRATE_PATTERN_L;
531 else{
532 calibrate_new_pattern(sparrow);
535 sparrow->calibrate.index--;
536 sparrow->calibrate.wait = sparrow->calibrate.pattern[sparrow->calibrate.index];
537 //GST_DEBUG("cycle_wait %u, cycle_index %u\n", sparrow->calibrate.wait, sparrow->calibrate.index);
538 sparrow->lag_record = (sparrow->lag_record << 1) | 1;
539 sparrow->calibrate.transitions++;
541 else {
542 sparrow->lag_record = (sparrow->lag_record << 1);
544 sparrow->lag_record &= ((1 << MAX_CALIBRATION_LAG) - 1);
545 //XXX record the pattern in sparrow->lag_record
546 sparrow->calibrate.wait--;
547 return sparrow->calibrate.index & 1;
550 static void
551 see_grid(GstSparrow *sparrow, guint8 *in){
554 static void
555 find_grid(GstSparrow *sparrow, guint8 *in, guint8 *out){
556 see_grid(sparrow, in);
557 int on = cycle_pattern(sparrow, TRUE);
558 memset(out, 0, sparrow->out.size);
559 if (on){
560 draw_shapes(sparrow, out);
565 static void
566 find_self(GstSparrow *sparrow, guint8 *in, guint8 *out){
567 if(calibrate_find_square(sparrow, in)){
568 change_state(sparrow, SPARROW_WAIT_FOR_GRID);
569 return;
571 int on = cycle_pattern(sparrow, TRUE);
572 memset(out, 0, sparrow->out.size);
573 if (on){
574 draw_shapes(sparrow, out);
576 #if 1
577 add_random_signal(sparrow, out);
578 #endif
581 /* wait for the other projector to stop changing: sufficient to look for no
582 significant changes for as long as the longest pattern interval */
584 static int
585 wait_for_blank(GstSparrow *sparrow, guint8 *in, guint8 *out){
586 guint32 i;
587 abs_diff(sparrow, in, sparrow->prev_frame, sparrow->work_frame);
588 for (i = 0; i < sparrow->in.pixcount; i++){
589 guint32 signal = sparrow->work_frame[i * PIXSIZE + 2]; //possibly R, G, or B, but never A
590 if (signal > CALIBRATE_SIGNAL_THRESHOLD){
591 sparrow->countdown = WAIT_COUNTDOWN;
592 break;
595 memset(out, 0, sparrow->out.size);
596 sparrow->countdown--;
597 return (sparrow->countdown == 0);
601 static void
602 extract_caps(sparrow_format *im, GstCaps *caps)
604 GstStructure *s = gst_caps_get_structure (caps, 0);
605 gst_structure_get_int(s, "width", &(im->width));
606 gst_structure_get_int(s, "height", &(im->height));
607 im->rmask = get_mask(s, "red_mask");
608 im->rshift = mask_to_shift(im->rmask);
609 im->gmask = get_mask(s, "green_mask");
610 im->gshift = mask_to_shift(im->gmask);
611 im->bmask = get_mask(s, "blue_mask");
612 im->bshift = mask_to_shift(im->bmask);
614 im->pixcount = im->width * im->height;
615 im->size = im->pixcount * PIXSIZE;
617 GST_DEBUG("\ncaps:\n%" GST_PTR_FORMAT, caps);
618 GST_DEBUG("shifts: r %u g %u b %u\n", im->rshift, im->gshift, im->bshift);
619 GST_DEBUG("dimensions: w %u h %u pix %u size %u\n", im->width, im->height,
620 im->pixcount, im->size);
623 static inline IplImage *
624 init_ipl_image(sparrow_format *dim){
625 CvSize size = {dim->width, dim->height};
626 IplImage* im = cvCreateImageHeader(size, IPL_DEPTH_8U, PIXSIZE);
627 return cvInitImageHeader(im, size, IPL_DEPTH_8U, PIXSIZE, 0, 8);
630 static void
631 calibrate_init_grid(GstSparrow *sparrow){}
633 static void
634 change_state(GstSparrow *sparrow, sparrow_state state)
636 switch(state){
637 case SPARROW_FIND_SELF:
638 calibrate_init_squares(sparrow);
639 break;
640 case SPARROW_WAIT_FOR_GRID:
641 break;
642 case SPARROW_FIND_GRID:
643 calibrate_init_grid(sparrow);
644 break;
645 case SPARROW_INIT:
646 case SPARROW_FIND_EDGES:
647 case SPARROW_PLAY:
648 break;
650 sparrow->state = state;
655 /*Functions below here are NOT static */
657 void INVISIBLE
658 sparrow_rotate_history(GstSparrow *sparrow, GstBuffer *inbuf){
659 if (sparrow->in_buffer){
660 gst_buffer_unref(sparrow->prev_buffer);
661 sparrow->prev_buffer = sparrow->in_buffer;
662 sparrow->prev_frame = sparrow->in_frame;
664 gst_buffer_ref(inbuf);
665 sparrow->in_buffer = inbuf;
667 sparrow->in_frame = GST_BUFFER_DATA(inbuf);
670 /* called by gst_sparrow_init() */
671 void INVISIBLE
672 sparrow_pre_init(GstSparrow *sparrow){
675 /* called by gst_sparrow_set_caps() */
676 gboolean INVISIBLE
677 sparrow_init(GstSparrow *sparrow, GstCaps *incaps, GstCaps *outcaps){
678 extract_caps(&(sparrow->in), incaps);
679 extract_caps(&(sparrow->out), outcaps);
680 sparrow_format *in = &(sparrow->in);
682 GST_DEBUG("allocating %u * %u for lag_table\n", in->pixcount, sizeof(lag_times_t));
683 sparrow->lag_table = zalloc_aligned_or_die(in->pixcount * sizeof(lag_times_t));
684 sparrow->work_frame = zalloc_aligned_or_die(in->size);
685 sparrow->dsfmt = zalloc_aligned_or_die(sizeof(dsfmt_t));
687 sparrow->prev_buffer = gst_buffer_new_and_alloc(in->size);
688 sparrow->prev_frame = GST_BUFFER_DATA(sparrow->prev_buffer);
689 memset(sparrow->prev_frame, 0, in->size);
691 /*initialise IPL structs for openCV */
692 for (int i = 0; i < 3; i++){
693 sparrow->in_ipl[i] = init_ipl_image(&(sparrow->in));
696 rng_init(sparrow, sparrow->rng_seed);
698 if (sparrow->debug){
699 init_debug(sparrow);
702 calibrate_new_pattern(sparrow);
704 change_state(sparrow, SPARROW_FIND_SELF);
705 return TRUE;
708 /*called by gst_sparrow_transform_ip */
709 void INVISIBLE
710 sparrow_transform(GstSparrow *sparrow, guint8 *in, guint8 *out)
712 switch(sparrow->state){
713 case SPARROW_FIND_SELF:
714 find_self(sparrow, in, out);
715 break;
716 case SPARROW_WAIT_FOR_GRID:
717 if (wait_for_blank(sparrow, in, out)){
718 change_state(sparrow, SPARROW_FIND_GRID);
720 break;
721 case SPARROW_FIND_GRID:
722 find_grid(sparrow, in, out);
723 break;
724 default:
725 gamma_negation(sparrow, in, out);
727 sparrow->frame_count++;
730 void
731 INVISIBLE
732 sparrow_finalise(GstSparrow *sparrow)
734 //free everything
737 //cvReleaseImageHeader(IplImage** image)