LCOV - code coverage report
Current view: top level - plugins/elements - gstinputselector.c (source / functions) Hit Total Coverage
Test: GStreamer 0.10.32.1 Lines: 310 591 52.5 %
Date: 2011-03-25 Functions: 27 41 65.9 %
Branches: 86 407 21.1 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer input selector
       2                 :            :  * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
       3                 :            :  * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
       4                 :            :  * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
       5                 :            :  * Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
       6                 :            :  * Copyright (C) 2007 Andy Wingo <wingo@pobox.com>
       7                 :            :  * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
       8                 :            :  * Copyright (C) 2011 Sebastian Dröge <sebastian.droege@collabora.co.uk>
       9                 :            :  *
      10                 :            :  * This library is free software; you can redistribute it and/or
      11                 :            :  * modify it under the terms of the GNU Library General Public
      12                 :            :  * License as published by the Free Software Foundation; either
      13                 :            :  * version 2 of the License, or (at your option) any later version.
      14                 :            :  *
      15                 :            :  * This library is distributed in the hope that it will be useful,
      16                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18                 :            :  * Library General Public License for more details.
      19                 :            :  *
      20                 :            :  * You should have received a copy of the GNU Library General Public
      21                 :            :  * License along with this library; if not, write to the
      22                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      23                 :            :  * Boston, MA 02111-1307, USA.
      24                 :            :  */
      25                 :            : 
      26                 :            : /**
      27                 :            :  * SECTION:element-input-selector
      28                 :            :  * @see_also: #GstOutputSelector
      29                 :            :  *
      30                 :            :  * Direct one out of N input streams to the output pad.
      31                 :            :  *
      32                 :            :  * The input pads are from a GstPad subclass and have additional
      33                 :            :  * properties, which users may find useful, namely:
      34                 :            :  *
      35                 :            :  * <itemizedlist>
      36                 :            :  * <listitem>
      37                 :            :  * "running-time": Running time of stream on pad (#gint64)
      38                 :            :  * </listitem>
      39                 :            :  * <listitem>
      40                 :            :  * "tags": The currently active tags on the pad (#GstTagList, boxed type)
      41                 :            :  * </listitem>
      42                 :            :  * <listitem>
      43                 :            :  * "active": If the pad is currently active (#gboolean)
      44                 :            :  * </listitem>
      45                 :            :  * <listitem>
      46                 :            :  * "always-ok" : Make an inactive pads return #GST_FLOW_OK instead of
      47                 :            :  * #GST_FLOW_NOT_LINKED
      48                 :            :  * </listitem>
      49                 :            :  * </itemizedlist>
      50                 :            :  *
      51                 :            :  * Since: 0.10.32
      52                 :            :  */
      53                 :            : 
      54                 :            : #ifdef HAVE_CONFIG_H
      55                 :            : #include "config.h"
      56                 :            : #endif
      57                 :            : 
      58                 :            : #include <string.h>
      59                 :            : 
      60                 :            : #include "gstinputselector.h"
      61                 :            : 
      62                 :            : GST_DEBUG_CATEGORY_STATIC (input_selector_debug);
      63                 :            : #define GST_CAT_DEFAULT input_selector_debug
      64                 :            : 
      65                 :            : #if GLIB_CHECK_VERSION(2, 26, 0)
      66                 :            : #define NOTIFY_MUTEX_LOCK()
      67                 :            : #define NOTIFY_MUTEX_UNLOCK()
      68                 :            : #else
      69                 :            : static GStaticRecMutex notify_mutex = G_STATIC_REC_MUTEX_INIT;
      70                 :            : #define NOTIFY_MUTEX_LOCK() g_static_rec_mutex_lock (&notify_mutex)
      71                 :            : #define NOTIFY_MUTEX_UNLOCK() g_static_rec_mutex_unlock (&notify_mutex)
      72                 :            : #endif
      73                 :            : 
      74                 :            : #define GST_INPUT_SELECTOR_GET_LOCK(sel) (((GstInputSelector*)(sel))->lock)
      75                 :            : #define GST_INPUT_SELECTOR_GET_COND(sel) (((GstInputSelector*)(sel))->cond)
      76                 :            : #define GST_INPUT_SELECTOR_LOCK(sel) (g_mutex_lock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
      77                 :            : #define GST_INPUT_SELECTOR_UNLOCK(sel) (g_mutex_unlock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
      78                 :            : #define GST_INPUT_SELECTOR_WAIT(sel) (g_cond_wait (GST_INPUT_SELECTOR_GET_COND(sel), \
      79                 :            :       GST_INPUT_SELECTOR_GET_LOCK(sel)))
      80                 :            : #define GST_INPUT_SELECTOR_BROADCAST(sel) (g_cond_broadcast (GST_INPUT_SELECTOR_GET_COND(sel)))
      81                 :            : 
      82                 :            : static GstStaticPadTemplate gst_input_selector_sink_factory =
      83                 :            : GST_STATIC_PAD_TEMPLATE ("sink%d",
      84                 :            :     GST_PAD_SINK,
      85                 :            :     GST_PAD_REQUEST,
      86                 :            :     GST_STATIC_CAPS_ANY);
      87                 :            : 
      88                 :            : static GstStaticPadTemplate gst_input_selector_src_factory =
      89                 :            : GST_STATIC_PAD_TEMPLATE ("src",
      90                 :            :     GST_PAD_SRC,
      91                 :            :     GST_PAD_ALWAYS,
      92                 :            :     GST_STATIC_CAPS_ANY);
      93                 :            : 
      94                 :            : enum
      95                 :            : {
      96                 :            :   PROP_0,
      97                 :            :   PROP_N_PADS,
      98                 :            :   PROP_ACTIVE_PAD
      99                 :            : };
     100                 :            : 
     101                 :            : #define DEFAULT_PAD_ALWAYS_OK TRUE
     102                 :            : 
     103                 :            : enum
     104                 :            : {
     105                 :            :   PROP_PAD_0,
     106                 :            :   PROP_PAD_RUNNING_TIME,
     107                 :            :   PROP_PAD_TAGS,
     108                 :            :   PROP_PAD_ACTIVE,
     109                 :            :   PROP_PAD_ALWAYS_OK
     110                 :            : };
     111                 :            : 
     112                 :            : enum
     113                 :            : {
     114                 :            :   /* methods */
     115                 :            :   SIGNAL_BLOCK,
     116                 :            :   SIGNAL_SWITCH,
     117                 :            :   LAST_SIGNAL
     118                 :            : };
     119                 :            : static guint gst_input_selector_signals[LAST_SIGNAL] = { 0 };
     120                 :            : 
     121                 :            : static inline gboolean gst_input_selector_is_active_sinkpad (GstInputSelector *
     122                 :            :     sel, GstPad * pad);
     123                 :            : static GstPad *gst_input_selector_activate_sinkpad (GstInputSelector * sel,
     124                 :            :     GstPad * pad);
     125                 :            : static GstPad *gst_input_selector_get_linked_pad (GstPad * pad,
     126                 :            :     gboolean strict);
     127                 :            : 
     128                 :            : #define GST_TYPE_SELECTOR_PAD \
     129                 :            :   (gst_selector_pad_get_type())
     130                 :            : #define GST_SELECTOR_PAD(obj) \
     131                 :            :   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SELECTOR_PAD, GstSelectorPad))
     132                 :            : #define GST_SELECTOR_PAD_CLASS(klass) \
     133                 :            :   (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SELECTOR_PAD, GstSelectorPadClass))
     134                 :            : #define GST_IS_SELECTOR_PAD(obj) \
     135                 :            :   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SELECTOR_PAD))
     136                 :            : #define GST_IS_SELECTOR_PAD_CLASS(klass) \
     137                 :            :   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SELECTOR_PAD))
     138                 :            : #define GST_SELECTOR_PAD_CAST(obj) \
     139                 :            :   ((GstSelectorPad *)(obj))
     140                 :            : 
     141                 :            : typedef struct _GstSelectorPad GstSelectorPad;
     142                 :            : typedef struct _GstSelectorPadClass GstSelectorPadClass;
     143                 :            : 
     144                 :            : struct _GstSelectorPad
     145                 :            : {
     146                 :            :   GstPad parent;
     147                 :            : 
     148                 :            :   gboolean active;              /* when buffer have passed the pad */
     149                 :            :   gboolean pushed;              /* when buffer was pushed downstream since activation */
     150                 :            :   gboolean eos;                 /* when EOS has been received */
     151                 :            :   gboolean eos_sent;            /* when EOS was sent downstream */
     152                 :            :   gboolean discont;             /* after switching we create a discont */
     153                 :            :   gboolean flushing;            /* set after flush-start and before flush-stop */
     154                 :            :   gboolean always_ok;
     155                 :            :   GstSegment segment;           /* the current segment on the pad */
     156                 :            :   GstTagList *tags;             /* last tags received on the pad */
     157                 :            : 
     158                 :            :   gboolean segment_pending;
     159                 :            : };
     160                 :            : 
     161                 :            : struct _GstSelectorPadClass
     162                 :            : {
     163                 :            :   GstPadClass parent;
     164                 :            : };
     165                 :            : 
     166                 :            : static void gst_selector_pad_class_init (GstSelectorPadClass * klass);
     167                 :            : static void gst_selector_pad_init (GstSelectorPad * pad);
     168                 :            : static void gst_selector_pad_finalize (GObject * object);
     169                 :            : static void gst_selector_pad_get_property (GObject * object,
     170                 :            :     guint prop_id, GValue * value, GParamSpec * pspec);
     171                 :            : static void gst_selector_pad_set_property (GObject * object,
     172                 :            :     guint prop_id, const GValue * value, GParamSpec * pspec);
     173                 :            : 
     174                 :            : static GstPadClass *selector_pad_parent_class = NULL;
     175                 :            : 
     176                 :            : static gint64 gst_selector_pad_get_running_time (GstSelectorPad * pad);
     177                 :            : static void gst_selector_pad_reset (GstSelectorPad * pad);
     178                 :            : static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
     179                 :            : static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
     180                 :            : static gboolean gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps);
     181                 :            : static GstIterator *gst_selector_pad_iterate_linked_pads (GstPad * pad);
     182                 :            : static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
     183                 :            : static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
     184                 :            :     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
     185                 :            : 
     186                 :            : static GType
     187                 :         24 : gst_selector_pad_get_type (void)
     188                 :            : {
     189                 :            :   static volatile gsize selector_pad_type = 0;
     190                 :            :   static const GTypeInfo selector_pad_info = {
     191                 :            :     sizeof (GstSelectorPadClass),
     192                 :            :     NULL,
     193                 :            :     NULL,
     194                 :            :     (GClassInitFunc) gst_selector_pad_class_init,
     195                 :            :     NULL,
     196                 :            :     NULL,
     197                 :            :     sizeof (GstSelectorPad),
     198                 :            :     0,
     199                 :            :     (GInstanceInitFunc) gst_selector_pad_init,
     200                 :            :   };
     201                 :            : 
     202         [ +  + ]:         24 :   if (g_once_init_enter (&selector_pad_type)) {
     203                 :          1 :     GType tmp = g_type_register_static (GST_TYPE_PAD, "GstSelectorPad",
     204                 :            :         &selector_pad_info, 0);
     205                 :          1 :     g_once_init_leave (&selector_pad_type, tmp);
     206                 :            :   }
     207                 :            : 
     208                 :         24 :   return (GType) selector_pad_type;
     209                 :            : }
     210                 :            : 
     211                 :            : static void
     212                 :          1 : gst_selector_pad_class_init (GstSelectorPadClass * klass)
     213                 :            : {
     214                 :            :   GObjectClass *gobject_class;
     215                 :            : 
     216                 :          1 :   gobject_class = (GObjectClass *) klass;
     217                 :            : 
     218                 :          1 :   selector_pad_parent_class = g_type_class_peek_parent (klass);
     219                 :            : 
     220                 :          1 :   gobject_class->finalize = gst_selector_pad_finalize;
     221                 :            : 
     222                 :          1 :   gobject_class->get_property = gst_selector_pad_get_property;
     223                 :          1 :   gobject_class->set_property = gst_selector_pad_set_property;
     224                 :            : 
     225                 :          1 :   g_object_class_install_property (gobject_class, PROP_PAD_RUNNING_TIME,
     226                 :            :       g_param_spec_int64 ("running-time", "Running time",
     227                 :            :           "Running time of stream on pad", 0, G_MAXINT64, 0,
     228                 :            :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     229                 :          1 :   g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
     230                 :            :       g_param_spec_boxed ("tags", "Tags",
     231                 :            :           "The currently active tags on the pad", GST_TYPE_TAG_LIST,
     232                 :            :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     233                 :          1 :   g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
     234                 :            :       g_param_spec_boolean ("active", "Active",
     235                 :            :           "If the pad is currently active", FALSE,
     236                 :            :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     237                 :            :   /* FIXME: better property name? */
     238                 :          1 :   g_object_class_install_property (gobject_class, PROP_PAD_ALWAYS_OK,
     239                 :            :       g_param_spec_boolean ("always-ok", "Always OK",
     240                 :            :           "Make an inactive pad return OK instead of NOT_LINKED",
     241                 :            :           DEFAULT_PAD_ALWAYS_OK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     242                 :          1 : }
     243                 :            : 
     244                 :            : static void
     245                 :         24 : gst_selector_pad_init (GstSelectorPad * pad)
     246                 :            : {
     247                 :         24 :   pad->always_ok = DEFAULT_PAD_ALWAYS_OK;
     248                 :         24 :   gst_selector_pad_reset (pad);
     249                 :         24 : }
     250                 :            : 
     251                 :            : static void
     252                 :         24 : gst_selector_pad_finalize (GObject * object)
     253                 :            : {
     254                 :            :   GstSelectorPad *pad;
     255                 :            : 
     256                 :         24 :   pad = GST_SELECTOR_PAD_CAST (object);
     257                 :            : 
     258         [ -  + ]:         24 :   if (pad->tags)
     259                 :          0 :     gst_tag_list_free (pad->tags);
     260                 :            : 
     261                 :         24 :   G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object);
     262                 :         24 : }
     263                 :            : 
     264                 :            : static void
     265                 :          0 : gst_selector_pad_set_property (GObject * object, guint prop_id,
     266                 :            :     const GValue * value, GParamSpec * pspec)
     267                 :            : {
     268                 :          0 :   GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
     269                 :            : 
     270         [ #  # ]:          0 :   switch (prop_id) {
     271                 :            :     case PROP_PAD_ALWAYS_OK:
     272                 :          0 :       GST_OBJECT_LOCK (object);
     273                 :          0 :       spad->always_ok = g_value_get_boolean (value);
     274                 :          0 :       GST_OBJECT_UNLOCK (object);
     275                 :          0 :       break;
     276                 :            :     default:
     277                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     278                 :          0 :       break;
     279                 :            :   }
     280                 :          0 : }
     281                 :            : 
     282                 :            : static void
     283                 :          0 : gst_selector_pad_get_property (GObject * object, guint prop_id,
     284                 :            :     GValue * value, GParamSpec * pspec)
     285                 :            : {
     286                 :          0 :   GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
     287                 :            : 
     288   [ #  #  #  #  :          0 :   switch (prop_id) {
                      # ]
     289                 :            :     case PROP_PAD_RUNNING_TIME:
     290                 :          0 :       g_value_set_int64 (value, gst_selector_pad_get_running_time (spad));
     291                 :          0 :       break;
     292                 :            :     case PROP_PAD_TAGS:
     293                 :          0 :       GST_OBJECT_LOCK (object);
     294                 :          0 :       g_value_set_boxed (value, spad->tags);
     295                 :          0 :       GST_OBJECT_UNLOCK (object);
     296                 :          0 :       break;
     297                 :            :     case PROP_PAD_ACTIVE:
     298                 :            :     {
     299                 :            :       GstInputSelector *sel;
     300                 :            : 
     301                 :          0 :       sel = GST_INPUT_SELECTOR (gst_pad_get_parent (spad));
     302                 :          0 :       g_value_set_boolean (value, gst_input_selector_is_active_sinkpad (sel,
     303                 :            :               GST_PAD_CAST (spad)));
     304                 :          0 :       gst_object_unref (sel);
     305                 :          0 :       break;
     306                 :            :     }
     307                 :            :     case PROP_PAD_ALWAYS_OK:
     308                 :          0 :       GST_OBJECT_LOCK (object);
     309                 :          0 :       g_value_set_boolean (value, spad->always_ok);
     310                 :          0 :       GST_OBJECT_UNLOCK (object);
     311                 :          0 :       break;
     312                 :            :     default:
     313                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     314                 :          0 :       break;
     315                 :            :   }
     316                 :          0 : }
     317                 :            : 
     318                 :            : static gint64
     319                 :         12 : gst_selector_pad_get_running_time (GstSelectorPad * pad)
     320                 :            : {
     321                 :         12 :   gint64 ret = 0;
     322                 :            : 
     323                 :         12 :   GST_OBJECT_LOCK (pad);
     324         [ +  + ]:         12 :   if (pad->active) {
     325                 :          9 :     gint64 last_stop = pad->segment.last_stop;
     326                 :            : 
     327         [ +  - ]:          9 :     if (last_stop >= 0)
     328                 :          9 :       ret = gst_segment_to_running_time (&pad->segment, GST_FORMAT_TIME,
     329                 :            :           last_stop);
     330                 :            :   }
     331                 :         12 :   GST_OBJECT_UNLOCK (pad);
     332                 :            : 
     333 [ -  + ][ #  # ]:         12 :   GST_DEBUG_OBJECT (pad, "running time: %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     334                 :            :       GST_TIME_ARGS (ret));
     335                 :            : 
     336                 :         12 :   return ret;
     337                 :            : }
     338                 :            : 
     339                 :            : static void
     340                 :         48 : gst_selector_pad_reset (GstSelectorPad * pad)
     341                 :            : {
     342                 :         48 :   GST_OBJECT_LOCK (pad);
     343                 :         48 :   pad->active = FALSE;
     344                 :         48 :   pad->pushed = FALSE;
     345                 :         48 :   pad->eos = FALSE;
     346                 :         48 :   pad->eos_sent = FALSE;
     347                 :         48 :   pad->segment_pending = FALSE;
     348                 :         48 :   pad->discont = FALSE;
     349                 :         48 :   pad->flushing = FALSE;
     350                 :         48 :   gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
     351                 :         48 :   GST_OBJECT_UNLOCK (pad);
     352                 :         48 : }
     353                 :            : 
     354                 :            : /* strictly get the linked pad from the sinkpad. If the pad is active we return
     355                 :            :  * the srcpad else we return NULL */
     356                 :            : static GstIterator *
     357                 :          0 : gst_selector_pad_iterate_linked_pads (GstPad * pad)
     358                 :            : {
     359                 :          0 :   GstInputSelector *sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
     360                 :            :   GstPad *otherpad;
     361                 :            :   GstIterator *it;
     362                 :            : 
     363                 :          0 :   otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
     364                 :          0 :   it = gst_iterator_new_single (GST_TYPE_PAD, otherpad,
     365                 :            :       (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
     366                 :            : 
     367         [ #  # ]:          0 :   if (otherpad)
     368                 :          0 :     gst_object_unref (otherpad);
     369                 :          0 :   gst_object_unref (sel);
     370                 :            : 
     371                 :          0 :   return it;
     372                 :            : }
     373                 :            : 
     374                 :            : static gboolean
     375                 :          0 : gst_selector_pad_event (GstPad * pad, GstEvent * event)
     376                 :            : {
     377                 :          0 :   gboolean res = TRUE;
     378                 :            :   gboolean forward;
     379                 :            :   GstInputSelector *sel;
     380                 :            :   GstSelectorPad *selpad;
     381                 :            :   GstPad *prev_active_sinkpad;
     382                 :            :   GstPad *active_sinkpad;
     383                 :            : 
     384                 :          0 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
     385                 :          0 :   selpad = GST_SELECTOR_PAD_CAST (pad);
     386                 :            : 
     387                 :          0 :   GST_INPUT_SELECTOR_LOCK (sel);
     388                 :          0 :   prev_active_sinkpad = sel->active_sinkpad;
     389                 :          0 :   active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
     390                 :            : 
     391                 :            :   /* only forward if we are dealing with the active sinkpad */
     392                 :          0 :   forward = (pad == active_sinkpad);
     393                 :          0 :   GST_INPUT_SELECTOR_UNLOCK (sel);
     394                 :            : 
     395 [ #  # ][ #  # ]:          0 :   if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad) {
     396                 :            :     NOTIFY_MUTEX_LOCK ();
     397                 :          0 :     g_object_notify (G_OBJECT (sel), "active-pad");
     398                 :            :     NOTIFY_MUTEX_UNLOCK ();
     399                 :            :   }
     400                 :            : 
     401   [ #  #  #  #  :          0 :   switch (GST_EVENT_TYPE (event)) {
                   #  # ]
     402                 :            :     case GST_EVENT_FLUSH_START:
     403                 :            :       /* Unblock the pad if it's waiting */
     404                 :          0 :       GST_INPUT_SELECTOR_LOCK (sel);
     405                 :          0 :       selpad->flushing = TRUE;
     406                 :          0 :       GST_INPUT_SELECTOR_BROADCAST (sel);
     407                 :          0 :       GST_INPUT_SELECTOR_UNLOCK (sel);
     408                 :          0 :       break;
     409                 :            :     case GST_EVENT_FLUSH_STOP:
     410                 :          0 :       GST_INPUT_SELECTOR_LOCK (sel);
     411                 :          0 :       gst_selector_pad_reset (selpad);
     412                 :          0 :       sel->pending_close = FALSE;
     413                 :          0 :       GST_INPUT_SELECTOR_UNLOCK (sel);
     414                 :          0 :       break;
     415                 :            :     case GST_EVENT_NEWSEGMENT:
     416                 :            :     {
     417                 :            :       gboolean update;
     418                 :            :       GstFormat format;
     419                 :            :       gdouble rate, arate;
     420                 :            :       gint64 start, stop, time;
     421                 :            : 
     422                 :          0 :       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
     423                 :            :           &start, &stop, &time);
     424                 :            : 
     425         [ #  # ]:          0 :       GST_DEBUG_OBJECT (pad,
     426                 :            :           "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
     427                 :            :           "format %d, "
     428                 :            :           "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
     429                 :            :           G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
     430                 :            : 
     431                 :          0 :       GST_INPUT_SELECTOR_LOCK (sel);
     432                 :          0 :       GST_OBJECT_LOCK (selpad);
     433                 :          0 :       gst_segment_set_newsegment_full (&selpad->segment, update,
     434                 :            :           rate, arate, format, start, stop, time);
     435                 :          0 :       GST_OBJECT_UNLOCK (selpad);
     436                 :            : 
     437                 :            :       /* If we aren't forwarding the event because the pad is not the
     438                 :            :        * active_sinkpad, then set the flag on the pad
     439                 :            :        * that says a segment needs sending if/when that pad is activated.
     440                 :            :        * For all other cases, we send the event immediately, which makes
     441                 :            :        * sparse streams and other segment updates work correctly downstream.
     442                 :            :        */
     443         [ #  # ]:          0 :       if (!forward)
     444                 :          0 :         selpad->segment_pending = TRUE;
     445                 :            : 
     446                 :          0 :       GST_INPUT_SELECTOR_UNLOCK (sel);
     447                 :          0 :       break;
     448                 :            :     }
     449                 :            :     case GST_EVENT_TAG:
     450                 :            :     {
     451                 :            :       GstTagList *tags, *oldtags, *newtags;
     452                 :            : 
     453                 :          0 :       gst_event_parse_tag (event, &tags);
     454                 :            : 
     455                 :          0 :       GST_OBJECT_LOCK (selpad);
     456                 :          0 :       oldtags = selpad->tags;
     457                 :            : 
     458                 :          0 :       newtags = gst_tag_list_merge (oldtags, tags, GST_TAG_MERGE_REPLACE);
     459                 :          0 :       selpad->tags = newtags;
     460         [ #  # ]:          0 :       if (oldtags)
     461                 :          0 :         gst_tag_list_free (oldtags);
     462         [ #  # ]:          0 :       GST_DEBUG_OBJECT (pad, "received tags %" GST_PTR_FORMAT, newtags);
     463                 :          0 :       GST_OBJECT_UNLOCK (selpad);
     464                 :            : 
     465                 :          0 :       g_object_notify (G_OBJECT (selpad), "tags");
     466                 :          0 :       break;
     467                 :            :     }
     468                 :            :     case GST_EVENT_EOS:
     469                 :          0 :       selpad->eos = TRUE;
     470                 :            : 
     471         [ #  # ]:          0 :       if (forward) {
     472                 :          0 :         selpad->eos_sent = TRUE;
     473                 :            :       } else {
     474                 :            :         GstSelectorPad *tmp;
     475                 :            : 
     476                 :            :         /* If the active sinkpad is in EOS state but EOS
     477                 :            :          * was not sent downstream this means that the pad
     478                 :            :          * got EOS before it was set as active pad and that
     479                 :            :          * the previously active pad got EOS after it was
     480                 :            :          * active
     481                 :            :          */
     482                 :          0 :         GST_INPUT_SELECTOR_LOCK (sel);
     483                 :          0 :         active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
     484                 :          0 :         tmp = GST_SELECTOR_PAD (active_sinkpad);
     485 [ #  # ][ #  # ]:          0 :         forward = (tmp->eos && !tmp->eos_sent);
     486                 :          0 :         tmp->eos_sent = TRUE;
     487                 :          0 :         GST_INPUT_SELECTOR_UNLOCK (sel);
     488                 :            :       }
     489         [ #  # ]:          0 :       GST_DEBUG_OBJECT (pad, "received EOS");
     490                 :          0 :       break;
     491                 :            :     default:
     492                 :          0 :       break;
     493                 :            :   }
     494         [ #  # ]:          0 :   if (forward) {
     495         [ #  # ]:          0 :     GST_DEBUG_OBJECT (pad, "forwarding event");
     496                 :          0 :     res = gst_pad_push_event (sel->srcpad, event);
     497                 :            :   } else
     498                 :          0 :     gst_event_unref (event);
     499                 :            : 
     500                 :          0 :   gst_object_unref (sel);
     501                 :            : 
     502                 :          0 :   return res;
     503                 :            : }
     504                 :            : 
     505                 :            : static GstCaps *
     506                 :         24 : gst_selector_pad_getcaps (GstPad * pad)
     507                 :            : {
     508                 :            :   GstInputSelector *sel;
     509                 :            :   GstCaps *caps;
     510                 :            : 
     511                 :         24 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
     512                 :            : 
     513         [ -  + ]:         24 :   GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
     514                 :         24 :   caps = gst_pad_peer_get_caps_reffed (sel->srcpad);
     515         [ -  + ]:         24 :   if (caps == NULL)
     516                 :          0 :     caps = gst_caps_new_any ();
     517                 :            : 
     518                 :         24 :   gst_object_unref (sel);
     519                 :            : 
     520                 :         24 :   return caps;
     521                 :            : }
     522                 :            : 
     523                 :            : static gboolean
     524                 :          0 : gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps)
     525                 :            : {
     526                 :            :   GstInputSelector *sel;
     527                 :            :   gboolean res;
     528                 :            : 
     529                 :          0 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
     530                 :            : 
     531         [ #  # ]:          0 :   GST_DEBUG_OBJECT (sel, "Checking acceptcaps of srcpad peer");
     532                 :          0 :   res = gst_pad_peer_accept_caps (sel->srcpad, caps);
     533                 :          0 :   gst_object_unref (sel);
     534                 :            : 
     535                 :          0 :   return res;
     536                 :            : }
     537                 :            : 
     538                 :            : static GstFlowReturn
     539                 :          0 : gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
     540                 :            :     guint size, GstCaps * caps, GstBuffer ** buf)
     541                 :            : {
     542                 :            :   GstInputSelector *sel;
     543                 :            :   GstFlowReturn result;
     544                 :            :   GstPad *active_sinkpad;
     545                 :            :   GstPad *prev_active_sinkpad;
     546                 :            :   GstSelectorPad *selpad;
     547                 :            : 
     548                 :          0 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
     549                 :          0 :   selpad = GST_SELECTOR_PAD_CAST (pad);
     550                 :            : 
     551         [ #  # ]:          0 :   GST_LOG_OBJECT (pad, "received alloc");
     552                 :            : 
     553                 :          0 :   GST_INPUT_SELECTOR_LOCK (sel);
     554                 :          0 :   prev_active_sinkpad = sel->active_sinkpad;
     555                 :          0 :   active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
     556                 :            : 
     557         [ #  # ]:          0 :   if (pad != active_sinkpad)
     558                 :          0 :     goto not_active;
     559                 :            : 
     560                 :          0 :   GST_INPUT_SELECTOR_UNLOCK (sel);
     561                 :            : 
     562 [ #  # ][ #  # ]:          0 :   if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad) {
     563                 :            :     NOTIFY_MUTEX_LOCK ();
     564                 :          0 :     g_object_notify (G_OBJECT (sel), "active-pad");
     565                 :            :     NOTIFY_MUTEX_UNLOCK ();
     566                 :            :   }
     567                 :            : 
     568                 :          0 :   result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf);
     569                 :            : 
     570                 :            : done:
     571                 :          0 :   gst_object_unref (sel);
     572                 :            : 
     573                 :          0 :   return result;
     574                 :            : 
     575                 :            :   /* ERRORS */
     576                 :            : not_active:
     577                 :            :   {
     578                 :          0 :     gboolean active_pad_pushed = GST_SELECTOR_PAD_CAST (active_sinkpad)->pushed;
     579                 :            : 
     580                 :          0 :     GST_INPUT_SELECTOR_UNLOCK (sel);
     581                 :            : 
     582                 :            :     /* unselected pad, perform fallback alloc or return unlinked when
     583                 :            :      * asked */
     584                 :          0 :     GST_OBJECT_LOCK (selpad);
     585 [ #  # ][ #  # ]:          0 :     if (selpad->always_ok || !active_pad_pushed) {
     586         [ #  # ]:          0 :       GST_DEBUG_OBJECT (pad, "Not selected, performing fallback allocation");
     587                 :          0 :       *buf = NULL;
     588                 :          0 :       result = GST_FLOW_OK;
     589                 :            :     } else {
     590         [ #  # ]:          0 :       GST_DEBUG_OBJECT (pad, "Not selected, return NOT_LINKED");
     591                 :          0 :       result = GST_FLOW_NOT_LINKED;
     592                 :            :     }
     593                 :          0 :     GST_OBJECT_UNLOCK (selpad);
     594                 :            : 
     595                 :          0 :     goto done;
     596                 :            :   }
     597                 :            : }
     598                 :            : 
     599                 :            : /* must be called with the SELECTOR_LOCK, will block while the pad is blocked 
     600                 :            :  * or return TRUE when flushing */
     601                 :            : static gboolean
     602                 :         84 : gst_input_selector_wait (GstInputSelector * self, GstSelectorPad * pad)
     603                 :            : {
     604 [ -  + ][ #  # ]:         84 :   while (self->blocked && !self->flushing && !pad->flushing) {
                 [ #  # ]
     605                 :            :     /* we can be unlocked here when we are shutting down (flushing) or when we
     606                 :            :      * get unblocked */
     607                 :          0 :     GST_INPUT_SELECTOR_WAIT (self);
     608                 :            :   }
     609                 :         84 :   return self->flushing;
     610                 :            : }
     611                 :            : 
     612                 :            : static GstFlowReturn
     613                 :         84 : gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
     614                 :            : {
     615                 :            :   GstInputSelector *sel;
     616                 :            :   GstFlowReturn res;
     617                 :            :   GstPad *active_sinkpad;
     618                 :            :   GstPad *prev_active_sinkpad;
     619                 :            :   GstSelectorPad *selpad;
     620                 :            :   GstClockTime start_time;
     621                 :            :   GstSegment *seg;
     622                 :         84 :   GstEvent *close_event = NULL, *start_event = NULL;
     623                 :            :   GstCaps *caps;
     624                 :            : 
     625                 :         84 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
     626                 :         84 :   selpad = GST_SELECTOR_PAD_CAST (pad);
     627                 :         84 :   seg = &selpad->segment;
     628                 :            : 
     629                 :         84 :   GST_INPUT_SELECTOR_LOCK (sel);
     630                 :            :   /* wait or check for flushing */
     631         [ -  + ]:         84 :   if (gst_input_selector_wait (sel, selpad))
     632                 :          0 :     goto flushing;
     633                 :            : 
     634         [ -  + ]:         84 :   GST_LOG_OBJECT (pad, "getting active pad");
     635                 :            : 
     636                 :         84 :   prev_active_sinkpad = sel->active_sinkpad;
     637                 :         84 :   active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
     638                 :            : 
     639                 :            :   /* update the segment on the srcpad */
     640                 :         84 :   start_time = GST_BUFFER_TIMESTAMP (buf);
     641         [ -  + ]:         84 :   if (GST_CLOCK_TIME_IS_VALID (start_time)) {
     642 [ #  # ][ #  # ]:          0 :     GST_LOG_OBJECT (pad, "received start time %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     643                 :            :         GST_TIME_ARGS (start_time));
     644         [ #  # ]:          0 :     if (GST_BUFFER_DURATION_IS_VALID (buf))
     645 [ #  # ][ #  # ]:          0 :       GST_LOG_OBJECT (pad, "received end time %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     646                 :            :           GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf)));
     647                 :            : 
     648                 :          0 :     GST_OBJECT_LOCK (pad);
     649                 :          0 :     gst_segment_set_last_stop (seg, seg->format, start_time);
     650                 :          0 :     GST_OBJECT_UNLOCK (pad);
     651                 :            :   }
     652                 :            : 
     653                 :            :   /* Ignore buffers from pads except the selected one */
     654         [ +  + ]:         84 :   if (pad != active_sinkpad)
     655                 :         48 :     goto ignore;
     656                 :            : 
     657         [ +  + ]:         36 :   if (G_UNLIKELY (sel->pending_close)) {
     658                 :          9 :     GstSegment *cseg = &sel->segment;
     659                 :            : 
     660         [ -  + ]:          9 :     GST_DEBUG_OBJECT (sel,
     661                 :            :         "pushing close NEWSEGMENT update %d, rate %lf, applied rate %lf, "
     662                 :            :         "format %d, "
     663                 :            :         "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
     664                 :            :         G_GINT64_FORMAT, TRUE, cseg->rate, cseg->applied_rate, cseg->format,
     665                 :            :         cseg->start, cseg->stop, cseg->time);
     666                 :            : 
     667                 :            :     /* create update segment */
     668                 :          9 :     close_event = gst_event_new_new_segment_full (TRUE, cseg->rate,
     669                 :            :         cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time);
     670                 :            : 
     671                 :          9 :     sel->pending_close = FALSE;
     672                 :            :   }
     673                 :            :   /* if we have a pending segment, push it out now */
     674         [ +  + ]:         36 :   if (G_UNLIKELY (selpad->segment_pending)) {
     675         [ -  + ]:          9 :     GST_DEBUG_OBJECT (pad,
     676                 :            :         "pushing pending NEWSEGMENT update %d, rate %lf, applied rate %lf, "
     677                 :            :         "format %d, "
     678                 :            :         "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
     679                 :            :         G_GINT64_FORMAT, FALSE, seg->rate, seg->applied_rate, seg->format,
     680                 :            :         seg->start, seg->stop, seg->time);
     681                 :            : 
     682                 :          9 :     start_event = gst_event_new_new_segment_full (FALSE, seg->rate,
     683                 :            :         seg->applied_rate, seg->format, seg->start, seg->stop, seg->time);
     684                 :            : 
     685                 :          9 :     selpad->segment_pending = FALSE;
     686                 :            :   }
     687                 :         36 :   GST_INPUT_SELECTOR_UNLOCK (sel);
     688                 :            : 
     689 [ -  + ][ #  # ]:         36 :   if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad) {
     690                 :            :     NOTIFY_MUTEX_LOCK ();
     691                 :          0 :     g_object_notify (G_OBJECT (sel), "active-pad");
     692                 :            :     NOTIFY_MUTEX_UNLOCK ();
     693                 :            :   }
     694                 :            : 
     695         [ +  + ]:         36 :   if (close_event)
     696                 :          9 :     gst_pad_push_event (sel->srcpad, close_event);
     697                 :            : 
     698         [ +  + ]:         36 :   if (start_event)
     699                 :          9 :     gst_pad_push_event (sel->srcpad, start_event);
     700                 :            : 
     701         [ +  + ]:         36 :   if (selpad->discont) {
     702                 :          9 :     buf = gst_buffer_make_metadata_writable (buf);
     703                 :            : 
     704         [ -  + ]:          9 :     GST_DEBUG_OBJECT (pad, "Marking discont buffer %p", buf);
     705                 :          9 :     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
     706                 :          9 :     selpad->discont = FALSE;
     707                 :            :   }
     708                 :            : 
     709                 :            :   /* forward */
     710         [ -  + ]:         36 :   GST_LOG_OBJECT (pad, "Forwarding buffer %p", buf);
     711                 :            : 
     712         [ +  - ]:         36 :   if ((caps = GST_BUFFER_CAPS (buf))) {
     713         [ +  + ]:         36 :     if (GST_PAD_CAPS (sel->srcpad) != caps)
     714                 :          9 :       gst_pad_set_caps (sel->srcpad, caps);
     715                 :            :   }
     716                 :            : 
     717                 :         36 :   res = gst_pad_push (sel->srcpad, buf);
     718                 :         36 :   selpad->pushed = TRUE;
     719                 :            : 
     720                 :            : done:
     721                 :         84 :   gst_object_unref (sel);
     722                 :         84 :   return res;
     723                 :            : 
     724                 :            :   /* dropped buffers */
     725                 :            : ignore:
     726                 :            :   {
     727                 :         48 :     gboolean active_pad_pushed = GST_SELECTOR_PAD_CAST (active_sinkpad)->pushed;
     728                 :            : 
     729         [ -  + ]:         48 :     GST_DEBUG_OBJECT (pad, "Pad not active, discard buffer %p", buf);
     730                 :            :     /* when we drop a buffer, we're creating a discont on this pad */
     731                 :         48 :     selpad->discont = TRUE;
     732                 :         48 :     GST_INPUT_SELECTOR_UNLOCK (sel);
     733                 :         48 :     gst_buffer_unref (buf);
     734                 :            : 
     735                 :            :     /* figure out what to return upstream */
     736                 :         48 :     GST_OBJECT_LOCK (selpad);
     737 [ -  + ][ #  # ]:         48 :     if (selpad->always_ok || !active_pad_pushed)
     738                 :         48 :       res = GST_FLOW_OK;
     739                 :            :     else
     740                 :          0 :       res = GST_FLOW_NOT_LINKED;
     741                 :         48 :     GST_OBJECT_UNLOCK (selpad);
     742                 :            : 
     743                 :         48 :     goto done;
     744                 :            :   }
     745                 :            : flushing:
     746                 :            :   {
     747         [ #  # ]:          0 :     GST_DEBUG_OBJECT (pad, "We are flushing, discard buffer %p", buf);
     748                 :          0 :     GST_INPUT_SELECTOR_UNLOCK (sel);
     749                 :          0 :     gst_buffer_unref (buf);
     750                 :          0 :     res = GST_FLOW_WRONG_STATE;
     751                 :          0 :     goto done;
     752                 :            :   }
     753                 :            : }
     754                 :            : 
     755                 :            : static void gst_input_selector_dispose (GObject * object);
     756                 :            : 
     757                 :            : static void gst_input_selector_set_property (GObject * object,
     758                 :            :     guint prop_id, const GValue * value, GParamSpec * pspec);
     759                 :            : static void gst_input_selector_get_property (GObject * object,
     760                 :            :     guint prop_id, GValue * value, GParamSpec * pspec);
     761                 :            : 
     762                 :            : static GstPad *gst_input_selector_request_new_pad (GstElement * element,
     763                 :            :     GstPadTemplate * templ, const gchar * unused);
     764                 :            : static void gst_input_selector_release_pad (GstElement * element, GstPad * pad);
     765                 :            : 
     766                 :            : static GstStateChangeReturn gst_input_selector_change_state (GstElement *
     767                 :            :     element, GstStateChange transition);
     768                 :            : 
     769                 :            : static GstCaps *gst_input_selector_getcaps (GstPad * pad);
     770                 :            : static gboolean gst_input_selector_event (GstPad * pad, GstEvent * event);
     771                 :            : static gboolean gst_input_selector_query (GstPad * pad, GstQuery * query);
     772                 :            : static gint64 gst_input_selector_block (GstInputSelector * self);
     773                 :            : static void gst_input_selector_switch (GstInputSelector * self,
     774                 :            :     GstPad * pad, gint64 stop_time, gint64 start_time);
     775                 :            : 
     776                 :            : /* FIXME: create these marshallers using glib-genmarshal */
     777                 :            : #define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
     778                 :            : #define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
     779                 :            : 
     780                 :            : static void
     781                 :          0 : gst_input_selector_marshal_INT64__VOID (GClosure * closure,
     782                 :            :     GValue * return_value G_GNUC_UNUSED,
     783                 :            :     guint n_param_values,
     784                 :            :     const GValue * param_values,
     785                 :            :     gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
     786                 :            : {
     787                 :            :   typedef gint64 (*GMarshalFunc_INT64__VOID) (gpointer data1, gpointer data2);
     788                 :            :   register GMarshalFunc_INT64__VOID callback;
     789                 :          0 :   register GCClosure *cc = (GCClosure *) closure;
     790                 :            :   register gpointer data1, data2;
     791                 :            :   gint64 v_return;
     792                 :            : 
     793         [ #  # ]:          0 :   g_return_if_fail (return_value != NULL);
     794         [ #  # ]:          0 :   g_return_if_fail (n_param_values == 1);
     795                 :            : 
     796         [ #  # ]:          0 :   if (G_CCLOSURE_SWAP_DATA (closure)) {
     797                 :          0 :     data1 = closure->data;
     798                 :          0 :     data2 = g_value_peek_pointer (param_values + 0);
     799                 :            :   } else {
     800                 :          0 :     data1 = g_value_peek_pointer (param_values + 0);
     801                 :          0 :     data2 = closure->data;
     802                 :            :   }
     803                 :          0 :   callback =
     804         [ #  # ]:          0 :       (GMarshalFunc_INT64__VOID) (marshal_data ? marshal_data : cc->callback);
     805                 :            : 
     806                 :          0 :   v_return = callback (data1, data2);
     807                 :            : 
     808                 :          0 :   g_value_set_int64 (return_value, v_return);
     809                 :            : }
     810                 :            : 
     811                 :            : static void
     812                 :          0 : gst_input_selector_marshal_VOID__OBJECT_INT64_INT64 (GClosure * closure,
     813                 :            :     GValue * return_value G_GNUC_UNUSED,
     814                 :            :     guint n_param_values,
     815                 :            :     const GValue * param_values,
     816                 :            :     gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
     817                 :            : {
     818                 :            :   typedef void (*GMarshalFunc_VOID__OBJECT_INT64_INT64) (gpointer data1,
     819                 :            :       gpointer arg_1, gint64 arg_2, gint64 arg_3, gpointer data2);
     820                 :            :   register GMarshalFunc_VOID__OBJECT_INT64_INT64 callback;
     821                 :          0 :   register GCClosure *cc = (GCClosure *) closure;
     822                 :            :   register gpointer data1, data2;
     823                 :            : 
     824         [ #  # ]:          0 :   g_return_if_fail (n_param_values == 4);
     825                 :            : 
     826         [ #  # ]:          0 :   if (G_CCLOSURE_SWAP_DATA (closure)) {
     827                 :          0 :     data1 = closure->data;
     828                 :          0 :     data2 = g_value_peek_pointer (param_values + 0);
     829                 :            :   } else {
     830                 :          0 :     data1 = g_value_peek_pointer (param_values + 0);
     831                 :          0 :     data2 = closure->data;
     832                 :            :   }
     833                 :          0 :   callback =
     834         [ #  # ]:          0 :       (GMarshalFunc_VOID__OBJECT_INT64_INT64) (marshal_data ? marshal_data :
     835                 :            :       cc->callback);
     836                 :            : 
     837                 :          0 :   callback (data1,
     838                 :          0 :       g_marshal_value_peek_object (param_values + 1),
     839                 :          0 :       g_marshal_value_peek_int64 (param_values + 2),
     840                 :          0 :       g_marshal_value_peek_int64 (param_values + 3), data2);
     841                 :            : }
     842                 :            : 
     843                 :            : #define _do_init(bla) \
     844                 :            :     GST_DEBUG_CATEGORY_INIT (input_selector_debug, \
     845                 :            :         "input-selector", 0, "An input stream selector element");
     846                 :            : 
     847 [ +  + ][ +  - ]:        539 : GST_BOILERPLATE_FULL (GstInputSelector, gst_input_selector, GstElement,
     848                 :        539 :     GST_TYPE_ELEMENT, _do_init);
     849                 :            : 
     850                 :            : static void
     851                 :          9 : gst_input_selector_base_init (gpointer g_class)
     852                 :            : {
     853                 :          9 :   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
     854                 :            : 
     855                 :          9 :   gst_element_class_set_details_simple (element_class, "Input selector",
     856                 :            :       "Generic", "N-to-1 input stream selector",
     857                 :            :       "Julien Moutte <julien@moutte.net>, "
     858                 :            :       "Jan Schmidt <thaytan@mad.scientist.com>, "
     859                 :            :       "Wim Taymans <wim.taymans@gmail.com>");
     860                 :          9 :   gst_element_class_add_pad_template (element_class,
     861                 :            :       gst_static_pad_template_get (&gst_input_selector_sink_factory));
     862                 :          9 :   gst_element_class_add_pad_template (element_class,
     863                 :            :       gst_static_pad_template_get (&gst_input_selector_src_factory));
     864                 :          9 : }
     865                 :            : 
     866                 :            : static void
     867                 :          9 : gst_input_selector_class_init (GstInputSelectorClass * klass)
     868                 :            : {
     869                 :          9 :   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     870                 :          9 :   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
     871                 :            : 
     872                 :          9 :   gobject_class->dispose = gst_input_selector_dispose;
     873                 :            : 
     874                 :          9 :   gobject_class->set_property = gst_input_selector_set_property;
     875                 :          9 :   gobject_class->get_property = gst_input_selector_get_property;
     876                 :            : 
     877                 :          9 :   g_object_class_install_property (gobject_class, PROP_N_PADS,
     878                 :            :       g_param_spec_uint ("n-pads", "Number of Pads",
     879                 :            :           "The number of sink pads", 0, G_MAXUINT, 0,
     880                 :            :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     881                 :            : 
     882                 :          9 :   g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
     883                 :            :       g_param_spec_object ("active-pad", "Active pad",
     884                 :            :           "The currently active sink pad", GST_TYPE_PAD,
     885                 :            :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     886                 :            : 
     887                 :            :   /**
     888                 :            :    * GstInputSelector::block:
     889                 :            :    * @inputselector: the #GstInputSelector
     890                 :            :    *
     891                 :            :    * Block all sink pads in preparation for a switch. Returns the stop time of
     892                 :            :    * the current switch segment, as a running time, or 0 if there is no current
     893                 :            :    * active pad or the current active pad never received data.
     894                 :            :    */
     895                 :          9 :   gst_input_selector_signals[SIGNAL_BLOCK] =
     896                 :          9 :       g_signal_new ("block", G_TYPE_FROM_CLASS (klass),
     897                 :            :       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
     898                 :            :       G_STRUCT_OFFSET (GstInputSelectorClass, block), NULL, NULL,
     899                 :            :       gst_input_selector_marshal_INT64__VOID, G_TYPE_INT64, 0);
     900                 :            :   /**
     901                 :            :    * GstInputSelector::switch:
     902                 :            :    * @inputselector: the #GstInputSelector
     903                 :            :    * @pad:            the pad to switch to
     904                 :            :    * @stop_time:      running time at which to close the previous segment, or -1
     905                 :            :    *                  to use the running time of the previously active sink pad
     906                 :            :    * @start_time:     running time at which to start the new segment, or -1 to
     907                 :            :    *                  use the running time of the newly active sink pad
     908                 :            :    *
     909                 :            :    * Switch to a new feed. The segment opened by the previously active pad, if
     910                 :            :    * any, will be closed, and a new segment opened before data flows again.
     911                 :            :    *
     912                 :            :    * This signal must be emitted when the element has been blocked via the <link
     913                 :            :    * linkend="GstInputSelector-block">block</link> signal.
     914                 :            :    *
     915                 :            :    * If you have a stream with only one switch element, such as an audio-only
     916                 :            :    * stream, a stream switch should be performed by first emitting the block
     917                 :            :    * signal, and then emitting the switch signal with -1 for the stop and start
     918                 :            :    * time values.
     919                 :            :    *
     920                 :            :    * The intention of the @stop_time and @start_time arguments is to allow
     921                 :            :    * multiple switch elements to switch and maintain stream synchronization.
     922                 :            :    * When switching a stream with multiple feeds, you will need as many switch
     923                 :            :    * elements as you have feeds. For example, a feed with audio and video will
     924                 :            :    * have one switch element between the audio feeds and one for video.
     925                 :            :    *
     926                 :            :    * A switch over multiple switch elements should be performed as follows:
     927                 :            :    * First, emit the <link linkend="GstInputSelector-block">block</link>
     928                 :            :    * signal, collecting the returned values. The maximum running time returned
     929                 :            :    * by block should then be used as the time at which to close the previous
     930                 :            :    * segment.
     931                 :            :    *
     932                 :            :    * Then, query the running times of the new audio and video pads that you will
     933                 :            :    * switch to. Naturally, these pads are on separate switch elements. Take the
     934                 :            :    * minimum running time for those streams and use it for the time at which to
     935                 :            :    * open the new segment.
     936                 :            :    *
     937                 :            :    * If @pad is the same as the current active pad, the element will cancel any
     938                 :            :    * previous block without adjusting segments.
     939                 :            :    *
     940                 :            :    * <note><simpara>
     941                 :            :    * the signal changed from accepting the pad name to the pad object.
     942                 :            :    * </simpara></note>
     943                 :            :    *
     944                 :            :    * Since: 0.10.7
     945                 :            :    */
     946                 :          9 :   gst_input_selector_signals[SIGNAL_SWITCH] =
     947                 :          9 :       g_signal_new ("switch", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
     948                 :            :       G_STRUCT_OFFSET (GstInputSelectorClass, switch_),
     949                 :            :       NULL, NULL, gst_input_selector_marshal_VOID__OBJECT_INT64_INT64,
     950                 :            :       G_TYPE_NONE, 3, GST_TYPE_PAD, G_TYPE_INT64, G_TYPE_INT64);
     951                 :            : 
     952                 :          9 :   gstelement_class->request_new_pad = gst_input_selector_request_new_pad;
     953                 :          9 :   gstelement_class->release_pad = gst_input_selector_release_pad;
     954                 :          9 :   gstelement_class->change_state = gst_input_selector_change_state;
     955                 :            : 
     956                 :          9 :   klass->block = GST_DEBUG_FUNCPTR (gst_input_selector_block);
     957                 :            :   /* note the underscore because switch is a keyword otherwise */
     958                 :          9 :   klass->switch_ = GST_DEBUG_FUNCPTR (gst_input_selector_switch);
     959                 :          9 : }
     960                 :            : 
     961                 :            : static void
     962                 :         19 : gst_input_selector_init (GstInputSelector * sel,
     963                 :            :     GstInputSelectorClass * g_class)
     964                 :            : {
     965                 :         19 :   sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
     966                 :         19 :   gst_pad_set_iterate_internal_links_function (sel->srcpad,
     967                 :         19 :       GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
     968                 :         19 :   gst_pad_set_getcaps_function (sel->srcpad,
     969                 :         19 :       GST_DEBUG_FUNCPTR (gst_input_selector_getcaps));
     970                 :         19 :   gst_pad_set_query_function (sel->srcpad,
     971                 :         19 :       GST_DEBUG_FUNCPTR (gst_input_selector_query));
     972                 :         19 :   gst_pad_set_event_function (sel->srcpad,
     973                 :         19 :       GST_DEBUG_FUNCPTR (gst_input_selector_event));
     974                 :         19 :   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
     975                 :            :   /* sinkpad management */
     976                 :         19 :   sel->active_sinkpad = NULL;
     977                 :         19 :   sel->padcount = 0;
     978                 :         19 :   gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
     979                 :            : 
     980                 :         19 :   sel->lock = g_mutex_new ();
     981                 :         19 :   sel->cond = g_cond_new ();
     982                 :         19 :   sel->blocked = FALSE;
     983                 :         19 : }
     984                 :            : 
     985                 :            : static void
     986                 :         19 : gst_input_selector_dispose (GObject * object)
     987                 :            : {
     988                 :         19 :   GstInputSelector *sel = GST_INPUT_SELECTOR (object);
     989                 :            : 
     990         [ -  + ]:         19 :   if (sel->active_sinkpad) {
     991                 :          0 :     gst_object_unref (sel->active_sinkpad);
     992                 :          0 :     sel->active_sinkpad = NULL;
     993                 :            :   }
     994         [ +  - ]:         19 :   if (sel->lock) {
     995                 :         19 :     g_mutex_free (sel->lock);
     996                 :         19 :     sel->lock = NULL;
     997                 :            :   }
     998         [ +  - ]:         19 :   if (sel->cond) {
     999                 :         19 :     g_cond_free (sel->cond);
    1000                 :         19 :     sel->cond = NULL;
    1001                 :            :   }
    1002                 :            : 
    1003                 :         19 :   G_OBJECT_CLASS (parent_class)->dispose (object);
    1004                 :         19 : }
    1005                 :            : 
    1006                 :            : /* Solve the following equation for B.timestamp, and set that as the segment
    1007                 :            :  * stop:
    1008                 :            :  * B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
    1009                 :            :  */
    1010                 :            : static gint64
    1011                 :         18 : gst_segment_get_timestamp (GstSegment * segment, gint64 running_time)
    1012                 :            : {
    1013         [ +  - ]:         18 :   if (running_time <= segment->accum)
    1014                 :         18 :     return segment->start;
    1015                 :            :   else
    1016                 :         18 :     return (running_time - segment->accum) * segment->abs_rate + segment->start;
    1017                 :            : }
    1018                 :            : 
    1019                 :            : static void
    1020                 :          9 : gst_segment_set_stop (GstSegment * segment, gint64 running_time)
    1021                 :            : {
    1022                 :          9 :   segment->stop = gst_segment_get_timestamp (segment, running_time);
    1023                 :          9 :   segment->last_stop = -1;
    1024                 :          9 : }
    1025                 :            : 
    1026                 :            : static void
    1027                 :          9 : gst_segment_set_start (GstSegment * segment, gint64 running_time)
    1028                 :            : {
    1029                 :            :   gint64 new_start, duration;
    1030                 :            : 
    1031                 :          9 :   new_start = gst_segment_get_timestamp (segment, running_time);
    1032                 :            : 
    1033                 :            :   /* this is the duration we skipped */
    1034                 :          9 :   duration = new_start - segment->start;
    1035                 :            :   /* add the duration to the accumulated segment time */
    1036                 :          9 :   segment->accum += duration;
    1037                 :            :   /* move position in the segment */
    1038                 :          9 :   segment->time += duration;
    1039                 :          9 :   segment->start += duration;
    1040                 :          9 : }
    1041                 :            : 
    1042                 :            : /* this function must be called with the SELECTOR_LOCK. It returns TRUE when the
    1043                 :            :  * active pad changed. */
    1044                 :            : static gboolean
    1045                 :         40 : gst_input_selector_set_active_pad (GstInputSelector * self,
    1046                 :            :     GstPad * pad, gint64 stop_time, gint64 start_time)
    1047                 :            : {
    1048                 :            :   GstSelectorPad *old, *new;
    1049                 :            :   GstPad **active_pad_p;
    1050                 :            : 
    1051         [ +  + ]:         40 :   if (pad == self->active_sinkpad)
    1052                 :         16 :     return FALSE;
    1053                 :            : 
    1054                 :         24 :   old = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
    1055                 :         24 :   new = GST_SELECTOR_PAD_CAST (pad);
    1056                 :            : 
    1057 [ -  + ][ #  # ]:         24 :   GST_DEBUG_OBJECT (self, "setting active pad to %s:%s",
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1058                 :            :       GST_DEBUG_PAD_NAME (new));
    1059                 :            : 
    1060 [ +  - ][ +  + ]:         24 :   if (!GST_CLOCK_TIME_IS_VALID (stop_time) && old) {
    1061                 :            :     /* no stop time given, get the latest running_time on the active pad to 
    1062                 :            :      * close and open the new segment */
    1063                 :         12 :     stop_time = start_time = gst_selector_pad_get_running_time (old);
    1064 [ -  + ][ #  # ]:         12 :     GST_DEBUG_OBJECT (self, "using start/stop of %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1065                 :            :         GST_TIME_ARGS (start_time));
    1066                 :            :   }
    1067                 :            : 
    1068 [ +  + ][ +  + ]:         24 :   if (old && old->active && !self->pending_close && stop_time >= 0) {
         [ +  - ][ +  - ]
    1069                 :            :     /* schedule a last_stop update if one isn't already scheduled, and a
    1070                 :            :        segment has been pushed before. */
    1071                 :          9 :     memcpy (&self->segment, &old->segment, sizeof (self->segment));
    1072                 :            : 
    1073 [ -  + ][ #  # ]:          9 :     GST_DEBUG_OBJECT (self, "setting stop_time to %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1074                 :            :         GST_TIME_ARGS (stop_time));
    1075                 :          9 :     gst_segment_set_stop (&self->segment, stop_time);
    1076                 :          9 :     self->pending_close = TRUE;
    1077                 :            :   }
    1078         [ +  + ]:         24 :   if (old)
    1079                 :         12 :     old->pushed = FALSE;
    1080                 :            : 
    1081 [ +  - ][ +  + ]:         24 :   if (new && new->active && start_time >= 0) {
                 [ +  - ]
    1082 [ -  + ][ #  # ]:          9 :     GST_DEBUG_OBJECT (self, "setting start_time to %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1083                 :            :         GST_TIME_ARGS (start_time));
    1084                 :            :     /* schedule a new segment push */
    1085                 :          9 :     gst_segment_set_start (&new->segment, start_time);
    1086                 :          9 :     new->segment_pending = TRUE;
    1087                 :            :   }
    1088         [ +  - ]:         24 :   if (new)
    1089                 :         24 :     new->pushed = FALSE;
    1090                 :            : 
    1091                 :         24 :   active_pad_p = &self->active_sinkpad;
    1092                 :         24 :   gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
    1093         [ -  + ]:         24 :   GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT,
    1094                 :            :       self->active_sinkpad);
    1095                 :            : 
    1096                 :         40 :   return TRUE;
    1097                 :            : }
    1098                 :            : 
    1099                 :            : static void
    1100                 :         40 : gst_input_selector_set_property (GObject * object, guint prop_id,
    1101                 :            :     const GValue * value, GParamSpec * pspec)
    1102                 :            : {
    1103                 :         40 :   GstInputSelector *sel = GST_INPUT_SELECTOR (object);
    1104                 :            : 
    1105         [ +  - ]:         40 :   switch (prop_id) {
    1106                 :            :     case PROP_ACTIVE_PAD:
    1107                 :            :     {
    1108                 :            :       GstPad *pad;
    1109                 :            : 
    1110                 :         40 :       pad = g_value_get_object (value);
    1111                 :            : 
    1112                 :         40 :       GST_INPUT_SELECTOR_LOCK (sel);
    1113                 :         40 :       gst_input_selector_set_active_pad (sel, pad,
    1114                 :            :           GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
    1115                 :         40 :       GST_INPUT_SELECTOR_UNLOCK (sel);
    1116                 :         40 :       break;
    1117                 :            :     }
    1118                 :            :     default:
    1119                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    1120                 :          0 :       break;
    1121                 :            :   }
    1122                 :         40 : }
    1123                 :            : 
    1124                 :            : static void
    1125                 :          0 : gst_input_selector_get_property (GObject * object, guint prop_id,
    1126                 :            :     GValue * value, GParamSpec * pspec)
    1127                 :            : {
    1128                 :          0 :   GstInputSelector *sel = GST_INPUT_SELECTOR (object);
    1129                 :            : 
    1130      [ #  #  # ]:          0 :   switch (prop_id) {
    1131                 :            :     case PROP_N_PADS:
    1132                 :          0 :       GST_INPUT_SELECTOR_LOCK (object);
    1133                 :          0 :       g_value_set_uint (value, sel->n_pads);
    1134                 :          0 :       GST_INPUT_SELECTOR_UNLOCK (object);
    1135                 :          0 :       break;
    1136                 :            :     case PROP_ACTIVE_PAD:
    1137                 :          0 :       GST_INPUT_SELECTOR_LOCK (object);
    1138                 :          0 :       g_value_set_object (value, sel->active_sinkpad);
    1139                 :          0 :       GST_INPUT_SELECTOR_UNLOCK (object);
    1140                 :          0 :       break;
    1141                 :            :     default:
    1142                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    1143                 :          0 :       break;
    1144                 :            :   }
    1145                 :          0 : }
    1146                 :            : 
    1147                 :            : static GstPad *
    1148                 :         16 : gst_input_selector_get_linked_pad (GstPad * pad, gboolean strict)
    1149                 :            : {
    1150                 :            :   GstInputSelector *sel;
    1151                 :         16 :   GstPad *otherpad = NULL;
    1152                 :            : 
    1153                 :         16 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
    1154                 :            : 
    1155                 :         16 :   GST_INPUT_SELECTOR_LOCK (sel);
    1156         [ +  - ]:         16 :   if (pad == sel->srcpad)
    1157                 :         16 :     otherpad = sel->active_sinkpad;
    1158 [ #  # ][ #  # ]:          0 :   else if (pad == sel->active_sinkpad || !strict)
    1159                 :          0 :     otherpad = sel->srcpad;
    1160         [ -  + ]:         16 :   if (otherpad)
    1161                 :          0 :     gst_object_ref (otherpad);
    1162                 :         16 :   GST_INPUT_SELECTOR_UNLOCK (sel);
    1163                 :            : 
    1164                 :         16 :   gst_object_unref (sel);
    1165                 :            : 
    1166                 :         16 :   return otherpad;
    1167                 :            : }
    1168                 :            : 
    1169                 :            : static gboolean
    1170                 :          0 : gst_input_selector_event (GstPad * pad, GstEvent * event)
    1171                 :            : {
    1172                 :          0 :   gboolean res = FALSE;
    1173                 :            :   GstPad *otherpad;
    1174                 :            : 
    1175                 :          0 :   otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
    1176                 :            : 
    1177         [ #  # ]:          0 :   if (otherpad) {
    1178                 :          0 :     res = gst_pad_push_event (otherpad, event);
    1179                 :            : 
    1180                 :          0 :     gst_object_unref (otherpad);
    1181                 :            :   } else
    1182                 :          0 :     gst_event_unref (event);
    1183                 :          0 :   return res;
    1184                 :            : }
    1185                 :            : 
    1186                 :            : /* query on the srcpad. We override this function because by default it will
    1187                 :            :  * only forward the query to one random sinkpad */
    1188                 :            : static gboolean
    1189                 :          0 : gst_input_selector_query (GstPad * pad, GstQuery * query)
    1190                 :            : {
    1191                 :          0 :   gboolean res = TRUE;
    1192                 :            :   GstInputSelector *sel;
    1193                 :            :   GstPad *otherpad;
    1194                 :            : 
    1195                 :          0 :   sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
    1196                 :            : 
    1197                 :          0 :   otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
    1198                 :            : 
    1199         [ #  # ]:          0 :   switch (GST_QUERY_TYPE (query)) {
    1200                 :            :     case GST_QUERY_LATENCY:
    1201                 :            :     {
    1202                 :            :       GList *walk;
    1203                 :            :       GstClockTime resmin, resmax;
    1204                 :            :       gboolean reslive;
    1205                 :            : 
    1206                 :          0 :       resmin = 0;
    1207                 :          0 :       resmax = -1;
    1208                 :          0 :       reslive = FALSE;
    1209                 :            : 
    1210                 :            :       /* assume FALSE, we become TRUE if one query succeeds */
    1211                 :          0 :       res = FALSE;
    1212                 :            : 
    1213                 :            :       /* perform the query on all sinkpads and combine the results. We take the
    1214                 :            :        * max of min and the min of max for the result latency. */
    1215                 :          0 :       GST_INPUT_SELECTOR_LOCK (sel);
    1216         [ #  # ]:          0 :       for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk;
    1217         [ #  # ]:          0 :           walk = g_list_next (walk)) {
    1218                 :          0 :         GstPad *sinkpad = GST_PAD_CAST (walk->data);
    1219                 :            : 
    1220         [ #  # ]:          0 :         if (gst_pad_peer_query (sinkpad, query)) {
    1221                 :            :           GstClockTime min, max;
    1222                 :            :           gboolean live;
    1223                 :            : 
    1224                 :            :           /* one query succeeded, we succeed too */
    1225                 :          0 :           res = TRUE;
    1226                 :            : 
    1227                 :          0 :           gst_query_parse_latency (query, &live, &min, &max);
    1228                 :            : 
    1229 [ #  # ][ #  # ]:          0 :           GST_DEBUG_OBJECT (sinkpad,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1230                 :            :               "peer latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
    1231                 :            :               ", live %d", GST_TIME_ARGS (min), GST_TIME_ARGS (max), live);
    1232                 :            : 
    1233         [ #  # ]:          0 :           if (live) {
    1234         [ #  # ]:          0 :             if (min > resmin)
    1235                 :          0 :               resmin = min;
    1236         [ #  # ]:          0 :             if (resmax == -1)
    1237                 :          0 :               resmax = max;
    1238         [ #  # ]:          0 :             else if (max < resmax)
    1239                 :          0 :               resmax = max;
    1240         [ #  # ]:          0 :             if (reslive == FALSE)
    1241                 :          0 :               reslive = live;
    1242                 :            :           }
    1243                 :            :         }
    1244                 :            :       }
    1245                 :          0 :       GST_INPUT_SELECTOR_UNLOCK (sel);
    1246         [ #  # ]:          0 :       if (res) {
    1247                 :          0 :         gst_query_set_latency (query, reslive, resmin, resmax);
    1248                 :            : 
    1249 [ #  # ][ #  # ]:          0 :         GST_DEBUG_OBJECT (sel,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1250                 :            :             "total latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
    1251                 :            :             ", live %d", GST_TIME_ARGS (resmin), GST_TIME_ARGS (resmax),
    1252                 :            :             reslive);
    1253                 :            :       }
    1254                 :            : 
    1255                 :          0 :       break;
    1256                 :            :     }
    1257                 :            :     default:
    1258         [ #  # ]:          0 :       if (otherpad)
    1259                 :          0 :         res = gst_pad_peer_query (otherpad, query);
    1260                 :          0 :       break;
    1261                 :            :   }
    1262         [ #  # ]:          0 :   if (otherpad)
    1263                 :          0 :     gst_object_unref (otherpad);
    1264                 :          0 :   gst_object_unref (sel);
    1265                 :            : 
    1266                 :          0 :   return res;
    1267                 :            : }
    1268                 :            : 
    1269                 :            : static GstCaps *
    1270                 :         16 : gst_input_selector_getcaps (GstPad * pad)
    1271                 :            : {
    1272                 :            :   GstPad *otherpad;
    1273                 :            :   GstObject *parent;
    1274                 :            :   GstCaps *caps;
    1275                 :            : 
    1276                 :         16 :   parent = gst_object_get_parent (GST_OBJECT (pad));
    1277                 :            : 
    1278                 :         16 :   otherpad = gst_input_selector_get_linked_pad (pad, FALSE);
    1279                 :            : 
    1280         [ +  - ]:         16 :   if (!otherpad) {
    1281         [ -  + ]:         16 :     GST_DEBUG_OBJECT (pad, "Pad not linked, returning ANY");
    1282                 :         16 :     caps = gst_caps_new_any ();
    1283                 :            :   } else {
    1284 [ #  # ][ #  # ]:          0 :     GST_DEBUG_OBJECT (pad, "Pad is linked (to %s:%s), returning peer caps",
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1285                 :            :         GST_DEBUG_PAD_NAME (otherpad));
    1286                 :            :     /* if the peer has caps, use those. If the pad is not linked, this function
    1287                 :            :      * returns NULL and we return ANY */
    1288         [ #  # ]:          0 :     if (!(caps = gst_pad_peer_get_caps_reffed (otherpad)))
    1289                 :          0 :       caps = gst_caps_new_any ();
    1290                 :          0 :     gst_object_unref (otherpad);
    1291                 :            :   }
    1292                 :            : 
    1293                 :         16 :   gst_object_unref (parent);
    1294                 :         16 :   return caps;
    1295                 :            : }
    1296                 :            : 
    1297                 :            : /* check if the pad is the active sinkpad */
    1298                 :            : static inline gboolean
    1299                 :          0 : gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad)
    1300                 :            : {
    1301                 :            :   gboolean res;
    1302                 :            : 
    1303                 :          0 :   GST_INPUT_SELECTOR_LOCK (sel);
    1304                 :          0 :   res = (pad == sel->active_sinkpad);
    1305                 :          0 :   GST_INPUT_SELECTOR_UNLOCK (sel);
    1306                 :            : 
    1307                 :          0 :   return res;
    1308                 :            : }
    1309                 :            : 
    1310                 :            : /* Get or create the active sinkpad, must be called with SELECTOR_LOCK */
    1311                 :            : static GstPad *
    1312                 :         84 : gst_input_selector_activate_sinkpad (GstInputSelector * sel, GstPad * pad)
    1313                 :            : {
    1314                 :            :   GstPad *active_sinkpad;
    1315                 :            :   GstSelectorPad *selpad;
    1316                 :            : 
    1317                 :         84 :   selpad = GST_SELECTOR_PAD_CAST (pad);
    1318                 :            : 
    1319                 :         84 :   selpad->active = TRUE;
    1320                 :         84 :   active_sinkpad = sel->active_sinkpad;
    1321         [ -  + ]:         84 :   if (active_sinkpad == NULL) {
    1322                 :            :     /* first pad we get activity on becomes the activated pad by default */
    1323         [ #  # ]:          0 :     if (sel->active_sinkpad)
    1324                 :          0 :       gst_object_unref (sel->active_sinkpad);
    1325                 :          0 :     active_sinkpad = sel->active_sinkpad = gst_object_ref (pad);
    1326 [ #  # ][ #  # ]:          0 :     GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1327                 :            :   }
    1328                 :            : 
    1329                 :         84 :   return active_sinkpad;
    1330                 :            : }
    1331                 :            : 
    1332                 :            : static GstPad *
    1333                 :         24 : gst_input_selector_request_new_pad (GstElement * element,
    1334                 :            :     GstPadTemplate * templ, const gchar * unused)
    1335                 :            : {
    1336                 :            :   GstInputSelector *sel;
    1337                 :         24 :   gchar *name = NULL;
    1338                 :         24 :   GstPad *sinkpad = NULL;
    1339                 :            : 
    1340         [ -  + ]:         24 :   g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
    1341                 :            : 
    1342                 :         24 :   sel = GST_INPUT_SELECTOR (element);
    1343                 :            : 
    1344                 :         24 :   GST_INPUT_SELECTOR_LOCK (sel);
    1345                 :            : 
    1346         [ -  + ]:         24 :   GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
    1347                 :         24 :   name = g_strdup_printf ("sink%d", sel->padcount++);
    1348                 :         24 :   sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
    1349                 :         24 :       "name", name, "direction", templ->direction, "template", templ, NULL);
    1350                 :         24 :   g_free (name);
    1351                 :            : 
    1352                 :         24 :   sel->n_pads++;
    1353                 :            : 
    1354                 :         24 :   gst_pad_set_event_function (sinkpad,
    1355                 :         24 :       GST_DEBUG_FUNCPTR (gst_selector_pad_event));
    1356                 :         24 :   gst_pad_set_getcaps_function (sinkpad,
    1357                 :         24 :       GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
    1358                 :         24 :   gst_pad_set_acceptcaps_function (sinkpad,
    1359                 :         24 :       GST_DEBUG_FUNCPTR (gst_selector_pad_acceptcaps));
    1360                 :         24 :   gst_pad_set_chain_function (sinkpad,
    1361                 :         24 :       GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
    1362                 :         24 :   gst_pad_set_iterate_internal_links_function (sinkpad,
    1363                 :         24 :       GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
    1364                 :         24 :   gst_pad_set_bufferalloc_function (sinkpad,
    1365                 :         24 :       GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc));
    1366                 :            : 
    1367                 :         24 :   gst_pad_set_active (sinkpad, TRUE);
    1368                 :         24 :   gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
    1369                 :         24 :   GST_INPUT_SELECTOR_UNLOCK (sel);
    1370                 :            : 
    1371                 :         24 :   return sinkpad;
    1372                 :            : }
    1373                 :            : 
    1374                 :            : static void
    1375                 :         24 : gst_input_selector_release_pad (GstElement * element, GstPad * pad)
    1376                 :            : {
    1377                 :            :   GstInputSelector *sel;
    1378                 :            : 
    1379                 :         24 :   sel = GST_INPUT_SELECTOR (element);
    1380 [ -  + ][ #  # ]:         24 :   GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1381                 :            : 
    1382                 :         24 :   GST_INPUT_SELECTOR_LOCK (sel);
    1383                 :            :   /* if the pad was the active pad, makes us select a new one */
    1384         [ -  + ]:         24 :   if (sel->active_sinkpad == pad) {
    1385 [ #  # ][ #  # ]:          0 :     GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1386                 :          0 :     gst_object_unref (sel->active_sinkpad);
    1387                 :          0 :     sel->active_sinkpad = NULL;
    1388                 :            :   }
    1389                 :         24 :   sel->n_pads--;
    1390                 :            : 
    1391                 :         24 :   gst_pad_set_active (pad, FALSE);
    1392                 :         24 :   gst_element_remove_pad (GST_ELEMENT (sel), pad);
    1393                 :         24 :   GST_INPUT_SELECTOR_UNLOCK (sel);
    1394                 :         24 : }
    1395                 :            : 
    1396                 :            : static void
    1397                 :         23 : gst_input_selector_reset (GstInputSelector * sel)
    1398                 :            : {
    1399                 :            :   GList *walk;
    1400                 :            : 
    1401                 :         23 :   GST_INPUT_SELECTOR_LOCK (sel);
    1402                 :            :   /* clear active pad */
    1403         [ +  + ]:         23 :   if (sel->active_sinkpad) {
    1404                 :         12 :     gst_object_unref (sel->active_sinkpad);
    1405                 :         12 :     sel->active_sinkpad = NULL;
    1406                 :            :   }
    1407                 :            :   /* reset segment */
    1408                 :         23 :   gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
    1409                 :         23 :   sel->pending_close = FALSE;
    1410                 :            :   /* reset each of our sinkpads state */
    1411 [ +  - ][ +  + ]:         47 :   for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk; walk = g_list_next (walk)) {
    1412                 :         24 :     GstSelectorPad *selpad = GST_SELECTOR_PAD_CAST (walk->data);
    1413                 :            : 
    1414                 :         24 :     gst_selector_pad_reset (selpad);
    1415                 :            : 
    1416         [ -  + ]:         24 :     if (selpad->tags) {
    1417                 :          0 :       gst_tag_list_free (selpad->tags);
    1418                 :          0 :       selpad->tags = NULL;
    1419                 :            :     }
    1420                 :            :   }
    1421                 :         23 :   GST_INPUT_SELECTOR_UNLOCK (sel);
    1422                 :         23 : }
    1423                 :            : 
    1424                 :            : static GstStateChangeReturn
    1425                 :        146 : gst_input_selector_change_state (GstElement * element,
    1426                 :            :     GstStateChange transition)
    1427                 :            : {
    1428                 :        146 :   GstInputSelector *self = GST_INPUT_SELECTOR (element);
    1429                 :            :   GstStateChangeReturn result;
    1430                 :            : 
    1431      [ +  +  + ]:        146 :   switch (transition) {
    1432                 :            :     case GST_STATE_CHANGE_READY_TO_PAUSED:
    1433                 :         23 :       GST_INPUT_SELECTOR_LOCK (self);
    1434                 :         23 :       self->blocked = FALSE;
    1435                 :         23 :       self->flushing = FALSE;
    1436                 :         23 :       GST_INPUT_SELECTOR_UNLOCK (self);
    1437                 :         23 :       break;
    1438                 :            :     case GST_STATE_CHANGE_PAUSED_TO_READY:
    1439                 :            :       /* first unlock before we call the parent state change function, which
    1440                 :            :        * tries to acquire the stream lock when going to ready. */
    1441                 :         23 :       GST_INPUT_SELECTOR_LOCK (self);
    1442                 :         23 :       self->blocked = FALSE;
    1443                 :         23 :       self->flushing = TRUE;
    1444                 :         23 :       GST_INPUT_SELECTOR_BROADCAST (self);
    1445                 :         23 :       GST_INPUT_SELECTOR_UNLOCK (self);
    1446                 :         23 :       break;
    1447                 :            :     default:
    1448                 :        100 :       break;
    1449                 :            :   }
    1450                 :            : 
    1451                 :        146 :   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
    1452                 :            : 
    1453         [ +  + ]:        146 :   switch (transition) {
    1454                 :            :     case GST_STATE_CHANGE_PAUSED_TO_READY:
    1455                 :         23 :       gst_input_selector_reset (self);
    1456                 :         23 :       break;
    1457                 :            :     default:
    1458                 :        123 :       break;
    1459                 :            :   }
    1460                 :            : 
    1461                 :        146 :   return result;
    1462                 :            : }
    1463                 :            : 
    1464                 :            : static gint64
    1465                 :          0 : gst_input_selector_block (GstInputSelector * self)
    1466                 :            : {
    1467                 :          0 :   gint64 ret = 0;
    1468                 :            :   GstSelectorPad *spad;
    1469                 :            : 
    1470                 :          0 :   GST_INPUT_SELECTOR_LOCK (self);
    1471                 :            : 
    1472         [ #  # ]:          0 :   if (self->blocked)
    1473         [ #  # ]:          0 :     GST_WARNING_OBJECT (self, "switch already blocked");
    1474                 :            : 
    1475                 :          0 :   self->blocked = TRUE;
    1476                 :          0 :   spad = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
    1477                 :            : 
    1478         [ #  # ]:          0 :   if (spad)
    1479                 :          0 :     ret = gst_selector_pad_get_running_time (spad);
    1480                 :            :   else
    1481         [ #  # ]:          0 :     GST_DEBUG_OBJECT (self, "no active pad while blocking");
    1482                 :            : 
    1483                 :          0 :   GST_INPUT_SELECTOR_UNLOCK (self);
    1484                 :            : 
    1485                 :          0 :   return ret;
    1486                 :            : }
    1487                 :            : 
    1488                 :            : /* stop_time and start_time are running times */
    1489                 :            : static void
    1490                 :          0 : gst_input_selector_switch (GstInputSelector * self, GstPad * pad,
    1491                 :            :     gint64 stop_time, gint64 start_time)
    1492                 :            : {
    1493                 :            :   gboolean changed;
    1494                 :            : 
    1495         [ #  # ]:          0 :   g_return_if_fail (self->blocked == TRUE);
    1496                 :            : 
    1497                 :          0 :   GST_INPUT_SELECTOR_LOCK (self);
    1498                 :          0 :   changed =
    1499                 :            :       gst_input_selector_set_active_pad (self, pad, stop_time, start_time);
    1500                 :            : 
    1501                 :          0 :   self->blocked = FALSE;
    1502                 :          0 :   GST_INPUT_SELECTOR_BROADCAST (self);
    1503                 :          0 :   GST_INPUT_SELECTOR_UNLOCK (self);
    1504                 :            : 
    1505         [ #  # ]:          0 :   if (changed) {
    1506                 :            :     NOTIFY_MUTEX_LOCK ();
    1507                 :          0 :     g_object_notify (G_OBJECT (self), "active-pad");
    1508                 :            :     NOTIFY_MUTEX_UNLOCK ();
    1509                 :            :   }
    1510                 :            : }

Generated by: LCOV version 1.9