capsfilter: Remove transform_size
[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
78 static void
79 gst_capsfilter_base_init (gpointer g_class)
80 {
81   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
82
83   gst_element_class_set_details_simple (gstelement_class,
84       "CapsFilter",
85       "Generic",
86       "Pass data without modification, limiting formats",
87       "David Schleef <ds@schleef.org>");
88   gst_element_class_add_pad_template (gstelement_class,
89       gst_static_pad_template_get (&srctemplate));
90   gst_element_class_add_pad_template (gstelement_class,
91       gst_static_pad_template_get (&sinktemplate));
92 }
93
94 static void
95 gst_capsfilter_class_init (GstCapsFilterClass * klass)
96 {
97   GObjectClass *gobject_class;
98   GstBaseTransformClass *trans_class;
99
100   gobject_class = G_OBJECT_CLASS (klass);
101   gobject_class->set_property = gst_capsfilter_set_property;
102   gobject_class->get_property = gst_capsfilter_get_property;
103   gobject_class->dispose = gst_capsfilter_dispose;
104
105   g_object_class_install_property (gobject_class, PROP_FILTER_CAPS,
106       g_param_spec_boxed ("caps", _("Filter caps"),
107           _("Restrict the possible allowed capabilities (NULL means ANY). "
108               "Setting this property takes a reference to the supplied GstCaps "
109               "object."), GST_TYPE_CAPS,
110           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
111
112   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
113   trans_class->transform_caps =
114       GST_DEBUG_FUNCPTR (gst_capsfilter_transform_caps);
115   trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_capsfilter_transform_ip);
116   trans_class->prepare_output_buffer =
117       GST_DEBUG_FUNCPTR (gst_capsfilter_prepare_buf);
118 }
119
120 static void
121 gst_capsfilter_init (GstCapsFilter * filter, GstCapsFilterClass * g_class)
122 {
123   GstBaseTransform *trans = GST_BASE_TRANSFORM (filter);
124   gst_base_transform_set_gap_aware (trans, TRUE);
125   filter->filter_caps = gst_caps_new_any ();
126 }
127
128 static gboolean
129 copy_func (GQuark field_id, const GValue * value, GstStructure * dest)
130 {
131   gst_structure_id_set_value (dest, field_id, value);
132
133   return TRUE;
134 }
135
136 static void
137 gst_capsfilter_set_property (GObject * object, guint prop_id,
138     const GValue * value, GParamSpec * pspec)
139 {
140   GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
141
142   switch (prop_id) {
143     case PROP_FILTER_CAPS:{
144       GstCaps *new_caps;
145       GstCaps *old_caps, *suggest, *nego;
146       const GstCaps *new_caps_val = gst_value_get_caps (value);
147
148       if (new_caps_val == NULL) {
149         new_caps = gst_caps_new_any ();
150       } else {
151         new_caps = (GstCaps *) new_caps_val;
152         gst_caps_ref (new_caps);
153       }
154
155       GST_OBJECT_LOCK (capsfilter);
156       old_caps = capsfilter->filter_caps;
157       capsfilter->filter_caps = new_caps;
158       GST_OBJECT_UNLOCK (capsfilter);
159
160       gst_caps_unref (old_caps);
161
162       GST_DEBUG_OBJECT (capsfilter, "set new caps %" GST_PTR_FORMAT, new_caps);
163
164       /* filter the currently negotiated format against the new caps */
165       GST_OBJECT_LOCK (GST_BASE_TRANSFORM_SINK_PAD (object));
166       nego = GST_PAD_CAPS (GST_BASE_TRANSFORM_SINK_PAD (object));
167       if (nego) {
168         GST_DEBUG_OBJECT (capsfilter, "we had negotiated caps %" GST_PTR_FORMAT,
169             nego);
170
171         if (G_UNLIKELY (gst_caps_is_any (new_caps))) {
172           GST_DEBUG_OBJECT (capsfilter, "not settings any suggestion");
173
174           suggest = NULL;
175         } else {
176           GstStructure *s1, *s2;
177
178           /* first check if the name is the same */
179           s1 = gst_caps_get_structure (nego, 0);
180           s2 = gst_caps_get_structure (new_caps, 0);
181
182           if (gst_structure_get_name_id (s1) == gst_structure_get_name_id (s2)) {
183             /* same name, copy all fields from the new caps into the previously
184              * negotiated caps */
185             suggest = gst_caps_copy (nego);
186             s1 = gst_caps_get_structure (suggest, 0);
187             gst_structure_foreach (s2, (GstStructureForeachFunc) copy_func, s1);
188             GST_DEBUG_OBJECT (capsfilter, "copied structure fields");
189           } else {
190             GST_DEBUG_OBJECT (capsfilter, "different structure names");
191             /* different names, we can only suggest the complete caps */
192             suggest = gst_caps_copy (new_caps);
193           }
194         }
195       } else {
196         GST_DEBUG_OBJECT (capsfilter, "no negotiated caps");
197         /* no previous caps, the getcaps function will be used to find suitable
198          * caps */
199         suggest = NULL;
200       }
201       GST_OBJECT_UNLOCK (GST_BASE_TRANSFORM_SINK_PAD (object));
202
203       GST_DEBUG_OBJECT (capsfilter, "suggesting new caps %" GST_PTR_FORMAT,
204           suggest);
205       gst_base_transform_suggest (GST_BASE_TRANSFORM (object), suggest, 0);
206       if (suggest)
207         gst_caps_unref (suggest);
208
209       break;
210     }
211     default:
212       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213       break;
214   }
215 }
216
217 static void
218 gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
219     GParamSpec * pspec)
220 {
221   GstCapsFilter *capsfilter = GST_CAPSFILTER (object);
222
223   switch (prop_id) {
224     case PROP_FILTER_CAPS:
225       GST_OBJECT_LOCK (capsfilter);
226       gst_value_set_caps (value, capsfilter->filter_caps);
227       GST_OBJECT_UNLOCK (capsfilter);
228       break;
229     default:
230       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231       break;
232   }
233 }
234
235 static void
236 gst_capsfilter_dispose (GObject * object)
237 {
238   GstCapsFilter *filter = GST_CAPSFILTER (object);
239
240   gst_caps_replace (&filter->filter_caps, NULL);
241
242   G_OBJECT_CLASS (parent_class)->dispose (object);
243 }
244
245 static GstCaps *
246 gst_capsfilter_transform_caps (GstBaseTransform * base,
247     GstPadDirection direction, GstCaps * caps)
248 {
249   GstCapsFilter *capsfilter = GST_CAPSFILTER (base);
250   GstCaps *ret, *filter_caps;
251
252   GST_OBJECT_LOCK (capsfilter);
253   filter_caps = gst_caps_ref (capsfilter->filter_caps);
254   GST_OBJECT_UNLOCK (capsfilter);
255
256   ret = gst_caps_intersect (caps, filter_caps);
257   GST_DEBUG_OBJECT (capsfilter, "input:     %" GST_PTR_FORMAT, caps);
258   GST_DEBUG_OBJECT (capsfilter, "filter:    %" GST_PTR_FORMAT, filter_caps);
259   GST_DEBUG_OBJECT (capsfilter, "intersect: %" GST_PTR_FORMAT, ret);
260
261   gst_caps_unref (filter_caps);
262
263   return ret;
264 }
265
266 static GstFlowReturn
267 gst_capsfilter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
268 {
269   /* No actual work here. It's all done in the prepare output buffer
270    * func. */
271   return GST_FLOW_OK;
272 }
273
274 /* Output buffer preparation... if the buffer has no caps, and
275  * our allowed output caps is fixed, then give the caps to the
276  * buffer.
277  * This ensures that outgoing buffers have caps if we can, so
278  * that pipelines like:
279  *   gst-launch filesrc location=rawsamples.raw !
280  *       audio/x-raw-int,width=16,depth=16,rate=48000,channels=2,
281  *       endianness=4321,signed='(boolean)'true ! alsasink
282  * will work.
283  */
284 static GstFlowReturn
285 gst_capsfilter_prepare_buf (GstBaseTransform * trans, GstBuffer * input,
286     gint size, GstCaps * caps, GstBuffer ** buf)
287 {
288   GstFlowReturn ret = GST_FLOW_OK;
289
290   if (GST_BUFFER_CAPS (input) != NULL) {
291     /* Output buffer already has caps */
292     GST_LOG_OBJECT (trans, "Input buffer already has caps (implicitely fixed)");
293     /* FIXME : Move this behaviour to basetransform. The given caps are the ones
294      * of the source pad, therefore our outgoing buffers should always have
295      * those caps. */
296     if (GST_BUFFER_CAPS (input) != caps) {
297       /* caps are different, make a metadata writable output buffer to set
298        * caps */
299       if (gst_buffer_is_metadata_writable (input)) {
300         /* input is writable, just set caps and use this as the output */
301         *buf = input;
302         gst_buffer_set_caps (*buf, caps);
303         gst_buffer_ref (input);
304       } else {
305         GST_DEBUG_OBJECT (trans, "Creating sub-buffer and setting caps");
306         *buf = gst_buffer_create_sub (input, 0, GST_BUFFER_SIZE (input));
307         gst_buffer_set_caps (*buf, caps);
308       }
309     } else {
310       /* caps are right, just use a ref of the input as the outbuf */
311       *buf = input;
312       gst_buffer_ref (input);
313     }
314   } else {
315     /* Buffer has no caps. See if the output pad only supports fixed caps */
316     GstCaps *out_caps;
317
318     out_caps = GST_PAD_CAPS (trans->srcpad);
319
320     if (out_caps != NULL) {
321       gst_caps_ref (out_caps);
322     } else {
323       out_caps = gst_pad_get_allowed_caps (trans->srcpad);
324       g_return_val_if_fail (out_caps != NULL, GST_FLOW_ERROR);
325     }
326
327     out_caps = gst_caps_make_writable (out_caps);
328     gst_caps_do_simplify (out_caps);
329
330     if (gst_caps_is_fixed (out_caps) && !gst_caps_is_empty (out_caps)) {
331       GST_DEBUG_OBJECT (trans, "Have fixed output caps %"
332           GST_PTR_FORMAT " to apply to buffer with no caps", out_caps);
333       if (gst_buffer_is_metadata_writable (input)) {
334         gst_buffer_ref (input);
335         *buf = input;
336       } else {
337         GST_DEBUG_OBJECT (trans, "Creating sub-buffer and setting caps");
338         *buf = gst_buffer_create_sub (input, 0, GST_BUFFER_SIZE (input));
339       }
340       GST_BUFFER_CAPS (*buf) = out_caps;
341
342       if (GST_PAD_CAPS (trans->srcpad) == NULL)
343         gst_pad_set_caps (trans->srcpad, out_caps);
344     } else {
345       gchar *caps_str = gst_caps_to_string (out_caps);
346
347       GST_DEBUG_OBJECT (trans, "Cannot choose caps. Have unfixed output caps %"
348           GST_PTR_FORMAT, out_caps);
349       gst_caps_unref (out_caps);
350
351       ret = GST_FLOW_ERROR;
352       GST_ELEMENT_ERROR (trans, STREAM, FORMAT,
353           ("Filter caps do not completely specify the output format"),
354           ("Output caps are unfixed: %s", caps_str));
355       g_free (caps_str);
356     }
357   }
358
359   return ret;
360 }