LCOV - code coverage report
Current view: top level - plugins/elements - gsttee.c (source / functions) Hit Total Coverage
Test: GStreamer 0.10.32.1 Lines: 254 432 58.8 %
Date: 2011-03-25 Functions: 19 28 67.9 %
Branches: 72 245 29.4 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer
       2                 :            :  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       3                 :            :  *               2000,2001,2002,2003,2004,2005 Wim Taymans <wim@fluendo.com>
       4                 :            :  *               2007 Wim Taymans <wim.taymans@gmail.com>
       5                 :            :  *
       6                 :            :  * gsttee.c: Tee element, one in N out
       7                 :            :  *
       8                 :            :  * This library is free software; you can redistribute it and/or
       9                 :            :  * modify it under the terms of the GNU Library General Public
      10                 :            :  * License as published by the Free Software Foundation; either
      11                 :            :  * version 2 of the License, or (at your option) any later version.
      12                 :            :  *
      13                 :            :  * This library is distributed in the hope that it will be useful,
      14                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16                 :            :  * Library General Public License for more details.
      17                 :            :  *
      18                 :            :  * You should have received a copy of the GNU Library General Public
      19                 :            :  * License along with this library; if not, write to the
      20                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      21                 :            :  * Boston, MA 02111-1307, USA.
      22                 :            :  */
      23                 :            : 
      24                 :            : /**
      25                 :            :  * SECTION:element-tee
      26                 :            :  * @see_also: #GstIdentity
      27                 :            :  *
      28                 :            :  * Split data to multiple pads. Branching the data flow is useful when e.g.
      29                 :            :  * capturing a video where the video is shown on the screen and also encoded and
      30                 :            :  * written to a file. Another example is playing music and hooking up a
      31                 :            :  * visualisation module.
      32                 :            :  *
      33                 :            :  * One needs to use separate queue elements (or a multiqueue) in each branch to
      34                 :            :  * provide separate threads for each branch. Otherwise a blocked dataflow in one
      35                 :            :  * branch would stall the other branches.
      36                 :            :  *
      37                 :            :  * <refsect2>
      38                 :            :  * <title>Example launch line</title>
      39                 :            :  * |[
      40                 :            :  * gst-launch filesrc location=song.ogg ! decodebin2 ! tee name=t ! queue ! autoaudiosink t. ! queue ! audioconvert ! goom ! ffmpegcolorspace ! autovideosink
      41                 :            :  * ]| Play a song.ogg from local dir and render visualisations using the goom
      42                 :            :  * element.
      43                 :            :  * </refsect2>
      44                 :            :  */
      45                 :            : 
      46                 :            : #ifdef HAVE_CONFIG_H
      47                 :            : #  include "config.h"
      48                 :            : #endif
      49                 :            : 
      50                 :            : #include "gsttee.h"
      51                 :            : 
      52                 :            : #include <string.h>
      53                 :            : 
      54                 :            : static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
      55                 :            :     GST_PAD_SINK,
      56                 :            :     GST_PAD_ALWAYS,
      57                 :            :     GST_STATIC_CAPS_ANY);
      58                 :            : 
      59                 :            : GST_DEBUG_CATEGORY_STATIC (gst_tee_debug);
      60                 :            : #define GST_CAT_DEFAULT gst_tee_debug
      61                 :            : 
      62                 :            : #define GST_TYPE_TEE_PULL_MODE (gst_tee_pull_mode_get_type())
      63                 :            : static GType
      64                 :         19 : gst_tee_pull_mode_get_type (void)
      65                 :            : {
      66                 :            :   static GType type = 0;
      67                 :            :   static const GEnumValue data[] = {
      68                 :            :     {GST_TEE_PULL_MODE_NEVER, "Never activate in pull mode", "never"},
      69                 :            :     {GST_TEE_PULL_MODE_SINGLE, "Only one src pad can be active in pull mode",
      70                 :            :         "single"},
      71                 :            :     {0, NULL, NULL},
      72                 :            :   };
      73                 :            : 
      74         [ +  - ]:         19 :   if (!type) {
      75                 :         19 :     type = g_enum_register_static ("GstTeePullMode", data);
      76                 :            :   }
      77                 :         19 :   return type;
      78                 :            : }
      79                 :            : 
      80                 :            : /* lock to protect request pads from being removed while downstream */
      81                 :            : #define GST_TEE_DYN_LOCK(tee) g_mutex_lock ((tee)->dyn_lock)
      82                 :            : #define GST_TEE_DYN_UNLOCK(tee) g_mutex_unlock ((tee)->dyn_lock)
      83                 :            : 
      84                 :            : #define DEFAULT_PROP_NUM_SRC_PADS 0
      85                 :            : #define DEFAULT_PROP_HAS_SINK_LOOP  FALSE
      86                 :            : #define DEFAULT_PROP_HAS_CHAIN    TRUE
      87                 :            : #define DEFAULT_PROP_SILENT   TRUE
      88                 :            : #define DEFAULT_PROP_LAST_MESSAGE NULL
      89                 :            : #define DEFAULT_PULL_MODE   GST_TEE_PULL_MODE_NEVER
      90                 :            : 
      91                 :            : enum
      92                 :            : {
      93                 :            :   PROP_0,
      94                 :            :   PROP_NUM_SRC_PADS,
      95                 :            :   PROP_HAS_SINK_LOOP,
      96                 :            :   PROP_HAS_CHAIN,
      97                 :            :   PROP_SILENT,
      98                 :            :   PROP_LAST_MESSAGE,
      99                 :            :   PROP_PULL_MODE,
     100                 :            :   PROP_ALLOC_PAD,
     101                 :            : };
     102                 :            : 
     103                 :            : static GstStaticPadTemplate tee_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
     104                 :            :     GST_PAD_SRC,
     105                 :            :     GST_PAD_REQUEST,
     106                 :            :     GST_STATIC_CAPS_ANY);
     107                 :            : 
     108                 :            : #define _do_init(bla) \
     109                 :            :     GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
     110                 :            : 
     111 [ +  + ][ +  - ]:      15955 : GST_BOILERPLATE_FULL (GstTee, gst_tee, GstElement, GST_TYPE_ELEMENT, _do_init);
     112                 :            : 
     113                 :            : /* structure and quark to keep track of which pads have been pushed */
     114                 :            : static GQuark push_data;
     115                 :            : 
     116                 :            : static GParamSpec *pspec_last_message = NULL;
     117                 :            : static GParamSpec *pspec_alloc_pad = NULL;
     118                 :            : 
     119                 :            : typedef struct
     120                 :            : {
     121                 :            :   gboolean pushed;
     122                 :            :   GstFlowReturn result;
     123                 :            :   gboolean removed;
     124                 :            : } PushData;
     125                 :            : 
     126                 :            : static GstPad *gst_tee_request_new_pad (GstElement * element,
     127                 :            :     GstPadTemplate * temp, const gchar * unused);
     128                 :            : static void gst_tee_release_pad (GstElement * element, GstPad * pad);
     129                 :            : 
     130                 :            : static void gst_tee_finalize (GObject * object);
     131                 :            : static void gst_tee_set_property (GObject * object, guint prop_id,
     132                 :            :     const GValue * value, GParamSpec * pspec);
     133                 :            : static void gst_tee_get_property (GObject * object, guint prop_id,
     134                 :            :     GValue * value, GParamSpec * pspec);
     135                 :            : static void gst_tee_dispose (GObject * object);
     136                 :            : 
     137                 :            : static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer);
     138                 :            : static GstFlowReturn gst_tee_chain_list (GstPad * pad, GstBufferList * list);
     139                 :            : static GstFlowReturn gst_tee_buffer_alloc (GstPad * pad, guint64 offset,
     140                 :            :     guint size, GstCaps * caps, GstBuffer ** buf);
     141                 :            : static gboolean gst_tee_sink_acceptcaps (GstPad * pad, GstCaps * caps);
     142                 :            : static gboolean gst_tee_sink_activate_push (GstPad * pad, gboolean active);
     143                 :            : static gboolean gst_tee_src_check_get_range (GstPad * pad);
     144                 :            : static gboolean gst_tee_src_activate_pull (GstPad * pad, gboolean active);
     145                 :            : static GstFlowReturn gst_tee_src_get_range (GstPad * pad, guint64 offset,
     146                 :            :     guint length, GstBuffer ** buf);
     147                 :            : 
     148                 :            : 
     149                 :            : static void
     150                 :         19 : gst_tee_base_init (gpointer g_class)
     151                 :            : {
     152                 :         19 :   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
     153                 :            : 
     154                 :         19 :   gst_element_class_set_details_simple (gstelement_class,
     155                 :            :       "Tee pipe fitting",
     156                 :            :       "Generic",
     157                 :            :       "1-to-N pipe fitting",
     158                 :            :       "Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>");
     159                 :         19 :   gst_element_class_add_pad_template (gstelement_class,
     160                 :            :       gst_static_pad_template_get (&sinktemplate));
     161                 :         19 :   gst_element_class_add_pad_template (gstelement_class,
     162                 :            :       gst_static_pad_template_get (&tee_src_template));
     163                 :            : 
     164                 :         19 :   push_data = g_quark_from_static_string ("tee-push-data");
     165                 :         19 : }
     166                 :            : 
     167                 :            : static void
     168                 :         28 : gst_tee_dispose (GObject * object)
     169                 :            : {
     170                 :            :   GList *item;
     171                 :            : 
     172                 :            : restart:
     173 [ +  - ][ +  + ]:         43 :   for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
     174                 :         28 :     GstPad *pad = GST_PAD (item->data);
     175         [ +  + ]:         28 :     if (GST_PAD_IS_SRC (pad)) {
     176                 :         13 :       gst_element_release_request_pad (GST_ELEMENT (object), pad);
     177                 :         13 :       goto restart;
     178                 :            :     }
     179                 :            :   }
     180                 :            : 
     181                 :         15 :   G_OBJECT_CLASS (parent_class)->dispose (object);
     182                 :         15 : }
     183                 :            : 
     184                 :            : static void
     185                 :         15 : gst_tee_finalize (GObject * object)
     186                 :            : {
     187                 :            :   GstTee *tee;
     188                 :            : 
     189                 :         15 :   tee = GST_TEE (object);
     190                 :            : 
     191                 :         15 :   g_free (tee->last_message);
     192                 :            : 
     193                 :         15 :   g_mutex_free (tee->dyn_lock);
     194                 :            : 
     195                 :         15 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     196                 :         15 : }
     197                 :            : 
     198                 :            : static void
     199                 :         19 : gst_tee_class_init (GstTeeClass * klass)
     200                 :            : {
     201                 :            :   GObjectClass *gobject_class;
     202                 :            :   GstElementClass *gstelement_class;
     203                 :            : 
     204                 :         19 :   gobject_class = G_OBJECT_CLASS (klass);
     205                 :         19 :   gstelement_class = GST_ELEMENT_CLASS (klass);
     206                 :            : 
     207                 :         19 :   gobject_class->finalize = gst_tee_finalize;
     208                 :         19 :   gobject_class->set_property = gst_tee_set_property;
     209                 :         19 :   gobject_class->get_property = gst_tee_get_property;
     210                 :         19 :   gobject_class->dispose = gst_tee_dispose;
     211                 :            : 
     212                 :         19 :   g_object_class_install_property (gobject_class, PROP_NUM_SRC_PADS,
     213                 :            :       g_param_spec_int ("num-src-pads", "Num Src Pads",
     214                 :            :           "The number of source pads", 0, G_MAXINT, DEFAULT_PROP_NUM_SRC_PADS,
     215                 :            :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     216                 :         19 :   g_object_class_install_property (gobject_class, PROP_HAS_SINK_LOOP,
     217                 :            :       g_param_spec_boolean ("has-sink-loop", "Has Sink Loop",
     218                 :            :           "If the element should spawn a thread (unimplemented and deprecated)",
     219                 :            :           DEFAULT_PROP_HAS_SINK_LOOP,
     220                 :            :           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     221                 :         19 :   g_object_class_install_property (gobject_class, PROP_HAS_CHAIN,
     222                 :            :       g_param_spec_boolean ("has-chain", "Has Chain",
     223                 :            :           "If the element can operate in push mode", DEFAULT_PROP_HAS_CHAIN,
     224                 :            :           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     225                 :         19 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     226                 :            :       g_param_spec_boolean ("silent", "Silent",
     227                 :            :           "Don't produce last_message events", DEFAULT_PROP_SILENT,
     228                 :            :           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     229                 :         19 :   pspec_last_message = g_param_spec_string ("last-message", "Last Message",
     230                 :            :       "The message describing current status", DEFAULT_PROP_LAST_MESSAGE,
     231                 :            :       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
     232                 :         19 :   g_object_class_install_property (gobject_class, PROP_LAST_MESSAGE,
     233                 :            :       pspec_last_message);
     234                 :         19 :   g_object_class_install_property (gobject_class, PROP_PULL_MODE,
     235                 :            :       g_param_spec_enum ("pull-mode", "Pull mode",
     236                 :            :           "Behavior of tee in pull mode", GST_TYPE_TEE_PULL_MODE,
     237                 :            :           DEFAULT_PULL_MODE,
     238                 :            :           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     239                 :         19 :   pspec_alloc_pad = g_param_spec_object ("alloc-pad", "Allocation Src Pad",
     240                 :            :       "The pad used for gst_pad_alloc_buffer", GST_TYPE_PAD,
     241                 :            :       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     242                 :         19 :   g_object_class_install_property (gobject_class, PROP_ALLOC_PAD,
     243                 :            :       pspec_alloc_pad);
     244                 :            : 
     245                 :         19 :   gstelement_class->request_new_pad =
     246                 :         19 :       GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
     247                 :         19 :   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_tee_release_pad);
     248                 :         19 : }
     249                 :            : 
     250                 :            : static void
     251                 :         15 : gst_tee_init (GstTee * tee, GstTeeClass * g_class)
     252                 :            : {
     253                 :         15 :   tee->dyn_lock = g_mutex_new ();
     254                 :            : 
     255                 :         15 :   tee->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
     256                 :         15 :   tee->sink_mode = GST_ACTIVATE_NONE;
     257                 :            : 
     258                 :         15 :   gst_pad_set_setcaps_function (tee->sinkpad,
     259                 :         15 :       GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
     260                 :         15 :   gst_pad_set_getcaps_function (tee->sinkpad,
     261                 :         15 :       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
     262                 :         15 :   gst_pad_set_acceptcaps_function (tee->sinkpad,
     263                 :         15 :       GST_DEBUG_FUNCPTR (gst_tee_sink_acceptcaps));
     264                 :         15 :   gst_pad_set_bufferalloc_function (tee->sinkpad,
     265                 :         15 :       GST_DEBUG_FUNCPTR (gst_tee_buffer_alloc));
     266                 :         15 :   gst_pad_set_activatepush_function (tee->sinkpad,
     267                 :         15 :       GST_DEBUG_FUNCPTR (gst_tee_sink_activate_push));
     268                 :         15 :   gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
     269                 :         15 :   gst_pad_set_chain_list_function (tee->sinkpad,
     270                 :         15 :       GST_DEBUG_FUNCPTR (gst_tee_chain_list));
     271                 :         15 :   gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
     272                 :            : 
     273                 :         15 :   tee->last_message = NULL;
     274                 :         15 : }
     275                 :            : 
     276                 :            : static void
     277                 :          4 : gst_tee_notify_alloc_pad (GstTee * tee)
     278                 :            : {
     279                 :            : #if !GLIB_CHECK_VERSION(2,26,0)
     280                 :            :   g_object_notify ((GObject *) tee, "alloc-pad");
     281                 :            : #else
     282                 :          4 :   g_object_notify_by_pspec ((GObject *) tee, pspec_alloc_pad);
     283                 :            : #endif
     284                 :          4 : }
     285                 :            : 
     286                 :            : static GstPad *
     287                 :       7841 : gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
     288                 :            :     const gchar * unused)
     289                 :            : {
     290                 :            :   gchar *name;
     291                 :            :   GstPad *srcpad;
     292                 :            :   GstTee *tee;
     293                 :            :   GstActivateMode mode;
     294                 :            :   gboolean res;
     295                 :            :   PushData *data;
     296                 :            : 
     297                 :       7841 :   tee = GST_TEE (element);
     298                 :            : 
     299         [ -  + ]:       7841 :   GST_DEBUG_OBJECT (tee, "requesting pad");
     300                 :            : 
     301                 :       7841 :   GST_OBJECT_LOCK (tee);
     302                 :       7841 :   name = g_strdup_printf ("src%d", tee->pad_counter++);
     303                 :            : 
     304                 :       7841 :   srcpad = gst_pad_new_from_template (templ, name);
     305                 :       7841 :   g_free (name);
     306                 :            : 
     307                 :       7841 :   mode = tee->sink_mode;
     308                 :            : 
     309                 :            :   /* install the data, we automatically free it when the pad is disposed because
     310                 :            :    * of _release_pad or when the element goes away. */
     311                 :       7841 :   data = g_new0 (PushData, 1);
     312                 :       7841 :   data->pushed = FALSE;
     313                 :       7841 :   data->result = GST_FLOW_NOT_LINKED;
     314                 :       7841 :   data->removed = FALSE;
     315                 :       7841 :   g_object_set_qdata_full (G_OBJECT (srcpad), push_data, data, g_free);
     316                 :            : 
     317                 :       7841 :   GST_OBJECT_UNLOCK (tee);
     318                 :            : 
     319         [ +  + ]:       7841 :   switch (mode) {
     320                 :            :     case GST_ACTIVATE_PULL:
     321                 :            :       /* we already have a src pad in pull mode, and our pull mode can only be
     322                 :            :          SINGLE, so fall through to activate this new pad in push mode */
     323                 :            :     case GST_ACTIVATE_PUSH:
     324                 :       7809 :       res = gst_pad_activate_push (srcpad, TRUE);
     325                 :       7809 :       break;
     326                 :            :     default:
     327                 :         32 :       res = TRUE;
     328                 :         32 :       break;
     329                 :            :   }
     330                 :            : 
     331         [ -  + ]:       7841 :   if (!res)
     332                 :          0 :     goto activate_failed;
     333                 :            : 
     334                 :       7841 :   gst_pad_set_setcaps_function (srcpad,
     335                 :       7841 :       GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
     336                 :       7841 :   gst_pad_set_getcaps_function (srcpad,
     337                 :       7841 :       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
     338                 :       7841 :   gst_pad_set_activatepull_function (srcpad,
     339                 :       7841 :       GST_DEBUG_FUNCPTR (gst_tee_src_activate_pull));
     340                 :       7841 :   gst_pad_set_checkgetrange_function (srcpad,
     341                 :       7841 :       GST_DEBUG_FUNCPTR (gst_tee_src_check_get_range));
     342                 :       7841 :   gst_pad_set_getrange_function (srcpad,
     343                 :       7841 :       GST_DEBUG_FUNCPTR (gst_tee_src_get_range));
     344                 :       7841 :   gst_element_add_pad (GST_ELEMENT_CAST (tee), srcpad);
     345                 :            : 
     346                 :       7841 :   return srcpad;
     347                 :            : 
     348                 :            :   /* ERRORS */
     349                 :            : activate_failed:
     350                 :            :   {
     351                 :          0 :     gboolean changed = FALSE;
     352                 :            : 
     353                 :          0 :     GST_OBJECT_LOCK (tee);
     354         [ #  # ]:          0 :     GST_DEBUG_OBJECT (tee, "warning failed to activate request pad");
     355         [ #  # ]:          0 :     if (tee->allocpad == srcpad) {
     356                 :          0 :       tee->allocpad = NULL;
     357                 :          0 :       changed = TRUE;
     358                 :            :     }
     359                 :          0 :     GST_OBJECT_UNLOCK (tee);
     360                 :          0 :     gst_object_unref (srcpad);
     361         [ #  # ]:          0 :     if (changed) {
     362                 :          0 :       gst_tee_notify_alloc_pad (tee);
     363                 :            :     }
     364                 :       7841 :     return NULL;
     365                 :            :   }
     366                 :            : }
     367                 :            : 
     368                 :            : static void
     369                 :       7841 : gst_tee_release_pad (GstElement * element, GstPad * pad)
     370                 :            : {
     371                 :            :   GstTee *tee;
     372                 :            :   PushData *data;
     373                 :       7841 :   gboolean changed = FALSE;
     374                 :            : 
     375                 :       7841 :   tee = GST_TEE (element);
     376                 :            : 
     377         [ -  + ]:       7841 :   GST_DEBUG_OBJECT (tee, "releasing pad");
     378                 :            : 
     379                 :            :   /* wait for pending pad_alloc to finish */
     380                 :       7841 :   GST_TEE_DYN_LOCK (tee);
     381                 :       7841 :   data = g_object_get_qdata (G_OBJECT (pad), push_data);
     382                 :            : 
     383                 :       7841 :   GST_OBJECT_LOCK (tee);
     384                 :            :   /* mark the pad as removed so that future pad_alloc fails with NOT_LINKED. */
     385                 :       7841 :   data->removed = TRUE;
     386         [ +  + ]:       7841 :   if (tee->allocpad == pad) {
     387                 :          2 :     tee->allocpad = NULL;
     388                 :          2 :     changed = TRUE;
     389                 :            :   }
     390                 :       7841 :   GST_OBJECT_UNLOCK (tee);
     391                 :            : 
     392                 :       7841 :   gst_pad_set_active (pad, FALSE);
     393                 :            : 
     394                 :       7841 :   gst_element_remove_pad (GST_ELEMENT_CAST (tee), pad);
     395                 :       7841 :   GST_TEE_DYN_UNLOCK (tee);
     396                 :            : 
     397         [ +  + ]:       7841 :   if (changed) {
     398                 :          2 :     gst_tee_notify_alloc_pad (tee);
     399                 :            :   }
     400                 :       7841 : }
     401                 :            : 
     402                 :            : static void
     403                 :         60 : gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
     404                 :            :     GParamSpec * pspec)
     405                 :            : {
     406                 :         60 :   GstTee *tee = GST_TEE (object);
     407                 :            : 
     408                 :         60 :   GST_OBJECT_LOCK (tee);
     409   [ +  +  +  +  :         60 :   switch (prop_id) {
                   -  - ]
     410                 :            :     case PROP_HAS_SINK_LOOP:
     411                 :         15 :       tee->has_sink_loop = g_value_get_boolean (value);
     412         [ -  + ]:         15 :       if (tee->has_sink_loop) {
     413                 :          0 :         g_warning ("tee will never implement has-sink-loop==TRUE");
     414                 :            :       }
     415                 :         15 :       break;
     416                 :            :     case PROP_HAS_CHAIN:
     417                 :         15 :       tee->has_chain = g_value_get_boolean (value);
     418                 :         15 :       break;
     419                 :            :     case PROP_SILENT:
     420                 :         15 :       tee->silent = g_value_get_boolean (value);
     421                 :         15 :       break;
     422                 :            :     case PROP_PULL_MODE:
     423                 :         15 :       tee->pull_mode = g_value_get_enum (value);
     424                 :         15 :       break;
     425                 :            :     case PROP_ALLOC_PAD:
     426                 :            :     {
     427                 :          0 :       GstPad *pad = g_value_get_object (value);
     428                 :          0 :       GST_OBJECT_LOCK (pad);
     429         [ #  # ]:          0 :       if (GST_OBJECT_PARENT (pad) == GST_OBJECT_CAST (object))
     430                 :          0 :         tee->allocpad = pad;
     431                 :            :       else
     432         [ #  # ]:          0 :         GST_WARNING_OBJECT (object, "Tried to set alloc pad %s which"
     433                 :            :             " is not my pad", GST_OBJECT_NAME (pad));
     434                 :          0 :       GST_OBJECT_UNLOCK (pad);
     435                 :          0 :       break;
     436                 :            :     }
     437                 :            :     default:
     438                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     439                 :          0 :       break;
     440                 :            :   }
     441                 :         60 :   GST_OBJECT_UNLOCK (tee);
     442                 :         60 : }
     443                 :            : 
     444                 :            : static void
     445                 :          0 : gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
     446                 :            :     GParamSpec * pspec)
     447                 :            : {
     448                 :          0 :   GstTee *tee = GST_TEE (object);
     449                 :            : 
     450                 :          0 :   GST_OBJECT_LOCK (tee);
     451   [ #  #  #  #  :          0 :   switch (prop_id) {
             #  #  #  # ]
     452                 :            :     case PROP_NUM_SRC_PADS:
     453                 :          0 :       g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
     454                 :          0 :       break;
     455                 :            :     case PROP_HAS_SINK_LOOP:
     456                 :          0 :       g_value_set_boolean (value, tee->has_sink_loop);
     457                 :          0 :       break;
     458                 :            :     case PROP_HAS_CHAIN:
     459                 :          0 :       g_value_set_boolean (value, tee->has_chain);
     460                 :          0 :       break;
     461                 :            :     case PROP_SILENT:
     462                 :          0 :       g_value_set_boolean (value, tee->silent);
     463                 :          0 :       break;
     464                 :            :     case PROP_LAST_MESSAGE:
     465                 :          0 :       g_value_set_string (value, tee->last_message);
     466                 :          0 :       break;
     467                 :            :     case PROP_PULL_MODE:
     468                 :          0 :       g_value_set_enum (value, tee->pull_mode);
     469                 :          0 :       break;
     470                 :            :     case PROP_ALLOC_PAD:
     471                 :          0 :       g_value_set_object (value, tee->allocpad);
     472                 :          0 :       break;
     473                 :            :     default:
     474                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     475                 :          0 :       break;
     476                 :            :   }
     477                 :          0 :   GST_OBJECT_UNLOCK (tee);
     478                 :          0 : }
     479                 :            : 
     480                 :            : /* we have no previous source pad we can use to proxy the pad alloc. Loop over
     481                 :            :  * the source pads, try to alloc a buffer on each one of them. Keep a reference
     482                 :            :  * to the first pad that succeeds, we will be using it to alloc more buffers
     483                 :            :  * later.  must be called with the OBJECT_LOCK on tee. */
     484                 :            : static GstFlowReturn
     485                 :          2 : gst_tee_find_buffer_alloc (GstTee * tee, guint64 offset, guint size,
     486                 :            :     GstCaps * caps, GstBuffer ** buf)
     487                 :            : {
     488                 :            :   GstFlowReturn res;
     489                 :            :   GList *pads;
     490                 :            :   guint32 cookie;
     491                 :            : 
     492                 :          2 :   res = GST_FLOW_NOT_LINKED;
     493                 :            : 
     494                 :            : retry:
     495                 :          2 :   pads = GST_ELEMENT_CAST (tee)->srcpads;
     496                 :          2 :   cookie = GST_ELEMENT_CAST (tee)->pads_cookie;
     497                 :            : 
     498         [ +  - ]:          2 :   while (pads) {
     499                 :            :     GstPad *pad;
     500                 :            :     PushData *data;
     501                 :            : 
     502                 :          2 :     pad = GST_PAD_CAST (pads->data);
     503                 :          2 :     gst_object_ref (pad);
     504 [ -  + ][ #  # ]:          2 :     GST_DEBUG_OBJECT (tee, "try alloc on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     505                 :          2 :     GST_OBJECT_UNLOCK (tee);
     506                 :            : 
     507                 :          2 :     GST_TEE_DYN_LOCK (tee);
     508                 :          2 :     data = g_object_get_qdata ((GObject *) pad, push_data);
     509         [ +  - ]:          2 :     if (!data->removed)
     510                 :          2 :       res = gst_pad_alloc_buffer (pad, offset, size, caps, buf);
     511                 :            :     else
     512                 :          0 :       res = GST_FLOW_NOT_LINKED;
     513                 :          2 :     GST_TEE_DYN_UNLOCK (tee);
     514                 :            : 
     515         [ -  + ]:          2 :     GST_DEBUG_OBJECT (tee, "got return value %d", res);
     516                 :            : 
     517                 :          2 :     gst_object_unref (pad);
     518                 :            : 
     519                 :          2 :     GST_OBJECT_LOCK (tee);
     520         [ -  + ]:          2 :     if (GST_ELEMENT_CAST (tee)->pads_cookie != cookie) {
     521         [ #  # ]:          0 :       GST_DEBUG_OBJECT (tee, "pad list changed, restart");
     522                 :            :       /* pad list changed, restart. If the pad alloc function returned OK we
     523                 :            :        * need to unref the buffer */
     524         [ #  # ]:          0 :       if (res == GST_FLOW_OK)
     525                 :          0 :         gst_buffer_unref (*buf);
     526                 :          0 :       *buf = NULL;
     527                 :          0 :       goto retry;
     528                 :            :     }
     529 [ +  - ][ +  - ]:          2 :     if (!data->removed && res == GST_FLOW_OK) {
     530 [ -  + ][ #  # ]:          2 :       GST_DEBUG_OBJECT (tee, "we have a buffer on pad %s:%s",
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     531                 :            :           GST_DEBUG_PAD_NAME (pad));
     532                 :            :       /* we have a buffer, keep the pad for later and exit the loop. */
     533                 :          2 :       tee->allocpad = pad;
     534                 :          2 :       GST_OBJECT_UNLOCK (tee);
     535                 :          2 :       gst_tee_notify_alloc_pad (tee);
     536                 :          2 :       GST_OBJECT_LOCK (tee);
     537                 :          2 :       break;
     538                 :            :     }
     539                 :            :     /* no valid buffer, try another pad */
     540         [ #  # ]:          0 :     pads = g_list_next (pads);
     541                 :            :   }
     542                 :            : 
     543                 :          2 :   return res;
     544                 :            : }
     545                 :            : 
     546                 :            : static GstFlowReturn
     547                 :          3 : gst_tee_buffer_alloc (GstPad * pad, guint64 offset, guint size,
     548                 :            :     GstCaps * caps, GstBuffer ** buf)
     549                 :            : {
     550                 :            :   GstTee *tee;
     551                 :            :   GstFlowReturn res;
     552                 :            :   GstPad *allocpad;
     553                 :            : 
     554                 :          3 :   tee = GST_TEE_CAST (GST_PAD_PARENT (pad));
     555                 :            : 
     556                 :          3 :   res = GST_FLOW_NOT_LINKED;
     557                 :            : 
     558                 :          3 :   GST_OBJECT_LOCK (tee);
     559         [ +  + ]:          3 :   if ((allocpad = tee->allocpad)) {
     560                 :            :     PushData *data;
     561                 :            : 
     562                 :            :     /* if we had a previous pad we used for allocating a buffer, continue using
     563                 :            :      * it. */
     564 [ -  + ][ #  # ]:          1 :     GST_DEBUG_OBJECT (tee, "using pad %s:%s for alloc",
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     565                 :            :         GST_DEBUG_PAD_NAME (allocpad));
     566                 :          1 :     gst_object_ref (allocpad);
     567                 :          1 :     GST_OBJECT_UNLOCK (tee);
     568                 :            : 
     569                 :          1 :     GST_TEE_DYN_LOCK (tee);
     570                 :          1 :     data = g_object_get_qdata ((GObject *) allocpad, push_data);
     571         [ +  - ]:          1 :     if (!data->removed)
     572                 :          1 :       res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf);
     573                 :            :     else
     574                 :          0 :       res = GST_FLOW_NOT_LINKED;
     575                 :          1 :     GST_TEE_DYN_UNLOCK (tee);
     576                 :            : 
     577                 :          1 :     gst_object_unref (allocpad);
     578                 :            : 
     579                 :          1 :     GST_OBJECT_LOCK (tee);
     580                 :            :   }
     581                 :            :   /* either we failed to alloc on the the previous pad or we did not have a
     582                 :            :    * previous pad. */
     583         [ +  + ]:          3 :   if (res == GST_FLOW_NOT_LINKED) {
     584                 :            :     /* find a new pad to alloc a buffer on */
     585         [ -  + ]:          2 :     GST_DEBUG_OBJECT (tee, "finding pad for alloc");
     586                 :          2 :     res = gst_tee_find_buffer_alloc (tee, offset, size, caps, buf);
     587                 :            :   }
     588                 :          3 :   GST_OBJECT_UNLOCK (tee);
     589                 :            : 
     590                 :          3 :   return res;
     591                 :            : }
     592                 :            : 
     593                 :            : /* on the sink we accept caps that are acceptable to all srcpads */
     594                 :            : static gboolean
     595                 :          0 : gst_tee_sink_acceptcaps (GstPad * pad, GstCaps * caps)
     596                 :            : {
     597                 :            :   GstTee *tee;
     598                 :            :   gboolean res, done;
     599                 :            :   GstIterator *it;
     600                 :            : 
     601                 :          0 :   tee = GST_TEE_CAST (GST_PAD_PARENT (pad));
     602                 :            : 
     603                 :          0 :   it = gst_element_iterate_src_pads (GST_ELEMENT_CAST (tee));
     604                 :            : 
     605                 :          0 :   res = TRUE;
     606                 :          0 :   done = FALSE;
     607 [ #  # ][ #  # ]:          0 :   while (!done && res) {
     608                 :            :     gpointer item;
     609                 :            : 
     610   [ #  #  #  #  :          0 :     switch (gst_iterator_next (it, &item)) {
                      # ]
     611                 :            :       case GST_ITERATOR_OK:
     612                 :          0 :         res &= gst_pad_peer_accept_caps (GST_PAD_CAST (item), caps);
     613                 :          0 :         gst_object_unref (item);
     614                 :          0 :         break;
     615                 :            :       case GST_ITERATOR_RESYNC:
     616                 :          0 :         res = TRUE;
     617                 :          0 :         gst_iterator_resync (it);
     618                 :          0 :         break;
     619                 :            :       case GST_ITERATOR_ERROR:
     620                 :          0 :         res = FALSE;
     621                 :          0 :         done = TRUE;
     622                 :          0 :         break;
     623                 :            :       case GST_ITERATOR_DONE:
     624                 :          0 :         done = TRUE;
     625                 :          0 :         break;
     626                 :            :     }
     627                 :            :   }
     628                 :          0 :   gst_iterator_free (it);
     629                 :            : 
     630                 :          0 :   return res;
     631                 :            : }
     632                 :            : 
     633                 :            : static void
     634                 :          0 : gst_tee_do_message (GstTee * tee, GstPad * pad, gpointer data, gboolean is_list)
     635                 :            : {
     636                 :          0 :   GST_OBJECT_LOCK (tee);
     637                 :          0 :   g_free (tee->last_message);
     638         [ #  # ]:          0 :   if (is_list) {
     639                 :          0 :     tee->last_message =
     640 [ #  # ][ #  # ]:          0 :         g_strdup_printf ("chain-list   ******* (%s:%s)t %p",
     641 [ #  # ][ #  # ]:          0 :         GST_DEBUG_PAD_NAME (pad), data);
                 [ #  # ]
     642                 :            :   } else {
     643                 :          0 :     tee->last_message =
     644 [ #  # ][ #  # ]:          0 :         g_strdup_printf ("chain        ******* (%s:%s)t (%d bytes, %"
     645 [ #  # ][ #  # ]:          0 :         G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad),
                 [ #  # ]
     646                 :            :         GST_BUFFER_SIZE (data), GST_BUFFER_TIMESTAMP (data), data);
     647                 :            :   }
     648                 :          0 :   GST_OBJECT_UNLOCK (tee);
     649                 :            : 
     650                 :            : #if !GLIB_CHECK_VERSION(2,26,0)
     651                 :            :   g_object_notify ((GObject *) tee, "last-message");
     652                 :            : #else
     653                 :          0 :   g_object_notify_by_pspec ((GObject *) tee, pspec_last_message);
     654                 :            : #endif
     655                 :          0 : }
     656                 :            : 
     657                 :            : static GstFlowReturn
     658                 :       1351 : gst_tee_do_push (GstTee * tee, GstPad * pad, gpointer data, gboolean is_list)
     659                 :            : {
     660                 :            :   GstFlowReturn res;
     661                 :            : 
     662                 :            :   /* Push */
     663         [ -  + ]:       1351 :   if (pad == tee->pull_pad) {
     664                 :            :     /* don't push on the pad we're pulling from */
     665                 :          0 :     res = GST_FLOW_OK;
     666         [ -  + ]:       1351 :   } else if (is_list) {
     667                 :          0 :     res =
     668                 :          0 :         gst_pad_push_list (pad,
     669                 :            :         gst_buffer_list_ref (GST_BUFFER_LIST_CAST (data)));
     670                 :            :   } else {
     671                 :       1351 :     res = gst_pad_push (pad, gst_buffer_ref (GST_BUFFER_CAST (data)));
     672                 :            :   }
     673                 :       1351 :   return res;
     674                 :            : }
     675                 :            : 
     676                 :            : static void
     677                 :       1258 : clear_pads (GstPad * pad, GstTee * tee)
     678                 :            : {
     679                 :            :   PushData *data;
     680                 :            : 
     681                 :       1258 :   data = g_object_get_qdata ((GObject *) pad, push_data);
     682                 :            : 
     683                 :            :   /* the data must be there or we have a screwed up internal state */
     684         [ -  + ]:       1258 :   g_assert (data != NULL);
     685                 :            : 
     686                 :       1258 :   data->pushed = FALSE;
     687                 :       1258 :   data->result = GST_FLOW_NOT_LINKED;
     688                 :       1258 : }
     689                 :            : 
     690                 :            : static GstFlowReturn
     691                 :       5019 : gst_tee_handle_data (GstTee * tee, gpointer data, gboolean is_list)
     692                 :            : {
     693                 :            :   GList *pads;
     694                 :            :   guint32 cookie;
     695                 :            :   GstFlowReturn ret, cret;
     696                 :            : 
     697         [ -  + ]:       5019 :   if (G_UNLIKELY (!tee->silent))
     698                 :          0 :     gst_tee_do_message (tee, tee->sinkpad, data, is_list);
     699                 :            : 
     700                 :       5019 :   GST_OBJECT_LOCK (tee);
     701                 :       5019 :   pads = GST_ELEMENT_CAST (tee)->srcpads;
     702                 :            : 
     703                 :            :   /* special case for zero pads */
     704         [ -  + ]:       5019 :   if (G_UNLIKELY (!pads))
     705                 :          0 :     goto no_pads;
     706                 :            : 
     707                 :            :   /* special case for just one pad that avoids reffing the buffer */
     708         [ +  + ]:       5019 :   if (!pads->next) {
     709                 :       4411 :     GstPad *pad = GST_PAD_CAST (pads->data);
     710                 :            : 
     711                 :       4411 :     GST_OBJECT_UNLOCK (tee);
     712                 :            : 
     713         [ -  + ]:       4411 :     if (pad == tee->pull_pad) {
     714                 :          0 :       ret = GST_FLOW_OK;
     715         [ -  + ]:       4411 :     } else if (is_list) {
     716                 :          0 :       ret = gst_pad_push_list (pad, GST_BUFFER_LIST_CAST (data));
     717                 :            :     } else {
     718                 :       4411 :       ret = gst_pad_push (pad, GST_BUFFER_CAST (data));
     719                 :            :     }
     720                 :       4411 :     return ret;
     721                 :            :   }
     722                 :            : 
     723                 :            :   /* mark all pads as 'not pushed on yet' */
     724                 :        608 :   g_list_foreach (pads, (GFunc) clear_pads, tee);
     725                 :            : 
     726                 :            : restart:
     727                 :       1385 :   cret = GST_FLOW_NOT_LINKED;
     728                 :       1385 :   pads = GST_ELEMENT_CAST (tee)->srcpads;
     729                 :       1385 :   cookie = GST_ELEMENT_CAST (tee)->pads_cookie;
     730                 :            : 
     731         [ +  + ]:       2507 :   while (pads) {
     732                 :            :     GstPad *pad;
     733                 :            :     PushData *pdata;
     734                 :            : 
     735                 :       1906 :     pad = GST_PAD_CAST (pads->data);
     736                 :            : 
     737                 :            :     /* get the private data, something is really wrong with the internal state
     738                 :            :      * when it is not there */
     739                 :       1906 :     pdata = g_object_get_qdata ((GObject *) pad, push_data);
     740         [ -  + ]:       1906 :     g_assert (pdata != NULL);
     741                 :            : 
     742         [ +  + ]:       1906 :     if (G_LIKELY (!pdata->pushed)) {
     743                 :            :       /* not yet pushed, release lock and start pushing */
     744                 :       1351 :       gst_object_ref (pad);
     745                 :       1351 :       GST_OBJECT_UNLOCK (tee);
     746                 :            : 
     747 [ -  + ][ #  # ]:       1351 :       GST_LOG_OBJECT (tee, "Starting to push %s %p",
     748                 :            :           is_list ? "list" : "buffer", data);
     749                 :            : 
     750                 :       1351 :       ret = gst_tee_do_push (tee, pad, data, is_list);
     751                 :            : 
     752         [ -  + ]:       1351 :       GST_LOG_OBJECT (tee, "Pushing item %p yielded result %s", data,
     753                 :            :           gst_flow_get_name (ret));
     754                 :            : 
     755                 :       1351 :       GST_OBJECT_LOCK (tee);
     756                 :            :       /* keep track of which pad we pushed and the result value. We need to do
     757                 :            :        * this before we release the refcount on the pad, the PushData is
     758                 :            :        * destroyed when the last ref of the pad goes away. */
     759                 :       1351 :       pdata->pushed = TRUE;
     760                 :       1351 :       pdata->result = ret;
     761                 :       1351 :       gst_object_unref (pad);
     762                 :            :     } else {
     763                 :            :       /* already pushed, use previous return value */
     764                 :        555 :       ret = pdata->result;
     765         [ -  + ]:        555 :       GST_LOG_OBJECT (tee, "pad already pushed with %s",
     766                 :            :           gst_flow_get_name (ret));
     767                 :            :     }
     768                 :            : 
     769                 :            :     /* before we go combining the return value, check if the pad list is still
     770                 :            :      * the same. It could be possible that the pad we just pushed was removed
     771                 :            :      * and the return value it not valid anymore */
     772         [ +  + ]:       1906 :     if (G_UNLIKELY (GST_ELEMENT_CAST (tee)->pads_cookie != cookie)) {
     773         [ -  + ]:        777 :       GST_LOG_OBJECT (tee, "pad list changed");
     774                 :            :       /* the list of pads changed, restart iteration. Pads that we already
     775                 :            :        * pushed on and are still in the new list, will not be pushed on
     776                 :            :        * again. */
     777                 :        777 :       goto restart;
     778                 :            :     }
     779                 :            : 
     780                 :            :     /* stop pushing more buffers when we have a fatal error */
     781 [ +  + ][ +  + ]:       1129 :     if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED))
     782                 :          7 :       goto error;
     783                 :            : 
     784                 :            :     /* keep all other return values, overwriting the previous one. */
     785         [ +  + ]:       1122 :     if (G_LIKELY (ret != GST_FLOW_NOT_LINKED)) {
     786         [ -  + ]:        654 :       GST_LOG_OBJECT (tee, "Replacing ret val %d with %d", cret, ret);
     787                 :        654 :       cret = ret;
     788                 :            :     }
     789         [ +  - ]:       1122 :     pads = g_list_next (pads);
     790                 :            :   }
     791                 :        601 :   GST_OBJECT_UNLOCK (tee);
     792                 :            : 
     793                 :        601 :   gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
     794                 :            : 
     795                 :            :   /* no need to unset gvalue */
     796                 :        601 :   return cret;
     797                 :            : 
     798                 :            :   /* ERRORS */
     799                 :            : no_pads:
     800                 :            :   {
     801         [ #  # ]:          0 :     GST_DEBUG_OBJECT (tee, "there are no pads, return not-linked");
     802                 :          0 :     ret = GST_FLOW_NOT_LINKED;
     803                 :          0 :     goto error;
     804                 :            :   }
     805                 :            : error:
     806                 :            :   {
     807         [ -  + ]:          7 :     GST_DEBUG_OBJECT (tee, "received error %s", gst_flow_get_name (ret));
     808                 :          7 :     GST_OBJECT_UNLOCK (tee);
     809                 :          7 :     gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
     810                 :       5019 :     return ret;
     811                 :            :   }
     812                 :            : }
     813                 :            : 
     814                 :            : static GstFlowReturn
     815                 :       5019 : gst_tee_chain (GstPad * pad, GstBuffer * buffer)
     816                 :            : {
     817                 :            :   GstFlowReturn res;
     818                 :            :   GstTee *tee;
     819                 :            : 
     820                 :       5019 :   tee = GST_TEE_CAST (GST_OBJECT_PARENT (pad));
     821                 :            : 
     822         [ -  + ]:       5019 :   GST_DEBUG_OBJECT (tee, "received buffer %p", buffer);
     823                 :            : 
     824                 :       5019 :   res = gst_tee_handle_data (tee, buffer, FALSE);
     825                 :            : 
     826         [ -  + ]:       5019 :   GST_DEBUG_OBJECT (tee, "handled buffer %s", gst_flow_get_name (res));
     827                 :            : 
     828                 :       5019 :   return res;
     829                 :            : }
     830                 :            : 
     831                 :            : static GstFlowReturn
     832                 :          0 : gst_tee_chain_list (GstPad * pad, GstBufferList * list)
     833                 :            : {
     834                 :            :   GstFlowReturn res;
     835                 :            :   GstTee *tee;
     836                 :            : 
     837                 :          0 :   tee = GST_TEE_CAST (gst_pad_get_parent (pad));
     838                 :            : 
     839         [ #  # ]:          0 :   GST_DEBUG_OBJECT (tee, "received list %p", list);
     840                 :            : 
     841                 :          0 :   res = gst_tee_handle_data (tee, list, TRUE);
     842                 :            : 
     843         [ #  # ]:          0 :   GST_DEBUG_OBJECT (tee, "handled list %s", gst_flow_get_name (res));
     844                 :            : 
     845                 :          0 :   gst_object_unref (tee);
     846                 :            : 
     847                 :          0 :   return res;
     848                 :            : }
     849                 :            : 
     850                 :            : static gboolean
     851                 :         26 : gst_tee_sink_activate_push (GstPad * pad, gboolean active)
     852                 :            : {
     853                 :            :   GstTee *tee;
     854                 :            : 
     855                 :         26 :   tee = GST_TEE (GST_OBJECT_PARENT (pad));
     856                 :            : 
     857                 :         26 :   GST_OBJECT_LOCK (tee);
     858                 :         26 :   tee->sink_mode = active && GST_ACTIVATE_PUSH;
     859                 :            : 
     860 [ +  + ][ -  + ]:         26 :   if (active && !tee->has_chain)
     861                 :          0 :     goto no_chain;
     862                 :         26 :   GST_OBJECT_UNLOCK (tee);
     863                 :            : 
     864                 :         26 :   return TRUE;
     865                 :            : 
     866                 :            :   /* ERRORS */
     867                 :            : no_chain:
     868                 :            :   {
     869                 :          0 :     GST_OBJECT_UNLOCK (tee);
     870         [ #  # ]:          0 :     GST_INFO_OBJECT (tee,
     871                 :            :         "Tee cannot operate in push mode with has-chain==FALSE");
     872                 :         26 :     return FALSE;
     873                 :            :   }
     874                 :            : }
     875                 :            : 
     876                 :            : static gboolean
     877                 :          0 : gst_tee_src_activate_pull (GstPad * pad, gboolean active)
     878                 :            : {
     879                 :            :   GstTee *tee;
     880                 :            :   gboolean res;
     881                 :            :   GstPad *sinkpad;
     882                 :            : 
     883                 :          0 :   tee = GST_TEE (gst_pad_get_parent (pad));
     884                 :            : 
     885                 :          0 :   GST_OBJECT_LOCK (tee);
     886                 :            : 
     887         [ #  # ]:          0 :   if (tee->pull_mode == GST_TEE_PULL_MODE_NEVER)
     888                 :          0 :     goto cannot_pull;
     889                 :            : 
     890 [ #  # ][ #  # ]:          0 :   if (tee->pull_mode == GST_TEE_PULL_MODE_SINGLE && active && tee->pull_pad)
                 [ #  # ]
     891                 :          0 :     goto cannot_pull_multiple_srcs;
     892                 :            : 
     893                 :          0 :   sinkpad = gst_object_ref (tee->sinkpad);
     894                 :            : 
     895                 :          0 :   GST_OBJECT_UNLOCK (tee);
     896                 :            : 
     897                 :          0 :   res = gst_pad_activate_pull (sinkpad, active);
     898                 :          0 :   gst_object_unref (sinkpad);
     899                 :            : 
     900         [ #  # ]:          0 :   if (!res)
     901                 :          0 :     goto sink_activate_failed;
     902                 :            : 
     903                 :          0 :   GST_OBJECT_LOCK (tee);
     904         [ #  # ]:          0 :   if (active) {
     905         [ #  # ]:          0 :     if (tee->pull_mode == GST_TEE_PULL_MODE_SINGLE)
     906                 :          0 :       tee->pull_pad = pad;
     907                 :            :   } else {
     908         [ #  # ]:          0 :     if (pad == tee->pull_pad)
     909                 :          0 :       tee->pull_pad = NULL;
     910                 :            :   }
     911                 :          0 :   tee->sink_mode = active && GST_ACTIVATE_PULL;
     912                 :          0 :   GST_OBJECT_UNLOCK (tee);
     913                 :            : 
     914                 :          0 :   gst_object_unref (tee);
     915                 :            : 
     916                 :          0 :   return res;
     917                 :            : 
     918                 :            :   /* ERRORS */
     919                 :            : cannot_pull:
     920                 :            :   {
     921                 :          0 :     GST_OBJECT_UNLOCK (tee);
     922         [ #  # ]:          0 :     GST_INFO_OBJECT (tee, "Cannot activate in pull mode, pull-mode "
     923                 :            :         "set to NEVER");
     924                 :          0 :     gst_object_unref (tee);
     925                 :          0 :     return FALSE;
     926                 :            :   }
     927                 :            : cannot_pull_multiple_srcs:
     928                 :            :   {
     929                 :          0 :     GST_OBJECT_UNLOCK (tee);
     930         [ #  # ]:          0 :     GST_INFO_OBJECT (tee, "Cannot activate multiple src pads in pull mode, "
     931                 :            :         "pull-mode set to SINGLE");
     932                 :          0 :     gst_object_unref (tee);
     933                 :          0 :     return FALSE;
     934                 :            :   }
     935                 :            : sink_activate_failed:
     936                 :            :   {
     937 [ #  # ][ #  # ]:          0 :     GST_INFO_OBJECT (tee, "Failed to %sactivate sink pad in pull mode",
     938                 :            :         active ? "" : "de");
     939                 :          0 :     gst_object_unref (tee);
     940                 :          0 :     return FALSE;
     941                 :            :   }
     942                 :            : }
     943                 :            : 
     944                 :            : static gboolean
     945                 :          0 : gst_tee_src_check_get_range (GstPad * pad)
     946                 :            : {
     947                 :            :   GstTee *tee;
     948                 :            :   gboolean res;
     949                 :            :   GstPad *sinkpad;
     950                 :            : 
     951                 :          0 :   tee = GST_TEE (gst_pad_get_parent (pad));
     952                 :            : 
     953                 :          0 :   GST_OBJECT_LOCK (tee);
     954                 :            : 
     955         [ #  # ]:          0 :   if (tee->pull_mode == GST_TEE_PULL_MODE_NEVER)
     956                 :          0 :     goto cannot_pull;
     957                 :            : 
     958 [ #  # ][ #  # ]:          0 :   if (tee->pull_mode == GST_TEE_PULL_MODE_SINGLE && tee->pull_pad)
     959                 :          0 :     goto cannot_pull_multiple_srcs;
     960                 :            : 
     961                 :          0 :   sinkpad = gst_object_ref (tee->sinkpad);
     962                 :            : 
     963                 :          0 :   GST_OBJECT_UNLOCK (tee);
     964                 :            : 
     965                 :          0 :   res = gst_pad_check_pull_range (sinkpad);
     966                 :          0 :   gst_object_unref (sinkpad);
     967                 :            : 
     968                 :          0 :   gst_object_unref (tee);
     969                 :            : 
     970                 :          0 :   return res;
     971                 :            : 
     972                 :            :   /* ERRORS */
     973                 :            : cannot_pull:
     974                 :            :   {
     975                 :          0 :     GST_OBJECT_UNLOCK (tee);
     976         [ #  # ]:          0 :     GST_INFO_OBJECT (tee, "Cannot activate in pull mode, pull-mode "
     977                 :            :         "set to NEVER");
     978                 :          0 :     gst_object_unref (tee);
     979                 :          0 :     return FALSE;
     980                 :            :   }
     981                 :            : cannot_pull_multiple_srcs:
     982                 :            :   {
     983                 :          0 :     GST_OBJECT_UNLOCK (tee);
     984         [ #  # ]:          0 :     GST_INFO_OBJECT (tee, "Cannot activate multiple src pads in pull mode, "
     985                 :            :         "pull-mode set to SINGLE");
     986                 :          0 :     gst_object_unref (tee);
     987                 :          0 :     return FALSE;
     988                 :            :   }
     989                 :            : }
     990                 :            : 
     991                 :            : static void
     992                 :          0 : gst_tee_push_eos (GstPad * pad, GstTee * tee)
     993                 :            : {
     994         [ #  # ]:          0 :   if (pad != tee->pull_pad)
     995                 :          0 :     gst_pad_push_event (pad, gst_event_new_eos ());
     996                 :          0 :   gst_object_unref (pad);
     997                 :          0 : }
     998                 :            : 
     999                 :            : static void
    1000                 :          0 : gst_tee_pull_eos (GstTee * tee)
    1001                 :            : {
    1002                 :            :   GstIterator *iter;
    1003                 :            : 
    1004                 :          0 :   iter = gst_element_iterate_src_pads (GST_ELEMENT (tee));
    1005                 :          0 :   gst_iterator_foreach (iter, (GFunc) gst_tee_push_eos, tee);
    1006                 :          0 :   gst_iterator_free (iter);
    1007                 :          0 : }
    1008                 :            : 
    1009                 :            : static GstFlowReturn
    1010                 :          0 : gst_tee_src_get_range (GstPad * pad, guint64 offset, guint length,
    1011                 :            :     GstBuffer ** buf)
    1012                 :            : {
    1013                 :            :   GstTee *tee;
    1014                 :            :   GstFlowReturn ret;
    1015                 :            : 
    1016                 :          0 :   tee = GST_TEE (gst_pad_get_parent (pad));
    1017                 :            : 
    1018                 :          0 :   ret = gst_pad_pull_range (tee->sinkpad, offset, length, buf);
    1019                 :            : 
    1020         [ #  # ]:          0 :   if (ret == GST_FLOW_OK)
    1021                 :          0 :     ret = gst_tee_handle_data (tee, gst_buffer_ref (*buf), FALSE);
    1022         [ #  # ]:          0 :   else if (ret == GST_FLOW_UNEXPECTED)
    1023                 :          0 :     gst_tee_pull_eos (tee);
    1024                 :            : 
    1025                 :          0 :   gst_object_unref (tee);
    1026                 :            : 
    1027                 :          0 :   return ret;
    1028                 :            : }

Generated by: LCOV version 1.9