35 #define GST_CAT_DEFAULT join_debug
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)))
48 GST_STATIC_PAD_TEMPLATE (
"sink_%u",
57 GST_STATIC_PAD_TEMPLATE (
"src",
71 GstPad * pad, gboolean strict);
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) \
131 GObjectClass *gobject_class;
133 gobject_class = (GObjectClass *) klass;
153 G_OBJECT_CLASS (gst_join_pad_parent_class)->finalize (
object);
163 GST_OBJECT_LOCK (pad);
164 gst_segment_init (&pad->
segment, GST_FORMAT_UNDEFINED);
165 GST_OBJECT_UNLOCK (pad);
177 GstIterator *it = NULL;
184 g_value_init (&val, GST_TYPE_PAD);
185 g_value_set_object (&val, otherpad);
186 it = gst_iterator_new_single (GST_TYPE_PAD, &val);
187 g_value_unset (&val);
188 gst_object_unref (otherpad);
202 GST_DEBUG_OBJECT (sinkpad,
"forward sticky event %" GST_PTR_FORMAT, *event);
204 if (GST_EVENT_TYPE (*event) == GST_EVENT_SEGMENT) {
208 e = gst_event_new_segment (seg);
211 gst_pad_push_event (sel->
srcpad, e);
212 }
else if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START
215 gst_pad_get_sticky_event (sel->
srcpad, GST_EVENT_STREAM_START, 0);
219 gst_pad_push_event (sel->
srcpad, gst_event_ref (*event));
221 gst_event_unref (tmp);
224 gst_pad_push_event (sel->
srcpad, gst_event_ref (*event));
239 GstPad *active_sinkpad;
243 GST_DEBUG_OBJECT (selpad,
"received event %" GST_PTR_FORMAT, event);
250 forward = (pad == active_sinkpad);
252 switch (GST_EVENT_TYPE (event)) {
255 GstCaps *prev_caps, *new_caps;
257 if (!(prev_caps = gst_pad_get_current_caps (active_sinkpad)))
260 gst_event_parse_caps (event, &new_caps);
262 if (!gst_caps_is_equal (prev_caps, new_caps)) {
263 GST_ERROR_OBJECT (sel,
"Capabilities of the sinks should be the same.");
267 gst_caps_unref (prev_caps);
271 case GST_EVENT_STREAM_START:{
272 if (!gst_event_parse_group_id (event, &selpad->
group_id)) {
278 case GST_EVENT_SEGMENT:
280 gst_event_copy_segment (event, &selpad->
segment);
283 GST_DEBUG_OBJECT (pad,
"configured SEGMENT %" GST_SEGMENT_FORMAT,
293 GST_DEBUG_OBJECT (pad,
"forwarding event");
294 res = gst_pad_push_event (sel->
srcpad, event);
296 gst_event_unref (event);
309 gboolean res =
FALSE;
312 switch (GST_QUERY_TYPE (query)) {
314 case GST_QUERY_POSITION:
315 case GST_QUERY_DURATION:
316 case GST_QUERY_CONTEXT:
321 res = gst_pad_peer_query (self->srcpad, query);
323 case GST_QUERY_ALLOCATION:{
324 GstPad *active_sinkpad;
332 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
337 if (pad != active_sinkpad) {
345 res = gst_pad_query_default (pad, parent, query);
361 GstPad *active_sinkpad;
362 GstPad *prev_active_sinkpad = NULL;
367 GST_DEBUG_OBJECT (selpad,
368 "entering chain for buf %p with timestamp %" GST_TIME_FORMAT, buf,
369 GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
373 GST_LOG_OBJECT (pad,
"getting active pad");
375 prev_active_sinkpad =
381 active_sinkpad = pad;
384 if (GST_BUFFER_PTS_IS_VALID (buf)) {
385 GstClockTime start_time = GST_BUFFER_PTS (buf);
387 GST_LOG_OBJECT (pad,
"received start time %" GST_TIME_FORMAT,
388 GST_TIME_ARGS (start_time));
389 if (GST_BUFFER_DURATION_IS_VALID (buf))
390 GST_LOG_OBJECT (pad,
"received end time %" GST_TIME_FORMAT,
391 GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf)));
393 GST_OBJECT_LOCK (pad);
394 selpad->
segment.position = start_time;
395 GST_OBJECT_UNLOCK (pad);
401 if (G_UNLIKELY (prev_active_sinkpad != active_sinkpad)) {
407 GST_LOG_OBJECT (pad,
"Forwarding buffer %p with timestamp %" GST_TIME_FORMAT,
408 buf, GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
410 res = gst_pad_push (sel->
srcpad, buf);
411 GST_LOG_OBJECT (pad,
"Buffer %p forwarded result=%d", buf, res);
413 if (prev_active_sinkpad)
414 gst_object_unref (prev_active_sinkpad);
415 prev_active_sinkpad = NULL;
424 guint prop_id, GValue * value, GParamSpec * pspec);
426 GstPadTemplate * templ,
const gchar * unused,
const GstCaps * caps);
428 #define gst_join_parent_class parent_class
430 GST_DEBUG_CATEGORY_INIT (join_debug,
431 "join", 0,
"An input stream join element"));
439 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
440 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
447 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));
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));
458 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>, ");
462 gst_element_class_add_static_pad_template (gstelement_class,
464 gst_element_class_add_static_pad_template (gstelement_class,
476 sel->
srcpad = gst_pad_new (
"src", GST_PAD_SRC);
477 gst_pad_set_iterate_internal_links_function (sel->
srcpad,
479 GST_OBJECT_FLAG_SET (sel->
srcpad, GST_PAD_FLAG_PROXY_CAPS);
480 gst_element_add_pad (GST_ELEMENT (sel), sel->
srcpad);
486 g_mutex_init (&sel->
lock);
487 g_cond_init (&sel->
cond);
502 G_OBJECT_CLASS (parent_class)->dispose (
object);
513 g_mutex_clear (&sel->
lock);
514 g_cond_clear (&sel->
cond);
516 G_OBJECT_CLASS (parent_class)->finalize (
object);
528 GstPad **active_pad_p;
530 if (pad == self->active_sinkpad)
535 g_return_val_if_fail (GST_PAD_IS_SINK (pad),
FALSE);
537 g_return_val_if_fail (GST_PAD_PARENT (pad) == GST_ELEMENT_CAST (
self),
544 GST_DEBUG_OBJECT (
self,
"setting active pad to %s:%s",
545 GST_DEBUG_PAD_NAME (
new));
547 active_pad_p = &
self->active_sinkpad;
548 gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
550 if (old && old !=
new)
551 gst_pad_push_event (GST_PAD_CAST (old), gst_event_new_reconfigure ());
553 gst_pad_push_event (GST_PAD_CAST (
new), gst_event_new_reconfigure ());
555 GST_DEBUG_OBJECT (
self,
"New active pad is %" GST_PTR_FORMAT,
556 self->active_sinkpad);
566 GValue * value, GParamSpec * pspec)
573 g_value_set_uint (value, sel->
n_pads);
582 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
593 GstPad *otherpad = NULL;
601 gst_object_ref (otherpad);
614 GstPad *active_sinkpad;
617 if (active_sinkpad == NULL) {
618 GValue item = G_VALUE_INIT;
619 GstIterator *iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (sel));
620 GstIteratorResult ires;
622 while ((ires = gst_iterator_next (iter, &item)) == GST_ITERATOR_RESYNC)
623 gst_iterator_resync (iter);
624 if (ires == GST_ITERATOR_OK) {
630 active_sinkpad = sel->
active_sinkpad = g_value_dup_object (&item);
631 g_value_reset (&item);
632 GST_DEBUG_OBJECT (sel,
"Activating pad %s:%s",
633 GST_DEBUG_PAD_NAME (active_sinkpad));
635 GST_WARNING_OBJECT (sel,
"Couldn't find a default sink pad");
636 gst_iterator_free (iter);
639 return active_sinkpad;
647 const gchar * unused,
const GstCaps * caps)
651 GstPad *sinkpad = NULL;
655 g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
661 GST_LOG_OBJECT (sel,
"Creating new pad sink_%u", sel->
padcount);
662 name = g_strdup_printf (
"sink_%u", sel->
padcount++);
664 "name", name,
"direction", templ->direction,
"template", templ, NULL);
672 gst_pad_set_iterate_internal_links_function (sinkpad,
675 GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
676 GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
677 gst_pad_set_active (sinkpad,
TRUE);
678 gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
691 "gstreamer join element");
693 if (!gst_element_register (plugin,
"join", GST_RANK_NONE,
GST_TYPE_JOIN)) {
701 #define PACKAGE "join"
707 "Select the out that arrived first among the input streams",
709 "https://github.com/nnstreamer/nnstreamer")