static gboolean gst_stream_splitter_sink_setcaps (GstPad * pad, GstCaps * caps) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) GST_PAD_PARENT (pad); guint32 cookie; GList *tmp; gboolean res; GST_DEBUG_OBJECT (stream_splitter, "caps %" GST_PTR_FORMAT, caps); /* Try on all pads, choose the one that succeeds as the current stream */ STREAMS_LOCK (stream_splitter); resync: if (G_UNLIKELY (stream_splitter->srcpads == NULL)) { res = FALSE; goto beach; } res = FALSE; tmp = stream_splitter->srcpads; cookie = stream_splitter->cookie; while (tmp) { GstPad *srcpad = (GstPad *) tmp->data; GstCaps *peercaps; STREAMS_UNLOCK (stream_splitter); peercaps = gst_pad_peer_query_caps (srcpad, NULL); if (peercaps) { res = gst_caps_can_intersect (caps, peercaps); gst_caps_unref (peercaps); } STREAMS_LOCK (stream_splitter); if (G_UNLIKELY (cookie != stream_splitter->cookie)) goto resync; if (res) { /* FIXME : we need to switch properly */ GST_DEBUG_OBJECT (srcpad, "Setting caps on this pad was successful"); stream_splitter->current = srcpad; goto beach; } tmp = tmp->next; } beach: STREAMS_UNLOCK (stream_splitter); return res; }
static GstCaps * gst_stream_splitter_sink_getcaps (GstPad * pad, GstCaps * filter) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) GST_PAD_PARENT (pad); guint32 cookie; GList *tmp; GstCaps *res = NULL; /* Return the combination of all downstream caps */ STREAMS_LOCK (stream_splitter); resync: if (G_UNLIKELY (stream_splitter->srcpads == NULL)) { res = (filter ? gst_caps_ref (filter) : gst_caps_new_any ()); goto beach; } res = NULL; cookie = stream_splitter->cookie; tmp = stream_splitter->srcpads; while (tmp) { GstPad *srcpad = (GstPad *) tmp->data; /* Ensure srcpad doesn't get destroyed while we query peer */ gst_object_ref (srcpad); STREAMS_UNLOCK (stream_splitter); if (res) { GstCaps *peercaps = gst_pad_peer_query_caps (srcpad, filter); if (peercaps) res = gst_caps_merge (res, peercaps); } else { res = gst_pad_peer_query_caps (srcpad, filter); } STREAMS_LOCK (stream_splitter); gst_object_unref (srcpad); if (G_UNLIKELY (cookie != stream_splitter->cookie)) { if (res) gst_caps_unref (res); goto resync; } tmp = tmp->next; } beach: STREAMS_UNLOCK (stream_splitter); return res; }
static void gst_stream_splitter_release_pad (GstElement * element, GstPad * pad) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) element; GList *tmp; STREAMS_LOCK (stream_splitter); tmp = g_list_find (stream_splitter->srcpads, pad); if (tmp) { GstPad *pad = (GstPad *) tmp->data; stream_splitter->srcpads = g_list_delete_link (stream_splitter->srcpads, tmp); stream_splitter->cookie++; if (pad == stream_splitter->current) { /* Deactivate current flow */ GST_DEBUG_OBJECT (element, "Removed pad was the current one"); stream_splitter->current = NULL; } gst_element_remove_pad (element, pad); } STREAMS_UNLOCK (stream_splitter); return; }
static GstFlowReturn gst_stream_splitter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent; GstFlowReturn res; GstPad *srcpad = NULL; STREAMS_LOCK (stream_splitter); if (stream_splitter->current) srcpad = gst_object_ref (stream_splitter->current); STREAMS_UNLOCK (stream_splitter); if (G_UNLIKELY (srcpad == NULL)) goto nopad; if (G_UNLIKELY (stream_splitter->pending_events)) gst_stream_splitter_push_pending_events (stream_splitter, srcpad); /* Forward to currently activated stream */ res = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return res; nopad: GST_WARNING_OBJECT (stream_splitter, "No output pad was configured"); return GST_FLOW_ERROR; }
static gboolean gst_stream_combiner_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent; GstPad *sinkpad = NULL; gboolean ret = FALSE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS: ret = gst_pad_query_default (pad, parent, query); break; default: STREAMS_LOCK (stream_combiner); if (stream_combiner->current) sinkpad = stream_combiner->current; else if (stream_combiner->sinkpads) sinkpad = (GstPad *) stream_combiner->sinkpads->data; STREAMS_UNLOCK (stream_combiner); if (sinkpad) /* Forward upstream as is */ ret = gst_pad_peer_query (sinkpad, query); break; } return ret; }
static gboolean gst_stream_combiner_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent; GstStreamCombinerPad *combiner_pad = GST_STREAM_COMBINER_PAD (pad); /* FIXME : IMPLEMENT */ GST_DEBUG_OBJECT (pad, "Got event %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: STREAMS_LOCK (stream_combiner); combiner_pad->is_eos = TRUE; if (!_all_sink_pads_eos (stream_combiner)) { gst_event_unref (event); event = NULL; } else { GST_DEBUG_OBJECT (stream_combiner, "All sink pads eos, pushing eos"); } STREAMS_UNLOCK (stream_combiner); break; default: break; } /* SEGMENT : lock, wait for other stream to EOS, select stream, unlock, push */ /* FLUSH_START : lock, mark as flushing, unlock. if wasn't flushing forward */ /* FLUSH_STOP : lock, unmark as flushing, unlock, if was flushing forward */ /* OTHER : if selected pad forward */ if (event) return gst_pad_push_event (stream_combiner->srcpad, event); return FALSE; }
static gboolean gst_stream_splitter_sink_acceptcaps (GstPad * pad, GstCaps * caps) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) GST_PAD_PARENT (pad); guint32 cookie; GList *tmp; gboolean res = FALSE; /* check if one of the downstream elements accepts the caps */ STREAMS_LOCK (stream_splitter); resync: res = FALSE; if (G_UNLIKELY (stream_splitter->srcpads == NULL)) goto beach; cookie = stream_splitter->cookie; tmp = stream_splitter->srcpads; while (tmp) { GstPad *srcpad = (GstPad *) tmp->data; /* Ensure srcpad doesn't get destroyed while we query peer */ gst_object_ref (srcpad); STREAMS_UNLOCK (stream_splitter); res = gst_pad_peer_query_accept_caps (srcpad, caps); STREAMS_LOCK (stream_splitter); gst_object_unref (srcpad); if (G_UNLIKELY (cookie != stream_splitter->cookie)) goto resync; if (res) break; tmp = tmp->next; } beach: STREAMS_UNLOCK (stream_splitter); return res; }
static GstPad * gst_stream_splitter_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name, const GstCaps * caps) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) element; GstPad *srcpad; srcpad = gst_pad_new_from_static_template (&src_template, name); STREAMS_LOCK (stream_splitter); stream_splitter->srcpads = g_list_append (stream_splitter->srcpads, srcpad); gst_pad_set_active (srcpad, TRUE); gst_element_add_pad (element, srcpad); stream_splitter->cookie++; STREAMS_UNLOCK (stream_splitter); return srcpad; }
static gboolean gst_stream_combiner_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent; GstPad *sinkpad = NULL; STREAMS_LOCK (stream_combiner); if (stream_combiner->current) sinkpad = stream_combiner->current; else if (stream_combiner->sinkpads) sinkpad = (GstPad *) stream_combiner->sinkpads->data; STREAMS_UNLOCK (stream_combiner); if (sinkpad) /* Forward upstream as is */ return gst_pad_push_event (sinkpad, event); return FALSE; }
static GstFlowReturn gst_stream_splitter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent; GstFlowReturn res; GstPad *srcpad = NULL; STREAMS_LOCK (stream_splitter); if (stream_splitter->current) srcpad = gst_object_ref (stream_splitter->current); STREAMS_UNLOCK (stream_splitter); if (G_UNLIKELY (srcpad == NULL)) goto nopad; if (G_UNLIKELY (stream_splitter->pending_events)) { GList *tmp; GST_DEBUG_OBJECT (srcpad, "Pushing out pending events"); for (tmp = stream_splitter->pending_events; tmp; tmp = tmp->next) { GstEvent *event = (GstEvent *) tmp->data; gst_pad_push_event (srcpad, event); } g_list_free (stream_splitter->pending_events); stream_splitter->pending_events = NULL; } /* Forward to currently activated stream */ res = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return res; nopad: GST_WARNING_OBJECT (stream_splitter, "No output pad was configured"); return GST_FLOW_ERROR; }
static gboolean gst_stream_splitter_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent; gboolean res = TRUE; gboolean toall = FALSE; gboolean store = FALSE; gboolean eos = FALSE; gboolean flushpending = FALSE; /* FLUSH_START/STOP : forward to all * EOS : transform to CUSTOM_REAL_EOS and forward to all * INBAND events : store to send in chain function to selected chain * OUT_OF_BAND events : send to all */ GST_DEBUG_OBJECT (stream_splitter, "Got event %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); res = gst_stream_splitter_sink_setcaps (pad, caps); store = TRUE; break; } case GST_EVENT_FLUSH_STOP: flushpending = TRUE; toall = TRUE; break; case GST_EVENT_FLUSH_START: toall = TRUE; break; case GST_EVENT_EOS: /* Replace with our custom eos event */ gst_event_unref (event); event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, gst_structure_new_empty ("stream-switching-eos")); toall = TRUE; eos = TRUE; break; default: if (GST_EVENT_TYPE (event) & GST_EVENT_TYPE_SERIALIZED) store = TRUE; } if (flushpending) { g_list_foreach (stream_splitter->pending_events, (GFunc) gst_event_unref, NULL); g_list_free (stream_splitter->pending_events); stream_splitter->pending_events = NULL; } if (store) { stream_splitter->pending_events = g_list_append (stream_splitter->pending_events, event); } else if (toall || eos) { GList *tmp; guint32 cookie; /* Send to all pads */ STREAMS_LOCK (stream_splitter); resync: if (G_UNLIKELY (stream_splitter->srcpads == NULL)) { STREAMS_UNLOCK (stream_splitter); /* No source pads */ gst_event_unref (event); res = FALSE; goto beach; } tmp = stream_splitter->srcpads; cookie = stream_splitter->cookie; while (tmp) { GstPad *srcpad = (GstPad *) tmp->data; STREAMS_UNLOCK (stream_splitter); /* In case of EOS, we first push out the real one to flush out * each streams (but which will be discarded in the streamcombiner) * before our custom one (which will be converted back to and EOS * in the streamcombiner) */ if (eos) gst_pad_push_event (srcpad, gst_event_new_eos ()); gst_event_ref (event); res = gst_pad_push_event (srcpad, event); STREAMS_LOCK (stream_splitter); if (G_UNLIKELY (cookie != stream_splitter->cookie)) goto resync; tmp = tmp->next; } STREAMS_UNLOCK (stream_splitter); gst_event_unref (event); } else { GstPad *pad; /* Only send to current pad */ STREAMS_LOCK (stream_splitter); pad = stream_splitter->current; STREAMS_UNLOCK (stream_splitter); if (pad) res = gst_pad_push_event (pad, event); else { gst_event_unref (event); res = FALSE; } } beach: return res; }
static gboolean gst_stream_splitter_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent; gboolean res = TRUE; gboolean toall = FALSE; gboolean store = FALSE; gboolean flushpending = FALSE; /* FLUSH_START/STOP : forward to all * INBAND events : store to send in chain function to selected chain * OUT_OF_BAND events : send to all */ GST_DEBUG_OBJECT (stream_splitter, "Got event %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); res = gst_stream_splitter_sink_setcaps (pad, caps); store = TRUE; break; } case GST_EVENT_FLUSH_STOP: flushpending = TRUE; toall = TRUE; break; case GST_EVENT_FLUSH_START: toall = TRUE; break; case GST_EVENT_EOS: toall = TRUE; break; default: if (GST_EVENT_TYPE (event) & GST_EVENT_TYPE_SERIALIZED) store = TRUE; } if (flushpending) { g_list_foreach (stream_splitter->pending_events, (GFunc) gst_event_unref, NULL); g_list_free (stream_splitter->pending_events); stream_splitter->pending_events = NULL; } if (store) { stream_splitter->pending_events = g_list_append (stream_splitter->pending_events, event); } else if (toall) { GList *tmp; guint32 cookie; /* Send to all pads */ STREAMS_LOCK (stream_splitter); resync: if (G_UNLIKELY (stream_splitter->srcpads == NULL)) { STREAMS_UNLOCK (stream_splitter); /* No source pads */ gst_event_unref (event); res = FALSE; goto beach; } tmp = stream_splitter->srcpads; cookie = stream_splitter->cookie; while (tmp) { GstPad *srcpad = (GstPad *) tmp->data; STREAMS_UNLOCK (stream_splitter); gst_event_ref (event); res = gst_pad_push_event (srcpad, event); STREAMS_LOCK (stream_splitter); if (G_UNLIKELY (cookie != stream_splitter->cookie)) goto resync; tmp = tmp->next; } STREAMS_UNLOCK (stream_splitter); gst_event_unref (event); } else { GstPad *pad; /* Only send to current pad */ STREAMS_LOCK (stream_splitter); pad = stream_splitter->current; STREAMS_UNLOCK (stream_splitter); if (pad) res = gst_pad_push_event (pad, event); else { gst_event_unref (event); res = FALSE; } } beach: return res; }