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.
20 #include "gstsparrow.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 */
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
));
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() ^ (size_t)&(sparrow
);
44 GST_DEBUG("Real seed %u\n", seed
);
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 */
58 ppm_dump(sparrow_format
*rgb
, guint8
*data
, guint32 width
, guint32 height
, char *name
)
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
);
79 /*pgm for greyscale */
81 pgm_dump(guint8
*data
, guint32 width
, guint32 height
, char *name
)
83 FILE *fh
= fopen(name
, "w");
84 size_t size
= width
* height
;
85 fprintf(fh
, "P5\n%u %u\n255\n", width
, height
);
86 size_t wrote
= fwrite(data
, 1, size
, fh
);
88 GST_DEBUG("wanted to write %u bytes; fwrite said %u\n", size
, wrote
);
95 #define PPM_FILENAME_TEMPLATE "/tmp/sparrow_%05d.%s"
96 #define PPM_FILENAME_LENGTH (sizeof(PPM_FILENAME_TEMPLATE) + 15)
99 debug_frame(GstSparrow
*sparrow
, guint8
*data
, guint32 width
, guint32 height
, int pixsize
){
100 char name
[PPM_FILENAME_LENGTH
];
102 if (pixsize
== 4){ /*rgb*/
103 res
= snprintf(name
, PPM_FILENAME_LENGTH
, PPM_FILENAME_TEMPLATE
, sparrow
->frame_count
, "ppm");
105 ppm_dump(&(sparrow
->in
), data
, width
, height
, name
);
109 res
= snprintf(name
, PPM_FILENAME_LENGTH
, PPM_FILENAME_TEMPLATE
, sparrow
->frame_count
, "pgm");
111 pgm_dump(data
, width
, height
, name
);
116 /** interpret gst attributes **/
118 /* Extract a colour (R,G,B) bitmask from gobject */
119 static guint32
get_mask(GstStructure
*s
, char *mask_name
){
121 int res
= gst_structure_get_int(s
, mask_name
, &mask
);
123 GST_WARNING("No mask for '%s' !\n", mask_name
);
125 return (guint32
)mask
;
129 extract_caps(sparrow_format
*im
, GstCaps
*caps
)
131 GstStructure
*s
= gst_caps_get_structure (caps
, 0);
132 gst_structure_get_int(s
, "width", &(im
->width
));
133 gst_structure_get_int(s
, "height", &(im
->height
));
134 im
->rshift
= mask_to_shift(get_mask(s
, "red_mask"));
135 im
->gshift
= mask_to_shift(get_mask(s
, "green_mask"));
136 im
->bshift
= mask_to_shift(get_mask(s
, "blue_mask"));
137 /* recalculate shifts as little-endian */
138 im
->rmask
= 0xff << im
->rshift
;
139 im
->gmask
= 0xff << im
->gshift
;
140 im
->bmask
= 0xff << im
->bshift
;
142 im
->pixcount
= im
->width
* im
->height
;
143 im
->size
= im
->pixcount
* PIXSIZE
;
144 im
->colours
[SPARROW_WHITE
] = im
->rmask
| im
->gmask
| im
->bmask
;
145 im
->colours
[SPARROW_GREEN
] = im
->gmask
;
146 im
->colours
[SPARROW_MAGENTA
] = im
->rmask
| im
->bmask
;
148 GST_DEBUG("\ncaps:\n%" GST_PTR_FORMAT
, caps
);
149 GST_DEBUG("shifts: r %u g %u b %u\n", im
->rshift
, im
->gshift
, im
->bshift
);
150 GST_DEBUG("dimensions: w %u h %u pix %u size %u\n", im
->width
, im
->height
,
151 im
->pixcount
, im
->size
);
156 /*Most functions below here are called from gstsparrow.c and are NOT static */
159 sparrow_rotate_history(GstSparrow
*sparrow
, GstBuffer
*inbuf
){
160 if (sparrow
->in_buffer
){
161 gst_buffer_unref(sparrow
->prev_buffer
);
162 sparrow
->prev_buffer
= sparrow
->in_buffer
;
163 sparrow
->prev_frame
= sparrow
->in_frame
;
165 gst_buffer_ref(inbuf
);
166 sparrow
->in_buffer
= inbuf
;
168 sparrow
->in_frame
= GST_BUFFER_DATA(inbuf
);
171 /* called by gst_sparrow_init(). The source/sink capabilities (and commandline
172 arguments[?]) are unknown at this stage, so there isn't much useful to do
175 sparrow_pre_init(GstSparrow
*sparrow
){
178 /* called by gst_sparrow_set_caps(). This sets up everything after gstreamer
179 has worked out what the pipeline will look like.
182 sparrow_init(GstSparrow
*sparrow
, GstCaps
*incaps
, GstCaps
*outcaps
){
183 change_state(sparrow
, SPARROW_INIT
);
184 extract_caps(&(sparrow
->in
), incaps
);
185 extract_caps(&(sparrow
->out
), outcaps
);
186 sparrow_format
*in
= &(sparrow
->in
);
188 sparrow
->work_frame
= zalloc_aligned_or_die(in
->size
);
189 sparrow
->dsfmt
= zalloc_aligned_or_die(sizeof(dsfmt_t
));
190 sparrow
->screenmask
= malloc_aligned_or_die(in
->pixcount
);
193 size_t point_memsize
= (sizeof(sparrow_map_point_t
) * sparrow
->out
.pixcount
/ LINE_PERIOD
) + 1;
194 size_t row_memsize
= sizeof(sparrow_map_row_t
) * sparrow
->out
.height
+ 1;
195 sparrow
->map
.point_mem
= malloc_aligned_or_die(point_memsize
);
196 sparrow
->map
.rows
= zalloc_aligned_or_die(row_memsize
);
198 size_t lutsize
= sizeof(sparrow_map_lut_t
) * sparrow
->out
.pixcount
;
199 sparrow
->map_lut
= malloc_aligned_or_die(lutsize
);
202 sparrow
->prev_buffer
= gst_buffer_new_and_alloc(in
->size
);
203 sparrow
->prev_frame
= GST_BUFFER_DATA(sparrow
->prev_buffer
);
204 memset(sparrow
->prev_frame
, 0, in
->size
);
206 sparrow
->timer_start
.tv_sec
= 0;
207 sparrow
->timer_stop
.tv_sec
= 0;
210 rng_init(sparrow
, sparrow
->rng_seed
);
216 if (sparrow
->rng_seed
& 2){/*XXX need better test */
217 sparrow
->colour
= SPARROW_GREEN
;
220 sparrow
->colour
= SPARROW_MAGENTA
;
223 sparrow
->timer_log
= (sparrow
->use_timer
) ? fopen(TIMER_LOG_FILE
, "w") : NULL
;
226 change_state(sparrow
, SPARROW_FIND_EDGES
);
229 change_state(sparrow
, SPARROW_NEXT_STATE
);
235 sparrow_finalise(GstSparrow
*sparrow
)
237 free(sparrow
->work_frame
);
238 free(sparrow
->dsfmt
);
239 free(sparrow
->screenmask
);
241 free(sparrow
->map
.point_mem
);
242 free(sparrow
->map
.rows
);
244 free(sparrow
->map_lut
);
248 if (sparrow
->timer_log
){
249 fclose(sparrow
->timer_log
);
252 //cvReleaseImageHeader(IplImage** image)
256 /* initialisation functions and sparrow_transform() use this to set up a new
259 change_state(GstSparrow
*sparrow
, sparrow_state state
)
261 GST_DEBUG("state is %d, sparrow->state is %d\n", state
, sparrow
->state
);
262 switch(sparrow
->state
){
263 case SPARROW_FIND_SELF
:
264 finalise_find_self(sparrow
);
266 case SPARROW_FIND_SCREEN
:
267 finalise_find_screen(sparrow
);
269 case SPARROW_FIND_EDGES
:
270 finalise_find_edges(sparrow
);
273 finalise_play(sparrow
);
278 GST_DEBUG("change_state got unknown state: %d\n", state
);
280 if (state
== SPARROW_NEXT_STATE
){
281 state
= sparrow
->state
+ 1;
284 case SPARROW_FIND_SELF
:
285 init_find_self(sparrow
);
287 case SPARROW_FIND_SCREEN
:
288 init_find_screen(sparrow
);
290 case SPARROW_FIND_EDGES
:
291 init_find_edges(sparrow
);
297 GST_DEBUG("change_state got unknown state: %d\n", state
);
299 sparrow
->state
= state
;
303 /*called by gst_sparrow_transform_ip every frame.
305 decide what to do based on sparrow->state. All the processing is done in a
306 "mode_*" function, which returns a state or SPARROW_STATUS_QUO. If a state
307 is returned, then change_state() is called to initialise the state, even if
308 it is the current state (so states can use this to reset).
311 sparrow_transform(GstSparrow
*sparrow
, guint8
*in
, guint8
*out
)
313 sparrow_state new_state
;
315 TIMER_START(sparrow
);
317 //GST_DEBUG("in %p, out %p\n", in, out);
318 switch(sparrow
->state
){
319 case SPARROW_FIND_SELF
:
320 new_state
= mode_find_self(sparrow
, in
, out
);
322 case SPARROW_FIND_SCREEN
:
323 new_state
= mode_find_screen(sparrow
, in
, out
);
325 case SPARROW_FIND_EDGES
:
326 new_state
= mode_find_edges(sparrow
, in
, out
);
329 new_state
= mode_play(sparrow
, in
, out
);
331 sparrow
->frame_count
++;
332 if (new_state
!= SPARROW_STATUS_QUO
){
333 change_state(sparrow
, new_state
);