docs: use the gtk-doc syntax to link to properties
[platform/upstream/gst-plugins-good.git] / gst / debugutils / gstcapssetter.c
1 /* GStreamer Element
2  * Copyright (C) 2006-2009 Mark Nauwelaerts <mnauw@users.sourceforge.net>
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., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1307, USA.
18  */
19
20 /**
21  * SECTION:element-capssetter
22  *
23  * Sets or merges caps on a stream's buffers. That is, a buffer's caps are
24  * updated using (fields of) #GstCapsSetter:caps. Note that this may contain
25  * multiple structures (though not likely recommended), but each of these must
26  * be fixed (or will otherwise be rejected).
27  * 
28  * If #GstCapsSetter:join is %TRUE, then the incoming caps' mime-type is
29  * compared to the mime-type(s) of provided caps and only matching structure(s)
30  * are considered for updating.
31  * 
32  * If #GstCapsSetter:replace is %TRUE, then any caps update is preceded by
33  * clearing existing fields, making provided fields (as a whole) replace
34  * incoming ones. Otherwise, no clearing is performed, in which case provided
35  * fields are added/merged onto incoming caps
36  * 
37  * Although this element might mainly serve as debug helper,
38  * it can also practically be used to correct a faulty pixel-aspect-ratio,
39  * or to modify a yuv fourcc value to effectively swap chroma components or such
40  * alike.
41  */
42
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "gstcapssetter.h"
49
50 #include <string.h>
51
52
53 GST_DEBUG_CATEGORY_STATIC (caps_setter_debug);
54 #define GST_CAT_DEFAULT caps_setter_debug
55
56
57 /* signals and args */
58 enum
59 {
60   /* FILL ME */
61   LAST_SIGNAL
62 };
63
64 enum
65 {
66   PROP_0,
67   PROP_CAPS,
68   PROP_JOIN,
69   PROP_REPLACE
70       /* FILL ME */
71 };
72
73 #define DEFAULT_JOIN              TRUE
74 #define DEFAULT_REPLACE           FALSE
75
76 static GstStaticPadTemplate gst_caps_setter_src_template =
77 GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
78     GST_PAD_SRC,
79     GST_PAD_ALWAYS,
80     GST_STATIC_CAPS_ANY);
81
82 static GstStaticPadTemplate gst_caps_setter_sink_template =
83 GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
84     GST_PAD_SINK,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS_ANY);
87
88
89 static gboolean gst_caps_setter_transform_size (GstBaseTransform * trans,
90     GstPadDirection direction, GstCaps * caps, gsize size,
91     GstCaps * othercaps, gsize * othersize);
92 static GstCaps *gst_caps_setter_transform_caps (GstBaseTransform * trans,
93     GstPadDirection direction, GstCaps * caps, GstCaps * cfilter);
94 static GstFlowReturn gst_caps_setter_transform_ip (GstBaseTransform * btrans,
95     GstBuffer * in);
96
97 static void gst_caps_setter_finalize (GObject * object);
98
99 static void gst_caps_setter_set_property (GObject * object, guint prop_id,
100     const GValue * value, GParamSpec * pspec);
101 static void gst_caps_setter_get_property (GObject * object, guint prop_id,
102     GValue * value, GParamSpec * pspec);
103
104 #define gst_caps_setter_parent_class parent_class
105 G_DEFINE_TYPE (GstCapsSetter, gst_caps_setter, GST_TYPE_BASE_TRANSFORM);
106
107 static void
108 gst_caps_setter_class_init (GstCapsSetterClass * g_class)
109 {
110   GObjectClass *gobject_class = (GObjectClass *) g_class;
111   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
112   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) g_class;
113
114   GST_DEBUG_CATEGORY_INIT (caps_setter_debug, "capssetter", 0, "capssetter");
115
116   gobject_class->set_property = gst_caps_setter_set_property;
117   gobject_class->get_property = gst_caps_setter_get_property;
118
119   gobject_class->finalize = gst_caps_setter_finalize;
120
121   g_object_class_install_property (gobject_class, PROP_CAPS,
122       g_param_spec_boxed ("caps", "Merge caps",
123           "Merge these caps (thereby overwriting) in the stream",
124           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
125   g_object_class_install_property (gobject_class, PROP_JOIN,
126       g_param_spec_boolean ("join", "Join",
127           "Match incoming caps' mime-type to mime-type of provided caps",
128           DEFAULT_JOIN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129   g_object_class_install_property (gobject_class, PROP_REPLACE,
130       g_param_spec_boolean ("replace", "Replace",
131           "Drop fields of incoming caps", DEFAULT_REPLACE,
132           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
133
134   gst_element_class_set_static_metadata (element_class, "CapsSetter",
135       "Generic",
136       "Set/merge caps on stream",
137       "Mark Nauwelaerts <mnauw@users.sourceforge.net>");
138
139   gst_element_class_add_pad_template (element_class,
140       gst_static_pad_template_get (&gst_caps_setter_sink_template));
141   gst_element_class_add_pad_template (element_class,
142       gst_static_pad_template_get (&gst_caps_setter_src_template));
143
144   trans_class->transform_size =
145       GST_DEBUG_FUNCPTR (gst_caps_setter_transform_size);
146   trans_class->transform_caps =
147       GST_DEBUG_FUNCPTR (gst_caps_setter_transform_caps);
148   /* dummy seems needed */
149   trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_caps_setter_transform_ip);
150 }
151
152 static void
153 gst_caps_setter_init (GstCapsSetter * filter)
154 {
155   filter->caps = gst_caps_new_any ();
156   filter->join = DEFAULT_JOIN;
157   filter->replace = DEFAULT_REPLACE;
158 }
159
160 static void
161 gst_caps_setter_finalize (GObject * object)
162 {
163   GstCapsSetter *filter = GST_CAPS_SETTER (object);
164
165   gst_caps_replace (&filter->caps, NULL);
166
167   G_OBJECT_CLASS (parent_class)->finalize (object);
168 }
169
170 static gboolean
171 gst_caps_setter_transform_size (GstBaseTransform * trans,
172     GstPadDirection direction, GstCaps * caps, gsize size,
173     GstCaps * othercaps, gsize * othersize)
174 {
175   *othersize = size;
176
177   return TRUE;
178 }
179
180 static GstCaps *
181 gst_caps_setter_transform_caps (GstBaseTransform * trans,
182     GstPadDirection direction, GstCaps * caps, GstCaps * cfilter)
183 {
184   GstCapsSetter *filter = GST_CAPS_SETTER (trans);
185   GstCaps *ret = NULL, *filter_caps = NULL;
186   GstStructure *structure, *merge;
187   const gchar *name;
188   gint i, j;
189
190   GST_DEBUG_OBJECT (trans,
191       "receiving caps: %" GST_PTR_FORMAT ", with filter: %" GST_PTR_FORMAT,
192       caps, cfilter);
193
194   /* pass filter caps upstream, or any if no filter */
195   if (direction != GST_PAD_SINK) {
196     if (!cfilter || gst_caps_is_empty (cfilter)) {
197       return gst_caps_ref (GST_CAPS_ANY);
198     } else {
199       return gst_caps_ref (cfilter);
200     }
201   }
202
203   ret = gst_caps_copy (caps);
204
205   /* this function is always called with a simple caps */
206   if (!GST_CAPS_IS_SIMPLE (ret))
207     return ret;
208
209   structure = gst_caps_get_structure (ret, 0);
210   name = gst_structure_get_name (structure);
211
212   GST_OBJECT_LOCK (filter);
213   filter_caps = gst_caps_ref (filter->caps);
214   GST_OBJECT_UNLOCK (filter);
215
216   for (i = 0; i < gst_caps_get_size (filter_caps); ++i) {
217     merge = gst_caps_get_structure (filter_caps, i);
218     if (gst_structure_has_name (merge, name) || !filter->join) {
219
220       if (!filter->join)
221         gst_structure_set_name (structure, gst_structure_get_name (merge));
222
223       if (filter->replace)
224         gst_structure_remove_all_fields (structure);
225
226       for (j = 0; j < gst_structure_n_fields (merge); ++j) {
227         const gchar *fname;
228
229         fname = gst_structure_nth_field_name (merge, j);
230         gst_structure_set_value (structure, fname,
231             gst_structure_get_value (merge, fname));
232       }
233     }
234   }
235
236   GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
237
238   gst_caps_unref (filter_caps);
239
240   return ret;
241 }
242
243 static GstFlowReturn
244 gst_caps_setter_transform_ip (GstBaseTransform * btrans, GstBuffer * in)
245 {
246   return GST_FLOW_OK;
247 }
248
249 static gboolean
250 gst_caps_is_fixed_foreach (GQuark field_id, const GValue * value,
251     gpointer unused)
252 {
253   return gst_value_is_fixed (value);
254 }
255
256 static void
257 gst_caps_setter_set_property (GObject * object, guint prop_id,
258     const GValue * value, GParamSpec * pspec)
259 {
260   GstCapsSetter *filter = GST_CAPS_SETTER (object);
261
262   switch (prop_id) {
263     case PROP_CAPS:{
264       GstCaps *new_caps;
265       const GstCaps *new_caps_val = gst_value_get_caps (value);
266       gint i;
267
268       if (new_caps_val == NULL) {
269         new_caps = gst_caps_new_any ();
270       } else {
271         new_caps = gst_caps_copy (new_caps_val);
272       }
273
274       for (i = 0; new_caps && (i < gst_caps_get_size (new_caps)); ++i) {
275         GstStructure *s;
276
277         s = gst_caps_get_structure (new_caps, i);
278         if (!gst_structure_foreach (s, gst_caps_is_fixed_foreach, NULL)) {
279           GST_ERROR_OBJECT (filter, "rejected unfixed caps: %" GST_PTR_FORMAT,
280               new_caps);
281           gst_caps_unref (new_caps);
282           new_caps = NULL;
283           break;
284         }
285       }
286
287       if (new_caps) {
288         GST_OBJECT_LOCK (filter);
289         gst_caps_replace (&filter->caps, new_caps);
290         /* drop extra ref */
291         gst_caps_unref (new_caps);
292         GST_OBJECT_UNLOCK (filter);
293
294         GST_DEBUG_OBJECT (filter, "set new caps %" GST_PTR_FORMAT, new_caps);
295       }
296
297       /* try to activate these new caps next time around */
298       gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (filter));
299       break;
300     }
301     case PROP_JOIN:
302       filter->join = g_value_get_boolean (value);
303       break;
304     case PROP_REPLACE:
305       filter->replace = g_value_get_boolean (value);
306       break;
307     default:
308       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
309       break;
310   }
311 }
312
313 static void
314 gst_caps_setter_get_property (GObject * object, guint prop_id, GValue * value,
315     GParamSpec * pspec)
316 {
317   GstCapsSetter *filter = GST_CAPS_SETTER (object);
318
319   switch (prop_id) {
320     case PROP_CAPS:
321       gst_value_set_caps (value, filter->caps);
322       break;
323     case PROP_JOIN:
324       g_value_set_boolean (value, filter->join);
325       break;
326     case PROP_REPLACE:
327       g_value_set_boolean (value, filter->replace);
328       break;
329     default:
330       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
331       break;
332   }
333 }