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