videobox: Add const qualifier to the source frame data
[platform/upstream/gstreamer.git] / gst / videobox / gstvideobox.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2010> Sebastian Dröge <sebastian.droege@collabora.co.uk>
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 /**
21  * SECTION:element-videobox
22  * @see_also: #GstVideoCrop
23  *
24  * This plugin crops or enlarges the image. It takes 4 values as input, a
25  * top, bottom, left and right offset. Positive values will crop that much
26  * pixels from the respective border of the image, negative values will add
27  * that much pixels. When pixels are added, you can specify their color. 
28  * Some predefined colors are usable with an enum property.
29  * 
30  * The plugin is alpha channel aware and will try to negotiate with a format
31  * that supports alpha channels first. When alpha channel is active two
32  * other properties, alpha and border_alpha can be used to set the alpha
33  * values of the inner picture and the border respectively. an alpha value of
34  * 0.0 means total transparency, 1.0 is opaque.
35  * 
36  * The videobox plugin has many uses such as doing a mosaic of pictures, 
37  * letterboxing video, cutting out pieces of video, picture in picture, etc..
38  *
39  * Setting autocrop to true changes the behavior of the plugin so that
40  * caps determine crop properties rather than the other way around: given
41  * input and output dimensions, the crop values are selected so that the
42  * smaller frame is effectively centered in the larger frame.  This
43  * involves either cropping or padding.
44  * 
45  * If you use autocrop there is little point in setting the other
46  * properties manually because they will be overriden if the caps change,
47  * but nothing stops you from doing so.
48  * 
49  * Sample pipeline:
50  * |[
51  * gst-launch videotestsrc ! videobox autocrop=true ! \
52  *   "video/x-raw-yuv, width=600, height=400" ! ffmpegcolorspace ! ximagesink
53  * ]|
54  */
55
56 #ifdef HAVE_CONFIG_H
57 #include "config.h"
58 #endif
59
60 #include "gstvideobox.h"
61
62 #include <math.h>
63 #include <liboil/liboil.h>
64 #include <string.h>
65
66 #include <gst/controller/gstcontroller.h>
67
68 GST_DEBUG_CATEGORY_STATIC (videobox_debug);
69 #define GST_CAT_DEFAULT videobox_debug
70
71 #define DEFAULT_LEFT      0
72 #define DEFAULT_RIGHT     0
73 #define DEFAULT_TOP       0
74 #define DEFAULT_BOTTOM    0
75 #define DEFAULT_FILL_TYPE VIDEO_BOX_FILL_BLACK
76 #define DEFAULT_ALPHA     1.0
77 #define DEFAULT_BORDER_ALPHA 1.0
78
79 enum
80 {
81   PROP_0,
82   PROP_LEFT,
83   PROP_RIGHT,
84   PROP_TOP,
85   PROP_BOTTOM,
86   PROP_FILL_TYPE,
87   PROP_ALPHA,
88   PROP_BORDER_ALPHA,
89   PROP_AUTOCROP
90       /* FILL ME */
91 };
92
93 static GstStaticPadTemplate gst_video_box_src_template =
94     GST_STATIC_PAD_TEMPLATE ("src",
95     GST_PAD_SRC,
96     GST_PAD_ALWAYS,
97     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
98         GST_VIDEO_CAPS_YUV ("I420"))
99     );
100
101 static GstStaticPadTemplate gst_video_box_sink_template =
102     GST_STATIC_PAD_TEMPLATE ("sink",
103     GST_PAD_SINK,
104     GST_PAD_ALWAYS,
105     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
106         GST_VIDEO_CAPS_YUV ("I420"))
107     );
108
109 GST_BOILERPLATE (GstVideoBox, gst_video_box, GstBaseTransform,
110     GST_TYPE_BASE_TRANSFORM);
111
112 static void gst_video_box_set_property (GObject * object, guint prop_id,
113     const GValue * value, GParamSpec * pspec);
114 static void gst_video_box_get_property (GObject * object, guint prop_id,
115     GValue * value, GParamSpec * pspec);
116
117 static gboolean video_box_recalc_transform (GstVideoBox * video_box);
118 static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
119     GstPadDirection direction, GstCaps * from);
120 static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
121     GstCaps * in, GstCaps * out);
122 static gboolean gst_video_box_get_unit_size (GstBaseTransform * trans,
123     GstCaps * caps, guint * size);
124 static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
125     GstBuffer * in, GstBuffer * out);
126
127 #define GST_TYPE_VIDEO_BOX_FILL (gst_video_box_fill_get_type())
128 static GType
129 gst_video_box_fill_get_type (void)
130 {
131   static GType video_box_fill_type = 0;
132   static const GEnumValue video_box_fill[] = {
133     {VIDEO_BOX_FILL_BLACK, "Black", "black"},
134     {VIDEO_BOX_FILL_GREEN, "Colorkey green", "green"},
135     {VIDEO_BOX_FILL_BLUE, "Colorkey blue", "blue"},
136     {0, NULL, NULL},
137   };
138
139   if (!video_box_fill_type) {
140     video_box_fill_type =
141         g_enum_register_static ("GstVideoBoxFill", video_box_fill);
142   }
143   return video_box_fill_type;
144 }
145
146
147 static void
148 gst_video_box_base_init (gpointer g_class)
149 {
150   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
151
152   gst_element_class_set_details_simple (element_class, "Video box filter",
153       "Filter/Effect/Video",
154       "Resizes a video by adding borders or cropping",
155       "Wim Taymans <wim@fluendo.com>");
156
157   gst_element_class_add_pad_template (element_class,
158       gst_static_pad_template_get (&gst_video_box_sink_template));
159   gst_element_class_add_pad_template (element_class,
160       gst_static_pad_template_get (&gst_video_box_src_template));
161 }
162
163 static void
164 gst_video_box_finalize (GObject * object)
165 {
166   GstVideoBox *video_box = GST_VIDEO_BOX (object);
167
168   if (video_box->mutex) {
169     g_mutex_free (video_box->mutex);
170     video_box->mutex = NULL;
171   }
172
173   G_OBJECT_CLASS (parent_class)->finalize (object);
174 }
175
176 static void
177 gst_video_box_class_init (GstVideoBoxClass * klass)
178 {
179   GObjectClass *gobject_class = (GObjectClass *) klass;
180   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
181
182   gobject_class->set_property = gst_video_box_set_property;
183   gobject_class->get_property = gst_video_box_get_property;
184   gobject_class->finalize = gst_video_box_finalize;
185
186   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILL_TYPE,
187       g_param_spec_enum ("fill", "Fill", "How to fill the borders",
188           GST_TYPE_VIDEO_BOX_FILL, DEFAULT_FILL_TYPE,
189           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
190   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LEFT,
191       g_param_spec_int ("left", "Left",
192           "Pixels to box at left (<0  = add a border)", G_MININT, G_MAXINT,
193           DEFAULT_LEFT,
194           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
195   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RIGHT,
196       g_param_spec_int ("right", "Right",
197           "Pixels to box at right (<0 = add a border)", G_MININT, G_MAXINT,
198           DEFAULT_RIGHT,
199           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
200   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOP,
201       g_param_spec_int ("top", "Top",
202           "Pixels to box at top (<0 = add a border)", G_MININT, G_MAXINT,
203           DEFAULT_TOP,
204           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
205   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BOTTOM,
206       g_param_spec_int ("bottom", "Bottom",
207           "Pixels to box at bottom (<0 = add a border)", G_MININT, G_MAXINT,
208           DEFAULT_BOTTOM,
209           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
210   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
211       g_param_spec_double ("alpha", "Alpha", "Alpha value picture", 0.0, 1.0,
212           DEFAULT_ALPHA,
213           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
214   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER_ALPHA,
215       g_param_spec_double ("border-alpha", "Border Alpha",
216           "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
217           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
218   /**
219    * GstVideoBox:autocrop
220    *
221    * If set to %TRUE videobox will automatically crop/pad the input
222    * video to be centered in the output.
223    *
224    * Since: 0.10.16
225    **/
226   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOCROP,
227       g_param_spec_boolean ("autocrop", "Auto crop",
228           "Auto crop", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
229
230   trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
231   trans_class->transform_caps =
232       GST_DEBUG_FUNCPTR (gst_video_box_transform_caps);
233   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_box_set_caps);
234   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_video_box_get_unit_size);
235 }
236
237 static void
238 gst_video_box_init (GstVideoBox * video_box, GstVideoBoxClass * g_class)
239 {
240   video_box->box_right = DEFAULT_RIGHT;
241   video_box->box_left = DEFAULT_LEFT;
242   video_box->box_top = DEFAULT_TOP;
243   video_box->box_bottom = DEFAULT_BOTTOM;
244   video_box->crop_right = 0;
245   video_box->crop_left = 0;
246   video_box->crop_top = 0;
247   video_box->crop_bottom = 0;
248   video_box->fill_type = DEFAULT_FILL_TYPE;
249   video_box->alpha = DEFAULT_ALPHA;
250   video_box->border_alpha = DEFAULT_BORDER_ALPHA;
251   video_box->autocrop = FALSE;
252
253   video_box->mutex = g_mutex_new ();
254 }
255
256 static void
257 gst_video_box_set_property (GObject * object, guint prop_id,
258     const GValue * value, GParamSpec * pspec)
259 {
260   GstVideoBox *video_box = GST_VIDEO_BOX (object);
261
262   g_mutex_lock (video_box->mutex);
263   switch (prop_id) {
264     case PROP_LEFT:
265       video_box->box_left = g_value_get_int (value);
266       if (video_box->box_left < 0) {
267         video_box->border_left = -video_box->box_left;
268         video_box->crop_left = 0;
269       } else {
270         video_box->border_left = 0;
271         video_box->crop_left = video_box->box_left;
272       }
273       break;
274     case PROP_RIGHT:
275       video_box->box_right = g_value_get_int (value);
276       if (video_box->box_right < 0) {
277         video_box->border_right = -video_box->box_right;
278         video_box->crop_right = 0;
279       } else {
280         video_box->border_right = 0;
281         video_box->crop_right = video_box->box_right;
282       }
283       break;
284     case PROP_TOP:
285       video_box->box_top = g_value_get_int (value);
286       if (video_box->box_top < 0) {
287         video_box->border_top = -video_box->box_top;
288         video_box->crop_top = 0;
289       } else {
290         video_box->border_top = 0;
291         video_box->crop_top = video_box->box_top;
292       }
293       break;
294     case PROP_BOTTOM:
295       video_box->box_bottom = g_value_get_int (value);
296       if (video_box->box_bottom < 0) {
297         video_box->border_bottom = -video_box->box_bottom;
298         video_box->crop_bottom = 0;
299       } else {
300         video_box->border_bottom = 0;
301         video_box->crop_bottom = video_box->box_bottom;
302       }
303       break;
304     case PROP_FILL_TYPE:
305       video_box->fill_type = g_value_get_enum (value);
306       break;
307     case PROP_ALPHA:
308       video_box->alpha = g_value_get_double (value);
309       break;
310     case PROP_BORDER_ALPHA:
311       video_box->border_alpha = g_value_get_double (value);
312       break;
313     case PROP_AUTOCROP:
314       video_box->autocrop = g_value_get_boolean (value);
315       break;
316     default:
317       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318       break;
319   }
320   video_box_recalc_transform (video_box);
321
322   GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
323   gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (video_box));
324
325   g_mutex_unlock (video_box->mutex);
326 }
327
328 static void
329 gst_video_box_autocrop (GstVideoBox * video_box)
330 {
331   gint crop_w = video_box->in_width - video_box->out_width;
332   gint crop_h = video_box->in_height - video_box->out_height;
333
334   video_box->box_left = crop_w / 2;
335   if (video_box->box_left < 0) {
336     video_box->border_left = -video_box->box_left;
337     video_box->crop_left = 0;
338   } else {
339     video_box->border_left = 0;
340     video_box->crop_left = video_box->box_left;
341   }
342
343   /* Round down/up for odd width differences */
344   if (crop_w < 0)
345     crop_w -= 1;
346   else
347     crop_w += 1;
348
349   video_box->box_right = crop_w / 2;
350   if (video_box->box_right < 0) {
351     video_box->border_right = -video_box->box_right;
352     video_box->crop_right = 0;
353   } else {
354     video_box->border_right = 0;
355     video_box->crop_right = video_box->box_right;
356   }
357
358   video_box->box_top = crop_h / 2;
359   if (video_box->box_top < 0) {
360     video_box->border_top = -video_box->box_top;
361     video_box->crop_top = 0;
362   } else {
363     video_box->border_top = 0;
364     video_box->crop_top = video_box->box_top;
365   }
366
367   /* Round down/up for odd height differences */
368   if (crop_h < 0)
369     crop_h -= 1;
370   else
371     crop_h += 1;
372   video_box->box_bottom = crop_h / 2;
373
374   if (video_box->box_bottom < 0) {
375     video_box->border_bottom = -video_box->box_bottom;
376     video_box->crop_bottom = 0;
377   } else {
378     video_box->border_bottom = 0;
379     video_box->crop_bottom = video_box->box_bottom;
380   }
381 }
382
383 static void
384 gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
385     GParamSpec * pspec)
386 {
387   GstVideoBox *video_box = GST_VIDEO_BOX (object);
388
389   switch (prop_id) {
390     case PROP_LEFT:
391       g_value_set_int (value, video_box->box_left);
392       break;
393     case PROP_RIGHT:
394       g_value_set_int (value, video_box->box_right);
395       break;
396     case PROP_TOP:
397       g_value_set_int (value, video_box->box_top);
398       break;
399     case PROP_BOTTOM:
400       g_value_set_int (value, video_box->box_bottom);
401       break;
402     case PROP_FILL_TYPE:
403       g_value_set_enum (value, video_box->fill_type);
404       break;
405     case PROP_ALPHA:
406       g_value_set_double (value, video_box->alpha);
407       break;
408     case PROP_BORDER_ALPHA:
409       g_value_set_double (value, video_box->border_alpha);
410       break;
411     case PROP_AUTOCROP:
412       g_value_set_boolean (value, video_box->autocrop);
413       break;
414     default:
415       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
416       break;
417   }
418 }
419
420 static GstCaps *
421 gst_video_box_transform_caps (GstBaseTransform * trans,
422     GstPadDirection direction, GstCaps * from)
423 {
424   GstVideoBox *video_box = GST_VIDEO_BOX (trans);
425   GstCaps *to, *ret;
426   const GstCaps *templ;
427   GstStructure *structure;
428   GstPad *other;
429   gint width, height;
430
431   to = gst_caps_copy (from);
432   structure = gst_caps_get_structure (to, 0);
433
434   /* get rid of format */
435   gst_structure_remove_field (structure, "format");
436
437   /* otherwise caps nego will fail: */
438   if (video_box->autocrop) {
439     gst_structure_remove_field (structure, "width");
440     gst_structure_remove_field (structure, "height");
441   } else {
442     /* calculate width and height */
443     if (gst_structure_get_int (structure, "width", &width)) {
444       if (direction == GST_PAD_SINK) {
445         width -= video_box->box_left;
446         width -= video_box->box_right;
447       } else {
448         width += video_box->box_left;
449         width += video_box->box_right;
450       }
451       if (width <= 0)
452         width = 1;
453
454       GST_DEBUG_OBJECT (trans, "New caps width: %d", width);
455       gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
456     }
457
458     if (gst_structure_get_int (structure, "height", &height)) {
459       if (direction == GST_PAD_SINK) {
460         height -= video_box->box_top;
461         height -= video_box->box_bottom;
462       } else {
463         height += video_box->box_top;
464         height += video_box->box_bottom;
465       }
466
467       if (height <= 0)
468         height = 1;
469
470       GST_DEBUG_OBJECT (trans, "New caps height: %d", height);
471       gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
472     }
473   }
474
475   /* filter against set allowed caps on the pad */
476   other = (direction == GST_PAD_SINK) ? trans->srcpad : trans->sinkpad;
477
478   templ = gst_pad_get_pad_template_caps (other);
479   ret = gst_caps_intersect (to, templ);
480   gst_caps_unref (to);
481
482   GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
483       " to %" GST_PTR_FORMAT, direction, from, ret);
484
485   return ret;
486 }
487
488 static gboolean
489 video_box_recalc_transform (GstVideoBox * video_box)
490 {
491   gboolean res = TRUE;
492
493   /* if we have the same format in and out and we don't need to perform any
494    * cropping at all, we can just operate in passthrough mode */
495   if (video_box->in_format == video_box->out_format &&
496       video_box->box_left == 0 && video_box->box_right == 0 &&
497       video_box->box_top == 0 && video_box->box_bottom == 0) {
498
499     GST_LOG_OBJECT (video_box, "we are using passthrough");
500     gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
501         TRUE);
502   } else {
503     GST_LOG_OBJECT (video_box, "we are not using passthrough");
504     gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
505         FALSE);
506   }
507   return res;
508 }
509
510 static gboolean
511 gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
512 {
513   GstVideoBox *video_box = GST_VIDEO_BOX (trans);
514   gboolean ret;
515
516   g_mutex_lock (video_box->mutex);
517
518   ret =
519       gst_video_format_parse_caps (in, &video_box->in_format,
520       &video_box->in_width, &video_box->in_height);
521   ret &=
522       gst_video_format_parse_caps (out, &video_box->out_format,
523       &video_box->out_width, &video_box->out_height);
524
525   /* something wrong getting the caps */
526   if (!ret)
527     goto no_caps;
528
529   GST_DEBUG_OBJECT (trans, "Input w: %d h: %d", video_box->in_width,
530       video_box->in_height);
531   GST_DEBUG_OBJECT (trans, "Output w: %d h: %d", video_box->out_width,
532       video_box->out_height);
533
534   if (video_box->autocrop)
535     gst_video_box_autocrop (video_box);
536
537   /* recalc the transformation strategy */
538   ret = video_box_recalc_transform (video_box);
539
540   g_mutex_unlock (video_box->mutex);
541
542   return ret;
543
544   /* ERRORS */
545 no_caps:
546   {
547     GST_DEBUG_OBJECT (video_box,
548         "Invalid caps: %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, in, out);
549     g_mutex_unlock (video_box->mutex);
550     return FALSE;
551   }
552 }
553
554 static gboolean
555 gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
556     guint * size)
557 {
558   GstVideoBox *video_box = GST_VIDEO_BOX (trans);
559   GstVideoFormat format;
560   gint width, height;
561   gboolean ret;
562
563   g_assert (size);
564
565   ret = gst_video_format_parse_caps (caps, &format, &width, &height);
566   if (!ret) {
567     GST_ERROR_OBJECT (video_box, "Invalid caps: %" GST_PTR_FORMAT, caps);
568     return FALSE;
569   }
570
571   *size = gst_video_format_get_size (format, width, height);
572
573   GST_LOG_OBJECT (video_box, "Returning from _unit_size %d", *size);
574
575   return TRUE;
576 }
577
578 static const guint8 yuv_colors_Y[VIDEO_BOX_FILL_LAST] = { 16, 150, 29 };
579 static const guint8 yuv_colors_U[VIDEO_BOX_FILL_LAST] = { 128, 46, 255 };
580 static const guint8 yuv_colors_V[VIDEO_BOX_FILL_LAST] = { 128, 21, 107 };
581
582 static void
583 gst_video_box_copy_plane_i420 (GstVideoBox * video_box, const guint8 * src,
584     guint8 * dest, gint br, gint bl, gint bt, gint bb, gint src_crop_width,
585     gint src_crop_height, gint src_stride, gint dest_width, gint dest_stride,
586     guint8 fill_color)
587 {
588   gint j;
589
590   /* top border */
591   for (j = 0; j < bt; j++) {
592     oil_splat_u8_ns (dest, &fill_color, dest_width);
593     dest += dest_stride;
594   }
595
596   /* copy and add left and right border */
597   for (j = 0; j < src_crop_height; j++) {
598     oil_splat_u8_ns (dest, &fill_color, bl);
599     oil_memcpy (dest + bl, src, src_crop_width);
600     oil_splat_u8_ns (dest + bl + src_crop_width, &fill_color, br);
601     dest += dest_stride;
602     src += src_stride;
603   }
604
605   /* bottom border */
606   for (j = 0; j < bb; j++) {
607     oil_splat_u8_ns (dest, &fill_color, dest_width);
608     dest += dest_stride;
609   }
610 }
611
612 static void
613 gst_video_box_apply_alpha (guint8 * dest, guint8 alpha)
614 {
615   if (dest[0] != 0)
616     dest[0] = alpha;
617 }
618
619 static void
620 gst_video_box_ayuv_ayuv (GstVideoBox * video_box, const guint8 * src,
621     guint8 * dest)
622 {
623   gint dblen = video_box->out_height * video_box->out_width;
624   guint32 *destb = (guint32 *) dest;
625   const guint32 *srcb = (const guint32 *) src;
626   guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
627   guint8 i_alpha = (guint8) (video_box->alpha * 255);
628   gint br, bl, bt, bb, crop_w, crop_h;
629   gint i;
630   guint32 *loc = destb;
631   guint32 empty_pixel;
632
633   GST_LOG_OBJECT (video_box, "Processing AYUV -> AYUV data");
634
635   crop_h = 0;
636   crop_w = 0;
637   empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
638       (yuv_colors_Y[video_box->fill_type] << 16) |
639       (yuv_colors_U[video_box->fill_type] << 8) |
640       yuv_colors_V[video_box->fill_type]);
641
642   br = video_box->box_right;
643   bl = video_box->box_left;
644   bt = video_box->box_top;
645   bb = video_box->box_bottom;
646
647   if (br >= 0 && bl >= 0) {
648     crop_w = video_box->in_width - (br + bl);
649   } else if (br >= 0 && bl < 0) {
650     crop_w = video_box->in_width - (br);
651   } else if (br < 0 && bl >= 0) {
652     crop_w = video_box->in_width - (bl);
653   } else if (br < 0 && bl < 0) {
654     crop_w = video_box->in_width;
655   }
656
657   if (bb >= 0 && bt >= 0) {
658     crop_h = video_box->in_height - (bb + bt);
659   } else if (bb >= 0 && bt < 0) {
660     crop_h = video_box->in_height - (bb);
661   } else if (bb < 0 && bt >= 0) {
662     crop_h = video_box->in_height - (bt);
663   } else if (bb < 0 && bt < 0) {
664     crop_h = video_box->in_height;
665   }
666
667   GST_DEBUG_OBJECT (video_box, "Borders are: L:%d, R:%d, T:%d, B:%d", bl, br,
668       bt, bb);
669   GST_DEBUG_OBJECT (video_box, "Alpha value is: %d", i_alpha);
670
671   if (crop_h <= 0 || crop_w <= 0) {
672     oil_splat_u32_ns (destb, &empty_pixel, dblen);
673   } else {
674     const guint32 *src_loc = srcb;
675
676     /* Top border */
677     if (bt < 0) {
678       oil_splat_u32_ns (loc, &empty_pixel, (-bt) * video_box->out_width);
679       loc = loc + ((-bt) * video_box->out_width);
680     } else {
681       src_loc = src_loc + (bt * video_box->in_width);
682     }
683
684     if (bl >= 0)
685       src_loc += bl;
686
687     for (i = 0; i < crop_h; i++) {
688       gint j;
689
690       /* Left border */
691       if (bl < 0) {
692         oil_splat_u32_ns (loc, &empty_pixel, -bl);
693         loc += (-bl);
694       }
695
696       /* Cropped area */
697       oil_copy_u8 ((guint8 *) loc, (guint8 *) src_loc, crop_w * 4);
698
699       for (j = 0; j < crop_w; j++)
700         gst_video_box_apply_alpha ((guint8 *) & loc[j], i_alpha);
701
702       src_loc += video_box->in_width;
703       loc += crop_w;
704
705       /* Right border */
706       if (br < 0) {
707         oil_splat_u32_ns (loc, &empty_pixel, -br);
708         loc += (-br);
709       }
710     }
711
712     /* Bottom border */
713     if (bb < 0) {
714       oil_splat_u32_ns (loc, &empty_pixel, (-bb) * video_box->out_width);
715     }
716   }
717
718   GST_LOG_OBJECT (video_box, "image created");
719 }
720
721 static gpointer
722 gst_video_box_clear (gpointer dest, gint size)
723 {
724   guint8 nil = 255;
725
726   oil_splat_u8_ns (dest, &nil, size);
727
728   return dest;
729 }
730
731 static gint
732 UVfloor (gint j)
733 {
734   return floor (((float) j) / 2);
735 }
736
737 static gint
738 UVceil (gint j)
739 {
740   return ceil (((float) j) / 2);
741 }
742
743 static void
744 gst_video_box_ayuv_i420 (GstVideoBox * video_box, const guint8 * src,
745     guint8 * dest)
746 {
747   gint br, bl, bt, bb, crop_w, crop_h, rest;
748   gint Ysize, Usize, Vsize;
749   guint8 *Ydest, *Udest, *Vdest;
750   guint8 *Utemp, *Vtemp;
751   guint32 empty_px_values[3];
752   gint i, j;
753   guint Ywidth, Uwidth, Vwidth;
754
755   GST_LOG_OBJECT (video_box, "AYUV to I420 conversion");
756
757   crop_h = 0;
758   crop_w = 0;
759   rest = 0;
760
761   empty_px_values[0] = yuv_colors_Y[video_box->fill_type];
762   empty_px_values[1] = yuv_colors_U[video_box->fill_type];
763   empty_px_values[2] = yuv_colors_V[video_box->fill_type];
764
765   Ywidth =
766       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0,
767       video_box->out_width);
768   Uwidth =
769       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1,
770       video_box->out_width);
771   Vwidth =
772       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2,
773       video_box->out_width);
774
775   Ydest =
776       dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
777       video_box->out_width, video_box->out_height);
778   Udest =
779       dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
780       video_box->out_width, video_box->out_height);
781   Vdest =
782       dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
783       video_box->out_width, video_box->out_height);
784
785   Ysize =
786       Ywidth * gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 0,
787       video_box->out_height);
788   Usize =
789       Ywidth * gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 1,
790       video_box->out_height);
791   Vsize =
792       Ywidth * gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 2,
793       video_box->out_height);
794
795   br = video_box->box_right;
796   bl = video_box->box_left;
797   bt = video_box->box_top;
798   bb = video_box->box_bottom;
799
800   if (br >= 0 && bl >= 0) {
801     rest = Ywidth - video_box->out_width;
802     crop_w = video_box->in_width - (bl + br);
803   } else if (br >= 0 && bl < 0) {
804     rest = Ywidth - video_box->out_width;
805     crop_w = video_box->in_width - (br);
806   } else if (br < 0 && bl >= 0) {
807     rest = Ywidth - video_box->out_width;
808     crop_w = video_box->in_width - (bl);
809   } else if (br < 0 && bl < 0) {
810     rest = Ywidth - video_box->out_width;
811     crop_w = video_box->in_width;
812   }
813
814   if (bb >= 0 && bt >= 0) {
815     crop_h = video_box->in_height - (bb + bt);
816   } else if (bb >= 0 && bt < 0) {
817     crop_h = video_box->in_height - (bb);
818   } else if (bb < 0 && bt >= 0) {
819     crop_h = video_box->in_height - (bt);
820   } else if (bb < 0 && bt < 0) {
821     crop_h = video_box->in_height;
822   }
823
824   Utemp = g_malloc0 (Uwidth);
825   Vtemp = g_malloc0 (Vwidth);
826
827   GST_LOG_OBJECT (video_box, "Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt,
828       bb);
829
830   GST_LOG_OBJECT (video_box, "Starting conversion");
831
832   if (crop_h <= 0 || crop_w <= 0) {
833     oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], Ysize);
834     oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1], Usize);
835     oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2], Vsize);
836   } else {
837     gboolean sumbuff = FALSE;
838     const guint32 *src_loc1;
839     gint a = 0;
840
841     src_loc1 = (const guint32 *) src;
842
843     if (bt < 0) {
844       oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], (-bt) * Ywidth);
845
846       oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1],
847           (UVfloor (-bt) * Uwidth) + 7);
848       oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2],
849           UVfloor (-bt) * Vwidth);
850
851       if ((-bt) % 2 > 0) {
852         oil_splat_u8_ns (Utemp, (guint8 *) & empty_px_values[1], Uwidth);
853         oil_splat_u8_ns (Vtemp, (guint8 *) & empty_px_values[2], Vwidth);
854         sumbuff = TRUE;
855       }
856
857       Ydest += ((-bt) * Ywidth);
858       Udest += (UVfloor (-bt) * Uwidth);
859       Vdest += (UVfloor (-bt) * Vwidth);
860     } else {
861       src_loc1 = src_loc1 + (bt * video_box->in_width);
862     }
863
864     if (bl >= 0)
865       src_loc1 += bl;
866
867     GST_LOG_OBJECT (video_box, "Cropped area");
868     GST_LOG_OBJECT (video_box, "Ydest value: %p Ywidth: %u", Ydest, Ywidth);
869     GST_LOG_OBJECT (video_box, "Udest value: %p Uwidth: %u", Udest, Uwidth);
870     GST_LOG_OBJECT (video_box, "Vdest value: %p Vwidth: %u", Vdest, Vwidth);
871     GST_LOG_OBJECT (video_box, "Rest: %d", rest);
872     for (i = 0; i < crop_h; i++) {
873       a = 0;
874       if (sumbuff) {
875         /* left border */
876         if (bl < 0) {
877           oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -bl);
878
879           for (j = 0; j < -bl; j++) {
880             Utemp[UVfloor (j)] = (Utemp[UVfloor (j)] + empty_px_values[1]) / 2;
881             Vtemp[UVfloor (j)] = (Vtemp[UVfloor (j)] + empty_px_values[2]) / 2;
882           }
883           Ydest += -bl;
884           a = -bl;
885         }
886
887         for (j = 0; j < crop_w; j++) {
888           /* check ARCH */
889           Ydest[j] = ((guint8 *) & src_loc1[j])[1];
890           Utemp[UVfloor (a + j)] =
891               (Utemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[2]) / 2;
892           Vtemp[UVfloor (a + j)] =
893               (Vtemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[3]) / 2;
894         }
895         Ydest += crop_w;
896
897         /* right border */
898         if (br < 0) {
899           oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -br);
900           for (j = 0; j < -br; j++) {
901             Utemp[UVfloor (a + crop_w + j)] =
902                 (Utemp[UVfloor (a + crop_w + j)] + empty_px_values[1]) / 2;
903             Vtemp[UVfloor (a + crop_w + j)] =
904                 (Vtemp[UVfloor (a + crop_w + j)] + empty_px_values[2]) / 2;
905           }
906           Ydest += -br;
907         }
908         oil_copy_u8 (Udest, Utemp, Uwidth);
909         oil_copy_u8 (Vdest, Vtemp, Vwidth);
910         Udest += Uwidth;
911         Vdest += Vwidth;
912         Ydest += rest;
913         gst_video_box_clear (Utemp, Uwidth);
914         gst_video_box_clear (Vtemp, Vwidth);
915         src_loc1 += video_box->in_width;
916         sumbuff = FALSE;
917       } else {
918         /* left border */
919         a = 0;
920         if (bl < 0) {
921           oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -bl);
922           oil_splat_u8_ns (Vtemp, (guint8 *) & empty_px_values[1],
923               UVceil (-bl));
924           oil_splat_u8_ns (Utemp, (guint8 *) & empty_px_values[2],
925               UVceil (-bl));
926           Ydest += -bl;
927           a = -bl;
928         }
929
930         for (j = 0; j < crop_w; j++) {
931           /* check ARCH */
932           Ydest[j] = ((guint8 *) & src_loc1[j])[1];
933
934           if ((a + j) % 2 > 0) {
935             Utemp[UVfloor (a + j)] =
936                 (Utemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[2]) / 2;
937             Vtemp[UVfloor (a + j)] =
938                 (Vtemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[3]) / 2;
939           } else {
940             Utemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[2];
941             Vtemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[3];
942           }
943         }
944         Ydest += crop_w;
945
946         /* right border */
947         if (br < 0) {
948           j = 0;
949           if ((a + crop_w) % 2 > 0) {
950             Utemp[UVfloor (a + crop_w)] =
951                 (Utemp[UVfloor (a + crop_w)] + empty_px_values[1]) / 2;
952             Vtemp[UVfloor (a + crop_w)] =
953                 (Vtemp[UVfloor (a + crop_w)] + empty_px_values[2]) / 2;
954             a++;
955             j = -1;
956           }
957
958           oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -br);
959           oil_splat_u8_ns (&Utemp[UVfloor (a + crop_w)],
960               (guint8 *) & empty_px_values[1], UVceil ((-br) + j));
961           oil_splat_u8_ns (&Vtemp[UVfloor (a + crop_w)],
962               (guint8 *) & empty_px_values[2], UVceil ((-br) + j));
963           Ydest += -br;
964         }
965         Ydest += rest;
966         src_loc1 += video_box->in_width;
967         sumbuff = TRUE;
968       }
969     }
970
971     /* bottom border */
972     if (bb < 0) {
973       oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], (-bb) * Ywidth);
974       if (sumbuff) {
975         for (i = 0; i < Uwidth; i++) {
976           Utemp[i] = (Utemp[i] + empty_px_values[1]) / 2;
977         }
978         for (i = 0; i < Vwidth; i++) {
979           Vtemp[i] = (Vtemp[i] + empty_px_values[2]) / 2;
980         }
981
982         oil_copy_u8 (Udest, Utemp, Uwidth);
983         oil_copy_u8 (Vdest, Vtemp, Vwidth);
984         Udest += Uwidth;
985         Vdest += Vwidth;
986         sumbuff = FALSE;
987       }
988       oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1],
989           (UVfloor ((-bb))) * Uwidth);
990       oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2],
991           (UVfloor ((-bb))) * Vwidth);
992     }
993     if (sumbuff) {
994       oil_copy_u8 (Udest, Utemp, Uwidth);
995       oil_copy_u8 (Vdest, Vtemp, Vwidth);
996     }
997   }
998
999   GST_LOG_OBJECT (video_box, "image created");
1000   g_free (Utemp);
1001   g_free (Vtemp);
1002 }
1003
1004 static void
1005 gst_video_box_i420_ayuv (GstVideoBox * video_box, const guint8 * src,
1006     guint8 * dest)
1007 {
1008   const guint8 *srcY, *srcU, *srcV;
1009   gint crop_width, crop_width2, crop_height;
1010   gint out_width, out_height;
1011   gint src_stridey, src_strideu, src_stridev;
1012   gint br, bl, bt, bb;
1013   gint colorY, colorU, colorV;
1014   gint i, j;
1015   guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
1016   guint8 i_alpha = (guint8) (video_box->alpha * 255);
1017   guint32 *destp;
1018   guint32 *destb = (guint32 *) dest;
1019   guint32 ayuv;
1020
1021   br = video_box->border_right;
1022   bl = video_box->border_left;
1023   bt = video_box->border_top;
1024   bb = video_box->border_bottom;
1025
1026   out_width = video_box->out_width;
1027   out_height = video_box->out_height;
1028
1029   src_stridey =
1030       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0,
1031       video_box->in_width);
1032   src_strideu =
1033       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1,
1034       video_box->in_width);
1035   src_stridev =
1036       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2,
1037       video_box->in_width);
1038
1039   crop_width = video_box->in_width;
1040   crop_width -= (video_box->crop_left + video_box->crop_right);
1041   crop_width2 = crop_width / 2;
1042   crop_height = video_box->in_height;
1043   crop_height -= (video_box->crop_top + video_box->crop_bottom);
1044
1045   srcY =
1046       src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
1047       video_box->in_width, video_box->in_height);
1048   srcY += src_stridey * video_box->crop_top + video_box->crop_left;
1049   srcU =
1050       src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
1051       video_box->in_width, video_box->in_height);
1052   srcU += src_strideu * (video_box->crop_top / 2) + (video_box->crop_left / 2);
1053   srcV =
1054       src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
1055       video_box->in_width, video_box->in_height);
1056   srcV += src_stridev * (video_box->crop_top / 2) + (video_box->crop_left / 2);
1057
1058   colorY = yuv_colors_Y[video_box->fill_type];
1059   colorU = yuv_colors_U[video_box->fill_type];
1060   colorV = yuv_colors_V[video_box->fill_type];
1061
1062   ayuv =
1063       GUINT32_FROM_BE ((b_alpha << 24) | (colorY << 16) | (colorU << 8) |
1064       colorV);
1065
1066   /* top border */
1067   if (bt) {
1068     size_t nb_pixels = bt * out_width;
1069
1070     oil_splat_u32_ns (destb, &ayuv, nb_pixels);
1071     destb += nb_pixels;
1072   }
1073   for (i = 0; i < crop_height; i++) {
1074     destp = destb;
1075     /* left border */
1076     if (bl) {
1077       oil_splat_u32_ns (destp, &ayuv, bl);
1078       destp += bl;
1079     }
1080     dest = (guint8 *) destp;
1081     /* center */
1082     /* We can splat the alpha channel for the whole line */
1083     oil_splat_u8 (dest, 4, &i_alpha, crop_width);
1084     for (j = 0; j < crop_width2; j++) {
1085       dest++;
1086       *dest++ = *srcY++;
1087       *dest++ = *srcU;
1088       *dest++ = *srcV;
1089       dest++;
1090       *dest++ = *srcY++;
1091       *dest++ = *srcU++;
1092       *dest++ = *srcV++;
1093     }
1094     if (i % 2 == 0) {
1095       srcU -= crop_width2;
1096       srcV -= crop_width2;
1097     } else {
1098       srcU += src_strideu - crop_width2;
1099       srcV += src_stridev - crop_width2;
1100     }
1101     srcY += src_stridey - (crop_width2 * 2);
1102
1103     destp = (guint32 *) dest;
1104     /* right border */
1105     if (br) {
1106       oil_splat_u32_ns (destp, &ayuv, br);
1107     }
1108     destb += out_width;
1109   }
1110   /* bottom border */
1111   if (bb) {
1112     size_t nb_pixels = bb * out_width;
1113
1114     oil_splat_u32_ns (destb, &ayuv, nb_pixels);
1115   }
1116 }
1117
1118
1119 static void
1120 gst_video_box_i420_i420 (GstVideoBox * video_box, const guint8 * src,
1121     guint8 * dest)
1122 {
1123   const guint8 *srcY, *srcU, *srcV;
1124   guint8 *destY, *destU, *destV;
1125   gint crop_width, crop_height;
1126   gint out_width, out_height;
1127   gint src_width, src_height;
1128   gint src_stride, dest_stride;
1129   gint br, bl, bt, bb;
1130
1131   br = video_box->border_right;
1132   bl = video_box->border_left;
1133   bt = video_box->border_top;
1134   bb = video_box->border_bottom;
1135
1136   out_width = video_box->out_width;
1137   out_height = video_box->out_height;
1138
1139   src_width = video_box->in_width;
1140   src_height = video_box->in_height;
1141
1142   crop_width = src_width - (video_box->crop_left + video_box->crop_right);
1143   crop_height = src_height - (video_box->crop_top + video_box->crop_bottom);
1144
1145   /* Y plane */
1146   src_stride =
1147       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, src_width);
1148   dest_stride =
1149       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, out_width);
1150
1151   destY =
1152       dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
1153       out_width, out_height);
1154
1155   srcY =
1156       src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
1157       src_width, src_height);
1158   srcY += src_stride * video_box->crop_top + video_box->crop_left;
1159
1160   gst_video_box_copy_plane_i420 (video_box, srcY, destY, br, bl, bt, bb,
1161       crop_width, crop_height, src_stride, out_width, dest_stride,
1162       yuv_colors_Y[video_box->fill_type]);
1163
1164   br /= 2;
1165   bb /= 2;
1166   bl /= 2;
1167   bt /= 2;
1168
1169   /* we need to round up to make sure we draw all the U and V lines */
1170   crop_width = (crop_width + 1) / 2;
1171   crop_height = (crop_height + 1) / 2;
1172
1173   /* U plane */
1174   src_stride =
1175       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, src_width);
1176   dest_stride =
1177       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, out_width);
1178
1179   destU =
1180       dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
1181       out_width, out_height);
1182
1183   srcU =
1184       src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
1185       src_width, src_height);
1186   srcU += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);
1187
1188   gst_video_box_copy_plane_i420 (video_box, srcU, destU, br, bl, bt, bb,
1189       crop_width, crop_height, src_stride, out_width / 2, dest_stride,
1190       yuv_colors_U[video_box->fill_type]);
1191
1192   /* V plane */
1193   src_stride =
1194       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, src_width);
1195   dest_stride =
1196       gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, out_width);
1197
1198   destV =
1199       dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
1200       out_width, out_height);
1201
1202   srcV =
1203       src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
1204       src_width, src_height);
1205   srcV += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);
1206
1207   gst_video_box_copy_plane_i420 (video_box, srcV, destV, br, bl, bt, bb,
1208       crop_width, crop_height, src_stride, out_width / 2, dest_stride,
1209       yuv_colors_V[video_box->fill_type]);
1210 }
1211
1212 static GstFlowReturn
1213 gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
1214     GstBuffer * out)
1215 {
1216   GstVideoBox *video_box = GST_VIDEO_BOX (trans);
1217   const guint8 *indata;
1218   guint8 *outdata;
1219   GstClockTime timestamp, stream_time;
1220
1221   timestamp = GST_BUFFER_TIMESTAMP (in);
1222   stream_time =
1223       gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
1224
1225   GST_DEBUG_OBJECT (video_box, "sync to %" GST_TIME_FORMAT,
1226       GST_TIME_ARGS (timestamp));
1227
1228   if (GST_CLOCK_TIME_IS_VALID (stream_time))
1229     gst_object_sync_values (G_OBJECT (video_box), stream_time);
1230
1231   indata = GST_BUFFER_DATA (in);
1232   outdata = GST_BUFFER_DATA (out);
1233
1234   g_mutex_lock (video_box->mutex);
1235   switch (video_box->in_format) {
1236     case GST_VIDEO_FORMAT_AYUV:
1237       switch (video_box->out_format) {
1238         case GST_VIDEO_FORMAT_AYUV:
1239           gst_video_box_ayuv_ayuv (video_box, indata, outdata);
1240           break;
1241         case GST_VIDEO_FORMAT_I420:
1242           gst_video_box_ayuv_i420 (video_box, indata, outdata);
1243           break;
1244         default:
1245           goto invalid_format;
1246       }
1247       break;
1248     case GST_VIDEO_FORMAT_I420:
1249       switch (video_box->out_format) {
1250         case GST_VIDEO_FORMAT_AYUV:
1251           gst_video_box_i420_ayuv (video_box, indata, outdata);
1252           break;
1253         case GST_VIDEO_FORMAT_I420:
1254           gst_video_box_i420_i420 (video_box, indata, outdata);
1255           break;
1256         default:
1257           goto invalid_format;
1258       }
1259       break;
1260     default:
1261       goto invalid_format;
1262   }
1263   g_mutex_unlock (video_box->mutex);
1264   return GST_FLOW_OK;
1265
1266   /* ERRORS */
1267 invalid_format:
1268   {
1269     g_mutex_unlock (video_box->mutex);
1270     return GST_FLOW_ERROR;
1271   }
1272 }
1273
1274 /* FIXME: 0.11 merge with videocrop plugin */
1275 static gboolean
1276 plugin_init (GstPlugin * plugin)
1277 {
1278   oil_init ();
1279
1280   gst_controller_init (NULL, NULL);
1281
1282   GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
1283       "Resizes a video by adding borders or cropping");
1284
1285   return gst_element_register (plugin, "videobox", GST_RANK_NONE,
1286       GST_TYPE_VIDEO_BOX);
1287 }
1288
1289 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1290     GST_VERSION_MINOR,
1291     "videobox",
1292     "resizes a video by adding borders or cropping",
1293     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)