static gboolean gst_output_selector_query (GstPad * pad, GstObject * parent, GstQuery * query) { gboolean res = TRUE; GstOutputSelector *sel; GstPad *active = NULL; sel = GST_OUTPUT_SELECTOR (parent); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS: { switch (sel->pad_negotiation_mode) { case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL: /* Send caps to all src pads */ res = gst_pad_proxy_query_caps (pad, query); break; case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE: res = FALSE; break; default: active = gst_output_selector_get_active (sel); if (active) { res = gst_pad_peer_query (active, query); gst_object_unref (active); } else { res = FALSE; } break; } break; } default: res = gst_pad_query_default (pad, parent, query); break; } return res; }
static void gst_output_selector_release_pad (GstElement * element, GstPad * pad) { GstOutputSelector *osel; osel = GST_OUTPUT_SELECTOR (element); GST_DEBUG_OBJECT (osel, "releasing pad"); /* Disable active pad if it's the to be removed pad */ GST_OBJECT_LOCK (osel); if (osel->active_srcpad == pad) { osel->active_srcpad = NULL; GST_OBJECT_UNLOCK (osel); g_object_notify (G_OBJECT (osel), "active-pad"); } else { GST_OBJECT_UNLOCK (osel); } gst_pad_set_active (pad, FALSE); gst_element_remove_pad (GST_ELEMENT_CAST (osel), pad); }
static gboolean gst_output_selector_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstOutputSelector *sel; GstPad *active = NULL; sel = GST_OUTPUT_SELECTOR (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { res = gst_output_selector_forward_event (sel, event); break; } case GST_EVENT_SEGMENT: { gst_event_copy_segment (event, &sel->segment); GST_DEBUG_OBJECT (sel, "configured SEGMENT %" GST_SEGMENT_FORMAT, &sel->segment); /* fall through */ } default: { active = gst_output_selector_get_active (sel); if (active) { res = gst_pad_push_event (active, event); gst_object_unref (active); } else { gst_event_unref (event); } break; } } return res; }
static GstPad * gst_output_selector_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name, const GstCaps * caps) { gchar *padname; GstPad *srcpad; GstOutputSelector *osel; osel = GST_OUTPUT_SELECTOR (element); GST_DEBUG_OBJECT (osel, "requesting pad"); GST_OBJECT_LOCK (osel); padname = g_strdup_printf ("src_%u", osel->nb_srcpads++); srcpad = gst_pad_new_from_template (templ, padname); GST_OBJECT_UNLOCK (osel); gst_pad_set_active (srcpad, TRUE); /* Forward sticky events to the new srcpad */ gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events, srcpad); gst_element_add_pad (GST_ELEMENT (osel), srcpad); /* Set the first requested src pad as active by default */ GST_OBJECT_LOCK (osel); if (osel->active_srcpad == NULL) { osel->active_srcpad = srcpad; GST_OBJECT_UNLOCK (osel); g_object_notify (G_OBJECT (osel), "active-pad"); } else { GST_OBJECT_UNLOCK (osel); } g_free (padname); return srcpad; }
static GstFlowReturn gst_output_selector_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn res; GstOutputSelector *osel; GstClockTime position, duration; GstPad *active_srcpad; osel = GST_OUTPUT_SELECTOR (parent); /* * The _switch function might push a buffer if 'resend-latest' is true. * * Elements/Applications (e.g. camerabin) might use pad probes to * switch output-selector's active pad. If we simply switch and don't * recheck any pending pad switch the following codepath could end * up pushing a buffer on a non-active pad. This is bad. * * So we always should check the pending_srcpad before going further down * the chain and pushing the new buffer */ while (osel->pending_srcpad) { /* Do the switch */ gst_output_selector_switch (osel); } active_srcpad = gst_output_selector_get_active (osel); if (!active_srcpad) { GST_DEBUG_OBJECT (osel, "No active srcpad"); gst_buffer_unref (buf); return GST_FLOW_OK; } GST_OBJECT_LOCK (osel); if (osel->latest_buffer) { gst_buffer_unref (osel->latest_buffer); osel->latest_buffer = NULL; } if (osel->resend_latest) { /* Keep reference to latest buffer to resend it after switch */ osel->latest_buffer = gst_buffer_ref (buf); } GST_OBJECT_UNLOCK (osel); /* Keep track of last stop and use it in SEGMENT start after switching to a new src pad */ position = GST_BUFFER_TIMESTAMP (buf); if (GST_CLOCK_TIME_IS_VALID (position)) { duration = GST_BUFFER_DURATION (buf); if (GST_CLOCK_TIME_IS_VALID (duration)) { position += duration; } GST_LOG_OBJECT (osel, "setting last stop %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); osel->segment.position = position; } GST_LOG_OBJECT (osel, "pushing buffer to %" GST_PTR_FORMAT, active_srcpad); res = gst_pad_push (active_srcpad, buf); gst_object_unref (active_srcpad); return res; }
static gboolean gst_output_selector_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstOutputSelector *sel; GstPad *active = NULL; sel = GST_OUTPUT_SELECTOR (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { switch (sel->pad_negotiation_mode) { case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL: /* Send caps to all src pads */ res = gst_pad_event_default (pad, parent, event); break; case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE: gst_event_unref (event); break; default: active = gst_output_selector_get_active (sel); if (active) { res = gst_pad_push_event (active, event); gst_object_unref (active); } else { gst_event_unref (event); } break; } break; } case GST_EVENT_SEGMENT: { gst_event_copy_segment (event, &sel->segment); GST_DEBUG_OBJECT (sel, "configured SEGMENT %" GST_SEGMENT_FORMAT, &sel->segment); /* Send newsegment to all src pads */ res = gst_pad_event_default (pad, parent, event); break; } case GST_EVENT_EOS: /* Send eos to all src pads */ res = gst_pad_event_default (pad, parent, event); break; default: { /* Send other events to pending or active src pad */ active = gst_output_selector_get_active (sel); if (active) { res = gst_pad_push_event (active, event); gst_object_unref (active); } else { gst_event_unref (event); } break; } } return res; }