LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/join - gstjoin.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer.git#5d55fc62547faa02e861af5ef93cc1c89800934a Lines: 94.9 % 256 243
Test Date: 2024-09-25 09:08:39 Functions: 96.3 % 27 26

            Line data    Source code
       1              : /* SPDX-License-Identifier: LGPL-2.1-only */
       2              : /**
       3              :  * Copyright (C) 2020 Gichan Jang <gichan2.jang@samsung.com>
       4              :  */
       5              : /**
       6              :  * @file        gstjoin.c
       7              :  * @date        10 Nov 2020
       8              :  * @brief       Select the out that arrived first among the input streams
       9              :  * @see         https://github.com/nnstreamer/nnstreamer
      10              :  * @author      Gichan Jang <gichan2.jang@samsung.com>
      11              :  * @bug         No known bugs except for NYI items
      12              :  */
      13              : /**
      14              :  * SECTION:element-join
      15              :  * @see_also #GstInputSelector
      16              :  * @note A join has reduced and changed input-selector's function.
      17              :  *
      18              :  * Connect recently arrived buffer from N input streams to the output pad.
      19              :  * N streams should not operate at the same time.
      20              :  * All capabilities (input stream i and output stream) should be the same.
      21              :  * For example, If one sinkpad is receiving buffer, the others should be stopped.
      22              :  * <refsect2>
      23              :  * <title>Example launch line</title>
      24              :  * gst-launch-1.0 ... (input stream 0) ! join.sink_0 \
      25              :  *                ... (input stream 1) ! join.sink_1 \
      26              :  *                ... \
      27              :                   ... (input stream N) ! join.sink_n \
      28              :                   join name=join ! (arrived input stream) ...
      29              :  * </refsect2>
      30              :  */
      31              : 
      32              : #include "gstjoin.h"
      33              : 
      34              : GST_DEBUG_CATEGORY_STATIC (join_debug);
      35              : #define GST_CAT_DEFAULT join_debug
      36              : 
      37              : #define GST_JOIN_GET_LOCK(sel) (&((GstJoin*)(sel))->lock)
      38              : #define GST_JOIN_GET_COND(sel) (&((GstJoin*)(sel))->cond)
      39              : #define GST_JOIN_LOCK(sel) (g_mutex_lock (GST_JOIN_GET_LOCK(sel)))
      40              : #define GST_JOIN_UNLOCK(sel) (g_mutex_unlock (GST_JOIN_GET_LOCK(sel)))
      41              : #define GST_JOIN_WAIT(sel) (g_cond_wait (GST_JOIN_GET_COND(sel), \
      42              :                         GST_JOIN_GET_LOCK(sel)))
      43              : 
      44              : /**
      45              :  * @brief The capabilities of the inputs
      46              :  */
      47              : static GstStaticPadTemplate gst_join_sink_factory =
      48              : GST_STATIC_PAD_TEMPLATE ("sink_%u",
      49              :     GST_PAD_SINK,
      50              :     GST_PAD_REQUEST,
      51              :     GST_STATIC_CAPS_ANY);
      52              : 
      53              : /**
      54              :  * @brief The capabilities of the outputs
      55              :  */
      56              : static GstStaticPadTemplate gst_join_src_factory =
      57              : GST_STATIC_PAD_TEMPLATE ("src",
      58              :     GST_PAD_SRC,
      59              :     GST_PAD_ALWAYS,
      60              :     GST_STATIC_CAPS_ANY);
      61              : 
      62              : enum
      63              : {
      64              :   PROP_0,
      65              :   PROP_N_PADS,
      66              :   PROP_ACTIVE_PAD,
      67              : };
      68              : 
      69              : static GstPad *gst_join_get_active_sinkpad (GstJoin * sel);
      70              : static GstPad *gst_join_get_linked_pad (GstJoin * sel,
      71              :     GstPad * pad, gboolean strict);
      72              : static gboolean gst_join_set_active_pad (GstJoin * self, GstPad * pad);
      73              : 
      74              : #define GST_TYPE_JOIN_PAD \
      75              :   (gst_join_pad_get_type())
      76              : #define GST_JOIN_PAD(obj) \
      77              :   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_JOIN_PAD, GstJoinPad))
      78              : #define GST_JOIN_PAD_CLASS(klass) \
      79              :   (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_JOIN_PAD, GstJoinPadClass))
      80              : #define GST_IS_JOIN_PAD(obj) \
      81              :   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_JOIN_PAD))
      82              : #define GST_IS_JOIN_PAD_CLASS(klass) \
      83              :   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_JOIN_PAD))
      84              : #define GST_JOIN_PAD_CAST(obj) \
      85              :   ((GstJoinPad *)(obj))
      86              : 
      87              : typedef struct _GstJoinPad GstJoinPad;
      88              : typedef struct _GstJoinPadClass GstJoinPadClass;
      89              : 
      90              : /**
      91              :  * @brief GstJoinPad data structure.
      92              :  */
      93              : struct _GstJoinPad
      94              : {
      95              :   GstPad parent;
      96              : 
      97              :   guint group_id;               /* Group ID from the last stream-start */
      98              : 
      99              :   GstSegment segment;           /* the current segment on the pad */
     100              :   guint32 segment_seqnum;       /* sequence number of the current segment */
     101              : };
     102              : 
     103              : /**
     104              :  * @brief _GstJoinPadClass data structure
     105              :  */
     106              : struct _GstJoinPadClass
     107              : {
     108              :   GstPadClass parent;
     109              : };
     110              : 
     111              : GType gst_join_pad_get_type (void);
     112              : static void gst_join_pad_finalize (GObject * object);
     113              : static void gst_join_pad_reset (GstJoinPad * pad);
     114              : static gboolean gst_join_pad_event (GstPad * pad, GstObject * parent,
     115              :     GstEvent * event);
     116              : static gboolean gst_join_pad_query (GstPad * pad, GstObject * parent,
     117              :     GstQuery * query);
     118              : static GstIterator *gst_join_pad_iterate_linked_pads (GstPad * pad,
     119              :     GstObject * parent);
     120              : static GstFlowReturn gst_join_pad_chain (GstPad * pad, GstObject * parent,
     121              :     GstBuffer * buf);
     122              : 
     123          300 : G_DEFINE_TYPE (GstJoinPad, gst_join_pad, GST_TYPE_PAD);
     124              : 
     125              : /**
     126              :  * @brief initialize the join's pad class
     127              :  */
     128              : static void
     129            7 : gst_join_pad_class_init (GstJoinPadClass * klass)
     130              : {
     131              :   GObjectClass *gobject_class;
     132              : 
     133            7 :   gobject_class = (GObjectClass *) klass;
     134              : 
     135            7 :   gobject_class->finalize = gst_join_pad_finalize;
     136            7 : }
     137              : 
     138              : /**
     139              :  * @brief initialize the join pad
     140              :  */
     141              : static void
     142           36 : gst_join_pad_init (GstJoinPad * pad)
     143              : {
     144           36 :   gst_join_pad_reset (pad);
     145           36 : }
     146              : 
     147              : /**
     148              :  * @brief finalize the join pad
     149              :  */
     150              : static void
     151           24 : gst_join_pad_finalize (GObject * object)
     152              : {
     153           24 :   G_OBJECT_CLASS (gst_join_pad_parent_class)->finalize (object);
     154           24 : }
     155              : 
     156              : /**
     157              :  * @brief Clear and reset join pad.
     158              :  * @note must be called with the JOIN_LOCK
     159              :  */
     160              : static void
     161           36 : gst_join_pad_reset (GstJoinPad * pad)
     162              : {
     163           36 :   GST_OBJECT_LOCK (pad);
     164           36 :   gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
     165           36 :   GST_OBJECT_UNLOCK (pad);
     166           36 : }
     167              : 
     168              : /**
     169              :  * @brief strictly get the linked pad from the sinkpad.
     170              :  * @return If the pad is active, return the srcpad else return NULL.
     171              :  */
     172              : static GstIterator *
     173          142 : gst_join_pad_iterate_linked_pads (GstPad * pad, GstObject * parent)
     174              : {
     175              :   GstJoin *sel;
     176              :   GstPad *otherpad;
     177          142 :   GstIterator *it = NULL;
     178          142 :   GValue val = { 0, };
     179              : 
     180          142 :   sel = GST_JOIN (parent);
     181              : 
     182          142 :   otherpad = gst_join_get_linked_pad (sel, pad, TRUE);
     183          142 :   if (otherpad) {
     184           37 :     g_value_init (&val, GST_TYPE_PAD);
     185           37 :     g_value_set_object (&val, otherpad);
     186           37 :     it = gst_iterator_new_single (GST_TYPE_PAD, &val);
     187           37 :     g_value_unset (&val);
     188           37 :     gst_object_unref (otherpad);
     189              :   }
     190              : 
     191          142 :   return it;
     192              : }
     193              : 
     194              : /**
     195              :  * @brief forward sticky event
     196              :  */
     197              : static gboolean
     198          367 : forward_sticky_events (GstPad * sinkpad, GstEvent ** event, gpointer user_data)
     199              : {
     200          367 :   GstJoin *sel = GST_JOIN (user_data);
     201              : 
     202          367 :   GST_DEBUG_OBJECT (sinkpad, "forward sticky event %" GST_PTR_FORMAT, *event);
     203              : 
     204          367 :   if (GST_EVENT_TYPE (*event) == GST_EVENT_SEGMENT) {
     205          125 :     GstSegment *seg = &GST_JOIN_PAD (sinkpad)->segment;
     206              :     GstEvent *e;
     207              : 
     208          125 :     e = gst_event_new_segment (seg);
     209          125 :     gst_event_set_seqnum (e, GST_JOIN_PAD_CAST (sinkpad)->segment_seqnum);
     210              : 
     211          125 :     gst_pad_push_event (sel->srcpad, e);
     212          242 :   } else if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START
     213          117 :       && !sel->have_group_id) {
     214              :     GstEvent *tmp =
     215            0 :         gst_pad_get_sticky_event (sel->srcpad, GST_EVENT_STREAM_START, 0);
     216              : 
     217              :     /* Only push stream-start once if not all our streams have a stream-id */
     218            0 :     if (!tmp) {
     219            0 :       gst_pad_push_event (sel->srcpad, gst_event_ref (*event));
     220              :     } else {
     221            0 :       gst_event_unref (tmp);
     222              :     }
     223              :   } else {
     224          242 :     gst_pad_push_event (sel->srcpad, gst_event_ref (*event));
     225              :   }
     226          367 :   return TRUE;
     227              : }
     228              : 
     229              : /**
     230              :  * @brief event function for sink pad
     231              :  */
     232              : static gboolean
     233          116 : gst_join_pad_event (GstPad * pad, GstObject * parent, GstEvent * event)
     234              : {
     235          116 :   gboolean res = TRUE;
     236              :   gboolean forward;
     237              :   GstJoin *sel;
     238              :   GstJoinPad *selpad;
     239              :   GstPad *active_sinkpad;
     240              : 
     241          116 :   sel = GST_JOIN (parent);
     242          116 :   selpad = GST_JOIN_PAD_CAST (pad);
     243          116 :   GST_DEBUG_OBJECT (selpad, "received event %" GST_PTR_FORMAT, event);
     244              : 
     245          116 :   GST_JOIN_LOCK (sel);
     246              : 
     247          116 :   active_sinkpad = gst_join_get_active_sinkpad (sel);
     248              : 
     249              :   /* only forward if we are dealing with the active sinkpad */
     250          116 :   forward = (pad == active_sinkpad);
     251              : 
     252          116 :   switch (GST_EVENT_TYPE (event)) {
     253           34 :     case GST_EVENT_CAPS:
     254              :     {
     255              :       GstCaps *prev_caps, *new_caps;
     256              : 
     257           34 :       if (!(prev_caps = gst_pad_get_current_caps (active_sinkpad)))
     258           34 :         break;
     259              : 
     260           15 :       gst_event_parse_caps (event, &new_caps);
     261              : 
     262           15 :       if (!gst_caps_is_equal (prev_caps, new_caps)) {
     263            3 :         GST_ERROR_OBJECT (sel, "Capabilities of the sinks should be the same.");
     264            3 :         res = FALSE;
     265              :       }
     266              : 
     267           15 :       gst_caps_unref (prev_caps);
     268              : 
     269           15 :       break;
     270              :     }
     271           26 :     case GST_EVENT_STREAM_START:{
     272           26 :       if (!gst_event_parse_group_id (event, &selpad->group_id)) {
     273            0 :         sel->have_group_id = FALSE;
     274            0 :         selpad->group_id = 0;
     275              :       }
     276           26 :       break;
     277              :     }
     278           31 :     case GST_EVENT_SEGMENT:
     279              :     {
     280           31 :       gst_event_copy_segment (event, &selpad->segment);
     281           31 :       selpad->segment_seqnum = gst_event_get_seqnum (event);
     282              : 
     283           31 :       GST_DEBUG_OBJECT (pad, "configured SEGMENT %" GST_SEGMENT_FORMAT,
     284              :           &selpad->segment);
     285           31 :       break;
     286              :     }
     287           25 :     default:
     288           25 :       break;
     289              :   }
     290          116 :   GST_JOIN_UNLOCK (sel);
     291              : 
     292          116 :   if (forward) {
     293           39 :     GST_DEBUG_OBJECT (pad, "forwarding event");
     294           39 :     res = gst_pad_push_event (sel->srcpad, event);
     295              :   } else {
     296           77 :     gst_event_unref (event);
     297              :   }
     298              : 
     299          115 :   return res;
     300              : }
     301              : 
     302              : /**
     303              :  * @brief handlesink sink pad query
     304              :  * @return TRUE if the query was performed successfully.
     305              :  */
     306              : static gboolean
     307          573 : gst_join_pad_query (GstPad * pad, GstObject * parent, GstQuery * query)
     308              : {
     309          573 :   gboolean res = FALSE;
     310          573 :   GstJoin *self = (GstJoin *) parent;
     311              : 
     312          573 :   switch (GST_QUERY_TYPE (query)) {
     313          512 :     case GST_QUERY_CAPS:
     314              :     case GST_QUERY_POSITION:
     315              :     case GST_QUERY_DURATION:
     316              :     case GST_QUERY_CONTEXT:
     317              :       /**
     318              :        * always proxy caps/position/duration/context queries, regardless of active pad or not
     319              :        * See https://bugzilla.gnome.org/show_bug.cgi?id=775445
     320              :        */
     321          512 :       res = gst_pad_peer_query (self->srcpad, query);
     322          512 :       break;
     323            4 :     case GST_QUERY_ALLOCATION:{
     324              :       GstPad *active_sinkpad;
     325            4 :       GstJoin *sel = GST_JOIN (parent);
     326              : 
     327              :       /**
     328              :        * Only do the allocation query for the active sinkpad,
     329              :        * after switching a reconfigure event is sent and upstream
     330              :        * should reconfigure and do a new allocation query
     331              :        */
     332            4 :       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
     333            4 :         GST_JOIN_LOCK (sel);
     334            4 :         active_sinkpad = gst_join_get_active_sinkpad (sel);
     335            4 :         GST_JOIN_UNLOCK (sel);
     336              : 
     337            4 :         if (pad != active_sinkpad) {
     338            1 :           res = FALSE;
     339            1 :           goto done;
     340              :         }
     341              :       }
     342              :     }
     343              :       /* fall through */
     344              :     default:
     345           60 :       res = gst_pad_query_default (pad, parent, query);
     346           60 :       break;
     347              :   }
     348              : 
     349          573 : done:
     350          573 :   return res;
     351              : }
     352              : 
     353              : /**
     354              :  * @brief Chain function, this function does the actual processing.
     355              :  */
     356              : static GstFlowReturn
     357          139 : gst_join_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     358              : {
     359              :   GstJoin *sel;
     360              :   GstFlowReturn res;
     361              :   GstPad *active_sinkpad;
     362          139 :   GstPad *prev_active_sinkpad = NULL;
     363              :   GstJoinPad *selpad;
     364              : 
     365          139 :   sel = GST_JOIN (parent);
     366          139 :   selpad = GST_JOIN_PAD_CAST (pad);
     367          139 :   GST_DEBUG_OBJECT (selpad,
     368              :       "entering chain for buf %p with timestamp %" GST_TIME_FORMAT, buf,
     369              :       GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
     370              : 
     371          139 :   GST_JOIN_LOCK (sel);
     372              : 
     373          139 :   GST_LOG_OBJECT (pad, "getting active pad");
     374              : 
     375          139 :   prev_active_sinkpad =
     376          139 :       sel->active_sinkpad ? gst_object_ref (sel->active_sinkpad) : NULL;
     377              : 
     378          139 :   if (sel->active_sinkpad != pad) {
     379          125 :     gst_join_set_active_pad (sel, pad);
     380              :   }
     381          139 :   active_sinkpad = pad;
     382              : 
     383              :   /* update the segment on the srcpad */
     384          139 :   if (GST_BUFFER_PTS_IS_VALID (buf)) {
     385          137 :     GstClockTime start_time = GST_BUFFER_PTS (buf);
     386              : 
     387          137 :     GST_LOG_OBJECT (pad, "received start time %" GST_TIME_FORMAT,
     388              :         GST_TIME_ARGS (start_time));
     389          137 :     if (GST_BUFFER_DURATION_IS_VALID (buf))
     390          125 :       GST_LOG_OBJECT (pad, "received end time %" GST_TIME_FORMAT,
     391              :           GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf)));
     392              : 
     393          137 :     GST_OBJECT_LOCK (pad);
     394          137 :     selpad->segment.position = start_time;
     395          137 :     GST_OBJECT_UNLOCK (pad);
     396              :   }
     397              : 
     398          139 :   GST_JOIN_UNLOCK (sel);
     399              : 
     400              :   /* if we have a pending events, push them now */
     401          139 :   if (G_UNLIKELY (prev_active_sinkpad != active_sinkpad)) {
     402          125 :     gst_pad_sticky_events_foreach (GST_PAD_CAST (selpad), forward_sticky_events,
     403              :         sel);
     404              :   }
     405              : 
     406              :   /* forward */
     407          139 :   GST_LOG_OBJECT (pad, "Forwarding buffer %p with timestamp %" GST_TIME_FORMAT,
     408              :       buf, GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
     409              : 
     410          139 :   res = gst_pad_push (sel->srcpad, buf);
     411          139 :   GST_LOG_OBJECT (pad, "Buffer %p forwarded result=%d", buf, res);
     412              : 
     413          139 :   if (prev_active_sinkpad)
     414          139 :     gst_object_unref (prev_active_sinkpad);
     415          139 :   prev_active_sinkpad = NULL;
     416              : 
     417          139 :   return res;
     418              : }
     419              : 
     420              : static void gst_join_dispose (GObject * object);
     421              : static void gst_join_finalize (GObject * object);
     422              : 
     423              : static void gst_join_get_property (GObject * object,
     424              :     guint prop_id, GValue * value, GParamSpec * pspec);
     425              : static GstPad *gst_join_request_new_pad (GstElement * element,
     426              :     GstPadTemplate * templ, const gchar * unused, const GstCaps * caps);
     427              : 
     428              : #define gst_join_parent_class parent_class
     429          908 : G_DEFINE_TYPE_WITH_CODE (GstJoin, gst_join, GST_TYPE_ELEMENT,
     430              :     GST_DEBUG_CATEGORY_INIT (join_debug,
     431              :         "join", 0, "An input stream join element"));
     432              : 
     433              : /**
     434              :  * @brief initialize the join's class
     435              :  */
     436              : static void
     437           27 : gst_join_class_init (GstJoinClass * klass)
     438              : {
     439           27 :   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     440           27 :   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
     441              : 
     442           27 :   gobject_class->dispose = gst_join_dispose;
     443           27 :   gobject_class->finalize = gst_join_finalize;
     444              : 
     445           27 :   gobject_class->get_property = gst_join_get_property;
     446              : 
     447           27 :   g_object_class_install_property (gobject_class, PROP_N_PADS,
     448              :       g_param_spec_uint ("n-pads", "Number of Pads",
     449              :           "The number of sink pads", 0, G_MAXUINT, 0,
     450              :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     451              : 
     452           27 :   g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
     453              :       g_param_spec_object ("active-pad", "Active pad",
     454              :           "The currently active sink pad", GST_TYPE_PAD,
     455              :           G_PARAM_READABLE | GST_PARAM_MUTABLE_PLAYING |
     456              :           G_PARAM_STATIC_STRINGS));
     457              : 
     458           27 :   gst_element_class_set_static_metadata (gstelement_class, "Input join",
     459              :       "Generic", "N-to-1 input stream join",
     460              :       "Gichan Jang <gichan2.jang@samsung.com>, ");
     461              : 
     462           27 :   gst_element_class_add_static_pad_template (gstelement_class,
     463              :       &gst_join_sink_factory);
     464           27 :   gst_element_class_add_static_pad_template (gstelement_class,
     465              :       &gst_join_src_factory);
     466              : 
     467           27 :   gstelement_class->request_new_pad = gst_join_request_new_pad;
     468           27 : }
     469              : 
     470              : /**
     471              :  * @brief initialize the join element
     472              :  */
     473              : static void
     474           14 : gst_join_init (GstJoin * sel)
     475              : {
     476           14 :   sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
     477           14 :   gst_pad_set_iterate_internal_links_function (sel->srcpad,
     478              :       GST_DEBUG_FUNCPTR (gst_join_pad_iterate_linked_pads));
     479           14 :   GST_OBJECT_FLAG_SET (sel->srcpad, GST_PAD_FLAG_PROXY_CAPS);
     480           14 :   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
     481              :   /* sinkpad management */
     482           14 :   sel->active_sinkpad = NULL;
     483           14 :   sel->padcount = 0;
     484           14 :   sel->have_group_id = TRUE;
     485              : 
     486           14 :   g_mutex_init (&sel->lock);
     487           14 :   g_cond_init (&sel->cond);
     488           14 : }
     489              : 
     490              : /**
     491              :  * @brief dispose function for join element
     492              :  */
     493              : static void
     494           10 : gst_join_dispose (GObject * object)
     495              : {
     496           10 :   GstJoin *sel = GST_JOIN (object);
     497              : 
     498           10 :   if (sel->active_sinkpad) {
     499            8 :     gst_object_unref (sel->active_sinkpad);
     500            8 :     sel->active_sinkpad = NULL;
     501              :   }
     502           10 :   G_OBJECT_CLASS (parent_class)->dispose (object);
     503           10 : }
     504              : 
     505              : /**
     506              :  * @brief finalize join element.
     507              :  */
     508              : static void
     509           10 : gst_join_finalize (GObject * object)
     510              : {
     511           10 :   GstJoin *sel = GST_JOIN (object);
     512              : 
     513           10 :   g_mutex_clear (&sel->lock);
     514           10 :   g_cond_clear (&sel->cond);
     515              : 
     516           10 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     517           10 : }
     518              : 
     519              : /**
     520              :  * @brief set active sink pad.
     521              :  * @return TRUE when the active pad changed.
     522              :  * @note this function must be called with the JOIN_LOCK.
     523              :  */
     524              : static gboolean
     525          125 : gst_join_set_active_pad (GstJoin * self, GstPad * pad)
     526              : {
     527              :   GstJoinPad *old, *new;
     528              :   GstPad **active_pad_p;
     529              : 
     530          125 :   if (pad == self->active_sinkpad)
     531            0 :     return FALSE;
     532              : 
     533              :   /* guard against users setting a src pad or foreign pad as active pad */
     534          125 :   if (pad != NULL) {
     535          125 :     g_return_val_if_fail (GST_PAD_IS_SINK (pad), FALSE);
     536          125 :     g_return_val_if_fail (GST_IS_JOIN_PAD (pad), FALSE);
     537          125 :     g_return_val_if_fail (GST_PAD_PARENT (pad) == GST_ELEMENT_CAST (self),
     538              :         FALSE);
     539              :   }
     540              : 
     541          125 :   old = GST_JOIN_PAD_CAST (self->active_sinkpad);
     542          125 :   new = GST_JOIN_PAD_CAST (pad);
     543              : 
     544          125 :   GST_DEBUG_OBJECT (self, "setting active pad to %s:%s",
     545              :       GST_DEBUG_PAD_NAME (new));
     546              : 
     547          125 :   active_pad_p = &self->active_sinkpad;
     548          125 :   gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
     549              : 
     550          125 :   if (old && old != new)
     551          125 :     gst_pad_push_event (GST_PAD_CAST (old), gst_event_new_reconfigure ());
     552          125 :   if (new)
     553          125 :     gst_pad_push_event (GST_PAD_CAST (new), gst_event_new_reconfigure ());
     554              : 
     555          125 :   GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT,
     556              :       self->active_sinkpad);
     557              : 
     558          125 :   return TRUE;
     559              : }
     560              : 
     561              : /**
     562              :  * @brief Getter for join properties.
     563              :  */
     564              : static void
     565            3 : gst_join_get_property (GObject * object, guint prop_id,
     566              :     GValue * value, GParamSpec * pspec)
     567              : {
     568            3 :   GstJoin *sel = GST_JOIN (object);
     569              : 
     570            3 :   switch (prop_id) {
     571            1 :     case PROP_N_PADS:
     572            1 :       GST_JOIN_LOCK (object);
     573            1 :       g_value_set_uint (value, sel->n_pads);
     574            1 :       GST_JOIN_UNLOCK (object);
     575            1 :       break;
     576            2 :     case PROP_ACTIVE_PAD:
     577            2 :       GST_JOIN_LOCK (object);
     578            2 :       g_value_set_object (value, sel->active_sinkpad);
     579            2 :       GST_JOIN_UNLOCK (object);
     580            2 :       break;
     581            0 :     default:
     582            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     583            0 :       break;
     584              :   }
     585            3 : }
     586              : 
     587              : /**
     588              :  * @brief Get linked pad
     589              :  */
     590              : static GstPad *
     591          142 : gst_join_get_linked_pad (GstJoin * sel, GstPad * pad, gboolean strict)
     592              : {
     593          142 :   GstPad *otherpad = NULL;
     594              : 
     595          142 :   GST_JOIN_LOCK (sel);
     596          142 :   if (pad == sel->srcpad)
     597           82 :     otherpad = sel->active_sinkpad;
     598           60 :   else if (pad == sel->active_sinkpad || !strict)
     599           15 :     otherpad = sel->srcpad;
     600          142 :   if (otherpad)
     601           37 :     gst_object_ref (otherpad);
     602          142 :   GST_JOIN_UNLOCK (sel);
     603              : 
     604          142 :   return otherpad;
     605              : }
     606              : 
     607              : /**
     608              :  * @brief Get or create the active sinkpad.
     609              :  * @note  must be called with JOIN_LOCK.
     610              :  */
     611              : static GstPad *
     612          120 : gst_join_get_active_sinkpad (GstJoin * sel)
     613              : {
     614              :   GstPad *active_sinkpad;
     615              : 
     616          120 :   active_sinkpad = sel->active_sinkpad;
     617          120 :   if (active_sinkpad == NULL) {
     618           12 :     GValue item = G_VALUE_INIT;
     619           12 :     GstIterator *iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (sel));
     620              :     GstIteratorResult ires;
     621              : 
     622           12 :     while ((ires = gst_iterator_next (iter, &item)) == GST_ITERATOR_RESYNC)
     623            0 :       gst_iterator_resync (iter);
     624           12 :     if (ires == GST_ITERATOR_OK) {
     625              :       /**
     626              :        * If no pad is currently selected, we return the first usable pad to
     627              :        * guarantee consistency
     628              :        */
     629              : 
     630           12 :       active_sinkpad = sel->active_sinkpad = g_value_dup_object (&item);
     631           12 :       g_value_reset (&item);
     632           12 :       GST_DEBUG_OBJECT (sel, "Activating pad %s:%s",
     633              :           GST_DEBUG_PAD_NAME (active_sinkpad));
     634              :     } else
     635            0 :       GST_WARNING_OBJECT (sel, "Couldn't find a default sink pad");
     636           12 :     gst_iterator_free (iter);
     637              :   }
     638              : 
     639          120 :   return active_sinkpad;
     640              : }
     641              : 
     642              : /**
     643              :  * @brief request new sink pad
     644              :  */
     645              : static GstPad *
     646           36 : gst_join_request_new_pad (GstElement * element, GstPadTemplate * templ,
     647              :     const gchar * unused, const GstCaps * caps)
     648              : {
     649              :   GstJoin *sel;
     650           36 :   gchar *name = NULL;
     651           36 :   GstPad *sinkpad = NULL;
     652              :   (void) unused;
     653              :   (void) caps;
     654              : 
     655           36 :   g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
     656              : 
     657           36 :   sel = GST_JOIN (element);
     658              : 
     659           36 :   GST_JOIN_LOCK (sel);
     660              : 
     661           36 :   GST_LOG_OBJECT (sel, "Creating new pad sink_%u", sel->padcount);
     662           36 :   name = g_strdup_printf ("sink_%u", sel->padcount++);
     663           36 :   sinkpad = g_object_new (GST_TYPE_JOIN_PAD,
     664           36 :       "name", name, "direction", templ->direction, "template", templ, NULL);
     665           36 :   g_free (name);
     666              : 
     667           36 :   sel->n_pads++;
     668              : 
     669           36 :   gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (gst_join_pad_event));
     670           36 :   gst_pad_set_query_function (sinkpad, GST_DEBUG_FUNCPTR (gst_join_pad_query));
     671           36 :   gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (gst_join_pad_chain));
     672           36 :   gst_pad_set_iterate_internal_links_function (sinkpad,
     673              :       GST_DEBUG_FUNCPTR (gst_join_pad_iterate_linked_pads));
     674              : 
     675           36 :   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
     676           36 :   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
     677           36 :   gst_pad_set_active (sinkpad, TRUE);
     678           36 :   gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
     679           36 :   GST_JOIN_UNLOCK (sel);
     680              : 
     681           36 :   return sinkpad;
     682              : }
     683              : 
     684              : /**
     685              :  * @brief register this element
     686              :  */
     687              : static gboolean
     688           27 : plugin_init (GstPlugin * plugin)
     689              : {
     690           27 :   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "join", 0,
     691              :       "gstreamer join element");
     692              : 
     693           27 :   if (!gst_element_register (plugin, "join", GST_RANK_NONE, GST_TYPE_JOIN)) {
     694            0 :     return FALSE;
     695              :   }
     696              : 
     697           27 :   return TRUE;
     698              : }
     699              : 
     700              : #ifndef PACKAGE
     701              : #define PACKAGE "join"
     702              : #endif
     703              : 
     704           27 : GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
     705              :     GST_VERSION_MINOR,
     706              :     join,
     707              :     "Select the out that arrived first among the input streams",
     708              :     plugin_init, VERSION, "LGPL", PACKAGE,
     709              :     "https://github.com/nnstreamer/nnstreamer")
        

Generated by: LCOV version 2.0-1