tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / gst / smpte / gstsmptealpha.c
1 /* GStreamer
2  * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-smptealpha
22  *
23  * smptealpha can accept an I420 or AYUV video stream. An alpha channel is added
24  * using an effect specific SMPTE mask in the I420 input case. In the AYUV case,
25  * the alpha channel is modified using the effect specific SMPTE mask.
26  *
27  * The #GstSmpteAlpha:position property is a controllabe double between 0.0 and
28  * 1.0 that specifies the position in the transition. 0.0 is the start of the
29  * transition with the alpha channel to complete opaque where 1.0 has the alpha
30  * channel set to completely transparent.
31  *
32  * The #GstSmpteAlpha:depth property defines the precision in bits of the mask.
33  * A higher presision will create a mask with smoother gradients in order to
34  * avoid banding.
35  *
36  * <refsect2>
37  * <title>Sample pipelines</title>
38  * <para>
39  * Here is a pipeline to demonstrate the smpte transition :
40  * <programlisting>
41  * gst-launch -v videotestsrc ! smptealpha border=20000 type=44
42  * position=0.5 ! videomixer ! ffmpegcolorspace ! ximagesink 
43  * </programlisting>
44  * This shows a midway bowtie-h transition a from a videotestsrc to a
45  * transparent image. The edges of the transition are smoothed with a
46  * 20000 big border.
47  * </para>
48  * </refsect2>
49  */
50
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54 #include <string.h>
55
56 #include <gst/controller/gstcontroller.h>
57
58 #include "gstsmptealpha.h"
59 #include "paint.h"
60
61 GST_DEBUG_CATEGORY_STATIC (gst_smpte_alpha_debug);
62 #define GST_CAT_DEFAULT gst_smpte_alpha_debug
63
64 static GstStaticPadTemplate gst_smpte_alpha_src_template =
65     GST_STATIC_PAD_TEMPLATE ("src",
66     GST_PAD_SRC,
67     GST_PAD_ALWAYS,
68     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
69         GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
70         GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_ARGB)
71     );
72
73 static GstStaticPadTemplate gst_smpte_alpha_sink_template =
74     GST_STATIC_PAD_TEMPLATE ("sink",
75     GST_PAD_SINK,
76     GST_PAD_ALWAYS,
77     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420") ";" GST_VIDEO_CAPS_YUV ("YV12")
78         ";" GST_VIDEO_CAPS_YUV ("AYUV")
79         ";" GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_RGBA
80         ";" GST_VIDEO_CAPS_ARGB)
81     );
82
83 /* SMPTE signals and properties */
84
85 #define DEFAULT_PROP_TYPE       1
86 #define DEFAULT_PROP_BORDER     0
87 #define DEFAULT_PROP_DEPTH      16
88 #define DEFAULT_PROP_POSITION   0.0
89 #define DEFAULT_PROP_INVERT   FALSE
90
91 enum
92 {
93   PROP_0,
94   PROP_TYPE,
95   PROP_BORDER,
96   PROP_DEPTH,
97   PROP_POSITION,
98   PROP_INVERT,
99   PROP_LAST,
100 };
101
102 #define AYUV_SIZE(w,h)     ((w) * (h) * 4)
103
104 #define GST_TYPE_SMPTE_TRANSITION_TYPE (gst_smpte_alpha_transition_type_get_type())
105 static GType
106 gst_smpte_alpha_transition_type_get_type (void)
107 {
108   static GType smpte_transition_type = 0;
109   GEnumValue *smpte_transitions;
110
111   if (!smpte_transition_type) {
112     const GList *definitions;
113     gint i = 0;
114
115     definitions = gst_mask_get_definitions ();
116     smpte_transitions =
117         g_new0 (GEnumValue, g_list_length ((GList *) definitions) + 1);
118
119     while (definitions) {
120       GstMaskDefinition *definition = (GstMaskDefinition *) definitions->data;
121
122       definitions = g_list_next (definitions);
123
124       smpte_transitions[i].value = definition->type;
125       /* older GLib versions have the two fields as non-const, hence the cast */
126       smpte_transitions[i].value_nick = (gchar *) definition->short_name;
127       smpte_transitions[i].value_name = (gchar *) definition->long_name;
128
129       i++;
130     }
131
132     smpte_transition_type =
133         g_enum_register_static ("GstSMPTEAlphaTransitionType",
134         smpte_transitions);
135   }
136   return smpte_transition_type;
137 }
138
139
140 static void gst_smpte_alpha_finalize (GstSMPTEAlpha * smpte);
141
142 static void gst_smpte_alpha_set_property (GObject * object, guint prop_id,
143     const GValue * value, GParamSpec * pspec);
144 static void gst_smpte_alpha_get_property (GObject * object, guint prop_id,
145     GValue * value, GParamSpec * pspec);
146
147 static gboolean gst_smpte_alpha_setcaps (GstBaseTransform * btrans,
148     GstCaps * incaps, GstCaps * outcaps);
149 static gboolean gst_smpte_alpha_get_unit_size (GstBaseTransform * btrans,
150     GstCaps * caps, guint * size);
151 static GstFlowReturn gst_smpte_alpha_transform (GstBaseTransform * trans,
152     GstBuffer * in, GstBuffer * out);
153 static void gst_smpte_alpha_before_transform (GstBaseTransform * trans,
154     GstBuffer * buf);
155 static GstCaps *gst_smpte_alpha_transform_caps (GstBaseTransform * trans,
156     GstPadDirection direction, GstCaps * from);
157
158 GST_BOILERPLATE (GstSMPTEAlpha, gst_smpte_alpha, GstVideoFilter,
159     GST_TYPE_VIDEO_FILTER);
160
161 static void
162 gst_smpte_alpha_base_init (gpointer klass)
163 {
164   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
165
166   gst_element_class_add_static_pad_template (element_class,
167       &gst_smpte_alpha_sink_template);
168   gst_element_class_add_static_pad_template (element_class,
169       &gst_smpte_alpha_src_template);
170   gst_element_class_set_details_simple (element_class, "SMPTE transitions",
171       "Filter/Editor/Video",
172       "Apply the standard SMPTE transitions as alpha on video images",
173       "Wim Taymans <wim.taymans@gmail.com>");
174 }
175
176 static void
177 gst_smpte_alpha_class_init (GstSMPTEAlphaClass * klass)
178 {
179   GObjectClass *gobject_class = (GObjectClass *) klass;
180   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
181
182   gobject_class->set_property = gst_smpte_alpha_set_property;
183   gobject_class->get_property = gst_smpte_alpha_get_property;
184
185   gobject_class->finalize = (GObjectFinalizeFunc) gst_smpte_alpha_finalize;
186
187   _gst_mask_init ();
188
189   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TYPE,
190       g_param_spec_enum ("type", "Type", "The type of transition to use",
191           GST_TYPE_SMPTE_TRANSITION_TYPE, DEFAULT_PROP_TYPE,
192           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
193   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER,
194       g_param_spec_int ("border", "Border",
195           "The border width of the transition", 0, G_MAXINT,
196           DEFAULT_PROP_BORDER,
197           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEPTH,
199       g_param_spec_int ("depth", "Depth", "Depth of the mask in bits", 1, 24,
200           DEFAULT_PROP_DEPTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_POSITION,
202       g_param_spec_double ("position", "Position",
203           "Position of the transition effect", 0.0, 1.0, DEFAULT_PROP_POSITION,
204           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205   /**
206    * GstSMPTEAlpha:invert:
207    *
208    * Set to TRUE to invert the transition mask (ie. flip it horizontally).
209    *
210    * Since: 0.10.23
211    */
212   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_INVERT,
213       g_param_spec_boolean ("invert", "Invert",
214           "Invert transition mask", DEFAULT_PROP_POSITION,
215           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
216
217   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_smpte_alpha_setcaps);
218   trans_class->get_unit_size =
219       GST_DEBUG_FUNCPTR (gst_smpte_alpha_get_unit_size);
220   trans_class->transform = GST_DEBUG_FUNCPTR (gst_smpte_alpha_transform);
221   trans_class->before_transform =
222       GST_DEBUG_FUNCPTR (gst_smpte_alpha_before_transform);
223   trans_class->transform_caps =
224       GST_DEBUG_FUNCPTR (gst_smpte_alpha_transform_caps);
225 }
226
227 static gboolean
228 gst_smpte_alpha_update_mask (GstSMPTEAlpha * smpte, gint type,
229     gboolean invert, gint depth, gint width, gint height)
230 {
231   GstMask *newmask;
232
233   /* try to avoid regenerating the mask if we already have one that is
234    * correct */
235   if (smpte->mask) {
236     if (smpte->type == type &&
237         smpte->invert == invert &&
238         smpte->depth == depth &&
239         smpte->width == width && smpte->height == height)
240       return TRUE;
241   }
242
243   smpte->type = type;
244   smpte->invert = invert;
245   smpte->depth = depth;
246   smpte->width = width;
247   smpte->height = height;
248
249   /* Not negotiated yet */
250   if (width == 0 || height == 0) {
251     return TRUE;
252   }
253
254   newmask = gst_mask_factory_new (type, invert, depth, width, height);
255   if (!newmask)
256     goto mask_failed;
257
258   if (smpte->mask)
259     gst_mask_destroy (smpte->mask);
260
261   smpte->mask = newmask;
262
263   return TRUE;
264
265   /* ERRORS */
266 mask_failed:
267   {
268     GST_ERROR_OBJECT (smpte, "failed to create a mask");
269     return FALSE;
270   }
271 }
272
273 static void
274 gst_smpte_alpha_init (GstSMPTEAlpha * smpte, GstSMPTEAlphaClass * klass)
275 {
276   smpte->type = DEFAULT_PROP_TYPE;
277   smpte->border = DEFAULT_PROP_BORDER;
278   smpte->depth = DEFAULT_PROP_DEPTH;
279   smpte->position = DEFAULT_PROP_POSITION;
280   smpte->invert = DEFAULT_PROP_INVERT;
281 }
282
283 #define CREATE_ARGB_FUNC(name, A, R, G, B) \
284 static void \
285 gst_smpte_alpha_process_##name##_##name (GstSMPTEAlpha * smpte, const guint8 * in, \
286     guint8 * out, GstMask * mask, gint width, gint height, gint border, \
287     gint pos) \
288 { \
289   gint i, j; \
290   const guint32 *maskp; \
291   gint value; \
292   gint min, max; \
293   \
294   if (border == 0) \
295     border++; \
296   \
297   min = pos - border; \
298   max = pos; \
299   GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max, \
300       border); \
301   \
302   maskp = mask->data; \
303   \
304   /* we basically copy the source to dest but we scale the alpha channel with \
305    * the mask */ \
306   for (i = 0; i < height; i++) { \
307     for (j = 0; j < width; j++) { \
308       value = *maskp++; \
309       out[A] = (in[A] * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; \
310       out[R] = in[R]; \
311       out[G] = in[G]; \
312       out[B] = in[B]; \
313       out += 4; \
314       in += 4; \
315     } \
316   } \
317 }
318
319 CREATE_ARGB_FUNC (argb, 0, 1, 2, 3);
320 CREATE_ARGB_FUNC (bgra, 3, 2, 1, 0);
321 CREATE_ARGB_FUNC (abgr, 0, 3, 2, 1);
322 CREATE_ARGB_FUNC (rgba, 3, 0, 1, 2);
323
324 static void
325 gst_smpte_alpha_process_ayuv_ayuv (GstSMPTEAlpha * smpte, const guint8 * in,
326     guint8 * out, GstMask * mask, gint width, gint height, gint border,
327     gint pos)
328 {
329   gint i, j;
330   const guint32 *maskp;
331   gint value;
332   gint min, max;
333
334   if (border == 0)
335     border++;
336
337   min = pos - border;
338   max = pos;
339   GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max,
340       border);
341
342   maskp = mask->data;
343
344   /* we basically copy the source to dest but we scale the alpha channel with
345    * the mask */
346   for (i = 0; i < height; i++) {
347     for (j = 0; j < width; j++) {
348       value = *maskp++;
349       *out++ = (*in++ * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
350       *out++ = *in++;
351       *out++ = *in++;
352       *out++ = *in++;
353     }
354   }
355 }
356
357 static void
358 gst_smpte_alpha_process_i420_ayuv (GstSMPTEAlpha * smpte, const guint8 * in,
359     guint8 * out, GstMask * mask, gint width, gint height, gint border,
360     gint pos)
361 {
362   const guint8 *srcY;
363   const guint8 *srcU;
364   const guint8 *srcV;
365   gint i, j;
366   gint src_wrap, src_uv_wrap;
367   gint y_stride, uv_stride;
368   gboolean odd_width;
369   const guint32 *maskp;
370   gint value;
371   gint min, max;
372
373   if (border == 0)
374     border++;
375
376   min = pos - border;
377   max = pos;
378   GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max,
379       border);
380
381   maskp = mask->data;
382
383   y_stride = gst_video_format_get_row_stride (smpte->in_format, 0, width);
384   uv_stride = gst_video_format_get_row_stride (smpte->in_format, 1, width);
385
386   src_wrap = y_stride - width;
387   src_uv_wrap = uv_stride - (width / 2);
388
389   srcY = in;
390   srcU = in + gst_video_format_get_component_offset (smpte->in_format,
391       1, width, height);
392   srcV = in + gst_video_format_get_component_offset (smpte->in_format,
393       2, width, height);
394
395   odd_width = (width % 2 != 0);
396
397   for (i = 0; i < height; i++) {
398     for (j = 0; j < width / 2; j++) {
399       value = *maskp++;
400       *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
401       *out++ = *srcY++;
402       *out++ = *srcU;
403       *out++ = *srcV;
404       value = *maskp++;
405       *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
406       *out++ = *srcY++;
407       *out++ = *srcU++;
408       *out++ = *srcV++;
409     }
410     /* Might have one odd column left to do */
411     if (odd_width) {
412       value = *maskp++;
413       *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
414       *out++ = *srcY++;
415       *out++ = *srcU;
416       *out++ = *srcV;
417     }
418     if (i % 2 == 0) {
419       srcU -= width / 2;
420       srcV -= width / 2;
421     } else {
422       srcU += src_uv_wrap;
423       srcV += src_uv_wrap;
424     }
425     srcY += src_wrap;
426   }
427 }
428
429 static void
430 gst_smpte_alpha_before_transform (GstBaseTransform * trans, GstBuffer * buf)
431 {
432   GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (trans);
433   GstClockTime timestamp, stream_time;
434
435   /* first sync the controller to the current stream_time of the buffer */
436   timestamp = GST_BUFFER_TIMESTAMP (buf);
437   stream_time =
438       gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
439
440   GST_DEBUG_OBJECT (smpte, "sync to %" GST_TIME_FORMAT,
441       GST_TIME_ARGS (timestamp));
442
443   if (GST_CLOCK_TIME_IS_VALID (stream_time))
444     gst_object_sync_values (G_OBJECT (smpte), stream_time);
445 }
446
447 static GstFlowReturn
448 gst_smpte_alpha_transform (GstBaseTransform * trans, GstBuffer * in,
449     GstBuffer * out)
450 {
451   GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (trans);
452   gdouble position;
453   gint border;
454
455   if (G_UNLIKELY (!smpte->process))
456     goto not_negotiated;
457
458   /* these are the propertis we update with only the object lock, others are
459    * only updated with the TRANSFORM_LOCK. */
460   GST_OBJECT_LOCK (smpte);
461   position = smpte->position;
462   border = smpte->border;
463   GST_OBJECT_UNLOCK (smpte);
464
465   /* run the type specific filter code */
466   smpte->process (smpte, GST_BUFFER_DATA (in), GST_BUFFER_DATA (out),
467       smpte->mask, smpte->width, smpte->height, border,
468       ((1 << smpte->depth) + border) * position);
469
470   return GST_FLOW_OK;
471
472   /* ERRORS */
473 not_negotiated:
474   {
475     GST_ELEMENT_ERROR (smpte, CORE, NEGOTIATION, (NULL),
476         ("No input format negotiated"));
477     return GST_FLOW_NOT_NEGOTIATED;
478   }
479 }
480
481 static GstCaps *
482 gst_smpte_alpha_transform_caps (GstBaseTransform * trans,
483     GstPadDirection direction, GstCaps * from)
484 {
485   GstCaps *to = gst_caps_copy (from);
486   GstStructure *s;
487
488   gst_caps_truncate (to);
489   s = gst_caps_get_structure (to, 0);
490
491   if (gst_structure_has_name (s, "video/x-raw-yuv")) {
492     GValue list = { 0, };
493     GValue val = { 0, };
494
495     gst_structure_remove_field (s, "format");
496
497     g_value_init (&list, GST_TYPE_LIST);
498     g_value_init (&val, GST_TYPE_FOURCC);
499     gst_value_set_fourcc (&val, GST_STR_FOURCC ("AYUV"));
500     gst_value_list_append_value (&list, &val);
501     g_value_reset (&val);
502     gst_value_set_fourcc (&val, GST_STR_FOURCC ("I420"));
503     gst_value_list_append_value (&list, &val);
504     g_value_reset (&val);
505     gst_value_set_fourcc (&val, GST_STR_FOURCC ("YV12"));
506     gst_value_list_append_value (&list, &val);
507     g_value_unset (&val);
508     gst_structure_set_value (s, "format", &list);
509     g_value_unset (&list);
510   } else if (!gst_structure_has_name (s, "video/x-raw-rgb")) {
511     gst_caps_unref (to);
512     to = gst_caps_new_empty ();
513   }
514
515   return to;
516 }
517
518 static gboolean
519 gst_smpte_alpha_setcaps (GstBaseTransform * btrans, GstCaps * incaps,
520     GstCaps * outcaps)
521 {
522   GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (btrans);
523   gboolean ret;
524   gint width, height;
525
526   smpte->process = NULL;
527
528   if (!gst_video_format_parse_caps (incaps, &smpte->in_format, &width, &height))
529     goto invalid_caps;
530   if (!gst_video_format_parse_caps (outcaps, &smpte->out_format, &width,
531           &height))
532     goto invalid_caps;
533
534   /* try to update the mask now, this will also adjust the width/height on
535    * success */
536   GST_OBJECT_LOCK (smpte);
537   ret =
538       gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->invert,
539       smpte->depth, width, height);
540   GST_OBJECT_UNLOCK (smpte);
541   if (!ret)
542     goto mask_failed;
543
544   switch (smpte->out_format) {
545     case GST_VIDEO_FORMAT_AYUV:
546       switch (smpte->in_format) {
547         case GST_VIDEO_FORMAT_AYUV:
548           smpte->process = gst_smpte_alpha_process_ayuv_ayuv;
549           break;
550         case GST_VIDEO_FORMAT_I420:
551           smpte->process = gst_smpte_alpha_process_i420_ayuv;
552           break;
553         default:
554           break;
555       }
556       break;
557     case GST_VIDEO_FORMAT_ARGB:
558       switch (smpte->in_format) {
559         case GST_VIDEO_FORMAT_ARGB:
560           smpte->process = gst_smpte_alpha_process_argb_argb;
561           break;
562         default:
563           break;
564       }
565       break;
566     case GST_VIDEO_FORMAT_RGBA:
567       switch (smpte->in_format) {
568         case GST_VIDEO_FORMAT_RGBA:
569           smpte->process = gst_smpte_alpha_process_rgba_rgba;
570           break;
571         default:
572           break;
573       }
574       break;
575     case GST_VIDEO_FORMAT_ABGR:
576       switch (smpte->in_format) {
577         case GST_VIDEO_FORMAT_ABGR:
578           smpte->process = gst_smpte_alpha_process_abgr_abgr;
579           break;
580         default:
581           break;
582       }
583       break;
584     case GST_VIDEO_FORMAT_BGRA:
585       switch (smpte->in_format) {
586         case GST_VIDEO_FORMAT_BGRA:
587           smpte->process = gst_smpte_alpha_process_bgra_bgra;
588           break;
589         default:
590           break;
591       }
592       break;
593     default:
594       break;
595   }
596
597   return ret;
598
599   /* ERRORS */
600 invalid_caps:
601   {
602     GST_ERROR_OBJECT (smpte, "Invalid caps: %" GST_PTR_FORMAT, incaps);
603     return FALSE;
604   }
605 mask_failed:
606   {
607     GST_ERROR_OBJECT (smpte, "failed creating the mask");
608     return FALSE;
609   }
610 }
611
612 static gboolean
613 gst_smpte_alpha_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
614     guint * size)
615 {
616   gint width, height;
617   GstVideoFormat format;
618
619   if (!gst_video_format_parse_caps (caps, &format, &width, &height))
620     return FALSE;
621
622   *size = gst_video_format_get_size (format, width, height);
623
624   return TRUE;
625 }
626
627 static void
628 gst_smpte_alpha_finalize (GstSMPTEAlpha * smpte)
629 {
630   if (smpte->mask)
631     gst_mask_destroy (smpte->mask);
632   smpte->mask = NULL;
633
634   G_OBJECT_CLASS (parent_class)->finalize ((GObject *) smpte);
635 }
636
637 static void
638 gst_smpte_alpha_set_property (GObject * object, guint prop_id,
639     const GValue * value, GParamSpec * pspec)
640 {
641   GstSMPTEAlpha *smpte = GST_SMPTE_ALPHA (object);
642
643   switch (prop_id) {
644     case PROP_TYPE:{
645       gint type;
646
647       type = g_value_get_enum (value);
648
649       GST_BASE_TRANSFORM_LOCK (smpte);
650       GST_OBJECT_LOCK (smpte);
651       gst_smpte_alpha_update_mask (smpte, type, smpte->invert,
652           smpte->depth, smpte->width, smpte->height);
653       GST_OBJECT_UNLOCK (smpte);
654       GST_BASE_TRANSFORM_UNLOCK (smpte);
655       break;
656     }
657     case PROP_BORDER:
658       GST_OBJECT_LOCK (smpte);
659       smpte->border = g_value_get_int (value);
660       GST_OBJECT_UNLOCK (smpte);
661       break;
662     case PROP_DEPTH:{
663       gint depth;
664
665       depth = g_value_get_int (value);
666
667       GST_BASE_TRANSFORM_LOCK (smpte);
668       /* also lock with the object lock so that reading the property doesn't
669        * have to wait for the transform lock */
670       GST_OBJECT_LOCK (smpte);
671       gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->invert,
672           depth, smpte->width, smpte->height);
673       GST_OBJECT_UNLOCK (smpte);
674       GST_BASE_TRANSFORM_UNLOCK (smpte);
675       break;
676     }
677     case PROP_POSITION:
678       GST_OBJECT_LOCK (smpte);
679       smpte->position = g_value_get_double (value);
680       GST_OBJECT_UNLOCK (smpte);
681       break;
682     case PROP_INVERT:{
683       gboolean invert;
684
685       invert = g_value_get_boolean (value);
686       GST_BASE_TRANSFORM_LOCK (smpte);
687       /* also lock with the object lock so that reading the property doesn't
688        * have to wait for the transform lock */
689       GST_OBJECT_LOCK (smpte);
690       gst_smpte_alpha_update_mask (smpte, smpte->type, invert,
691           smpte->depth, smpte->width, smpte->height);
692       GST_OBJECT_UNLOCK (smpte);
693       GST_BASE_TRANSFORM_UNLOCK (smpte);
694       break;
695     }
696     default:
697       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
698       break;
699   }
700 }
701
702 static void
703 gst_smpte_alpha_get_property (GObject * object, guint prop_id,
704     GValue * value, GParamSpec * pspec)
705 {
706   GstSMPTEAlpha *smpte;
707
708   smpte = GST_SMPTE_ALPHA (object);
709
710   switch (prop_id) {
711     case PROP_TYPE:
712       GST_OBJECT_LOCK (smpte);
713       g_value_set_enum (value, smpte->type);
714       GST_OBJECT_UNLOCK (smpte);
715       break;
716     case PROP_BORDER:
717       GST_OBJECT_LOCK (smpte);
718       g_value_set_int (value, smpte->border);
719       GST_OBJECT_UNLOCK (smpte);
720       break;
721     case PROP_DEPTH:
722       GST_OBJECT_LOCK (smpte);
723       g_value_set_int (value, smpte->depth);
724       GST_OBJECT_UNLOCK (smpte);
725       break;
726     case PROP_POSITION:
727       GST_OBJECT_LOCK (smpte);
728       g_value_set_double (value, smpte->position);
729       GST_OBJECT_UNLOCK (smpte);
730       break;
731     case PROP_INVERT:
732       GST_OBJECT_LOCK (smpte);
733       g_value_set_boolean (value, smpte->invert);
734       GST_OBJECT_UNLOCK (smpte);
735       break;
736     default:
737       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
738       break;
739   }
740 }
741
742 gboolean
743 gst_smpte_alpha_plugin_init (GstPlugin * plugin)
744 {
745   GST_DEBUG_CATEGORY_INIT (gst_smpte_alpha_debug, "smptealpha", 0,
746       "SMPTE alpha effect");
747
748   /* initialize gst controller library */
749   gst_controller_init (NULL, NULL);
750
751   return gst_element_register (plugin, "smptealpha", GST_RANK_NONE,
752       GST_TYPE_SMPTE_ALPHA);
753 }