don't try to write 4 times as much memory as you have
[sparrow.git] / sparrow.c
blob05d4c9a099cc5bc60bdc39e2afe533c8b298840e
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);
29 /* set up whatever debugging methods are enabled */
30 static void
31 init_debug(GstSparrow *sparrow){
32 if (!sparrow->debug_frame){
33 sparrow->debug_frame = malloc_aligned_or_die(MAX(sparrow->in.size, sparrow->out.size));
37 /*RNG code */
38 /*seed with -1 for automatic seed choice */
39 static void rng_init(GstSparrow *sparrow, guint32 seed){
40 GST_DEBUG("in RNG init\n");
41 if (seed == (guint32)-1){
42 /* XXX should really use /dev/urandom */
43 seed = rand();
44 GST_DEBUG("Real seed %u\n", seed);
46 if (seed == 0)
47 seed = 12345;
49 dsfmt_init_gen_rand(sparrow->dsfmt, seed);
50 dsfmt_gen_rand_all(sparrow->dsfmt);
51 GST_DEBUG("RNG seeded with %u\n", seed);
54 /** debugging: write frames out somewhere. **/
56 /*spit out the frame as a ppm image */
57 static void
58 ppm_dump(sparrow_format *rgb, guint8 *data, guint32 width, guint32 height, char *name)
60 guint i;
61 FILE *fh = fopen(name, "w");
62 guint32 size = width * height;
63 fprintf(fh, "P6\n%u %u\n255\n", width, height);
64 /* 4 cases: xBGR xRGB BGRx RGBx
65 need to convert to 24bit R G B
66 XX maybe could optimise some cases?
68 guint32 *p = (guint32 *)data;
69 for (i = 0; i < size; i++){
70 putc((*p >> rgb->rshift) & 255, fh);
71 putc((*p >> rgb->gshift) & 255, fh);
72 putc((*p >> rgb->bshift) & 255, fh);
73 p++;
75 fflush(fh);
76 fclose(fh);
80 #define PPM_FILENAME_TEMPLATE "/tmp/sparrow_%05d.ppm"
81 #define PPM_FILENAME_LENGTH (sizeof(PPM_FILENAME_TEMPLATE) + 10)
83 void INVISIBLE
84 debug_frame(GstSparrow *sparrow, guint8 *data, guint32 width, guint32 height){
85 #if SPARROW_PPM_DEBUG
86 char name[PPM_FILENAME_LENGTH];
87 int res = snprintf(name, PPM_FILENAME_LENGTH, PPM_FILENAME_TEMPLATE, sparrow->frame_count);
88 if (res > 0){
89 ppm_dump(&(sparrow->in), data, width, height, name);
91 #endif
94 /** interpret gst attributes **/
96 /* Extract a colour (R,G,B) bitmask from gobject */
97 static guint32 get_mask(GstStructure *s, char *mask_name){
98 gint32 mask;
99 int res = gst_structure_get_int(s, mask_name, &mask);
100 if (!res){
101 GST_WARNING("No mask for '%s' !\n", mask_name);
103 return (guint32)mask;
106 static void
107 extract_caps(sparrow_format *im, GstCaps *caps)
109 GstStructure *s = gst_caps_get_structure (caps, 0);
110 gst_structure_get_int(s, "width", &(im->width));
111 gst_structure_get_int(s, "height", &(im->height));
112 im->rshift = mask_to_shift(get_mask(s, "red_mask"));
113 im->gshift = mask_to_shift(get_mask(s, "green_mask"));
114 im->bshift = mask_to_shift(get_mask(s, "blue_mask"));
115 /* recalculate shifts as little-endian */
116 im->rmask = 0xff << im->rshift;
117 im->gmask = 0xff << im->gshift;
118 im->bmask = 0xff << im->bshift;
120 im->pixcount = im->width * im->height;
121 im->size = im->pixcount * PIXSIZE;
122 im->colours[SPARROW_WHITE] = im->rmask | im->gmask | im->bmask;
123 im->colours[SPARROW_GREEN] = im->gmask;
124 im->colours[SPARROW_MAGENTA] = im->rmask | im->bmask;
126 GST_DEBUG("\ncaps:\n%" GST_PTR_FORMAT, caps);
127 GST_DEBUG("shifts: r %u g %u b %u\n", im->rshift, im->gshift, im->bshift);
128 GST_DEBUG("dimensions: w %u h %u pix %u size %u\n", im->width, im->height,
129 im->pixcount, im->size);
134 /*Most functions below here are called from gstsparrow.c and are NOT static */
136 void INVISIBLE
137 sparrow_rotate_history(GstSparrow *sparrow, GstBuffer *inbuf){
138 if (sparrow->in_buffer){
139 gst_buffer_unref(sparrow->prev_buffer);
140 sparrow->prev_buffer = sparrow->in_buffer;
141 sparrow->prev_frame = sparrow->in_frame;
143 gst_buffer_ref(inbuf);
144 sparrow->in_buffer = inbuf;
146 sparrow->in_frame = GST_BUFFER_DATA(inbuf);
149 /* called by gst_sparrow_init(). The source/sink capabilities (and commandline
150 arguments[?]) are unknown at this stage, so there isn't much useful to do
151 here.*/
152 void INVISIBLE
153 sparrow_pre_init(GstSparrow *sparrow){
156 /* called by gst_sparrow_set_caps(). This sets up everything after gstreamer
157 has worked out what the pipeline will look like.
159 gboolean INVISIBLE
160 sparrow_init(GstSparrow *sparrow, GstCaps *incaps, GstCaps *outcaps){
161 extract_caps(&(sparrow->in), incaps);
162 extract_caps(&(sparrow->out), outcaps);
163 sparrow_format *in = &(sparrow->in);
165 GST_DEBUG("allocating %u * %u for lag_table\n", in->pixcount, sizeof(lag_times_t));
166 sparrow->lag_table = zalloc_aligned_or_die(in->pixcount * sizeof(lag_times_t));
167 sparrow->work_frame = zalloc_aligned_or_die(in->size);
168 sparrow->dsfmt = zalloc_aligned_or_die(sizeof(dsfmt_t));
170 sparrow->prev_buffer = gst_buffer_new_and_alloc(in->size);
171 sparrow->prev_frame = GST_BUFFER_DATA(sparrow->prev_buffer);
172 memset(sparrow->prev_frame, 0, in->size);
174 sparrow->timer_start.tv_sec = 0;
175 sparrow->timer_stop.tv_sec = 0;
177 /*initialise IPL structs for openCV */
178 for (int i = 0; i < 3; i++){
179 sparrow->in_ipl[i] = init_ipl_image(&(sparrow->in));
182 rng_init(sparrow, sparrow->rng_seed);
184 if (sparrow->debug){
185 init_debug(sparrow);
188 sparrow->timer_log = (sparrow->use_timer) ? fopen(TIMER_LOG_FILE, "w") : NULL;
190 change_state(sparrow, SPARROW_FIND_SELF);
191 return TRUE;
194 void INVISIBLE
195 sparrow_finalise(GstSparrow *sparrow)
197 if (sparrow->timer_log){
198 fclose(sparrow->timer_log);
200 //free everything
201 //cvReleaseImageHeader(IplImage** image)
205 /* initialisation functions and sparrow_transform() use this to set up a new
206 state. */
207 static void
208 change_state(GstSparrow *sparrow, sparrow_state state)
210 if (state == SPARROW_NEXT_STATE){
211 state = sparrow->state + 1;
213 switch(state){
214 case SPARROW_FIND_SELF:
215 init_find_self(sparrow);
216 break;
217 case SPARROW_FIND_SCREEN:
218 init_find_screen(sparrow);
219 break;
220 case SPARROW_FIND_EDGES:
221 init_find_edges(sparrow);
222 break;
223 case SPARROW_PICK_COLOUR:
224 init_pick_colour(sparrow);
225 break;
226 case SPARROW_WAIT_FOR_GRID:
227 init_wait_for_grid(sparrow);
228 break;
229 case SPARROW_FIND_GRID:
230 init_find_grid(sparrow);
231 break;
232 case SPARROW_INIT:
233 case SPARROW_PLAY:
234 break;
235 default:
236 GST_DEBUG("change_state got unknown state: %d\n", state);
238 sparrow->state = state;
242 /*called by gst_sparrow_transform_ip every frame.
244 decide what to do based on sparrow->state. All the processing is done in a
245 "mode_*" function, which returns a state or SPARROW_STATUS_QUO. If a state
246 is returned, then change_state() is called to initialise the state, even if
247 it is the current state (so states can use this to reset).
249 void INVISIBLE
250 sparrow_transform(GstSparrow *sparrow, guint8 *in, guint8 *out)
252 sparrow_state new_state;
253 #if TIME_TRANSFORM
254 TIMER_START(sparrow);
255 #endif
256 switch(sparrow->state){
257 case SPARROW_FIND_SELF:
258 new_state = mode_find_self(sparrow, in, out);
259 break;
260 case SPARROW_FIND_SCREEN:
261 new_state = mode_find_screen(sparrow, in, out);
262 break;
263 case SPARROW_FIND_EDGES:
264 new_state = mode_find_edges(sparrow, in, out);
265 break;
266 case SPARROW_PICK_COLOUR:
267 new_state = mode_pick_colour(sparrow, in, out);
268 break;
269 case SPARROW_WAIT_FOR_GRID:
270 new_state = mode_wait_for_grid(sparrow, in, out);
271 break;
272 default:
273 new_state = mode_process_frame(sparrow, in, out);
275 sparrow->frame_count++;
276 if (new_state != SPARROW_STATUS_QUO){
277 change_state(sparrow, new_state);
279 #if TIME_TRANSFORM
280 TIMER_STOP(sparrow);
281 #endif