LCOV - code coverage report
Current view: top level - plugins/elements - gstcapsfilter.c (source / functions) Hit Total Coverage
Test: GStreamer 0.10.32.1 Lines: 96 153 62.7 %
Date: 2011-03-25 Functions: 10 13 76.9 %
Branches: 29 82 35.4 %

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

Generated by: LCOV version 1.9