2 * Copyright (C) 2006-2009 Mark Nauwelaerts <mnauw@users.sourceforge.net>
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.
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.
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.
21 * SECTION:element-capssetter
25 * Sets or merges caps on a stream's buffers.
26 * That is, a buffer's caps are updated using (fields of)
27 * <link linkend="GstCapsSetter--caps">caps</link>. Note that this may
28 * contain multiple structures (though not likely recommended), but each
29 * of these must be fixed (or will otherwise be rejected).
32 * If <link linkend="GstCapsSetter--join">join</link>
33 * is TRUE, then the incoming caps' mime-type is compared to the mime-type(s)
34 * of provided caps and only matching structure(s) are considered for updating.
37 * If <link linkend="GstCapsSetter--replace">replace</link>
38 * is TRUE, then any caps update is preceded by clearing existing fields,
39 * making provided fields (as a whole) replace incoming ones.
40 * Otherwise, no clearing is performed, in which case provided fields are
41 * added/merged onto incoming caps
44 * Although this element might mainly serve as debug helper,
45 * it can also practically be used to correct a faulty pixel-aspect-ratio,
46 * or to modify a yuv fourcc value to effectively swap chroma components or such
58 #include "gstcapssetter.h"
63 GST_DEBUG_CATEGORY_STATIC (caps_setter_debug);
64 #define GST_CAT_DEFAULT caps_setter_debug
67 /* signals and args */
83 #define DEFAULT_JOIN TRUE
84 #define DEFAULT_REPLACE FALSE
86 static GstElementDetails caps_setter_details =
87 GST_ELEMENT_DETAILS ("CapsSetter",
89 "Set/merge caps on stream",
90 "Mark Nauwelaerts <mnauw@users.sourceforge.net>");
92 static GstStaticPadTemplate gst_caps_setter_src_template =
93 GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SRC_NAME,
98 static GstStaticPadTemplate gst_caps_setter_sink_template =
99 GST_STATIC_PAD_TEMPLATE (GST_BASE_TRANSFORM_SINK_NAME,
102 GST_STATIC_CAPS_ANY);
105 static gboolean gst_caps_setter_transform_size (GstBaseTransform * trans,
106 GstPadDirection direction, GstCaps * caps, guint size,
107 GstCaps * othercaps, guint * othersize);
108 static GstCaps *gst_caps_setter_transform_caps (GstBaseTransform * trans,
109 GstPadDirection direction, GstCaps * caps);
110 static GstFlowReturn gst_caps_setter_transform_ip (GstBaseTransform * btrans,
113 static void gst_caps_setter_finalize (GObject * object);
115 static void gst_caps_setter_set_property (GObject * object, guint prop_id,
116 const GValue * value, GParamSpec * pspec);
117 static void gst_caps_setter_get_property (GObject * object, guint prop_id,
118 GValue * value, GParamSpec * pspec);
120 GST_BOILERPLATE (GstCapsSetter, gst_caps_setter, GstBaseTransform,
121 GST_TYPE_BASE_TRANSFORM);
124 gst_caps_setter_base_init (gpointer g_class)
126 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
128 gst_element_class_set_details (element_class, &caps_setter_details);
130 gst_element_class_add_pad_template (element_class,
131 gst_static_pad_template_get (&gst_caps_setter_sink_template));
132 gst_element_class_add_pad_template (element_class,
133 gst_static_pad_template_get (&gst_caps_setter_src_template));
137 gst_caps_setter_class_init (GstCapsSetterClass * g_class)
139 GObjectClass *gobject_class;
140 GstBaseTransformClass *trans_class;
142 gobject_class = G_OBJECT_CLASS (g_class);
143 trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
145 GST_DEBUG_CATEGORY_INIT (caps_setter_debug, "capssetter", 0, "capssetter");
147 gobject_class->set_property = gst_caps_setter_set_property;
148 gobject_class->get_property = gst_caps_setter_get_property;
150 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_caps_setter_finalize);
152 g_object_class_install_property (gobject_class, PROP_CAPS,
153 g_param_spec_boxed ("caps", "Merge caps",
154 "Merge these caps (thereby overwriting) in the stream",
155 GST_TYPE_CAPS, G_PARAM_READWRITE));
156 g_object_class_install_property (gobject_class, PROP_JOIN,
157 g_param_spec_boolean ("join", "Join",
158 "Match incoming caps' mime-type to mime-type of provided caps",
159 DEFAULT_JOIN, G_PARAM_READWRITE));
160 g_object_class_install_property (gobject_class, PROP_REPLACE,
161 g_param_spec_boolean ("replace", "Replace",
162 "Drop fields of incoming caps", DEFAULT_REPLACE, G_PARAM_READWRITE));
164 trans_class->transform_size =
165 GST_DEBUG_FUNCPTR (gst_caps_setter_transform_size);
166 trans_class->transform_caps =
167 GST_DEBUG_FUNCPTR (gst_caps_setter_transform_caps);
168 /* dummy seems needed */
169 trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_caps_setter_transform_ip);
173 gst_caps_setter_init (GstCapsSetter * filter, GstCapsSetterClass * g_class)
175 filter->caps = gst_caps_new_any ();
176 filter->join = DEFAULT_JOIN;
177 filter->replace = DEFAULT_REPLACE;
181 gst_caps_setter_finalize (GObject * object)
183 GstCapsSetter *filter = GST_CAPS_SETTER (object);
185 gst_caps_replace (&filter->caps, NULL);
187 G_OBJECT_CLASS (parent_class)->finalize (object);
191 gst_caps_setter_transform_size (GstBaseTransform * trans,
192 GstPadDirection direction, GstCaps * caps, guint size,
193 GstCaps * othercaps, guint * othersize)
201 gst_caps_setter_transform_caps (GstBaseTransform * trans,
202 GstPadDirection direction, GstCaps * caps)
204 GstCapsSetter *filter;
205 GstCaps *ret, *filter_caps;
206 GstStructure *structure, *merge;
210 filter = GST_CAPS_SETTER (trans);
212 GST_DEBUG_OBJECT (trans, "receiving caps: %" GST_PTR_FORMAT, caps);
214 ret = gst_caps_copy (caps);
216 /* this function is always called with a simple caps */
217 if (!GST_CAPS_IS_SIMPLE (ret) || direction != GST_PAD_SINK)
220 structure = gst_caps_get_structure (ret, 0);
221 name = gst_structure_get_name (structure);
223 GST_OBJECT_LOCK (filter);
224 filter_caps = gst_caps_ref (filter->caps);
225 GST_OBJECT_UNLOCK (filter);
227 for (i = 0; i < gst_caps_get_size (filter_caps); ++i) {
228 merge = gst_caps_get_structure (filter_caps, i);
229 if (gst_structure_has_name (merge, name) || !filter->join) {
232 gst_structure_set_name (structure, gst_structure_get_name (merge));
235 gst_structure_remove_all_fields (structure);
237 for (j = 0; j < gst_structure_n_fields (merge); ++j) {
240 fname = gst_structure_nth_field_name (merge, j);
241 gst_structure_set_value (structure, fname,
242 gst_structure_get_value (merge, fname));
247 GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
249 gst_caps_unref (filter_caps);
255 gst_caps_setter_transform_ip (GstBaseTransform * btrans, GstBuffer * in)
261 gst_caps_is_fixed_foreach (GQuark field_id, const GValue * value,
264 return gst_value_is_fixed (value);
268 gst_caps_setter_set_property (GObject * object, guint prop_id,
269 const GValue * value, GParamSpec * pspec)
271 GstCapsSetter *filter;
273 g_return_if_fail (GST_IS_CAPS_SETTER (object));
274 filter = GST_CAPS_SETTER (object);
279 const GstCaps *new_caps_val = gst_value_get_caps (value);
282 if (new_caps_val == NULL) {
283 new_caps = gst_caps_new_any ();
285 new_caps = gst_caps_copy (new_caps_val);
288 for (i = 0; new_caps && (i < gst_caps_get_size (new_caps)); ++i) {
291 s = gst_caps_get_structure (new_caps, i);
292 if (!gst_structure_foreach (s, gst_caps_is_fixed_foreach, NULL)) {
293 GST_ERROR_OBJECT (filter, "rejected unfixed caps: %" GST_PTR_FORMAT,
295 gst_caps_unref (new_caps);
302 GST_OBJECT_LOCK (filter);
303 gst_caps_replace (&filter->caps, new_caps);
305 gst_caps_unref (new_caps);
306 GST_OBJECT_UNLOCK (filter);
308 GST_DEBUG_OBJECT (filter, "set new caps %" GST_PTR_FORMAT, new_caps);
311 /* try to activate these new caps next time around */
312 gst_base_transform_reconfigure (GST_BASE_TRANSFORM (filter));
316 filter->join = g_value_get_boolean (value);
319 filter->replace = g_value_get_boolean (value);
322 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328 gst_caps_setter_get_property (GObject * object, guint prop_id, GValue * value,
331 GstCapsSetter *filter;
333 g_return_if_fail (GST_IS_CAPS_SETTER (object));
334 filter = GST_CAPS_SETTER (object);
338 gst_value_set_caps (value, filter->caps);
341 g_value_set_boolean (value, filter->join);
344 g_value_set_boolean (value, filter->replace);
347 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);