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