• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 /**
23  * SECTION:element-capsfilter
24  * @title: capsfilter
25  * @short_description: enforce limitations on the data format
26  *
27  * The element does not modify data as such, but can enforce limitations on the data format.
28  *
29  * ## Example launch line
30  * |[
31  * gst-launch-1.0 videotestsrc ! capsfilter caps=video/x-raw,format=GRAY8 ! videoconvert ! autovideosink
32  * ]| Limits acceptable video from videotestsrc to be grayscale. Equivalent to
33  * |[
34  * gst-launch-1.0 videotestsrc ! video/x-raw,format=GRAY8 ! videoconvert ! autovideosink
35  * ]| which is a short notation for the capsfilter element.
36  *
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #include "../../gst/gst-i18n-lib.h"
44 #include "gstcapsfilter.h"
45 #include "gstcoreelementselements.h"
46 
47 enum
48 {
49   PROP_0,
50   PROP_FILTER_CAPS,
51   PROP_CAPS_CHANGE_MODE
52 };
53 
54 #define DEFAULT_CAPS_CHANGE_MODE (GST_CAPS_FILTER_CAPS_CHANGE_MODE_IMMEDIATE)
55 
56 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
57     GST_PAD_SINK,
58     GST_PAD_ALWAYS,
59     GST_STATIC_CAPS_ANY);
60 
61 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
62     GST_PAD_SRC,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS_ANY);
65 
66 
67 GST_DEBUG_CATEGORY_STATIC (gst_capsfilter_debug);
68 #define GST_CAT_DEFAULT gst_capsfilter_debug
69 
70 /* TODO: Add a drop-buffers mode */
71 #define GST_TYPE_CAPS_FILTER_CAPS_CHANGE_MODE (gst_caps_filter_caps_change_mode_get_type())
72 static GType
gst_caps_filter_caps_change_mode_get_type(void)73 gst_caps_filter_caps_change_mode_get_type (void)
74 {
75   static GType type = 0;
76   static const GEnumValue data[] = {
77     {GST_CAPS_FILTER_CAPS_CHANGE_MODE_IMMEDIATE,
78         "Only accept the current filter caps", "immediate"},
79     {GST_CAPS_FILTER_CAPS_CHANGE_MODE_DELAYED,
80         "Temporarily accept previous filter caps", "delayed"},
81     {0, NULL, NULL},
82   };
83 
84   if (!type) {
85     type = g_enum_register_static ("GstCapsFilterCapsChangeMode", data);
86   }
87   return type;
88 }
89 
90 #define _do_init \
91     GST_DEBUG_CATEGORY_INIT (gst_capsfilter_debug, "capsfilter", 0, \
92     "capsfilter element");
93 #define gst_capsfilter_parent_class parent_class
94 G_DEFINE_TYPE_WITH_CODE (GstCapsFilter, gst_capsfilter, GST_TYPE_BASE_TRANSFORM,
95     _do_init);
96 
97 GST_ELEMENT_REGISTER_DEFINE (capsfilter, "capsfilter", GST_RANK_NONE,
98     GST_TYPE_CAPS_FILTER);
99 
100 static void gst_capsfilter_set_property (GObject * object, guint prop_id,
101     const GValue * value, GParamSpec * pspec);
102 static void gst_capsfilter_get_property (GObject * object, guint prop_id,
103     GValue * value, GParamSpec * pspec);
104 static void gst_capsfilter_dispose (GObject * object);
105 
106 static GstCaps *gst_capsfilter_transform_caps (GstBaseTransform * base,
107     GstPadDirection direction, GstCaps * caps, GstCaps * filter);
108 static gboolean gst_capsfilter_accept_caps (GstBaseTransform * base,
109     GstPadDirection direction, GstCaps * caps);
110 static GstFlowReturn gst_capsfilter_transform_ip (GstBaseTransform * base,
111     GstBuffer * buf);
112 static GstFlowReturn gst_capsfilter_prepare_buf (GstBaseTransform * trans,
113     GstBuffer * input, GstBuffer ** buf);
114 static gboolean gst_capsfilter_sink_event (GstBaseTransform * trans,
115     GstEvent * event);
116 static gboolean gst_capsfilter_stop (GstBaseTransform * trans);
117 
118 static void
gst_capsfilter_class_init(GstCapsFilterClass * klass)119 gst_capsfilter_class_init (GstCapsFilterClass * klass)
120 {
121   GObjectClass *gobject_class;
122   GstElementClass *gstelement_class;
123   GstBaseTransformClass *trans_class;
124 
125   gobject_class = G_OBJECT_CLASS (klass);
126   gobject_class->set_property = gst_capsfilter_set_property;
127   gobject_class->get_property = gst_capsfilter_get_property;
128   gobject_class->dispose = gst_capsfilter_dispose;
129 
130   g_object_class_install_property (gobject_class, PROP_FILTER_CAPS,
131       g_param_spec_boxed ("caps", _("Filter caps"),
132           _("Restrict the possible allowed capabilities (NULL means ANY). "
133               "Setting this property takes a reference to the supplied GstCaps "
134               "object."), GST_TYPE_CAPS,
135           G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
136           G_PARAM_STATIC_STRINGS));
137 
138   g_object_class_install_property (gobject_class, PROP_CAPS_CHANGE_MODE,
139       g_param_spec_enum ("caps-change-mode", _("Caps Change Mode"),
140           _("Filter caps change behaviour"),
141           GST_TYPE_CAPS_FILTER_CAPS_CHANGE_MODE, DEFAULT_CAPS_CHANGE_MODE,
142           G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
143           G_PARAM_STATIC_STRINGS));
144 
145   gstelement_class = GST_ELEMENT_CLASS (klass);
146   gst_element_class_set_static_metadata (gstelement_class,
147       "CapsFilter",
148       "Generic",
149       "Pass data without modification, limiting formats",
150       "David Schleef <ds@schleef.org>");
151   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
152   gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
153 
154   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
155   trans_class->transform_caps =
156       GST_DEBUG_FUNCPTR (gst_capsfilter_transform_caps);
157   trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_capsfilter_transform_ip);
158   trans_class->accept_caps = GST_DEBUG_FUNCPTR (gst_capsfilter_accept_caps);
159   trans_class->prepare_output_buffer =
160       GST_DEBUG_FUNCPTR (gst_capsfilter_prepare_buf);
161   trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_capsfilter_sink_event);
162   trans_class->stop = GST_DEBUG_FUNCPTR (gst_capsfilter_stop);
163 
164   gst_type_mark_as_plugin_api (GST_TYPE_CAPS_FILTER_CAPS_CHANGE_MODE, 0);
165 }
166 
167 static void
gst_capsfilter_init(GstCapsFilter * filter)168 gst_capsfilter_init (GstCapsFilter * filter)
169 {
170   GstBaseTransform *trans = GST_BASE_TRANSFORM (filter);
171   gst_base_transform_set_gap_aware (trans, TRUE);
172   gst_base_transform_set_prefer_passthrough (trans, FALSE);
173   filter->filter_caps = gst_caps_new_any ();
174   filter->filter_caps_used = FALSE;
175   filter->got_sink_caps = FALSE;
176   filter->caps_change_mode = DEFAULT_CAPS_CHANGE_MODE;
177 }
178 
179 static void
gst_capsfilter_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)180 gst_capsfilter_set_property (GObject * object, guint prop_id,
181     const GValue * value, GParamSpec * pspec)
182 {
183   GstCapsFilter *capsfilter = GST_CAPS_FILTER (object);
184 
185   switch (prop_id) {
186     case PROP_FILTER_CAPS:{
187       GstCaps *new_caps;
188       GstCaps *old_caps;
189       const GstCaps *new_caps_val = gst_value_get_caps (value);
190 
191       if (new_caps_val == NULL) {
192         new_caps = gst_caps_new_any ();
193       } else {
194         new_caps = (GstCaps *) new_caps_val;
195         gst_caps_ref (new_caps);
196       }
197 
198       GST_OBJECT_LOCK (capsfilter);
199       old_caps = capsfilter->filter_caps;
200       capsfilter->filter_caps = new_caps;
201       if (old_caps && capsfilter->filter_caps_used &&
202           capsfilter->caps_change_mode ==
203           GST_CAPS_FILTER_CAPS_CHANGE_MODE_DELAYED) {
204         capsfilter->previous_caps =
205             g_list_prepend (capsfilter->previous_caps, gst_caps_ref (old_caps));
206       } else if (capsfilter->caps_change_mode !=
207           GST_CAPS_FILTER_CAPS_CHANGE_MODE_DELAYED) {
208         g_list_free_full (capsfilter->previous_caps,
209             (GDestroyNotify) gst_caps_unref);
210         capsfilter->previous_caps = NULL;
211       }
212       capsfilter->filter_caps_used = FALSE;
213       GST_OBJECT_UNLOCK (capsfilter);
214 
215       gst_caps_unref (old_caps);
216 
217       GST_DEBUG_OBJECT (capsfilter, "set new caps %" GST_PTR_FORMAT, new_caps);
218 
219       gst_base_transform_reconfigure_sink (GST_BASE_TRANSFORM (object));
220       break;
221     }
222     case PROP_CAPS_CHANGE_MODE:{
223       GstCapsFilterCapsChangeMode old_change_mode;
224 
225       GST_OBJECT_LOCK (capsfilter);
226       old_change_mode = capsfilter->caps_change_mode;
227       capsfilter->caps_change_mode = g_value_get_enum (value);
228 
229       if (capsfilter->caps_change_mode != old_change_mode) {
230         g_list_free_full (capsfilter->previous_caps,
231             (GDestroyNotify) gst_caps_unref);
232         capsfilter->previous_caps = NULL;
233       }
234       GST_OBJECT_UNLOCK (capsfilter);
235       break;
236     }
237     default:
238       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
239       break;
240   }
241 }
242 
243 static void
gst_capsfilter_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)244 gst_capsfilter_get_property (GObject * object, guint prop_id, GValue * value,
245     GParamSpec * pspec)
246 {
247   GstCapsFilter *capsfilter = GST_CAPS_FILTER (object);
248 
249   switch (prop_id) {
250     case PROP_FILTER_CAPS:
251       GST_OBJECT_LOCK (capsfilter);
252       gst_value_set_caps (value, capsfilter->filter_caps);
253       GST_OBJECT_UNLOCK (capsfilter);
254       break;
255     case PROP_CAPS_CHANGE_MODE:
256       g_value_set_enum (value, capsfilter->caps_change_mode);
257       break;
258     default:
259       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
260       break;
261   }
262 }
263 
264 static void
gst_capsfilter_dispose(GObject * object)265 gst_capsfilter_dispose (GObject * object)
266 {
267   GstCapsFilter *filter = GST_CAPS_FILTER (object);
268 
269   gst_caps_replace (&filter->filter_caps, NULL);
270   g_list_free_full (filter->pending_events, (GDestroyNotify) gst_event_unref);
271   filter->pending_events = NULL;
272 
273   G_OBJECT_CLASS (parent_class)->dispose (object);
274 }
275 
276 static GstCaps *
gst_capsfilter_transform_caps(GstBaseTransform * base,GstPadDirection direction,GstCaps * caps,GstCaps * filter)277 gst_capsfilter_transform_caps (GstBaseTransform * base,
278     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
279 {
280   GstCapsFilter *capsfilter = GST_CAPS_FILTER (base);
281   GstCaps *ret, *filter_caps, *tmp;
282   gboolean retried = FALSE;
283   GstCapsFilterCapsChangeMode caps_change_mode;
284 
285   GST_OBJECT_LOCK (capsfilter);
286   filter_caps = gst_caps_ref (capsfilter->filter_caps);
287   capsfilter->filter_caps_used = TRUE;
288   caps_change_mode = capsfilter->caps_change_mode;
289   GST_OBJECT_UNLOCK (capsfilter);
290 
291 retry:
292   if (filter) {
293     tmp =
294         gst_caps_intersect_full (filter, filter_caps, GST_CAPS_INTERSECT_FIRST);
295     gst_caps_unref (filter_caps);
296     filter_caps = tmp;
297   }
298 
299   ret = gst_caps_intersect_full (filter_caps, caps, GST_CAPS_INTERSECT_FIRST);
300 
301   GST_DEBUG_OBJECT (capsfilter, "input:     %" GST_PTR_FORMAT, caps);
302   GST_DEBUG_OBJECT (capsfilter, "filter:    %" GST_PTR_FORMAT, filter);
303   GST_DEBUG_OBJECT (capsfilter, "caps filter:    %" GST_PTR_FORMAT,
304       filter_caps);
305   GST_DEBUG_OBJECT (capsfilter, "intersect: %" GST_PTR_FORMAT, ret);
306 
307   if (gst_caps_is_empty (ret)
308       && caps_change_mode ==
309       GST_CAPS_FILTER_CAPS_CHANGE_MODE_DELAYED && capsfilter->previous_caps
310       && !retried) {
311     GList *l;
312 
313     GST_DEBUG_OBJECT (capsfilter,
314         "Current filter caps are not compatible, retry with previous");
315     GST_OBJECT_LOCK (capsfilter);
316     gst_caps_unref (filter_caps);
317     gst_caps_unref (ret);
318     filter_caps = gst_caps_new_empty ();
319     for (l = capsfilter->previous_caps; l; l = l->next) {
320       filter_caps = gst_caps_merge (filter_caps, gst_caps_ref (l->data));
321     }
322     GST_OBJECT_UNLOCK (capsfilter);
323     retried = TRUE;
324     goto retry;
325   }
326 
327   gst_caps_unref (filter_caps);
328 
329   return ret;
330 }
331 
332 static gboolean
gst_capsfilter_accept_caps(GstBaseTransform * base,GstPadDirection direction,GstCaps * caps)333 gst_capsfilter_accept_caps (GstBaseTransform * base,
334     GstPadDirection direction, GstCaps * caps)
335 {
336   GstCapsFilter *capsfilter = GST_CAPS_FILTER (base);
337   GstCaps *filter_caps;
338   gboolean ret;
339 
340   GST_OBJECT_LOCK (capsfilter);
341   filter_caps = gst_caps_ref (capsfilter->filter_caps);
342   capsfilter->filter_caps_used = TRUE;
343   GST_OBJECT_UNLOCK (capsfilter);
344 
345   ret = gst_caps_can_intersect (caps, filter_caps);
346   GST_DEBUG_OBJECT (capsfilter, "can intersect: %d", ret);
347   if (!ret
348       && capsfilter->caps_change_mode ==
349       GST_CAPS_FILTER_CAPS_CHANGE_MODE_DELAYED) {
350     GList *l;
351 
352     GST_OBJECT_LOCK (capsfilter);
353     for (l = capsfilter->previous_caps; l; l = l->next) {
354       ret = gst_caps_can_intersect (caps, l->data);
355       if (ret)
356         break;
357     }
358     GST_OBJECT_UNLOCK (capsfilter);
359 
360     /* Tell upstream to reconfigure, it's still
361      * looking at old caps */
362     if (ret)
363       gst_base_transform_reconfigure_sink (base);
364   }
365 
366   gst_caps_unref (filter_caps);
367 
368   return ret;
369 }
370 
371 static GstFlowReturn
gst_capsfilter_transform_ip(GstBaseTransform * base,GstBuffer * buf)372 gst_capsfilter_transform_ip (GstBaseTransform * base, GstBuffer * buf)
373 {
374   /* No actual work here. It's all done in the prepare output buffer
375    * func. */
376   return GST_FLOW_OK;
377 }
378 
379 static void
gst_capsfilter_push_pending_events(GstCapsFilter * filter,GList * events)380 gst_capsfilter_push_pending_events (GstCapsFilter * filter, GList * events)
381 {
382   GList *l;
383 
384   for (l = g_list_last (events); l; l = l->prev) {
385     GST_LOG_OBJECT (filter, "Forwarding %s event",
386         GST_EVENT_TYPE_NAME (l->data));
387     GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (GST_BASE_TRANSFORM_CAST
388         (filter), l->data);
389   }
390   g_list_free (events);
391 }
392 
393 /* Output buffer preparation ... if the buffer has no caps, and our allowed
394  * output caps is fixed, then send the caps downstream, making sure caps are
395  * sent before segment event.
396  *
397  * This ensures that caps event is sent if we can, so that pipelines like:
398  *   gst-launch filesrc location=rawsamples.raw !
399  *       audio/x-raw,format=S16LE,rate=48000,channels=2 ! alsasink
400  * will work.
401  */
402 static GstFlowReturn
gst_capsfilter_prepare_buf(GstBaseTransform * trans,GstBuffer * input,GstBuffer ** buf)403 gst_capsfilter_prepare_buf (GstBaseTransform * trans, GstBuffer * input,
404     GstBuffer ** buf)
405 {
406   GstFlowReturn ret = GST_FLOW_OK;
407   GstCapsFilter *filter = GST_CAPS_FILTER (trans);
408 
409   /* always return the input as output buffer */
410   *buf = input;
411 
412   if (GST_PAD_MODE (trans->srcpad) == GST_PAD_MODE_PUSH
413       && !filter->got_sink_caps) {
414 
415     /* No caps. See if the output pad only supports fixed caps */
416     GstCaps *out_caps;
417     GList *pending_events = filter->pending_events;
418 
419     GST_LOG_OBJECT (trans, "Input pad does not have caps");
420 
421     filter->pending_events = NULL;
422 
423     out_caps = gst_pad_get_current_caps (trans->srcpad);
424     if (out_caps == NULL) {
425       out_caps = gst_pad_get_allowed_caps (trans->srcpad);
426       g_return_val_if_fail (out_caps != NULL, GST_FLOW_ERROR);
427     }
428 
429     out_caps = gst_caps_simplify (out_caps);
430 
431     if (gst_caps_is_fixed (out_caps) && !gst_caps_is_empty (out_caps)) {
432       GST_DEBUG_OBJECT (trans, "Have fixed output caps %"
433           GST_PTR_FORMAT " to apply to srcpad", out_caps);
434 
435       if (!gst_pad_has_current_caps (trans->srcpad)) {
436         if (gst_pad_set_caps (trans->srcpad, out_caps)) {
437           if (pending_events) {
438             gst_capsfilter_push_pending_events (filter, pending_events);
439             pending_events = NULL;
440           }
441         } else {
442           ret = GST_FLOW_NOT_NEGOTIATED;
443         }
444       } else {
445         gst_capsfilter_push_pending_events (filter, pending_events);
446         pending_events = NULL;
447       }
448 
449       g_list_free_full (pending_events, (GDestroyNotify) gst_event_unref);
450       gst_caps_unref (out_caps);
451     } else {
452       gchar *caps_str = gst_caps_to_string (out_caps);
453 
454       GST_DEBUG_OBJECT (trans, "Cannot choose caps. Have unfixed output caps %"
455           GST_PTR_FORMAT, out_caps);
456       gst_caps_unref (out_caps);
457 
458       GST_ELEMENT_ERROR (trans, STREAM, FORMAT,
459           ("Filter caps do not completely specify the output format"),
460           ("Output caps are unfixed: %s", caps_str));
461 
462       g_free (caps_str);
463       g_list_free_full (pending_events, (GDestroyNotify) gst_event_unref);
464 
465       ret = GST_FLOW_ERROR;
466     }
467   } else if (G_UNLIKELY (filter->pending_events)) {
468     GList *events = filter->pending_events;
469 
470     filter->pending_events = NULL;
471 
472     /* push pending events before a buffer */
473     gst_capsfilter_push_pending_events (filter, events);
474   }
475 
476   return ret;
477 }
478 
479 /* Queue the segment event if there was no caps event */
480 static gboolean
gst_capsfilter_sink_event(GstBaseTransform * trans,GstEvent * event)481 gst_capsfilter_sink_event (GstBaseTransform * trans, GstEvent * event)
482 {
483   GstCapsFilter *filter = GST_CAPS_FILTER (trans);
484   gboolean ret;
485 
486   if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
487     GList *l;
488 
489     for (l = filter->pending_events; l; l = l->next) {
490       if (GST_EVENT_TYPE (l->data) == GST_EVENT_SEGMENT ||
491           GST_EVENT_TYPE (l->data) == GST_EVENT_EOS) {
492         gst_event_unref (l->data);
493         filter->pending_events = g_list_delete_link (filter->pending_events, l);
494         break;
495       }
496     }
497   }
498 
499   if (!GST_EVENT_IS_STICKY (event)
500       || GST_EVENT_TYPE (event) <= GST_EVENT_CAPS)
501     goto done;
502 
503   /* If we get EOS before any buffers, just push all pending events */
504   if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
505     GList *l;
506 
507     for (l = g_list_last (filter->pending_events); l; l = l->prev) {
508       GST_LOG_OBJECT (trans, "Forwarding %s event",
509           GST_EVENT_TYPE_NAME (l->data));
510       GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, l->data);
511     }
512     g_list_free (filter->pending_events);
513     filter->pending_events = NULL;
514   } else if (!filter->got_sink_caps) {
515     GST_LOG_OBJECT (trans, "Got %s event before caps, queueing",
516         GST_EVENT_TYPE_NAME (event));
517 
518     filter->pending_events = g_list_prepend (filter->pending_events, event);
519 
520     return TRUE;
521   }
522 
523 done:
524 
525   GST_LOG_OBJECT (trans, "Forwarding %s event", GST_EVENT_TYPE_NAME (event));
526   ret =
527       GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans,
528       gst_event_ref (event));
529 
530   if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
531     filter->got_sink_caps = TRUE;
532     if (filter->caps_change_mode == GST_CAPS_FILTER_CAPS_CHANGE_MODE_DELAYED) {
533       GList *l;
534       GstCaps *caps;
535 
536       gst_event_parse_caps (event, &caps);
537 
538       /* Remove all previous caps up to one that works.
539        * Note that this might keep some leftover caps if there
540        * are multiple compatible caps */
541       GST_OBJECT_LOCK (filter);
542       for (l = g_list_last (filter->previous_caps); l; l = l->prev) {
543         if (gst_caps_can_intersect (caps, l->data)) {
544           while (l->next) {
545             gst_caps_unref (l->next->data);
546             l = g_list_delete_link (l, l->next);
547           }
548           break;
549         }
550       }
551       if (!l && gst_caps_can_intersect (caps, filter->filter_caps)) {
552         g_list_free_full (filter->previous_caps,
553             (GDestroyNotify) gst_caps_unref);
554         filter->previous_caps = NULL;
555         filter->filter_caps_used = TRUE;
556       }
557       GST_OBJECT_UNLOCK (filter);
558     }
559   }
560   gst_event_unref (event);
561 
562   return ret;
563 }
564 
565 static gboolean
gst_capsfilter_stop(GstBaseTransform * trans)566 gst_capsfilter_stop (GstBaseTransform * trans)
567 {
568   GstCapsFilter *filter = GST_CAPS_FILTER (trans);
569 
570   g_list_free_full (filter->pending_events, (GDestroyNotify) gst_event_unref);
571   filter->pending_events = NULL;
572 
573   GST_OBJECT_LOCK (filter);
574   g_list_free_full (filter->previous_caps, (GDestroyNotify) gst_caps_unref);
575   filter->previous_caps = NULL;
576   GST_OBJECT_UNLOCK (filter);
577 
578   filter->got_sink_caps = FALSE;
579 
580   return TRUE;
581 }
582