LCOV - code coverage report
Current view: top level - gst/liveadder - liveadder.c (source / functions) Hit Total Coverage
Test: GStreamer Bad Plug-ins 0.10.21.1 Lines: 101 672 15.0 %
Date: 2011-03-25 Functions: 10 37 27.0 %
Branches: 17 537 3.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Farsight Voice+Video library
       3                 :            :  *
       4                 :            :  *  Copyright 2008 Collabora Ltd
       5                 :            :  *  Copyright 2008 Nokia Corporation
       6                 :            :  *   @author: Olivier Crete <olivier.crete@collabora.co.uk>
       7                 :            :  *
       8                 :            :  * With parts copied from the adder plugin which is
       9                 :            :  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
      10                 :            :  *                    2001 Thomas <thomas@apestaart.org>
      11                 :            :  *               2005,2006 Wim Taymans <wim@fluendo.com>
      12                 :            :  *
      13                 :            :  * This library is free software; you can redistribute it and/or
      14                 :            :  * modify it under the terms of the GNU Lesser General Public
      15                 :            :  * License as published by the Free Software Foundation; either
      16                 :            :  * version 2.1 of the License, or (at your option) any later version.
      17                 :            :  *
      18                 :            :  * This library is distributed in the hope that it will be useful,
      19                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      20                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      21                 :            :  * Lesser General Public License for more details.
      22                 :            :  *
      23                 :            :  * You should have received a copy of the GNU Lesser General Public
      24                 :            :  * License along with this library; if not, write to the Free Software
      25                 :            :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
      26                 :            :  *
      27                 :            :  */
      28                 :            : /**
      29                 :            :  * SECTION:element-liveadder
      30                 :            :  * @see_also: adder
      31                 :            :  *
      32                 :            :  * The live adder allows to mix several streams into one by adding the data.
      33                 :            :  * Mixed data is clamped to the min/max values of the data format.
      34                 :            :  *
      35                 :            :  * Unlike the adder, the liveadder mixes the streams according the their
      36                 :            :  * timestamps and waits for some milli-seconds before trying doing the mixing.
      37                 :            :  *
      38                 :            :  * Last reviewed on 2008-02-10 (0.10.11)
      39                 :            :  */
      40                 :            : 
      41                 :            : #ifdef HAVE_CONFIG_H
      42                 :            : #include "config.h"
      43                 :            : #endif
      44                 :            : 
      45                 :            : #include "liveadder.h"
      46                 :            : 
      47                 :            : #include <gst/audio/audio.h>
      48                 :            : 
      49                 :            : #include <string.h>
      50                 :            : 
      51                 :            : #define DEFAULT_LATENCY_MS 60
      52                 :            : 
      53                 :            : GST_DEBUG_CATEGORY_STATIC (live_adder_debug);
      54                 :            : #define GST_CAT_DEFAULT (live_adder_debug)
      55                 :            : 
      56                 :            : static GstStaticPadTemplate gst_live_adder_sink_template =
      57                 :            :     GST_STATIC_PAD_TEMPLATE ("sink%d",
      58                 :            :     GST_PAD_SINK,
      59                 :            :     GST_PAD_REQUEST,
      60                 :            :     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
      61                 :            :         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
      62                 :            :     );
      63                 :            : 
      64                 :            : static GstStaticPadTemplate gst_live_adder_src_template =
      65                 :            :     GST_STATIC_PAD_TEMPLATE ("src",
      66                 :            :     GST_PAD_SRC,
      67                 :            :     GST_PAD_ALWAYS,
      68                 :            :     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
      69                 :            :         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
      70                 :            :     );
      71                 :            : 
      72                 :            : /* Valve signals and args */
      73                 :            : enum
      74                 :            : {
      75                 :            :   /* FILL ME */
      76                 :            :   LAST_SIGNAL
      77                 :            : };
      78                 :            : 
      79                 :            : enum
      80                 :            : {
      81                 :            :   PROP_0,
      82                 :            :   PROP_LATENCY,
      83                 :            : };
      84                 :            : 
      85                 :            : typedef struct _GstLiveAdderPadPrivate
      86                 :            : {
      87                 :            :   GstSegment segment;
      88                 :            :   gboolean eos;
      89                 :            : 
      90                 :            :   GstClockTime expected_timestamp;
      91                 :            : 
      92                 :            : } GstLiveAdderPadPrivate;
      93                 :            : 
      94                 :            : #define _do_init(bla) \
      95                 :            :   GST_DEBUG_CATEGORY_INIT (live_adder_debug, "liveadder", 0, "Live Adder");
      96                 :            : 
      97 [ +  + ][ +  - ]:         63 : GST_BOILERPLATE_FULL (GstLiveAdder, gst_live_adder, GstElement,
      98                 :         63 :     GST_TYPE_ELEMENT, _do_init);
      99                 :            : 
     100                 :            : 
     101                 :            : static void gst_live_adder_finalize (GObject * object);
     102                 :            : static void
     103                 :            : gst_live_adder_set_property (GObject * object,
     104                 :            :     guint prop_id, const GValue * value, GParamSpec * pspec);
     105                 :            : static void
     106                 :            : gst_live_adder_get_property (GObject * object,
     107                 :            :     guint prop_id, GValue * value, GParamSpec * pspec);
     108                 :            : 
     109                 :            : static GstPad *gst_live_adder_request_new_pad (GstElement * element,
     110                 :            :     GstPadTemplate * templ, const gchar * unused);
     111                 :            : static void gst_live_adder_release_pad (GstElement * element, GstPad * pad);
     112                 :            : static GstStateChangeReturn
     113                 :            : gst_live_adder_change_state (GstElement * element, GstStateChange transition);
     114                 :            : 
     115                 :            : static gboolean gst_live_adder_setcaps (GstPad * pad, GstCaps * caps);
     116                 :            : static GstCaps *gst_live_adder_sink_getcaps (GstPad * pad);
     117                 :            : static gboolean
     118                 :            : gst_live_adder_src_activate_push (GstPad * pad, gboolean active);
     119                 :            : static gboolean gst_live_adder_src_event (GstPad * pad, GstEvent * event);
     120                 :            : 
     121                 :            : static void gst_live_adder_loop (gpointer data);
     122                 :            : static gboolean gst_live_adder_query (GstPad * pad, GstQuery * query);
     123                 :            : static gboolean gst_live_adder_sink_event (GstPad * pad, GstEvent * event);
     124                 :            : 
     125                 :            : 
     126                 :            : static void reset_pad_private (GstPad * pad);
     127                 :            : 
     128                 :            : /* clipping versions */
     129                 :            : #define MAKE_FUNC(name,type,ttype,min,max)                      \
     130                 :            : static void name (type *out, type *in, gint bytes) {            \
     131                 :            :   gint i;                                                       \
     132                 :            :   for (i = 0; i < bytes / sizeof (type); i++)                   \
     133                 :            :     out[i] = CLAMP ((ttype)out[i] + (ttype)in[i], min, max);    \
     134                 :            : }
     135                 :            : 
     136                 :            : /* non-clipping versions (for float) */
     137                 :            : #define MAKE_FUNC_NC(name,type,ttype)                           \
     138                 :            : static void name (type *out, type *in, gint bytes) {            \
     139                 :            :   gint i;                                                       \
     140                 :            :   for (i = 0; i < bytes / sizeof (type); i++)                   \
     141                 :            :     out[i] = (ttype)out[i] + (ttype)in[i];                      \
     142                 :            : }
     143                 :            : 
     144                 :            : /* *INDENT-OFF* */
     145 [ #  # ][ #  # ]:          0 : MAKE_FUNC (add_int32, gint32, gint64, G_MININT32, G_MAXINT32)
     146 [ #  # ][ #  # ]:          0 : MAKE_FUNC (add_int16, gint16, gint32, G_MININT16, G_MAXINT16)
     147 [ #  # ][ #  # ]:          0 : MAKE_FUNC (add_int8, gint8, gint16, G_MININT8, G_MAXINT8)
     148         [ #  # ]:          0 : MAKE_FUNC (add_uint32, guint32, guint64, 0, G_MAXUINT32)
     149         [ #  # ]:          0 : MAKE_FUNC (add_uint16, guint16, guint32, 0, G_MAXUINT16)
     150         [ #  # ]:          0 : MAKE_FUNC (add_uint8, guint8, guint16, 0, G_MAXUINT8)
     151         [ #  # ]:          0 : MAKE_FUNC_NC (add_float64, gdouble, gdouble)
     152         [ #  # ]:          0 : MAKE_FUNC_NC (add_float32, gfloat, gfloat)
     153                 :            : /* *INDENT-ON* */
     154                 :            : 
     155                 :            : 
     156                 :            : static void
     157                 :          6 : gst_live_adder_base_init (gpointer klass)
     158                 :            : {
     159                 :          6 :   GstElementClass *gstelement_class = (GstElementClass *) klass;
     160                 :            : 
     161                 :          6 :   gst_element_class_add_pad_template (gstelement_class,
     162                 :            :       gst_static_pad_template_get (&gst_live_adder_src_template));
     163                 :          6 :   gst_element_class_add_pad_template (gstelement_class,
     164                 :            :       gst_static_pad_template_get (&gst_live_adder_sink_template));
     165                 :          6 :   gst_element_class_set_details_simple (gstelement_class, "Live Adder element",
     166                 :            :       "Generic/Audio",
     167                 :            :       "Mixes live/discontinuous audio streams",
     168                 :            :       "Olivier Crete <olivier.crete@collabora.co.uk>");
     169                 :          6 : }
     170                 :            : 
     171                 :            : static void
     172                 :          6 : gst_live_adder_class_init (GstLiveAdderClass * klass)
     173                 :            : {
     174                 :          6 :   GObjectClass *gobject_class = (GObjectClass *) klass;
     175                 :          6 :   GstElementClass *gstelement_class = (GstElementClass *) klass;
     176                 :            : 
     177                 :          6 :   gobject_class->finalize = gst_live_adder_finalize;
     178                 :          6 :   gobject_class->set_property = gst_live_adder_set_property;
     179                 :          6 :   gobject_class->get_property = gst_live_adder_get_property;
     180                 :            : 
     181                 :          6 :   gstelement_class->request_new_pad = gst_live_adder_request_new_pad;
     182                 :          6 :   gstelement_class->release_pad = gst_live_adder_release_pad;
     183                 :          6 :   gstelement_class->change_state = gst_live_adder_change_state;
     184                 :            : 
     185                 :          6 :   g_object_class_install_property (gobject_class, PROP_LATENCY,
     186                 :            :       g_param_spec_uint ("latency", "Buffer latency in ms",
     187                 :            :           "Amount of data to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
     188                 :            :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     189                 :          6 : }
     190                 :            : 
     191                 :            : static void
     192                 :          3 : gst_live_adder_init (GstLiveAdder * adder, GstLiveAdderClass * klass)
     193                 :            : {
     194                 :          3 :   adder->srcpad =
     195                 :          3 :       gst_pad_new_from_static_template (&gst_live_adder_src_template, "src");
     196                 :          3 :   gst_pad_set_getcaps_function (adder->srcpad,
     197                 :          3 :       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
     198                 :          3 :   gst_pad_set_setcaps_function (adder->srcpad,
     199                 :          3 :       GST_DEBUG_FUNCPTR (gst_live_adder_setcaps));
     200                 :          3 :   gst_pad_set_query_function (adder->srcpad,
     201                 :          3 :       GST_DEBUG_FUNCPTR (gst_live_adder_query));
     202                 :          3 :   gst_pad_set_event_function (adder->srcpad,
     203                 :          3 :       GST_DEBUG_FUNCPTR (gst_live_adder_src_event));
     204                 :          3 :   gst_pad_set_activatepush_function (adder->srcpad,
     205                 :          3 :       GST_DEBUG_FUNCPTR (gst_live_adder_src_activate_push));
     206                 :          3 :   gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
     207                 :            : 
     208                 :          3 :   adder->format = GST_LIVE_ADDER_FORMAT_UNSET;
     209                 :          3 :   adder->padcount = 0;
     210                 :          3 :   adder->func = NULL;
     211                 :          3 :   adder->not_empty_cond = g_cond_new ();
     212                 :            : 
     213                 :          3 :   adder->next_timestamp = GST_CLOCK_TIME_NONE;
     214                 :            : 
     215                 :          3 :   adder->latency_ms = DEFAULT_LATENCY_MS;
     216                 :            : 
     217                 :          3 :   adder->buffers = g_queue_new ();
     218                 :          3 : }
     219                 :            : 
     220                 :            : 
     221                 :            : static void
     222                 :          3 : gst_live_adder_finalize (GObject * object)
     223                 :            : {
     224                 :          3 :   GstLiveAdder *adder = GST_LIVE_ADDER (object);
     225                 :            : 
     226                 :          3 :   g_cond_free (adder->not_empty_cond);
     227                 :            : 
     228                 :          3 :   g_queue_foreach (adder->buffers, (GFunc) gst_mini_object_unref, NULL);
     229         [ -  + ]:          3 :   while (g_queue_pop_head (adder->buffers)) {
     230                 :            :   }
     231                 :          3 :   g_queue_free (adder->buffers);
     232                 :            : 
     233                 :          3 :   g_list_free (adder->sinkpads);
     234                 :            : 
     235                 :          3 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     236                 :          3 : }
     237                 :            : 
     238                 :            : 
     239                 :            : static void
     240                 :          0 : gst_live_adder_set_property (GObject * object,
     241                 :            :     guint prop_id, const GValue * value, GParamSpec * pspec)
     242                 :            : {
     243                 :          0 :   GstLiveAdder *adder = GST_LIVE_ADDER (object);
     244                 :            : 
     245         [ #  # ]:          0 :   switch (prop_id) {
     246                 :            :     case PROP_LATENCY:
     247                 :            :     {
     248                 :            :       guint64 new_latency, old_latency;
     249                 :            : 
     250                 :          0 :       new_latency = g_value_get_uint (value);
     251                 :            : 
     252                 :          0 :       GST_OBJECT_LOCK (adder);
     253                 :          0 :       old_latency = adder->latency_ms;
     254                 :          0 :       adder->latency_ms = new_latency;
     255                 :          0 :       GST_OBJECT_UNLOCK (adder);
     256                 :            : 
     257                 :            :       /* post message if latency changed, this will inform the parent pipeline
     258                 :            :        * that a latency reconfiguration is possible/needed. */
     259         [ #  # ]:          0 :       if (new_latency != old_latency) {
     260 [ #  # ][ #  # ]:          0 :         GST_DEBUG_OBJECT (adder, "latency changed to: %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     261                 :            :             GST_TIME_ARGS (new_latency));
     262                 :            : 
     263                 :          0 :         gst_element_post_message (GST_ELEMENT_CAST (adder),
     264                 :            :             gst_message_new_latency (GST_OBJECT_CAST (adder)));
     265                 :            :       }
     266                 :          0 :       break;
     267                 :            :     }
     268                 :            :     default:
     269                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     270                 :          0 :       break;
     271                 :            :   }
     272                 :          0 : }
     273                 :            : 
     274                 :            : 
     275                 :            : static void
     276                 :          0 : gst_live_adder_get_property (GObject * object,
     277                 :            :     guint prop_id, GValue * value, GParamSpec * pspec)
     278                 :            : {
     279                 :          0 :   GstLiveAdder *adder = GST_LIVE_ADDER (object);
     280                 :            : 
     281         [ #  # ]:          0 :   switch (prop_id) {
     282                 :            :     case PROP_LATENCY:
     283                 :          0 :       GST_OBJECT_LOCK (adder);
     284                 :          0 :       g_value_set_uint (value, adder->latency_ms);
     285                 :          0 :       GST_OBJECT_UNLOCK (adder);
     286                 :          0 :       break;
     287                 :            :     default:
     288                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     289                 :          0 :       break;
     290                 :            :   }
     291                 :          0 : }
     292                 :            : 
     293                 :            : 
     294                 :            : /* we can only accept caps that we and downstream can handle. */
     295                 :            : static GstCaps *
     296                 :          0 : gst_live_adder_sink_getcaps (GstPad * pad)
     297                 :            : {
     298                 :            :   GstLiveAdder *adder;
     299                 :            :   GstCaps *result, *peercaps, *sinkcaps;
     300                 :            : 
     301                 :          0 :   adder = GST_LIVE_ADDER (GST_PAD_PARENT (pad));
     302                 :            : 
     303                 :            :   /* get the downstream possible caps */
     304                 :          0 :   peercaps = gst_pad_peer_get_caps (adder->srcpad);
     305                 :            :   /* get the allowed caps on this sinkpad, we use the fixed caps function so
     306                 :            :    * that it does not call recursively in this function. */
     307                 :          0 :   sinkcaps = gst_pad_get_fixed_caps_func (pad);
     308         [ #  # ]:          0 :   if (peercaps) {
     309                 :            :     /* if the peer has caps, intersect */
     310         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
     311                 :          0 :     result = gst_caps_intersect (peercaps, sinkcaps);
     312                 :          0 :     gst_caps_unref (peercaps);
     313                 :          0 :     gst_caps_unref (sinkcaps);
     314                 :            :   } else {
     315                 :            :     /* the peer has no caps (or there is no peer), just use the allowed caps
     316                 :            :      * of this sinkpad. */
     317         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
     318                 :          0 :     result = sinkcaps;
     319                 :            :   }
     320                 :            : 
     321                 :          0 :   return result;
     322                 :            : }
     323                 :            : 
     324                 :            : /* the first caps we receive on any of the sinkpads will define the caps for all
     325                 :            :  * the other sinkpads because we can only mix streams with the same caps.
     326                 :            :  * */
     327                 :            : static gboolean
     328                 :          0 : gst_live_adder_setcaps (GstPad * pad, GstCaps * caps)
     329                 :            : {
     330                 :            :   GstLiveAdder *adder;
     331                 :            :   GList *pads;
     332                 :            :   GstStructure *structure;
     333                 :            :   const char *media_type;
     334                 :            : 
     335                 :          0 :   adder = GST_LIVE_ADDER (GST_PAD_PARENT (pad));
     336                 :            : 
     337         [ #  # ]:          0 :   GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
     338                 :            :       GST_PAD_NAME (pad), caps);
     339                 :            : 
     340                 :            :   /* FIXME, see if the other pads can accept the format. Also lock the
     341                 :            :    * format on the other pads to this new format. */
     342                 :          0 :   GST_OBJECT_LOCK (adder);
     343                 :          0 :   pads = GST_ELEMENT (adder)->pads;
     344         [ #  # ]:          0 :   while (pads) {
     345                 :          0 :     GstPad *otherpad = GST_PAD (pads->data);
     346                 :            : 
     347         [ #  # ]:          0 :     if (otherpad != pad)
     348                 :          0 :       gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
     349                 :            : 
     350         [ #  # ]:          0 :     pads = g_list_next (pads);
     351                 :            :   }
     352                 :            : 
     353                 :            :   /* parse caps now */
     354                 :          0 :   structure = gst_caps_get_structure (caps, 0);
     355                 :          0 :   media_type = gst_structure_get_name (structure);
     356         [ #  # ]:          0 :   if (strcmp (media_type, "audio/x-raw-int") == 0) {
     357         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format int");
     358                 :          0 :     adder->format = GST_LIVE_ADDER_FORMAT_INT;
     359                 :          0 :     gst_structure_get_int (structure, "width", &adder->width);
     360                 :          0 :     gst_structure_get_int (structure, "depth", &adder->depth);
     361                 :          0 :     gst_structure_get_int (structure, "endianness", &adder->endianness);
     362                 :          0 :     gst_structure_get_boolean (structure, "signed", &adder->is_signed);
     363                 :            : 
     364         [ #  # ]:          0 :     if (adder->endianness != G_BYTE_ORDER)
     365                 :          0 :       goto not_supported;
     366                 :            : 
     367   [ #  #  #  # ]:          0 :     switch (adder->width) {
     368                 :            :       case 8:
     369                 :          0 :         adder->func = (adder->is_signed ?
     370         [ #  # ]:          0 :             (GstLiveAdderFunction) add_int8 : (GstLiveAdderFunction) add_uint8);
     371                 :          0 :         break;
     372                 :            :       case 16:
     373                 :          0 :         adder->func = (adder->is_signed ?
     374         [ #  # ]:          0 :             (GstLiveAdderFunction) add_int16 : (GstLiveAdderFunction)
     375                 :            :             add_uint16);
     376                 :          0 :         break;
     377                 :            :       case 32:
     378                 :          0 :         adder->func = (adder->is_signed ?
     379         [ #  # ]:          0 :             (GstLiveAdderFunction) add_int32 : (GstLiveAdderFunction)
     380                 :            :             add_uint32);
     381                 :          0 :         break;
     382                 :            :       default:
     383                 :          0 :         goto not_supported;
     384                 :            :     }
     385         [ #  # ]:          0 :   } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
     386         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format float");
     387                 :          0 :     adder->format = GST_LIVE_ADDER_FORMAT_FLOAT;
     388                 :          0 :     gst_structure_get_int (structure, "width", &adder->width);
     389                 :            : 
     390      [ #  #  # ]:          0 :     switch (adder->width) {
     391                 :            :       case 32:
     392                 :          0 :         adder->func = (GstLiveAdderFunction) add_float32;
     393                 :          0 :         break;
     394                 :            :       case 64:
     395                 :          0 :         adder->func = (GstLiveAdderFunction) add_float64;
     396                 :          0 :         break;
     397                 :            :       default:
     398                 :          0 :         goto not_supported;
     399                 :            :     }
     400                 :            :   } else {
     401                 :          0 :     goto not_supported;
     402                 :            :   }
     403                 :            : 
     404                 :          0 :   gst_structure_get_int (structure, "channels", &adder->channels);
     405                 :          0 :   gst_structure_get_int (structure, "rate", &adder->rate);
     406                 :            :   /* precalc bps */
     407                 :          0 :   adder->bps = (adder->width / 8) * adder->channels;
     408                 :            : 
     409                 :          0 :   GST_OBJECT_UNLOCK (adder);
     410                 :          0 :   return TRUE;
     411                 :            : 
     412                 :            :   /* ERRORS */
     413                 :            : not_supported:
     414                 :            :   {
     415                 :          0 :     GST_OBJECT_UNLOCK (adder);
     416         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
     417                 :          0 :     return FALSE;
     418                 :            :   }
     419                 :            : }
     420                 :            : 
     421                 :            : static void
     422                 :          7 : gst_live_adder_flush_start (GstLiveAdder * adder)
     423                 :            : {
     424         [ -  + ]:          7 :   GST_DEBUG_OBJECT (adder, "Disabling pop on queue");
     425                 :            : 
     426                 :          7 :   GST_OBJECT_LOCK (adder);
     427                 :            :   /* mark ourselves as flushing */
     428                 :          7 :   adder->srcresult = GST_FLOW_WRONG_STATE;
     429                 :            : 
     430                 :            :   /* Empty the queue */
     431                 :          7 :   g_queue_foreach (adder->buffers, (GFunc) gst_mini_object_unref, NULL);
     432         [ -  + ]:          7 :   while (g_queue_pop_head (adder->buffers));
     433                 :            : 
     434                 :            :   /* unlock clock, we just unschedule, the entry will be released by the
     435                 :            :    * locking streaming thread. */
     436         [ -  + ]:          7 :   if (adder->clock_id)
     437                 :          0 :     gst_clock_id_unschedule (adder->clock_id);
     438                 :            : 
     439                 :          7 :   g_cond_broadcast (adder->not_empty_cond);
     440                 :          7 :   GST_OBJECT_UNLOCK (adder);
     441                 :          7 : }
     442                 :            : 
     443                 :            : static gboolean
     444                 :         14 : gst_live_adder_src_activate_push (GstPad * pad, gboolean active)
     445                 :            : {
     446                 :         14 :   gboolean result = TRUE;
     447                 :         14 :   GstLiveAdder *adder = NULL;
     448                 :            : 
     449                 :         14 :   adder = GST_LIVE_ADDER (gst_pad_get_parent (pad));
     450                 :            : 
     451         [ +  + ]:         14 :   if (active) {
     452                 :            :     /* Mark as non flushing */
     453                 :          7 :     GST_OBJECT_LOCK (adder);
     454                 :          7 :     adder->srcresult = GST_FLOW_OK;
     455                 :          7 :     GST_OBJECT_UNLOCK (adder);
     456                 :            : 
     457                 :            :     /* start pushing out buffers */
     458         [ -  + ]:          7 :     GST_DEBUG_OBJECT (adder, "Starting task on srcpad");
     459                 :          7 :     gst_pad_start_task (adder->srcpad,
     460                 :            :         (GstTaskFunction) gst_live_adder_loop, adder);
     461                 :            :   } else {
     462                 :            :     /* make sure all data processing stops ASAP */
     463                 :          7 :     gst_live_adder_flush_start (adder);
     464                 :            : 
     465                 :            :     /* NOTE this will hardlock if the state change is called from the src pad
     466                 :            :      * task thread because we will _join() the thread. */
     467         [ -  + ]:          7 :     GST_DEBUG_OBJECT (adder, "Stopping task on srcpad");
     468                 :          7 :     result = gst_pad_stop_task (pad);
     469                 :            :   }
     470                 :            : 
     471                 :         14 :   gst_object_unref (adder);
     472                 :            : 
     473                 :         14 :   return result;
     474                 :            : }
     475                 :            : 
     476                 :            : static gboolean
     477                 :          0 : gst_live_adder_sink_event (GstPad * pad, GstEvent * event)
     478                 :            : {
     479                 :          0 :   gboolean ret = TRUE;
     480                 :          0 :   GstLiveAdder *adder = NULL;
     481                 :          0 :   GstLiveAdderPadPrivate *padprivate = NULL;
     482                 :            : 
     483                 :          0 :   adder = GST_LIVE_ADDER (gst_pad_get_parent (pad));
     484                 :            : 
     485                 :          0 :   padprivate = gst_pad_get_element_private (pad);
     486                 :            : 
     487         [ #  # ]:          0 :   if (!padprivate)
     488                 :          0 :     return FALSE;
     489                 :            : 
     490         [ #  # ]:          0 :   GST_LOG_OBJECT (adder, "received %s", GST_EVENT_TYPE_NAME (event));
     491                 :            : 
     492   [ #  #  #  #  :          0 :   switch (GST_EVENT_TYPE (event)) {
                      # ]
     493                 :            :     case GST_EVENT_NEWSEGMENT:
     494                 :            :     {
     495                 :            :       GstFormat format;
     496                 :            :       gdouble rate, arate;
     497                 :            :       gint64 start, stop, time;
     498                 :            :       gboolean update;
     499                 :            : 
     500                 :          0 :       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
     501                 :            :           &start, &stop, &time);
     502                 :            : 
     503                 :          0 :       gst_event_unref (event);
     504                 :            : 
     505                 :            :       /* we need time for now */
     506         [ #  # ]:          0 :       if (format != GST_FORMAT_TIME)
     507                 :          0 :         goto newseg_wrong_format;
     508                 :            : 
     509 [ #  # ][ #  # ]:          0 :       GST_DEBUG_OBJECT (adder,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     510                 :            :           "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
     511                 :            :           ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
     512                 :            :           update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
     513                 :            :           GST_TIME_ARGS (time));
     514                 :            : 
     515                 :            :       /* now configure the values, we need these to time the release of the
     516                 :            :        * buffers on the srcpad. */
     517                 :          0 :       GST_OBJECT_LOCK (adder);
     518                 :          0 :       gst_segment_set_newsegment_full (&padprivate->segment, update,
     519                 :            :           rate, arate, format, start, stop, time);
     520                 :          0 :       GST_OBJECT_UNLOCK (adder);
     521                 :          0 :       break;
     522                 :            :     }
     523                 :            :     case GST_EVENT_FLUSH_START:
     524                 :          0 :       gst_live_adder_flush_start (adder);
     525                 :          0 :       ret = gst_pad_push_event (adder->srcpad, event);
     526                 :          0 :       break;
     527                 :            :     case GST_EVENT_FLUSH_STOP:
     528                 :          0 :       GST_OBJECT_LOCK (adder);
     529                 :          0 :       adder->segment_pending = TRUE;
     530                 :          0 :       adder->next_timestamp = GST_CLOCK_TIME_NONE;
     531                 :          0 :       reset_pad_private (pad);
     532                 :          0 :       adder->segment_pending = TRUE;
     533                 :          0 :       GST_OBJECT_UNLOCK (adder);
     534                 :          0 :       ret = gst_pad_push_event (adder->srcpad, event);
     535                 :          0 :       ret = gst_live_adder_src_activate_push (adder->srcpad, TRUE);
     536                 :          0 :       break;
     537                 :            :     case GST_EVENT_EOS:
     538                 :            :     {
     539                 :          0 :       GST_OBJECT_LOCK (adder);
     540                 :            : 
     541                 :          0 :       ret = adder->srcresult == GST_FLOW_OK;
     542 [ #  # ][ #  # ]:          0 :       if (ret && !padprivate->eos) {
     543         [ #  # ]:          0 :         GST_DEBUG_OBJECT (adder, "queuing EOS");
     544                 :          0 :         padprivate->eos = TRUE;
     545                 :          0 :         g_cond_broadcast (adder->not_empty_cond);
     546         [ #  # ]:          0 :       } else if (padprivate->eos) {
     547         [ #  # ]:          0 :         GST_DEBUG_OBJECT (adder, "dropping EOS, we are already EOS");
     548                 :            :       } else {
     549         [ #  # ]:          0 :         GST_DEBUG_OBJECT (adder, "dropping EOS, reason %s",
     550                 :            :             gst_flow_get_name (adder->srcresult));
     551                 :            :       }
     552                 :            : 
     553                 :          0 :       GST_OBJECT_UNLOCK (adder);
     554                 :            : 
     555                 :          0 :       gst_event_unref (event);
     556                 :          0 :       break;
     557                 :            :     }
     558                 :            :     default:
     559                 :          0 :       ret = gst_pad_push_event (adder->srcpad, event);
     560                 :          0 :       break;
     561                 :            :   }
     562                 :            : 
     563                 :            : done:
     564                 :          0 :   gst_object_unref (adder);
     565                 :            : 
     566                 :          0 :   return ret;
     567                 :            : 
     568                 :            :   /* ERRORS */
     569                 :            : newseg_wrong_format:
     570                 :            :   {
     571         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "received non TIME newsegment");
     572                 :          0 :     ret = FALSE;
     573                 :          0 :     goto done;
     574                 :            :   }
     575                 :            : }
     576                 :            : 
     577                 :            : static gboolean
     578                 :          0 : gst_live_adder_query_pos_dur (GstLiveAdder * adder, GstFormat informat,
     579                 :            :     gboolean position, gint64 * outvalue)
     580                 :            : {
     581                 :          0 :   gint64 max = G_MININT64;
     582                 :          0 :   gboolean res = TRUE;
     583                 :            :   GstIterator *it;
     584                 :          0 :   gboolean done = FALSE;
     585                 :            : 
     586                 :            : 
     587                 :          0 :   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
     588         [ #  # ]:          0 :   while (!done) {
     589                 :            :     GstIteratorResult ires;
     590                 :            :     gpointer item;
     591                 :          0 :     GstFormat format = informat;
     592                 :            : 
     593                 :          0 :     ires = gst_iterator_next (it, &item);
     594   [ #  #  #  # ]:          0 :     switch (ires) {
     595                 :            :       case GST_ITERATOR_DONE:
     596                 :          0 :         done = TRUE;
     597                 :          0 :         break;
     598                 :            :       case GST_ITERATOR_OK:
     599                 :            :       {
     600                 :          0 :         GstPad *pad = GST_PAD_CAST (item);
     601                 :            :         gint64 value;
     602                 :            :         gboolean curres;
     603                 :            : 
     604                 :            :         /* ask sink peer for duration */
     605         [ #  # ]:          0 :         if (position)
     606                 :          0 :           curres = gst_pad_query_peer_position (pad, &format, &value);
     607                 :            :         else
     608                 :          0 :           curres = gst_pad_query_peer_duration (pad, &format, &value);
     609                 :            : 
     610                 :            :         /* take max from all valid return values */
     611                 :            :         /* Only if the format is the one we requested, otherwise ignore it ?
     612                 :            :          */
     613                 :            : 
     614 [ #  # ][ #  # ]:          0 :         if (curres && format == informat) {
     615                 :          0 :           res &= curres;
     616                 :            : 
     617                 :            :           /* valid unknown length, stop searching */
     618         [ #  # ]:          0 :           if (value == -1) {
     619                 :          0 :             max = value;
     620                 :          0 :             done = TRUE;
     621         [ #  # ]:          0 :           } else if (value > max) {
     622                 :          0 :             max = value;
     623                 :            :           }
     624                 :            :         }
     625                 :          0 :         break;
     626                 :            :       }
     627                 :            :       case GST_ITERATOR_RESYNC:
     628                 :          0 :         max = -1;
     629                 :          0 :         res = TRUE;
     630                 :          0 :         break;
     631                 :            :       default:
     632                 :          0 :         res = FALSE;
     633                 :          0 :         done = TRUE;
     634                 :          0 :         break;
     635                 :            :     }
     636                 :            :   }
     637                 :          0 :   gst_iterator_free (it);
     638                 :            : 
     639         [ #  # ]:          0 :   if (res)
     640                 :          0 :     *outvalue = max;
     641                 :            : 
     642                 :          0 :   return res;
     643                 :            : }
     644                 :            : 
     645                 :            : /* FIXME:
     646                 :            :  *
     647                 :            :  * When we add a new stream (or remove a stream) the duration might
     648                 :            :  * also become invalid again and we need to post a new DURATION
     649                 :            :  * message to notify this fact to the parent.
     650                 :            :  * For now we take the max of all the upstream elements so the simple
     651                 :            :  * cases work at least somewhat.
     652                 :            :  */
     653                 :            : static gboolean
     654                 :          0 : gst_live_adder_query_duration (GstLiveAdder * adder, GstQuery * query)
     655                 :            : {
     656                 :            :   GstFormat format;
     657                 :            :   gint64 max;
     658                 :            :   gboolean res;
     659                 :            : 
     660                 :            :   /* parse format */
     661                 :          0 :   gst_query_parse_duration (query, &format, NULL);
     662                 :            : 
     663                 :          0 :   res = gst_live_adder_query_pos_dur (adder, format, FALSE, &max);
     664                 :            : 
     665         [ #  # ]:          0 :   if (res) {
     666                 :            :     /* and store the max */
     667                 :          0 :     gst_query_set_duration (query, format, max);
     668                 :            :   }
     669                 :            : 
     670                 :          0 :   return res;
     671                 :            : }
     672                 :            : 
     673                 :            : static gboolean
     674                 :          0 : gst_live_adder_query_position (GstLiveAdder * adder, GstQuery * query)
     675                 :            : {
     676                 :            :   GstFormat format;
     677                 :            :   gint64 max;
     678                 :            :   gboolean res;
     679                 :            : 
     680                 :            :   /* parse format */
     681                 :          0 :   gst_query_parse_position (query, &format, NULL);
     682                 :            : 
     683                 :          0 :   res = gst_live_adder_query_pos_dur (adder, format, TRUE, &max);
     684                 :            : 
     685         [ #  # ]:          0 :   if (res) {
     686                 :            :     /* and store the max */
     687                 :          0 :     gst_query_set_position (query, format, max);
     688                 :            :   }
     689                 :            : 
     690                 :          0 :   return res;
     691                 :            : }
     692                 :            : 
     693                 :            : 
     694                 :            : 
     695                 :            : static gboolean
     696                 :          0 : gst_live_adder_query (GstPad * pad, GstQuery * query)
     697                 :            : {
     698                 :            :   GstLiveAdder *adder;
     699                 :          0 :   gboolean res = FALSE;
     700                 :            : 
     701                 :          0 :   adder = GST_LIVE_ADDER (gst_pad_get_parent (pad));
     702                 :            : 
     703   [ #  #  #  # ]:          0 :   switch (GST_QUERY_TYPE (query)) {
     704                 :            :     case GST_QUERY_LATENCY:
     705                 :            :     {
     706                 :            :       /* We need to send the query upstream and add the returned latency to our
     707                 :            :        * own */
     708                 :          0 :       GstClockTime min_latency = 0, max_latency = G_MAXUINT64;
     709                 :            :       gpointer item;
     710                 :          0 :       GstIterator *iter = NULL;
     711                 :          0 :       gboolean done = FALSE;
     712                 :            : 
     713                 :          0 :       iter = gst_element_iterate_sink_pads (GST_ELEMENT (adder));
     714                 :            : 
     715         [ #  # ]:          0 :       while (!done) {
     716   [ #  #  #  #  :          0 :         switch (gst_iterator_next (iter, &item)) {
                      # ]
     717                 :            :           case GST_ITERATOR_OK:
     718                 :            :           {
     719                 :          0 :             GstPad *sinkpad = item;
     720                 :            :             GstClockTime pad_min_latency, pad_max_latency;
     721                 :            :             gboolean pad_us_live;
     722                 :            : 
     723         [ #  # ]:          0 :             if (gst_pad_peer_query (sinkpad, query)) {
     724                 :          0 :               gst_query_parse_latency (query, &pad_us_live, &pad_min_latency,
     725                 :            :                   &pad_max_latency);
     726                 :            : 
     727                 :          0 :               res = TRUE;
     728                 :            : 
     729 [ #  # ][ #  # ]:          0 :               GST_DEBUG_OBJECT (adder, "Peer latency for pad %s: min %"
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     730                 :            :                   GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
     731                 :            :                   GST_PAD_NAME (sinkpad),
     732                 :            :                   GST_TIME_ARGS (pad_min_latency),
     733                 :            :                   GST_TIME_ARGS (pad_max_latency));
     734                 :            : 
     735                 :          0 :               min_latency = MAX (pad_min_latency, min_latency);
     736                 :          0 :               max_latency = MIN (pad_max_latency, max_latency);
     737                 :            :             }
     738                 :          0 :             gst_object_unref (item);
     739                 :            :           }
     740                 :          0 :             break;
     741                 :            :           case GST_ITERATOR_RESYNC:
     742                 :          0 :             min_latency = 0;
     743                 :          0 :             max_latency = G_MAXUINT64;
     744                 :            : 
     745                 :          0 :             gst_iterator_resync (iter);
     746                 :          0 :             break;
     747                 :            :           case GST_ITERATOR_ERROR:
     748         [ #  # ]:          0 :             GST_ERROR_OBJECT (adder, "Error looping sink pads");
     749                 :          0 :             done = TRUE;
     750                 :          0 :             break;
     751                 :            :           case GST_ITERATOR_DONE:
     752                 :          0 :             done = TRUE;
     753                 :          0 :             break;
     754                 :            :         }
     755                 :            :       }
     756                 :          0 :       gst_iterator_free (iter);
     757                 :            : 
     758         [ #  # ]:          0 :       if (res) {
     759                 :          0 :         GstClockTime my_latency = adder->latency_ms * GST_MSECOND;
     760                 :          0 :         GST_OBJECT_LOCK (adder);
     761                 :          0 :         adder->peer_latency = min_latency;
     762                 :          0 :         min_latency += my_latency;
     763                 :          0 :         GST_OBJECT_UNLOCK (adder);
     764                 :            : 
     765                 :            :         /* Make sure we don't risk an overflow */
     766         [ #  # ]:          0 :         if (max_latency < G_MAXUINT64 - my_latency)
     767                 :          0 :           max_latency += my_latency;
     768                 :            :         else
     769                 :          0 :           max_latency = G_MAXUINT64;
     770                 :          0 :         gst_query_set_latency (query, TRUE, min_latency, max_latency);
     771 [ #  # ][ #  # ]:          0 :         GST_DEBUG_OBJECT (adder, "Calculated total latency : min %"
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     772                 :            :             GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
     773                 :            :             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
     774                 :            :       }
     775                 :          0 :       break;
     776                 :            :     }
     777                 :            :     case GST_QUERY_DURATION:
     778                 :          0 :       res = gst_live_adder_query_duration (adder, query);
     779                 :          0 :       break;
     780                 :            :     case GST_QUERY_POSITION:
     781                 :          0 :       res = gst_live_adder_query_position (adder, query);
     782                 :          0 :       break;
     783                 :            :     default:
     784                 :          0 :       res = gst_pad_query_default (pad, query);
     785                 :          0 :       break;
     786                 :            :   }
     787                 :            : 
     788                 :          0 :   gst_object_unref (adder);
     789                 :            : 
     790                 :          0 :   return res;
     791                 :            : }
     792                 :            : 
     793                 :            : static gboolean
     794                 :          0 : forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
     795                 :            : {
     796                 :          0 :   gst_event_ref (event);
     797         [ #  # ]:          0 :   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
     798         [ #  # ]:          0 :   if (!gst_pad_push_event (pad, event)) {
     799                 :          0 :     g_value_set_boolean (ret, FALSE);
     800         [ #  # ]:          0 :     GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
     801                 :            :         event, GST_EVENT_TYPE_NAME (event));
     802                 :            :   } else {
     803         [ #  # ]:          0 :     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
     804                 :            :         event, GST_EVENT_TYPE_NAME (event));
     805                 :            :   }
     806                 :            : 
     807                 :            :   /* unref the pad because of a FIXME in gst_iterator_unfold
     808                 :            :    * it does a gst_iterator_next which refs the pad, but it never unrefs it
     809                 :            :    */
     810                 :          0 :   gst_object_unref (pad);
     811                 :          0 :   return TRUE;
     812                 :            : }
     813                 :            : 
     814                 :            : /* forwards the event to all sinkpads, takes ownership of the
     815                 :            :  * event
     816                 :            :  *
     817                 :            :  * Returns: TRUE if the event could be forwarded on all
     818                 :            :  * sinkpads.
     819                 :            :  */
     820                 :            : static gboolean
     821                 :          0 : forward_event (GstLiveAdder * adder, GstEvent * event)
     822                 :            : {
     823                 :            :   gboolean ret;
     824                 :            :   GstIterator *it;
     825                 :          0 :   GValue vret = { 0 };
     826                 :            : 
     827         [ #  # ]:          0 :   GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
     828                 :            :       GST_EVENT_TYPE_NAME (event));
     829                 :            : 
     830                 :          0 :   ret = TRUE;
     831                 :            : 
     832                 :          0 :   g_value_init (&vret, G_TYPE_BOOLEAN);
     833                 :          0 :   g_value_set_boolean (&vret, TRUE);
     834                 :          0 :   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
     835                 :          0 :   gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
     836                 :            :       event);
     837                 :          0 :   gst_iterator_free (it);
     838                 :            : 
     839                 :          0 :   ret = g_value_get_boolean (&vret);
     840                 :            : 
     841                 :          0 :   return ret;
     842                 :            : }
     843                 :            : 
     844                 :            : 
     845                 :            : static gboolean
     846                 :          0 : gst_live_adder_src_event (GstPad * pad, GstEvent * event)
     847                 :            : {
     848                 :            :   GstLiveAdder *adder;
     849                 :            :   gboolean result;
     850                 :            : 
     851                 :          0 :   adder = GST_LIVE_ADDER (gst_pad_get_parent (pad));
     852                 :            : 
     853      [ #  #  # ]:          0 :   switch (GST_EVENT_TYPE (event)) {
     854                 :            :     case GST_EVENT_QOS:
     855                 :            :       /* TODO : QoS might be tricky */
     856                 :          0 :       result = FALSE;
     857                 :          0 :       break;
     858                 :            :     case GST_EVENT_NAVIGATION:
     859                 :            :       /* TODO : navigation is rather pointless. */
     860                 :          0 :       result = FALSE;
     861                 :          0 :       break;
     862                 :            :     default:
     863                 :            :       /* just forward the rest for now */
     864                 :          0 :       result = forward_event (adder, event);
     865                 :          0 :       break;
     866                 :            :   }
     867                 :            : 
     868                 :          0 :   gst_event_unref (event);
     869                 :          0 :   gst_object_unref (adder);
     870                 :            : 
     871                 :          0 :   return result;
     872                 :            : }
     873                 :            : 
     874                 :            : static guint
     875                 :          0 : gst_live_adder_length_from_duration (GstLiveAdder * adder,
     876                 :            :     GstClockTime duration)
     877                 :            : {
     878                 :          0 :   guint64 ret = (duration * adder->rate / GST_SECOND) * adder->bps;
     879                 :            : 
     880                 :          0 :   return (guint) ret;
     881                 :            : }
     882                 :            : 
     883                 :            : static GstFlowReturn
     884                 :          0 : gst_live_live_adder_chain (GstPad * pad, GstBuffer * buffer)
     885                 :            : {
     886                 :          0 :   GstLiveAdder *adder = GST_LIVE_ADDER (gst_pad_get_parent_element (pad));
     887                 :          0 :   GstLiveAdderPadPrivate *padprivate = NULL;
     888                 :          0 :   GstFlowReturn ret = GST_FLOW_OK;
     889                 :          0 :   GList *item = NULL;
     890                 :          0 :   GstClockTime skip = 0;
     891                 :          0 :   gint64 drift = 0;             /* Positive if new buffer after old buffer */
     892                 :            : 
     893                 :          0 :   GST_OBJECT_LOCK (adder);
     894                 :            : 
     895                 :          0 :   ret = adder->srcresult;
     896                 :            : 
     897 [ #  # ][ #  # ]:          0 :   GST_DEBUG ("Incoming buffer time:%" GST_TIME_FORMAT " duration:%"
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     898                 :            :       GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
     899                 :            :       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
     900                 :            : 
     901         [ #  # ]:          0 :   if (ret != GST_FLOW_OK) {
     902         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "Passing non-ok result from src: %s",
     903                 :            :         gst_flow_get_name (ret));
     904                 :          0 :     gst_buffer_unref (buffer);
     905                 :          0 :     goto out;
     906                 :            :   }
     907                 :            : 
     908                 :          0 :   padprivate = gst_pad_get_element_private (pad);
     909                 :            : 
     910         [ #  # ]:          0 :   if (!padprivate) {
     911                 :          0 :     ret = GST_FLOW_NOT_LINKED;
     912                 :          0 :     gst_buffer_unref (buffer);
     913                 :          0 :     goto out;
     914                 :            :   }
     915                 :            : 
     916         [ #  # ]:          0 :   if (padprivate->eos) {
     917         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "Received buffer after EOS");
     918                 :          0 :     ret = GST_FLOW_UNEXPECTED;
     919                 :          0 :     gst_buffer_unref (buffer);
     920                 :          0 :     goto out;
     921                 :            :   }
     922                 :            : 
     923         [ #  # ]:          0 :   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
     924                 :          0 :     goto invalid_timestamp;
     925                 :            : 
     926         [ #  # ]:          0 :   if (padprivate->segment.format == GST_FORMAT_UNDEFINED) {
     927         [ #  # ]:          0 :     GST_WARNING_OBJECT (adder, "No new-segment received,"
     928                 :            :         " initializing segment with time 0..-1");
     929                 :          0 :     gst_segment_init (&padprivate->segment, GST_FORMAT_TIME);
     930                 :          0 :     gst_segment_set_newsegment (&padprivate->segment,
     931                 :            :         FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0);
     932                 :            :   }
     933                 :            : 
     934         [ #  # ]:          0 :   if (padprivate->segment.format != GST_FORMAT_TIME)
     935                 :          0 :     goto invalid_segment;
     936                 :            : 
     937                 :          0 :   buffer = gst_buffer_make_metadata_writable (buffer);
     938                 :            : 
     939                 :          0 :   drift = GST_BUFFER_TIMESTAMP (buffer) - padprivate->expected_timestamp;
     940                 :            : 
     941                 :            :   /* Just see if we receive invalid timestamp/durations */
     942 [ #  # ][ #  # ]:          0 :   if (GST_CLOCK_TIME_IS_VALID (padprivate->expected_timestamp) &&
     943         [ #  # ]:          0 :       !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT) &&
     944                 :            :       (drift != 0)) {
     945 [ #  # ][ #  # ]:          0 :     GST_LOG_OBJECT (adder,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     946                 :            :         "Timestamp discontinuity without the DISCONT flag set"
     947                 :            :         " (expected %" GST_TIME_FORMAT ", got %" GST_TIME_FORMAT
     948                 :            :         " drift:%" G_GINT64_FORMAT "ms)",
     949                 :            :         GST_TIME_ARGS (padprivate->expected_timestamp),
     950                 :            :         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), drift / GST_MSECOND);
     951                 :            : 
     952                 :            :     /* We accept drifts of 10ms */
     953 [ #  # ][ #  # ]:          0 :     if (ABS (drift) < (10 * GST_MSECOND)) {
     954         [ #  # ]:          0 :       GST_DEBUG ("Correcting minor drift");
     955                 :          0 :       GST_BUFFER_TIMESTAMP (buffer) = padprivate->expected_timestamp;
     956                 :            :     }
     957                 :            :   }
     958                 :            : 
     959                 :            : 
     960                 :            :   /* If there is no duration, lets set one */
     961         [ #  # ]:          0 :   if (!GST_BUFFER_DURATION_IS_VALID (buffer)) {
     962                 :          0 :     GST_BUFFER_DURATION (buffer) =
     963                 :          0 :         gst_audio_duration_from_pad_buffer (pad, buffer);
     964                 :          0 :     padprivate->expected_timestamp = GST_CLOCK_TIME_NONE;
     965                 :            :   } else {
     966                 :          0 :     padprivate->expected_timestamp = GST_BUFFER_TIMESTAMP (buffer) +
     967                 :          0 :         GST_BUFFER_DURATION (buffer);
     968                 :            :   }
     969                 :            : 
     970                 :            : 
     971                 :            :   /*
     972                 :            :    * Lets clip the buffer to the segment (so we don't have to worry about
     973                 :            :    * cliping afterwards).
     974                 :            :    * This should also guarantee us that we'll have valid timestamps and
     975                 :            :    * durations afterwards
     976                 :            :    */
     977                 :            : 
     978                 :          0 :   buffer = gst_audio_buffer_clip (buffer, &padprivate->segment, adder->rate,
     979                 :            :       adder->bps);
     980                 :            : 
     981                 :            :   /* buffer can be NULL if it's completely outside of the segment */
     982         [ #  # ]:          0 :   if (!buffer) {
     983         [ #  # ]:          0 :     GST_DEBUG ("Buffer completely outside of configured segment, dropping it");
     984                 :          0 :     goto out;
     985                 :            :   }
     986                 :            : 
     987                 :            :   /*
     988                 :            :    * Make sure all incoming buffers share the same timestamping
     989                 :            :    */
     990                 :          0 :   GST_BUFFER_TIMESTAMP (buffer) =
     991                 :          0 :       gst_segment_to_running_time (&padprivate->segment,
     992                 :          0 :       padprivate->segment.format, GST_BUFFER_TIMESTAMP (buffer));
     993                 :            : 
     994                 :            : 
     995 [ #  # ][ #  # ]:          0 :   if (GST_CLOCK_TIME_IS_VALID (adder->next_timestamp) &&
     996                 :          0 :       GST_BUFFER_TIMESTAMP (buffer) < adder->next_timestamp) {
     997         [ #  # ]:          0 :     if (GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) <
     998                 :          0 :         adder->next_timestamp) {
     999 [ #  # ][ #  # ]:          0 :       GST_DEBUG_OBJECT (adder, "Buffer is late, dropping (ts: %" GST_TIME_FORMAT
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1000                 :            :           " duration: %" GST_TIME_FORMAT ")",
    1001                 :            :           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
    1002                 :            :           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
    1003                 :          0 :       gst_buffer_unref (buffer);
    1004                 :          0 :       goto out;
    1005                 :            :     } else {
    1006                 :          0 :       skip = adder->next_timestamp - GST_BUFFER_TIMESTAMP (buffer);
    1007 [ #  # ][ #  # ]:          0 :       GST_DEBUG_OBJECT (adder, "Buffer is partially late, skipping %"
         [ #  # ][ #  # ]
                 [ #  # ]
    1008                 :            :           GST_TIME_FORMAT, GST_TIME_ARGS (skip));
    1009                 :            :     }
    1010                 :            :   }
    1011                 :            : 
    1012                 :            :   /* If our new buffer's head is higher than the queue's head, lets wake up,
    1013                 :            :    * we may not have to wait for as long
    1014                 :            :    */
    1015   [ #  #  #  # ]:          0 :   if (adder->clock_id &&
    1016         [ #  # ]:          0 :       g_queue_peek_head (adder->buffers) != NULL &&
    1017                 :          0 :       GST_BUFFER_TIMESTAMP (buffer) + skip <
    1018                 :          0 :       GST_BUFFER_TIMESTAMP (g_queue_peek_head (adder->buffers)))
    1019                 :          0 :     gst_clock_id_unschedule (adder->clock_id);
    1020                 :            : 
    1021         [ #  # ]:          0 :   for (item = g_queue_peek_head_link (adder->buffers);
    1022         [ #  # ]:          0 :       item; item = g_list_next (item)) {
    1023                 :          0 :     GstBuffer *oldbuffer = item->data;
    1024                 :          0 :     GstClockTime old_skip = 0;
    1025                 :          0 :     GstClockTime mix_duration = 0;
    1026                 :          0 :     GstClockTime mix_start = 0;
    1027                 :          0 :     GstClockTime mix_end = 0;
    1028                 :            : 
    1029                 :            :     /* We haven't reached our place yet */
    1030         [ #  # ]:          0 :     if (GST_BUFFER_TIMESTAMP (buffer) + skip >=
    1031                 :          0 :         GST_BUFFER_TIMESTAMP (oldbuffer) + GST_BUFFER_DURATION (oldbuffer))
    1032                 :          0 :       continue;
    1033                 :            : 
    1034                 :            :     /* We're past our place, lets insert ouselves here */
    1035         [ #  # ]:          0 :     if (GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) <=
    1036                 :          0 :         GST_BUFFER_TIMESTAMP (oldbuffer))
    1037                 :          0 :       break;
    1038                 :            : 
    1039                 :            :     /* if we reach this spot, we have overlap, so we must mix */
    1040                 :            : 
    1041                 :            :     /* First make a subbuffer with the non-overlapping part */
    1042         [ #  # ]:          0 :     if (GST_BUFFER_TIMESTAMP (buffer) + skip < GST_BUFFER_TIMESTAMP (oldbuffer)) {
    1043                 :          0 :       GstBuffer *subbuffer = NULL;
    1044                 :          0 :       GstClockTime subbuffer_duration = GST_BUFFER_TIMESTAMP (oldbuffer) -
    1045                 :          0 :           (GST_BUFFER_TIMESTAMP (buffer) + skip);
    1046                 :            : 
    1047                 :          0 :       subbuffer = gst_buffer_create_sub (buffer,
    1048                 :            :           gst_live_adder_length_from_duration (adder, skip),
    1049                 :            :           gst_live_adder_length_from_duration (adder, subbuffer_duration));
    1050                 :            : 
    1051                 :          0 :       GST_BUFFER_TIMESTAMP (subbuffer) = GST_BUFFER_TIMESTAMP (buffer) + skip;
    1052                 :          0 :       GST_BUFFER_DURATION (subbuffer) = subbuffer_duration;
    1053                 :            : 
    1054                 :          0 :       skip += subbuffer_duration;
    1055                 :            : 
    1056                 :          0 :       g_queue_insert_before (adder->buffers, item, subbuffer);
    1057                 :            :     }
    1058                 :            : 
    1059                 :            :     /* Now we are on the overlapping part */
    1060                 :          0 :     oldbuffer = gst_buffer_make_writable (oldbuffer);
    1061                 :          0 :     item->data = oldbuffer;
    1062                 :            : 
    1063                 :          0 :     old_skip = GST_BUFFER_TIMESTAMP (buffer) + skip -
    1064                 :          0 :         GST_BUFFER_TIMESTAMP (oldbuffer);
    1065                 :            : 
    1066                 :          0 :     mix_start = GST_BUFFER_TIMESTAMP (oldbuffer) + old_skip;
    1067                 :            : 
    1068         [ #  # ]:          0 :     if (GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) <
    1069                 :          0 :         GST_BUFFER_TIMESTAMP (oldbuffer) + GST_BUFFER_DURATION (oldbuffer))
    1070                 :          0 :       mix_end = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
    1071                 :            :     else
    1072                 :          0 :       mix_end = GST_BUFFER_TIMESTAMP (oldbuffer) +
    1073                 :          0 :           GST_BUFFER_DURATION (oldbuffer);
    1074                 :            : 
    1075                 :          0 :     mix_duration = mix_end - mix_start;
    1076                 :            : 
    1077                 :          0 :     adder->func (GST_BUFFER_DATA (oldbuffer) +
    1078                 :          0 :         gst_live_adder_length_from_duration (adder, old_skip),
    1079                 :          0 :         GST_BUFFER_DATA (buffer) +
    1080                 :          0 :         gst_live_adder_length_from_duration (adder, skip),
    1081                 :            :         gst_live_adder_length_from_duration (adder, mix_duration));
    1082                 :            : 
    1083                 :          0 :     skip += mix_duration;
    1084                 :            :   }
    1085                 :            : 
    1086                 :          0 :   g_cond_broadcast (adder->not_empty_cond);
    1087                 :            : 
    1088         [ #  # ]:          0 :   if (skip == GST_BUFFER_DURATION (buffer)) {
    1089                 :          0 :     gst_buffer_unref (buffer);
    1090                 :            :   } else {
    1091         [ #  # ]:          0 :     if (skip) {
    1092                 :          0 :       GstClockTime subbuffer_duration = GST_BUFFER_DURATION (buffer) - skip;
    1093                 :          0 :       GstClockTime subbuffer_ts = GST_BUFFER_TIMESTAMP (buffer) + skip;
    1094                 :            : 
    1095                 :          0 :       buffer = gst_buffer_create_sub (buffer,
    1096                 :            :           gst_live_adder_length_from_duration (adder, skip),
    1097                 :            :           gst_live_adder_length_from_duration (adder, subbuffer_duration));
    1098                 :          0 :       GST_BUFFER_TIMESTAMP (buffer) = subbuffer_ts;
    1099                 :          0 :       GST_BUFFER_DURATION (buffer) = subbuffer_duration;
    1100                 :            :     }
    1101                 :            : 
    1102         [ #  # ]:          0 :     if (item)
    1103                 :          0 :       g_queue_insert_before (adder->buffers, item, buffer);
    1104                 :            :     else
    1105                 :          0 :       g_queue_push_tail (adder->buffers, buffer);
    1106                 :            :   }
    1107                 :            : 
    1108                 :            : out:
    1109                 :            : 
    1110                 :          0 :   GST_OBJECT_UNLOCK (adder);
    1111                 :          0 :   gst_object_unref (adder);
    1112                 :            : 
    1113                 :          0 :   return ret;
    1114                 :            : 
    1115                 :            : invalid_timestamp:
    1116                 :            : 
    1117                 :          0 :   GST_OBJECT_UNLOCK (adder);
    1118                 :          0 :   gst_buffer_unref (buffer);
    1119 [ #  # ][ #  # ]:          0 :   GST_ELEMENT_ERROR (adder, STREAM, FAILED,
         [ #  # ][ #  # ]
    1120                 :            :       ("Buffer without a valid timestamp received"),
    1121                 :            :       ("Invalid timestamp received on buffer"));
    1122                 :            : 
    1123                 :          0 :   return GST_FLOW_ERROR;
    1124                 :            : 
    1125                 :            : invalid_segment:
    1126                 :            :   {
    1127                 :          0 :     const gchar *format = gst_format_get_name (padprivate->segment.format);
    1128                 :          0 :     GST_OBJECT_UNLOCK (adder);
    1129                 :          0 :     gst_buffer_unref (buffer);
    1130 [ #  # ][ #  # ]:          0 :     GST_ELEMENT_ERROR (adder, STREAM, FAILED,
         [ #  # ][ #  # ]
    1131                 :            :         ("This element only supports TIME segments, received other type"),
    1132                 :            :         ("Received a segment of type %s, only support time segment", format));
    1133                 :            : 
    1134                 :          0 :     return GST_FLOW_ERROR;
    1135                 :            :   }
    1136                 :            : 
    1137                 :            : }
    1138                 :            : 
    1139                 :            : /*
    1140                 :            :  * This only works because the GstObject lock is taken
    1141                 :            :  *
    1142                 :            :  * It checks if all sink pads are EOS
    1143                 :            :  */
    1144                 :            : static gboolean
    1145                 :          0 : check_eos_locked (GstLiveAdder * adder)
    1146                 :            : {
    1147                 :            :   GList *item;
    1148                 :            : 
    1149                 :            :   /* We can't be EOS if we have no sinkpads */
    1150         [ #  # ]:          0 :   if (adder->sinkpads == NULL)
    1151                 :          0 :     return FALSE;
    1152                 :            : 
    1153 [ #  # ][ #  # ]:          0 :   for (item = adder->sinkpads; item; item = g_list_next (item)) {
    1154                 :          0 :     GstPad *pad = item->data;
    1155                 :          0 :     GstLiveAdderPadPrivate *padprivate = gst_pad_get_element_private (pad);
    1156                 :            : 
    1157 [ #  # ][ #  # ]:          0 :     if (padprivate && padprivate->eos != TRUE)
    1158                 :          0 :       return FALSE;
    1159                 :            :   }
    1160                 :            : 
    1161                 :          0 :   return TRUE;
    1162                 :            : }
    1163                 :            : 
    1164                 :            : static void
    1165                 :          0 : gst_live_adder_loop (gpointer data)
    1166                 :            : {
    1167                 :          0 :   GstLiveAdder *adder = GST_LIVE_ADDER (data);
    1168                 :          0 :   GstClockTime buffer_timestamp = 0;
    1169                 :          0 :   GstClockTime sync_time = 0;
    1170                 :          0 :   GstClock *clock = NULL;
    1171                 :          0 :   GstClockID id = NULL;
    1172                 :            :   GstClockReturn ret;
    1173                 :          0 :   GstBuffer *buffer = NULL;
    1174                 :            :   GstFlowReturn result;
    1175                 :          0 :   GstEvent *newseg_event = NULL;
    1176                 :            : 
    1177                 :          0 :   GST_OBJECT_LOCK (adder);
    1178                 :            : 
    1179                 :            : again:
    1180                 :            : 
    1181                 :            :   for (;;) {
    1182         [ #  # ]:          0 :     if (adder->srcresult != GST_FLOW_OK)
    1183                 :          0 :       goto flushing;
    1184         [ #  # ]:          0 :     if (!g_queue_is_empty (adder->buffers))
    1185                 :          0 :       break;
    1186         [ #  # ]:          0 :     if (check_eos_locked (adder))
    1187                 :          0 :       goto eos;
    1188                 :          0 :     g_cond_wait (adder->not_empty_cond, GST_OBJECT_GET_LOCK (adder));
    1189                 :          0 :   }
    1190                 :            : 
    1191                 :          0 :   buffer_timestamp = GST_BUFFER_TIMESTAMP (g_queue_peek_head (adder->buffers));
    1192                 :            : 
    1193                 :          0 :   clock = GST_ELEMENT_CLOCK (adder);
    1194                 :            : 
    1195                 :            :   /* If we have no clock, then we can't do anything.. error */
    1196         [ #  # ]:          0 :   if (!clock) {
    1197         [ #  # ]:          0 :     if (adder->playing)
    1198                 :          0 :       goto no_clock;
    1199                 :            :     else
    1200                 :          0 :       goto push_buffer;
    1201                 :            :   }
    1202                 :            : 
    1203 [ #  # ][ #  # ]:          0 :   GST_DEBUG_OBJECT (adder, "sync to timestamp %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1204                 :            :       GST_TIME_ARGS (buffer_timestamp));
    1205                 :            : 
    1206                 :          0 :   sync_time = buffer_timestamp + GST_ELEMENT_CAST (adder)->base_time;
    1207                 :            :   /* add latency, this includes our own latency and the peer latency. */
    1208                 :          0 :   sync_time += adder->latency_ms * GST_MSECOND;
    1209                 :          0 :   sync_time += adder->peer_latency;
    1210                 :            : 
    1211                 :            :   /* create an entry for the clock */
    1212                 :          0 :   id = adder->clock_id = gst_clock_new_single_shot_id (clock, sync_time);
    1213                 :          0 :   GST_OBJECT_UNLOCK (adder);
    1214                 :            : 
    1215                 :          0 :   ret = gst_clock_id_wait (id, NULL);
    1216                 :            : 
    1217                 :          0 :   GST_OBJECT_LOCK (adder);
    1218                 :            : 
    1219                 :            :   /* and free the entry */
    1220                 :          0 :   gst_clock_id_unref (id);
    1221                 :          0 :   adder->clock_id = NULL;
    1222                 :            : 
    1223                 :            :   /* at this point, the clock could have been unlocked by a timeout, a new
    1224                 :            :    * head element was added to the queue or because we are shutting down. Check
    1225                 :            :    * for shutdown first. */
    1226                 :            : 
    1227         [ #  # ]:          0 :   if (adder->srcresult != GST_FLOW_OK)
    1228                 :          0 :     goto flushing;
    1229                 :            : 
    1230         [ #  # ]:          0 :   if (ret == GST_CLOCK_UNSCHEDULED) {
    1231         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder,
    1232                 :            :         "Wait got unscheduled, will retry to push with new buffer");
    1233                 :          0 :     goto again;
    1234                 :            :   }
    1235                 :            : 
    1236 [ #  # ][ #  # ]:          0 :   if (ret != GST_CLOCK_OK && ret != GST_CLOCK_EARLY)
    1237                 :          0 :     goto clock_error;
    1238                 :            : 
    1239                 :            : push_buffer:
    1240                 :            : 
    1241                 :          0 :   buffer = g_queue_pop_head (adder->buffers);
    1242                 :            : 
    1243         [ #  # ]:          0 :   if (!buffer)
    1244                 :          0 :     goto again;
    1245                 :            : 
    1246                 :            :   /*
    1247                 :            :    * We make sure the timestamps are exactly contiguous
    1248                 :            :    * If its only small skew (due to rounding errors), we correct it
    1249                 :            :    * silently. Otherwise we put the discont flag
    1250                 :            :    */
    1251 [ #  # ][ #  # ]:          0 :   if (GST_CLOCK_TIME_IS_VALID (adder->next_timestamp) &&
    1252                 :          0 :       GST_BUFFER_TIMESTAMP (buffer) != adder->next_timestamp) {
    1253                 :          0 :     GstClockTimeDiff diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buffer),
    1254                 :            :         adder->next_timestamp);
    1255         [ #  # ]:          0 :     if (diff < 0)
    1256                 :          0 :       diff = -diff;
    1257                 :            : 
    1258         [ #  # ]:          0 :     if (diff < GST_SECOND / adder->rate) {
    1259                 :          0 :       GST_BUFFER_TIMESTAMP (buffer) = adder->next_timestamp;
    1260         [ #  # ]:          0 :       GST_DEBUG_OBJECT (adder, "Correcting slight skew");
    1261                 :          0 :       GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
    1262                 :            :     } else {
    1263                 :          0 :       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
    1264 [ #  # ][ #  # ]:          0 :       GST_DEBUG_OBJECT (adder, "Expected buffer at %" GST_TIME_FORMAT
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1265                 :            :           ", but is at %" GST_TIME_FORMAT ", setting discont",
    1266                 :            :           GST_TIME_ARGS (adder->next_timestamp),
    1267                 :            :           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
    1268                 :            :     }
    1269                 :            :   } else {
    1270                 :          0 :     GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
    1271                 :            :   }
    1272                 :            : 
    1273                 :          0 :   GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
    1274                 :          0 :   GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
    1275                 :            : 
    1276         [ #  # ]:          0 :   if (GST_BUFFER_DURATION_IS_VALID (buffer))
    1277                 :          0 :     adder->next_timestamp = GST_BUFFER_TIMESTAMP (buffer) +
    1278                 :          0 :         GST_BUFFER_DURATION (buffer);
    1279                 :            :   else
    1280                 :          0 :     adder->next_timestamp = GST_CLOCK_TIME_NONE;
    1281                 :            : 
    1282         [ #  # ]:          0 :   if (adder->segment_pending) {
    1283                 :            :     /*
    1284                 :            :      * We set the start at 0, because we re-timestamps to the running time
    1285                 :            :      */
    1286                 :          0 :     newseg_event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
    1287                 :            :         GST_FORMAT_TIME, 0, -1, 0);
    1288                 :            : 
    1289                 :          0 :     adder->segment_pending = FALSE;
    1290                 :            :   }
    1291                 :            : 
    1292                 :          0 :   GST_OBJECT_UNLOCK (adder);
    1293                 :            : 
    1294         [ #  # ]:          0 :   if (newseg_event)
    1295                 :          0 :     gst_pad_push_event (adder->srcpad, newseg_event);
    1296                 :            : 
    1297 [ #  # ][ #  # ]:          0 :   GST_LOG_OBJECT (adder, "About to push buffer time:%" GST_TIME_FORMAT
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1298                 :            :       " duration:%" GST_TIME_FORMAT,
    1299                 :            :       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
    1300                 :            :       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
    1301                 :            : 
    1302                 :          0 :   result = gst_pad_push (adder->srcpad, buffer);
    1303         [ #  # ]:          0 :   if (result != GST_FLOW_OK)
    1304                 :          0 :     goto pause;
    1305                 :            : 
    1306                 :          0 :   return;
    1307                 :            : 
    1308                 :            : flushing:
    1309                 :            :   {
    1310         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "we are flushing");
    1311                 :          0 :     gst_pad_pause_task (adder->srcpad);
    1312                 :          0 :     GST_OBJECT_UNLOCK (adder);
    1313                 :          0 :     return;
    1314                 :            :   }
    1315                 :            : 
    1316                 :            : clock_error:
    1317                 :            :   {
    1318                 :          0 :     gst_pad_pause_task (adder->srcpad);
    1319                 :          0 :     GST_OBJECT_UNLOCK (adder);
    1320 [ #  # ][ #  # ]:          0 :     GST_ELEMENT_ERROR (adder, STREAM, MUX, ("Error with the clock"),
         [ #  # ][ #  # ]
    1321                 :            :         ("Error with the clock: %d", ret));
    1322         [ #  # ]:          0 :     GST_ERROR_OBJECT (adder, "Error with the clock: %d", ret);
    1323                 :          0 :     return;
    1324                 :            :   }
    1325                 :            : 
    1326                 :            : no_clock:
    1327                 :            :   {
    1328                 :          0 :     gst_pad_pause_task (adder->srcpad);
    1329                 :          0 :     GST_OBJECT_UNLOCK (adder);
    1330 [ #  # ][ #  # ]:          0 :     GST_ELEMENT_ERROR (adder, STREAM, MUX, ("No available clock"),
         [ #  # ][ #  # ]
    1331                 :            :         ("No available clock"));
    1332         [ #  # ]:          0 :     GST_ERROR_OBJECT (adder, "No available clock");
    1333                 :          0 :     return;
    1334                 :            :   }
    1335                 :            : 
    1336                 :            : pause:
    1337                 :            :   {
    1338         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "pausing task, reason %s",
    1339                 :            :         gst_flow_get_name (result));
    1340                 :            : 
    1341                 :          0 :     GST_OBJECT_LOCK (adder);
    1342                 :            : 
    1343                 :            :     /* store result */
    1344                 :          0 :     adder->srcresult = result;
    1345                 :            :     /* we don't post errors or anything because upstream will do that for us
    1346                 :            :      * when we pass the return value upstream. */
    1347                 :          0 :     gst_pad_pause_task (adder->srcpad);
    1348                 :          0 :     GST_OBJECT_UNLOCK (adder);
    1349                 :          0 :     return;
    1350                 :            :   }
    1351                 :            : 
    1352                 :            : eos:
    1353                 :            :   {
    1354                 :            :     /* store result, we are flushing now */
    1355         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "We are EOS, pushing EOS downstream");
    1356                 :          0 :     adder->srcresult = GST_FLOW_UNEXPECTED;
    1357                 :          0 :     gst_pad_pause_task (adder->srcpad);
    1358                 :          0 :     GST_OBJECT_UNLOCK (adder);
    1359                 :          0 :     gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
    1360                 :          0 :     return;
    1361                 :            :   }
    1362                 :            : }
    1363                 :            : 
    1364                 :            : static GstPad *
    1365                 :          0 : gst_live_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
    1366                 :            :     const gchar * unused)
    1367                 :            : {
    1368                 :            :   gchar *name;
    1369                 :            :   GstLiveAdder *adder;
    1370                 :            :   GstPad *newpad;
    1371                 :            :   gint padcount;
    1372                 :          0 :   GstLiveAdderPadPrivate *padprivate = NULL;
    1373                 :            : 
    1374         [ #  # ]:          0 :   if (templ->direction != GST_PAD_SINK)
    1375                 :          0 :     goto not_sink;
    1376                 :            : 
    1377                 :          0 :   adder = GST_LIVE_ADDER (element);
    1378                 :            : 
    1379                 :            :   /* increment pad counter */
    1380                 :          0 :   padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
    1381                 :            : 
    1382                 :          0 :   name = g_strdup_printf ("sink%d", padcount);
    1383                 :          0 :   newpad = gst_pad_new_from_template (templ, name);
    1384         [ #  # ]:          0 :   GST_DEBUG_OBJECT (adder, "request new pad %s", name);
    1385                 :          0 :   g_free (name);
    1386                 :            : 
    1387                 :          0 :   gst_pad_set_getcaps_function (newpad,
    1388                 :          0 :       GST_DEBUG_FUNCPTR (gst_live_adder_sink_getcaps));
    1389                 :          0 :   gst_pad_set_setcaps_function (newpad,
    1390                 :          0 :       GST_DEBUG_FUNCPTR (gst_live_adder_setcaps));
    1391                 :          0 :   gst_pad_set_event_function (newpad,
    1392                 :          0 :       GST_DEBUG_FUNCPTR (gst_live_adder_sink_event));
    1393                 :            : 
    1394                 :          0 :   padprivate = g_new0 (GstLiveAdderPadPrivate, 1);
    1395                 :            : 
    1396                 :          0 :   gst_segment_init (&padprivate->segment, GST_FORMAT_UNDEFINED);
    1397                 :          0 :   padprivate->eos = FALSE;
    1398                 :          0 :   padprivate->expected_timestamp = GST_CLOCK_TIME_NONE;
    1399                 :            : 
    1400                 :          0 :   gst_pad_set_element_private (newpad, padprivate);
    1401                 :            : 
    1402                 :          0 :   gst_pad_set_chain_function (newpad, gst_live_live_adder_chain);
    1403                 :            : 
    1404                 :            : 
    1405         [ #  # ]:          0 :   if (!gst_pad_set_active (newpad, TRUE))
    1406                 :          0 :     goto could_not_activate;
    1407                 :            : 
    1408                 :            :   /* takes ownership of the pad */
    1409         [ #  # ]:          0 :   if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
    1410                 :          0 :     goto could_not_add;
    1411                 :            : 
    1412                 :          0 :   GST_OBJECT_LOCK (adder);
    1413                 :          0 :   adder->sinkpads = g_list_prepend (adder->sinkpads, newpad);
    1414                 :          0 :   GST_OBJECT_UNLOCK (adder);
    1415                 :            : 
    1416                 :          0 :   return newpad;
    1417                 :            : 
    1418                 :            :   /* errors */
    1419                 :            : not_sink:
    1420                 :            :   {
    1421                 :          0 :     g_warning ("gstadder: request new pad that is not a SINK pad\n");
    1422                 :          0 :     return NULL;
    1423                 :            :   }
    1424                 :            : could_not_add:
    1425                 :            :   {
    1426         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "could not add pad");
    1427                 :          0 :     g_free (padprivate);
    1428                 :          0 :     gst_object_unref (newpad);
    1429                 :          0 :     return NULL;
    1430                 :            :   }
    1431                 :            : could_not_activate:
    1432                 :            :   {
    1433         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adder, "could not activate new pad");
    1434                 :          0 :     g_free (padprivate);
    1435                 :          0 :     gst_object_unref (newpad);
    1436                 :          0 :     return NULL;
    1437                 :            :   }
    1438                 :            : }
    1439                 :            : 
    1440                 :            : static void
    1441                 :          0 : gst_live_adder_release_pad (GstElement * element, GstPad * pad)
    1442                 :            : {
    1443                 :            :   GstLiveAdder *adder;
    1444                 :            :   GstLiveAdderPadPrivate *padprivate;
    1445                 :            : 
    1446                 :          0 :   adder = GST_LIVE_ADDER (element);
    1447                 :            : 
    1448 [ #  # ][ #  # ]:          0 :   GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1449                 :            : 
    1450                 :          0 :   GST_OBJECT_LOCK (element);
    1451                 :          0 :   padprivate = gst_pad_get_element_private (pad);
    1452                 :          0 :   gst_pad_set_element_private (pad, NULL);
    1453                 :          0 :   adder->sinkpads = g_list_remove_all (adder->sinkpads, pad);
    1454                 :          0 :   GST_OBJECT_UNLOCK (element);
    1455                 :            : 
    1456                 :          0 :   g_free (padprivate);
    1457                 :            : 
    1458                 :          0 :   gst_element_remove_pad (element, pad);
    1459                 :          0 : }
    1460                 :            : 
    1461                 :            : static void
    1462                 :          0 : reset_pad_private (GstPad * pad)
    1463                 :            : {
    1464                 :            :   GstLiveAdderPadPrivate *padprivate;
    1465                 :            : 
    1466                 :          0 :   padprivate = gst_pad_get_element_private (pad);
    1467                 :            : 
    1468         [ #  # ]:          0 :   if (!padprivate)
    1469                 :          0 :     return;
    1470                 :            : 
    1471                 :          0 :   gst_segment_init (&padprivate->segment, GST_FORMAT_UNDEFINED);
    1472                 :            : 
    1473                 :          0 :   padprivate->expected_timestamp = GST_CLOCK_TIME_NONE;
    1474                 :          0 :   padprivate->eos = FALSE;
    1475                 :            : }
    1476                 :            : 
    1477                 :            : static GstStateChangeReturn
    1478                 :         34 : gst_live_adder_change_state (GstElement * element, GstStateChange transition)
    1479                 :            : {
    1480                 :            :   GstLiveAdder *adder;
    1481                 :            :   GstStateChangeReturn ret;
    1482                 :            : 
    1483                 :         34 :   adder = GST_LIVE_ADDER (element);
    1484                 :            : 
    1485      [ +  +  + ]:         34 :   switch (transition) {
    1486                 :            :     case GST_STATE_CHANGE_READY_TO_PAUSED:
    1487                 :          7 :       GST_OBJECT_LOCK (adder);
    1488                 :          7 :       adder->segment_pending = TRUE;
    1489                 :          7 :       adder->peer_latency = 0;
    1490                 :          7 :       adder->next_timestamp = GST_CLOCK_TIME_NONE;
    1491                 :          7 :       g_list_foreach (adder->sinkpads, (GFunc) reset_pad_private, NULL);
    1492                 :          7 :       GST_OBJECT_UNLOCK (adder);
    1493                 :          7 :       break;
    1494                 :            :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
    1495                 :          6 :       GST_OBJECT_LOCK (adder);
    1496                 :          6 :       adder->playing = FALSE;
    1497                 :          6 :       GST_OBJECT_UNLOCK (adder);
    1498                 :          6 :       break;
    1499                 :            :     default:
    1500                 :         21 :       break;
    1501                 :            :   }
    1502                 :            : 
    1503                 :         34 :   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
    1504                 :            : 
    1505         [ +  + ]:         34 :   switch (transition) {
    1506                 :            :     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
    1507                 :          6 :       GST_OBJECT_LOCK (adder);
    1508                 :          6 :       adder->playing = TRUE;
    1509                 :          6 :       GST_OBJECT_UNLOCK (adder);
    1510                 :          6 :       break;
    1511                 :            :     default:
    1512                 :         28 :       break;
    1513                 :            :   }
    1514                 :            : 
    1515                 :         34 :   return ret;
    1516                 :            : }
    1517                 :            : 
    1518                 :            : 
    1519                 :            : static gboolean
    1520                 :          6 : plugin_init (GstPlugin * plugin)
    1521                 :            : {
    1522         [ -  + ]:          6 :   if (!gst_element_register (plugin, "liveadder", GST_RANK_NONE,
    1523                 :            :           GST_TYPE_LIVE_ADDER)) {
    1524                 :          0 :     return FALSE;
    1525                 :            :   }
    1526                 :            : 
    1527                 :          6 :   return TRUE;
    1528                 :            : }
    1529                 :            : 
    1530                 :            : GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    1531                 :            :     GST_VERSION_MINOR,
    1532                 :            :     "liveadder",
    1533                 :            :     "Adds multiple live discontinuous streams",
    1534                 :            :     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

Generated by: LCOV version 1.9