d5a109e97ca30a9cd5852210f4fe5760cf17b4c9
[platform/upstream/gstreamer.git] / plugins / elements / gstcapsfilter.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Wim Taymans <wim@fluendo.com>
5  *                    2005 David Schleef <ds@schleef.org>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 /**
23  * SECTION:element-capsfilter
24  *
25  * The element does not modify data as such, but can enforce limitations on the
26  * data format.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "../../gst/gst-i18n-lib.h"
34 #include "gstcapsfilter.h"
35
36 enum
37 {
38   PROP_0,
39   PROP_FILTER_CAPS
40 };
41
42
43 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
44     GST_PAD_SINK,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS_ANY);
47
48 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
49     GST_PAD_SRC,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS_ANY);
52
53
54 GST_DEBUG_CATEGORY_STATIC (gst_capsfilter_debug);
55 #define GST_CAT_DEFAULT gst_capsfilter_debug
56
57 #define _do_init(bla) \
58     GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, \
59     "capsfilter element");
60
61 GST_BOILERPLATE_FULL (GstCapsFilter, gst_capsfilter, GstBaseTransform,
62     GST_TYPE_BASE_TRANSFORM, _do_init);
63
64
65 static void gst_capsfilter_set_property (GObject * object, guint prop_id,
66     const GValue * value, GParamSpec * pspec);
67 static void gst_capsfilter_get_property (GObject * object, guint prop_id,
68     GValue * value, GParamSpec * pspec);
69 static void gst_capsfilter_dispose (GObject * object);
70
71 static GstCaps *gst_capsfilter_transform_caps (GstBaseTransform * base,
72     GstPadDirection direction, GstCaps * caps);
73 static GstFlowReturn gst_capsfilter_transform_ip (GstBaseTransform * base,
74     GstBuffer * buf);
75 static GstFlowReturn gst_capsfilter_prepare_buf (GstBaseTransform * trans,
76     GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
77 static gboolean gst_capsfilter_transform_size (GstBaseTransform * trans,
78     GstPadDirection direction, GstCaps * caps, guint size,
79     GstCaps * othercaps, guint * othersize);
80
81 static void
82 gst_capsfilter_base_init (gpointer g_class)
83 {
84   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
85
86   gst_element_class_set_details_simple (gstelement_class,
87       "CapsFilter",
88       "Generic",
89       "Pass data without modification, limiting formats",
90       "David Schleef <ds@schleef.org>");
91   gst_element_class_add_pad_template (gstelement_class,
92       gst_static_pad_template_get (&srctemplate));
93   gst_element_class_add_pad_template (gstelement_class,
94       gst_static_pad_template_get (&sinktemplate));
95 }
96
97 static void
98 gst_capsfilter_class_init (GstCapsFilterClass * klass)
99 {
100   GObjectClass *gobject_class;
101   GstBaseTransformClass *trans_class;
102
103   gobject_class = G_OBJECT_CLASS (klass);
104   gobject_class->set_property = gst_capsfilter_set_property;
105   gobject_class->get_property = gst_capsfilter_get_property;
106   gobject_class->dispose = gst_capsfilter_dispose;
107
108   g_object_class_install_property (gobject_class, PROP_FILTER_CAPS,
109       g_param_spec_boxed ("caps", _("Filter caps"),
110           _("Restrict the possible allowed capabilities (NULL means ANY). "
111               "Setting this property takes a reference to the supplied GstCaps "
112               "object."), GST_TYPE_CAPS,
113           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114
115   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
116   trans_class->transform_caps =
117       GST_DEBUG_FUNCPTR (gst_capsfilter_transform_caps);
118   trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_capsfilter_transform_ip);
119   trans_class->prepare_output_buffer =
120       GST_DEBUG_FUNCPTR (gst_capsfilter_prepare_buf);
121   trans_class->transform_size =
122       GST_DEBUG_FUNCPTR (gst_capsfilter_transform_size);
123 }
124
125 static void
126 gst_capsfilter_init (GstCapsFilter * filter, GstCapsFilterClass * g_class)
127 {
128   GstBaseTransform *trans = GST_BASE_TRANSFORM (filter);
129   gst_base_transform_set_gap_aware (trans, TRUE);
130   filter->filter_caps = gst_caps_new_any ();
131 }
132
133 static gboolean
134 copy_func (GQuark field_id, const GValue * value, GstStructure * dest)
135 {
136   gst_structure_id_set_value (dest, field_id, value);
137
138   return TRUE;
139 }
140
141 static void
142 gst_capsfilter_set_property (GObject * object, guint prop_id,
143     const GValue * value, GParamSpec * pspec)
144 {
145   GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
146
147   switch (prop_id) {
148     case PROP_FILTER_CAPS:{
149       GstCaps *new_caps;
150       GstCaps *old_caps, *suggest, *nego;
151       const GstCaps *new_caps_val = gst_value_get_caps (value);
152
153       if (new_caps_val == NULL) {
154         new_caps = gst_caps_new_any ();
155       } else {
156         new_caps = (GstCaps *) new_caps_val;
157         gst_caps_ref (new_caps);
158       }
159
160       GST_OBJECT_LOCK (capsfilter);
161       old_caps = capsfilter->filter_caps;
162       capsfilter->filter_caps = new_caps;
163       GST_OBJECT_UNLOCK (capsfilter);
164
165       gst_caps_unref (old_caps);
166
167       GST_DEBUG_OBJECT (capsfilter, "set new caps %" GST_PTR_FORMAT, new_caps);
168
169       /* filter the currently negotiated format against the new caps */
170       GST_OBJECT_LOCK (GST_BASE_TRANSFORM_SINK_PAD (object));
171       nego = GST_PAD_CAPS (GST_BASE_TRANSFORM_SINK_PAD (object));
172       if (nego) {
173         GST_DEBUG_OBJECT (capsfilter, "we had negotiated caps %" GST_PTR_FORMAT,
174             nego);
175
176         if (G_UNLIKELY (gst_caps_is_any (new_caps))) {
177           GST_DEBUG_OBJECT (capsfilter, "not settings any suggestion");
178
179           suggest = NULL;
180         } else {
181           GstStructure *s1, *s2;
182
183           /* first check if the name is the same */
184           s1 = gst_caps_get_structure (nego, 0);
185           s2 = gst_caps_get_structure (new_caps, 0);
186
187           if (gst_structure_get_name_id (s1) == gst_structure_get_name_id (s2)) {
188             /* same name, copy all fields from the new caps into the previously
189              * negotiated caps */
190             suggest = gst_caps_copy (nego);
191             s1 = gst_caps_get_structure (suggest, 0);
192             gst_structure_foreach (s2, (GstStructureForeachFunc) copy_func, s1);
193             GST_DEBUG_OBJECT (capsfilter, "copied structure fields");
194           } else {
195             GST_DEBUG_OBJECT (capsfilter, "different structure names");
196             /* different names, we can only suggest the complete caps */
197             suggest = gst_caps_copy (new_caps);
198           }
199         }
200       } else {
201         GST_DEBUG_OBJECT (capsfilter, "no negotiated caps");
202         /* no previous caps, the getcaps function will be used to find suitable
203          * caps */
204         suggest = NULL;
205       }
206       GST_OBJECT_UNLOCK (GST_BASE_TRANSFORM_SINK_PAD (object));
207
208       GST_DEBUG_OBJECT (capsfilter, "suggesting new caps %" GST_PTR_FORMAT,
209           suggest);
210       gst_base_transform_suggest (GST_BASE_TRANSFORM (object), suggest, 0);
211       if (suggest)
212         gst_caps_unref (suggest);
213
214       break;
215     }
216     default:
217       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
218       break;
219   }
220 }
221
222 static void
223 gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
224     GParamSpec * pspec)
225 {
226   GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
227
228   switch (prop_id) {
229     case PROP_FILTER_CAPS:
230       GST_OBJECT_LOCK (capsfilter);
231       gst_value_set_caps (value, capsfilter->filter_caps);
232       GST_OBJECT_UNLOCK (capsfilter);
233       break;
234     default:
235       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236       break;
237   }
238 }
239
240 static void
241 gst_capsfilter_dispose (GObject * object)
242 {
243   GstCapsFilter *filter = GST_CAPSFILTER (object);
244
245   gst_caps_replace (&filter->filter_caps, NULL);
246
247   G_OBJECT_CLASS (parent_class)->dispose (object);
248 }
249
250 static GstCaps *
251 gst_capsfilter_transform_caps (GstBaseTransform * base,
252     GstPadDirection direction, GstCaps * caps)
253 {
254   GstCapsFilter *capsfilter = GST_CAPSFILTER (base);
255   GstCaps *ret, *filter_caps;
256
257   GST_OBJECT_LOCK (capsfilter);
258   filter_caps = gst_caps_ref (capsfilter->filter_caps);
259   GST_OBJECT_UNLOCK (capsfilter);
260
261   ret = gst_caps_intersect (caps, filter_caps);
262   GST_DEBUG_OBJECT (capsfilter, "input:     %" GST_PTR_FORMAT, caps);
263   GST_DEBUG_OBJECT (capsfilter, "filter:    %" GST_PTR_FORMAT, filter_caps);
264   GST_DEBUG_OBJECT (capsfilter, "intersect: %" GST_PTR_FORMAT, ret);
265
266   gst_caps_unref (filter_caps);
267
268   return ret;
269 }
270
271 static gboolean
272 gst_capsfilter_transform_size (GstBaseTransform * trans,
273     GstPadDirection direction, GstCaps * caps, guint size,
274     GstCaps * othercaps, guint * othersize)
275 {
276   /* return the same size */
277   *othersize = size;
278   return TRUE;
279 }
280
281
282 static GstFlowReturn
283 gst_capsfilter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
284 {
285   /* No actual work here. It's all done in the prepare output buffer
286    * func. */
287   return GST_FLOW_OK;
288 }
289
290 /* Output buffer preparation... if the buffer has no caps, and
291  * our allowed output caps is fixed, then give the caps to the
292  * buffer.
293  * This ensures that outgoing buffers have caps if we can, so
294  * that pipelines like:
295  *   gst-launch filesrc location=rawsamples.raw !
296  *       audio/x-raw-int,width=16,depth=16,rate=48000,channels=2,
297  *       endianness=4321,signed='(boolean)'true ! alsasink
298  * will work.
299  */
300 static GstFlowReturn
301 gst_capsfilter_prepare_buf (GstBaseTransform * trans, GstBuffer * input,
302     gint size, GstCaps * caps, GstBuffer ** buf)
303 {
304   GstFlowReturn ret = GST_FLOW_OK;
305
306   if (GST_BUFFER_CAPS (input) != NULL) {
307     /* Output buffer already has caps */
308     GST_LOG_OBJECT (trans, "Input buffer already has caps (implicitely fixed)");
309     /* FIXME : Move this behaviour to basetransform. The given caps are the ones
310      * of the source pad, therefore our outgoing buffers should always have
311      * those caps. */
312     if (GST_BUFFER_CAPS (input) != caps) {
313       /* caps are different, make a metadata writable output buffer to set
314        * caps */
315       if (gst_buffer_is_metadata_writable (input)) {
316         /* input is writable, just set caps and use this as the output */
317         *buf = input;
318         gst_buffer_set_caps (*buf, caps);
319         gst_buffer_ref (input);
320       } else {
321         GST_DEBUG_OBJECT (trans, "Creating sub-buffer and setting caps");
322         *buf = gst_buffer_create_sub (input, 0, GST_BUFFER_SIZE (input));
323         gst_buffer_set_caps (*buf, caps);
324       }
325     } else {
326       /* caps are right, just use a ref of the input as the outbuf */
327       *buf = input;
328       gst_buffer_ref (input);
329     }
330   } else {
331     /* Buffer has no caps. See if the output pad only supports fixed caps */
332     GstCaps *out_caps;
333
334     out_caps = GST_PAD_CAPS (trans->srcpad);
335
336     if (out_caps != NULL) {
337       gst_caps_ref (out_caps);
338     } else {
339       out_caps = gst_pad_get_allowed_caps (trans->srcpad);
340       g_return_val_if_fail (out_caps != NULL, GST_FLOW_ERROR);
341     }
342
343     out_caps = gst_caps_make_writable (out_caps);
344     gst_caps_do_simplify (out_caps);
345
346     if (gst_caps_is_fixed (out_caps) && !gst_caps_is_empty (out_caps)) {
347       GST_DEBUG_OBJECT (trans, "Have fixed output caps %"
348           GST_PTR_FORMAT " to apply to buffer with no caps", out_caps);
349       if (gst_buffer_is_metadata_writable (input)) {
350         gst_buffer_ref (input);
351         *buf = input;
352       } else {
353         GST_DEBUG_OBJECT (trans, "Creating sub-buffer and setting caps");
354         *buf = gst_buffer_create_sub (input, 0, GST_BUFFER_SIZE (input));
355       }
356       GST_BUFFER_CAPS (*buf) = out_caps;
357
358       if (GST_PAD_CAPS (trans->srcpad) == NULL)
359         gst_pad_set_caps (trans->srcpad, out_caps);
360     } else {
361       gchar *caps_str = gst_caps_to_string (out_caps);
362
363       GST_DEBUG_OBJECT (trans, "Cannot choose caps. Have unfixed output caps %"
364           GST_PTR_FORMAT, out_caps);
365       gst_caps_unref (out_caps);
366
367       ret = GST_FLOW_ERROR;
368       GST_ELEMENT_ERROR (trans, STREAM, FORMAT,
369           ("Filter caps do not completely specify the output format"),
370           ("Output caps are unfixed: %s", caps_str));
371       g_free (caps_str);
372     }
373   }
374
375   return ret;
376 }