bayer2rgb: Add framerate to the sink caps
[platform/upstream/gstreamer.git] / gst / bayer / gstbayer2rgb.c
1 /* 
2  * GStreamer
3  * Copyright (C) 2007 David Schleef <ds@schleef.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * March 2008
21  * Logic enhanced by William Brack <wbrack@mmm.com.hk>
22  */
23
24 /**
25  * SECTION:element-bayer2rgb
26  *
27  * Decodes raw camera bayer (fourcc BA81) to RGB.
28  */
29
30 /*
31  * In order to guard against my advancing maturity, some extra detailed
32  * information about the logic of the decode is included here.  Much of
33  * this was inspired by a technical paper from siliconimaging.com, which
34  * in turn was based upon an article from IEEE,
35  * T. Sakamoto, C. Nakanishi and T. Hase,
36  * “Software pixel interpolation for digital still cameras suitable for
37  *  a 32-bit MCU,”
38  * IEEE Trans. Consumer Electronics, vol. 44, no. 4, November 1998.
39  *
40  * The code assumes a Bayer matrix of the type produced by the fourcc
41  * BA81 (v4l2 format SBGGR8) of width w and height h which looks like:
42  *       0 1 2 3  w-2 w-1
43  *
44  *   0   B G B G ....B G
45  *   1   G R G R ....G R
46  *   2   B G B G ....B G
47  *       ...............
48  * h-2   B G B G ....B G
49  * h-1   G R G R ....G R
50  *
51  * We expand this matrix, producing a separate {r, g, b} triple for each
52  * of the individual elements.  The algorithm for doing this expansion is
53  * as follows.
54  *
55  * We are designing for speed of transformation, at a slight expense of code.
56  * First, we calculate the appropriate triples for the four corners, the
57  * remainder of the top and bottom rows, and the left and right columns.
58  * The reason for this is that those elements are transformed slightly
59  * differently than all of the remainder of the matrix. Finally, we transform
60  * all of the remainder.
61  *
62  * The transformation into the "appropriate triples" is based upon the
63  * "nearest neighbor" principal, with some additional complexity for the
64  * calculation of the "green" element, where an "adaptive" pairing is used.
65  *
66  * For purposes of documentation and indentification, each element of the
67  * original array can be put into one of four classes:
68  *   R   A red element
69  *   B   A blue element
70  *   GR  A green element which is followed by a red one
71  *   GB  A green element which is followed by a blue one
72  */
73
74 #ifdef HAVE_CONFIG_H
75 #include "config.h"
76 #endif
77
78 #include <gst/gst.h>
79 #include <gst/base/gstbasetransform.h>
80 #include <gst/video/video.h>
81 #include <string.h>
82 #include <stdlib.h>
83 #include "_stdint.h"
84
85 #define GST_CAT_DEFAULT gst_bayer2rgb_debug
86 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
87
88 enum
89 {
90   GST_BAYER_2_RGB_FORMAT_BGGR = 0,
91   GST_BAYER_2_RGB_FORMAT_GBRG,
92   GST_BAYER_2_RGB_FORMAT_GRBG,
93   GST_BAYER_2_RGB_FORMAT_RGGB
94 };
95
96
97 #define GST_TYPE_BAYER2RGB            (gst_bayer2rgb_get_type())
98 #define GST_BAYER2RGB(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BAYER2RGB,GstBayer2RGB))
99 #define GST_IS_BAYER2RGB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BAYER2RGB))
100 #define GST_BAYER2RGB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_BAYER2RGB,GstBayer2RGBClass))
101 #define GST_IS_BAYER2RGB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_BAYER2RGB))
102 #define GST_BAYER2RGB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_BAYER2RGB,GstBayer2RGBClass))
103 typedef struct _GstBayer2RGB GstBayer2RGB;
104 typedef struct _GstBayer2RGBClass GstBayer2RGBClass;
105
106 typedef void (*GstBayer2RGBProcessFunc) (GstBayer2RGB *, guint8 *, guint);
107
108 struct _GstBayer2RGB
109 {
110   GstBaseTransform basetransform;
111
112   /* < private > */
113   int width;
114   int height;
115   int stride;
116   int pixsize;                  /* bytes per pixel */
117   int r_off;                    /* offset for red */
118   int g_off;                    /* offset for green */
119   int b_off;                    /* offset for blue */
120   int format;
121 };
122
123 struct _GstBayer2RGBClass
124 {
125   GstBaseTransformClass parent;
126 };
127
128 //#define SRC_CAPS GST_VIDEO_CAPS_RGBx
129 #define SRC_CAPS                                 \
130   GST_VIDEO_CAPS_RGBx ";"                        \
131   GST_VIDEO_CAPS_xRGB ";"                        \
132   GST_VIDEO_CAPS_BGRx ";"                        \
133   GST_VIDEO_CAPS_xBGR ";"                        \
134   GST_VIDEO_CAPS_RGBA ";"                        \
135   GST_VIDEO_CAPS_ARGB ";"                        \
136   GST_VIDEO_CAPS_BGRA ";"                        \
137   GST_VIDEO_CAPS_ABGR ";"                        \
138   GST_VIDEO_CAPS_RGB ";"                         \
139   GST_VIDEO_CAPS_BGR
140
141 #define SINK_CAPS "video/x-raw-bayer,format=(string){bggr,grbg,gbrg,rggb}," \
142   "width=(int)[1,MAX],height=(int)[1,MAX],framerate=(fraction)[0/1,MAX]"
143
144 enum
145 {
146   PROP_0
147 };
148
149 #define DEBUG_INIT(bla) \
150   GST_DEBUG_CATEGORY_INIT (gst_bayer2rgb_debug, "bayer2rgb", 0, "bayer2rgb element");
151
152 GType gst_bayer2rgb_get_type (void);
153 GST_BOILERPLATE_FULL (GstBayer2RGB, gst_bayer2rgb, GstBaseTransform,
154     GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
155
156 static void gst_bayer2rgb_set_property (GObject * object, guint prop_id,
157     const GValue * value, GParamSpec * pspec);
158 static void gst_bayer2rgb_get_property (GObject * object, guint prop_id,
159     GValue * value, GParamSpec * pspec);
160
161 static gboolean gst_bayer2rgb_set_caps (GstBaseTransform * filter,
162     GstCaps * incaps, GstCaps * outcaps);
163 static GstFlowReturn gst_bayer2rgb_transform (GstBaseTransform * base,
164     GstBuffer * inbuf, GstBuffer * outbuf);
165 static void gst_bayer2rgb_reset (GstBayer2RGB * filter);
166 static GstCaps *gst_bayer2rgb_transform_caps (GstBaseTransform * base,
167     GstPadDirection direction, GstCaps * caps);
168 static gboolean gst_bayer2rgb_get_unit_size (GstBaseTransform * base,
169     GstCaps * caps, guint * size);
170
171
172 static void
173 gst_bayer2rgb_base_init (gpointer klass)
174 {
175   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
176
177   gst_element_class_set_details_simple (element_class,
178       "Bayer to RGB decoder for cameras", "Filter/Converter/Video",
179       "Converts video/x-raw-bayer to video/x-raw-rgb",
180       "William Brack <wbrack@mmm.com.hk>");
181
182   gst_element_class_add_pad_template (element_class,
183       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
184           gst_caps_from_string (SRC_CAPS)));
185   gst_element_class_add_pad_template (element_class,
186       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
187           gst_caps_from_string (SINK_CAPS)));
188 }
189
190 static void
191 gst_bayer2rgb_class_init (GstBayer2RGBClass * klass)
192 {
193   GObjectClass *gobject_class;
194
195   gobject_class = (GObjectClass *) klass;
196   gobject_class->set_property = gst_bayer2rgb_set_property;
197   gobject_class->get_property = gst_bayer2rgb_get_property;
198
199   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
200       GST_DEBUG_FUNCPTR (gst_bayer2rgb_transform_caps);
201   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
202       GST_DEBUG_FUNCPTR (gst_bayer2rgb_get_unit_size);
203   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
204       GST_DEBUG_FUNCPTR (gst_bayer2rgb_set_caps);
205   GST_BASE_TRANSFORM_CLASS (klass)->transform =
206       GST_DEBUG_FUNCPTR (gst_bayer2rgb_transform);
207 }
208
209 static void
210 gst_bayer2rgb_init (GstBayer2RGB * filter, GstBayer2RGBClass * klass)
211 {
212   gst_bayer2rgb_reset (filter);
213   gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
214 }
215
216 /* No properties are implemented, so only a warning is produced */
217 static void
218 gst_bayer2rgb_set_property (GObject * object, guint prop_id,
219     const GValue * value, GParamSpec * pspec)
220 {
221
222   switch (prop_id) {
223     default:
224       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225       break;
226   }
227 }
228
229 static void
230 gst_bayer2rgb_get_property (GObject * object, guint prop_id,
231     GValue * value, GParamSpec * pspec)
232 {
233
234   switch (prop_id) {
235     default:
236       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
237       break;
238   }
239 }
240
241 /* Routine to convert colormask value into relative byte offset */
242 static int
243 get_pix_offset (int mask, int bpp)
244 {
245   int bpp32 = (bpp / 8) - 3;
246
247   switch (mask) {
248     case 255:
249       return 2 + bpp32;
250     case 65280:
251       return 1 + bpp32;
252     case 16711680:
253       return 0 + bpp32;
254     case -16777216:
255       return 0;
256     default:
257       GST_ERROR ("Invalid color mask 0x%08x", mask);
258       return -1;
259   }
260 }
261
262 static gboolean
263 gst_bayer2rgb_set_caps (GstBaseTransform * base, GstCaps * incaps,
264     GstCaps * outcaps)
265 {
266   GstBayer2RGB *bayer2rgb = GST_BAYER2RGB (base);
267   GstStructure *structure;
268   int val, bpp;
269   const char *format;
270
271   GST_DEBUG ("in caps %" GST_PTR_FORMAT " out caps %" GST_PTR_FORMAT, incaps,
272       outcaps);
273
274   structure = gst_caps_get_structure (incaps, 0);
275
276   gst_structure_get_int (structure, "width", &bayer2rgb->width);
277   gst_structure_get_int (structure, "height", &bayer2rgb->height);
278   bayer2rgb->stride = GST_ROUND_UP_4 (bayer2rgb->width);
279
280   format = gst_structure_get_string (structure, "format");
281   if (g_str_equal (format, "bggr")) {
282     bayer2rgb->format = GST_BAYER_2_RGB_FORMAT_BGGR;
283   } else if (g_str_equal (format, "gbrg")) {
284     bayer2rgb->format = GST_BAYER_2_RGB_FORMAT_GBRG;
285   } else if (g_str_equal (format, "grbg")) {
286     bayer2rgb->format = GST_BAYER_2_RGB_FORMAT_GRBG;
287   } else if (g_str_equal (format, "rggb")) {
288     bayer2rgb->format = GST_BAYER_2_RGB_FORMAT_RGGB;
289   } else {
290     return FALSE;
291   }
292
293   /* To cater for different RGB formats, we need to set params for later */
294   structure = gst_caps_get_structure (outcaps, 0);
295   gst_structure_get_int (structure, "bpp", &bpp);
296   bayer2rgb->pixsize = bpp / 8;
297   gst_structure_get_int (structure, "red_mask", &val);
298   bayer2rgb->r_off = get_pix_offset (val, bpp);
299   gst_structure_get_int (structure, "green_mask", &val);
300   bayer2rgb->g_off = get_pix_offset (val, bpp);
301   gst_structure_get_int (structure, "blue_mask", &val);
302   bayer2rgb->b_off = get_pix_offset (val, bpp);
303
304   return TRUE;
305 }
306
307 static void
308 gst_bayer2rgb_reset (GstBayer2RGB * filter)
309 {
310   filter->width = 0;
311   filter->height = 0;
312   filter->stride = 0;
313   filter->pixsize = 0;
314   filter->r_off = 0;
315   filter->g_off = 0;
316   filter->b_off = 0;
317 }
318
319 static GstCaps *
320 gst_bayer2rgb_transform_caps (GstBaseTransform * base,
321     GstPadDirection direction, GstCaps * caps)
322 {
323   GstStructure *structure;
324   GstCaps *newcaps;
325   GstStructure *newstruct;
326
327   GST_DEBUG_OBJECT (caps, "transforming caps (from)");
328
329   structure = gst_caps_get_structure (caps, 0);
330
331   if (direction == GST_PAD_SRC) {
332     newcaps = gst_caps_from_string ("video/x-raw-bayer,"
333         "format=(string){bggr,grbg,gbrg,rggb}");
334   } else {
335     newcaps = gst_caps_new_simple ("video/x-raw-rgb", NULL);
336   }
337   newstruct = gst_caps_get_structure (newcaps, 0);
338
339   gst_structure_set_value (newstruct, "width",
340       gst_structure_get_value (structure, "width"));
341   gst_structure_set_value (newstruct, "height",
342       gst_structure_get_value (structure, "height"));
343   gst_structure_set_value (newstruct, "framerate",
344       gst_structure_get_value (structure, "framerate"));
345
346   GST_DEBUG_OBJECT (newcaps, "transforming caps (into)");
347
348   return newcaps;
349 }
350
351 static gboolean
352 gst_bayer2rgb_get_unit_size (GstBaseTransform * base, GstCaps * caps,
353     guint * size)
354 {
355   GstStructure *structure;
356   int width;
357   int height;
358   int pixsize;
359   const char *name;
360
361   structure = gst_caps_get_structure (caps, 0);
362
363   if (gst_structure_get_int (structure, "width", &width) &&
364       gst_structure_get_int (structure, "height", &height)) {
365     name = gst_structure_get_name (structure);
366     /* Our name must be either video/x-raw-bayer video/x-raw-rgb */
367     if (strcmp (name, "video/x-raw-rgb")) {
368       /* For bayer, we handle only BA81 (BGGR), which is BPP=24 */
369       *size = GST_ROUND_UP_4 (width) * height;
370       return TRUE;
371     } else {
372       /* For output, calculate according to format */
373       if (gst_structure_get_int (structure, "bpp", &pixsize)) {
374         *size = width * height * (pixsize / 8);
375         return TRUE;
376       }
377     }
378
379   }
380   GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
381       ("Incomplete caps, some required field missing"));
382   return FALSE;
383 }
384
385 /*
386  * We define values for the colors, just to make the code more readable.
387  */
388 #define RED     0               /* Pure red element */
389 #define GREENB  1               /* Green element which is on a blue line */
390 #define BLUE    2               /* Pure blue element */
391 #define GREENR  3               /* Green element which is on a red line */
392
393 static int
394 get_pixel_type (GstBayer2RGB * filter, int x, int y)
395 {
396   int type;
397
398   if (((x ^ filter->format) & 1)) {
399     if ((y ^ (filter->format >> 1)) & 1)
400       type = RED;
401     else
402       type = GREENB;
403   } else {
404     if ((y ^ (filter->format >> 1)) & 1)
405       type = GREENR;
406     else
407       type = BLUE;
408   }
409   return type;
410 }
411
412 /* Routine to generate the top and bottom edges (not including corners) */
413 static void
414 hborder (uint8_t * input, uint8_t * output, int bot_top,
415     int typ, GstBayer2RGB * filter)
416 {
417   uint8_t *op;                  /* output pointer */
418   uint8_t *ip;                  /* input pointer */
419   uint8_t *nx;                  /* next line pointer */
420   int ix;                       /* loop index */
421
422   op = output + (bot_top * filter->width * (filter->height - 1) + 1) *
423       filter->pixsize;
424   ip = input + bot_top * filter->stride * (filter->height - 1);
425   /* calculate minus or plus one line, depending upon bot_top flag */
426   nx = ip + (1 - 2 * bot_top) * filter->stride;
427   /* Stepping horizontally */
428   for (ix = 1; ix < filter->width - 1; ix++, op += filter->pixsize) {
429     switch (typ) {
430       case RED:
431         op[filter->r_off] = ip[ix];
432         op[filter->g_off] = (ip[ix + 1] + ip[ix - 1] + nx[ix] + 1) / 3;
433         op[filter->b_off] = (nx[ix + 1] + nx[ix - 1] + 1) / 2;
434         typ = GREENR;
435         break;
436       case GREENR:
437         op[filter->r_off] = (ip[ix + 1] + ip[ix - 1] + 1) / 2;
438         op[filter->g_off] = ip[ix];
439         op[filter->b_off] = nx[ix];
440         typ = RED;
441         break;
442       case GREENB:
443         op[filter->r_off] = nx[ix];
444         op[filter->g_off] = ip[ix];
445         op[filter->b_off] = (ip[ix + 1] + ip[ix - 1] + 1) / 2;
446         typ = BLUE;
447         break;
448       case BLUE:
449         op[filter->r_off] = (nx[ix + 1] + nx[ix - 1] + 1) / 2;
450         op[filter->g_off] = (ip[ix + 1] + ip[ix - 1] + nx[ix] + 1) / 3;
451         op[filter->b_off] = ip[ix];
452         typ = GREENB;
453         break;
454     }
455   }
456 }
457
458 /* Routine to generate the left and right edges, not including corners */
459 static void
460 vborder (uint8_t * input, uint8_t * output, int right_left,
461     int typ, GstBayer2RGB * filter)
462 {
463   uint8_t *op;                  /* output pointer */
464   uint8_t *ip;                  /* input pointer */
465   uint8_t *la;                  /* line above pointer */
466   uint8_t *lb;                  /* line below pointer */
467   int ix;                       /* loop index */
468   int lr;                       /* 'left-right' flag - +1 is right, -1 is left */
469
470   lr = (1 - 2 * right_left);
471   /* stepping vertically */
472   for (ix = 1; ix < filter->height - 1; ix++) {
473     ip = input + right_left * (filter->width - 1) + ix * filter->stride;
474     op = output + (right_left * (filter->width - 1) + ix * filter->width) *
475         filter->pixsize;
476     la = ip + filter->stride;
477     lb = ip - filter->stride;
478     switch (typ) {
479       case RED:
480         op[filter->r_off] = ip[0];
481         op[filter->g_off] = (la[0] + ip[lr] + lb[0] + 1) / 3;
482         op[filter->b_off] = (la[lr] + lb[lr] + 1) / 2;
483         typ = GREENB;
484         break;
485       case GREENR:
486         op[filter->r_off] = ip[lr];
487         op[filter->g_off] = ip[0];
488         op[filter->b_off] = (la[lr] + lb[lr] + 1) / 2;
489         typ = BLUE;
490         break;
491       case GREENB:
492         op[filter->r_off] = (la[lr] + lb[lr] + 1) / 2;
493         op[filter->g_off] = ip[0];
494         op[filter->b_off] = ip[lr];
495         typ = RED;
496         break;
497       case BLUE:
498         op[filter->r_off] = (la[lr] + lb[lr] + 1) / 2;
499         op[filter->g_off] = (la[0] + ip[lr] + lb[0] + 1) / 3;
500         op[filter->b_off] = ip[0];
501         typ = GREENR;
502         break;
503     }
504   }
505 }
506
507 /* Produce the four (top, bottom, left, right) edges */
508 static void
509 do_row0_col0 (uint8_t * input, uint8_t * output, GstBayer2RGB * filter)
510 {
511   /* Horizontal edges */
512   hborder (input, output, 0, get_pixel_type (filter, 1, 0), filter);
513   hborder (input, output, 1, get_pixel_type (filter, 1, filter->height - 1),
514       filter);
515
516   /* Vertical edges */
517   vborder (input, output, 0, get_pixel_type (filter, 0, 1), filter);
518   vborder (input, output, 1, get_pixel_type (filter, filter->width - 1, 1),
519       filter);
520 }
521
522 static void
523 corner (uint8_t * input, uint8_t * output, int x, int y,
524     int xd, int yd, int typ, GstBayer2RGB * filter)
525 {
526   uint8_t *ip;                  /* input pointer */
527   uint8_t *op;                  /* output pointer */
528   uint8_t *nx;                  /* adjacent line */
529
530   op = output + y * filter->width * filter->pixsize + x * filter->pixsize;
531   ip = input + y * filter->stride + x;
532   nx = ip + yd * filter->stride;
533   switch (typ) {
534     case RED:
535       op[filter->r_off] = ip[0];
536       op[filter->g_off] = (nx[0] + ip[xd] + 1) / 2;
537       op[filter->b_off] = nx[xd];
538       break;
539     case GREENR:
540       op[filter->r_off] = ip[xd];
541       op[filter->g_off] = ip[0];
542       op[filter->b_off] = nx[0];
543       break;
544     case GREENB:
545       op[filter->r_off] = nx[0];
546       op[filter->g_off] = ip[0];
547       op[filter->b_off] = ip[xd];
548       break;
549     case BLUE:
550       op[filter->r_off] = nx[xd];
551       op[filter->g_off] = (nx[0] + ip[xd] + 1) / 2;
552       op[filter->b_off] = ip[0];
553       break;
554   }
555 }
556
557 static void
558 do_corners (uint8_t * input, uint8_t * output, GstBayer2RGB * filter)
559 {
560   /* Top left */
561   corner (input, output, 0, 0, 1, 1, get_pixel_type (filter, 0, 0), filter);
562   /* Bottom left */
563   corner (input, output, 0, filter->height - 1, 1, -1,
564       get_pixel_type (filter, 0, filter->height - 1), filter);
565   /* Top right */
566   corner (input, output, filter->width - 1, 0, -1, 0,
567       get_pixel_type (filter, filter->width - 1, 0), filter);
568   /* Bottom right */
569   corner (input, output, filter->width - 1, filter->height - 1, -1, -1,
570       get_pixel_type (filter, filter->width - 1, filter->height - 1), filter);
571 }
572
573 static void
574 do_body (uint8_t * input, uint8_t * output, GstBayer2RGB * filter)
575 {
576   int ip, op;                   /* input and output pointers */
577   int w, h;                     /* loop indices */
578   int type;                     /* calculated colour of current element */
579   int a1, a2;
580   int v1, v2, h1, h2;
581
582   /*
583    * We are processing row (line) by row, starting with the second
584    * row and continuing through the next to last.  Each row is processed
585    * column by column, starting with the second and continuing through
586    * to the next to last.
587    */
588   for (h = 1; h < filter->height - 1; h++) {
589     /*
590      * Remember we are processing "row by row". For each row, we need
591      * to set the type of the first element to be processed.  Since we
592      * have already processed the edges, the "first element" will be
593      * the pixel at position (1,1).  Assuming BG format, this should
594      * be RED for odd-numbered rows and GREENB for even rows.
595      */
596     type = get_pixel_type (filter, 1, h);
597     /* Calculate the starting position for the row */
598     op = h * filter->width * filter->pixsize;   /* output (converted) pos */
599     ip = h * filter->stride;    /* input (bayer data) pos */
600     for (w = 1; w < filter->width - 1; w++) {
601       op += filter->pixsize;    /* we are processing "horizontally" */
602       ip++;
603       switch (type) {
604         case RED:
605           output[op + filter->r_off] = input[ip];
606           output[op + filter->b_off] = (input[ip - filter->stride - 1] +
607               input[ip - filter->stride + 1] +
608               input[ip + filter->stride - 1] +
609               input[ip + filter->stride + 1] + 2) / 4;
610           v1 = input[ip + filter->stride];
611           v2 = input[ip - filter->stride];
612           h1 = input[ip + 1];
613           h2 = input[ip - 1];
614           a1 = abs (v1 - v2);
615           a2 = abs (h1 - h2);
616           if (a1 < a2)
617             output[op + filter->g_off] = (v1 + v2 + 1) / 2;
618           else if (a1 > a2)
619             output[op + filter->g_off] = (h1 + h2 + 1) / 2;
620           else
621             output[op + filter->g_off] = (v1 + h1 + v2 + h2 + 2) / 4;
622           type = GREENR;
623           break;
624         case GREENR:
625           output[op + filter->r_off] = (input[ip + 1] + input[ip - 1] + 1) / 2;
626           output[op + filter->g_off] = input[ip];
627           output[op + filter->b_off] = (input[ip - filter->stride] +
628               input[ip + filter->stride] + 1) / 2;
629           type = RED;
630           break;
631         case GREENB:
632           output[op + filter->r_off] = (input[ip - filter->stride] +
633               input[ip + filter->stride] + 1) / 2;
634           output[op + filter->g_off] = input[ip];
635           output[op + filter->b_off] = (input[ip + 1] + input[ip - 1] + 1) / 2;
636           type = BLUE;
637           break;
638         case BLUE:
639           output[op + filter->r_off] = (input[ip - filter->stride - 1] +
640               input[ip - filter->stride + 1] +
641               input[ip + filter->stride - 1] +
642               input[ip + filter->stride + 1] + 2) / 4;
643           output[op + filter->b_off] = input[ip];
644           v1 = input[ip + filter->stride];
645           v2 = input[ip - filter->stride];
646           h1 = input[ip + 1];
647           h2 = input[ip - 1];
648           a1 = abs (v1 - v2);
649           a2 = abs (h1 - h2);
650           if (a1 < a2)
651             output[op + filter->g_off] = (v1 + v2 + 1) / 2;
652           else if (a1 > a2)
653             output[op + filter->g_off] = (h1 + h2 + 1) / 2;
654           else
655             output[op + filter->g_off] = (v1 + h1 + v2 + h2 + 2) / 4;
656           type = GREENB;
657           break;
658       }
659     }
660   }
661 }
662
663 static GstFlowReturn
664 gst_bayer2rgb_transform (GstBaseTransform * base, GstBuffer * inbuf,
665     GstBuffer * outbuf)
666 {
667   GstBayer2RGB *filter = GST_BAYER2RGB (base);
668   uint8_t *input, *output;
669
670   /*
671    * We need to lock our filter params to prevent changing
672    * caps in the middle of a transformation (nice way to get
673    * segfaults)
674    */
675   GST_OBJECT_LOCK (filter);
676
677   GST_DEBUG ("transforming buffer");
678   input = (uint8_t *) GST_BUFFER_DATA (inbuf);
679   output = (uint8_t *) GST_BUFFER_DATA (outbuf);
680   do_corners (input, output, filter);
681   do_row0_col0 (input, output, filter);
682   do_body (input, output, filter);
683
684   GST_OBJECT_UNLOCK (filter);
685   return GST_FLOW_OK;
686 }