static gboolean gst_rtp_pt_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRtpPtDemux *rtpdemux; gboolean res = FALSE; rtpdemux = GST_RTP_PT_DEMUX (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { gst_rtp_pt_demux_clear_pt_map (rtpdemux); /* don't forward the event, we cleared the ptmap and on the next buffer we * will add the pt to the caps and push a new caps event */ gst_event_unref (event); res = TRUE; break; } case GST_EVENT_CUSTOM_DOWNSTREAM: { const GstStructure *s; s = gst_event_get_structure (event); if (gst_structure_has_name (s, "GstRTPPacketLost")) { GstPad *srcpad = find_pad_for_pt (rtpdemux, rtpdemux->last_pt); if (srcpad) { res = gst_pad_push_event (srcpad, event); gst_object_unref (srcpad); } else { gst_event_unref (event); } } else { res = gst_pad_event_default (pad, parent, event); } break; } default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
static gboolean gst_rtp_pt_demux_sink_event (GstPad * pad, GstEvent * event) { GstRtpPtDemux *rtpdemux; gboolean res = FALSE; rtpdemux = GST_RTP_PT_DEMUX (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_DOWNSTREAM: { const GstStructure *s; s = gst_event_get_structure (event); if (gst_structure_has_name (s, "GstRTPPacketLost")) { GstRtpPtDemuxPad *rtpdemuxpad = find_pad_for_pt (rtpdemux, rtpdemux->last_pt); if (rtpdemuxpad) res = gst_pad_push_event (rtpdemuxpad->pad, event); else gst_event_unref (event); } else { res = gst_pad_event_default (pad, event); } break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (rtpdemux); return res; }
static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstRtpPtDemux *rtpdemux; GstElement *element = GST_ELEMENT (GST_OBJECT_PARENT (pad)); guint8 pt; GstPad *srcpad; GstRtpPtDemuxPad *rtpdemuxpad; GstCaps *caps; rtpdemux = GST_RTP_PT_DEMUX (GST_OBJECT_PARENT (pad)); if (!gst_rtp_buffer_validate (buf)) goto invalid_buffer; pt = gst_rtp_buffer_get_payload_type (buf); GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt); rtpdemuxpad = find_pad_for_pt (rtpdemux, pt); if (rtpdemuxpad == NULL) { /* new PT, create a src pad */ GstElementClass *klass; GstPadTemplate *templ; gchar *padname; klass = GST_ELEMENT_GET_CLASS (rtpdemux); templ = gst_element_class_get_pad_template (klass, "src_%d"); padname = g_strdup_printf ("src_%d", pt); srcpad = gst_pad_new_from_template (templ, padname); gst_pad_use_fixed_caps (srcpad); g_free (padname); caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); GST_DEBUG ("Adding pt=%d to the list.", pt); rtpdemuxpad = g_new0 (GstRtpPtDemuxPad, 1); rtpdemuxpad->pt = pt; rtpdemuxpad->newcaps = FALSE; rtpdemuxpad->pad = srcpad; GST_OBJECT_LOCK (rtpdemux); rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad); GST_OBJECT_UNLOCK (rtpdemux); gst_pad_set_active (srcpad, TRUE); gst_element_add_pad (element, srcpad); GST_DEBUG ("emitting new-payload-type for pt %d", pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad); } srcpad = rtpdemuxpad->pad; if (pt != rtpdemux->last_pt) { gint emit_pt = pt; /* our own signal with an extra flag that this is the only pad */ rtpdemux->last_pt = pt; GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt); } if (rtpdemuxpad->newcaps) { GST_DEBUG ("need new caps"); caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); rtpdemuxpad->newcaps = FALSE; } gst_buffer_set_caps (buf, GST_PAD_CAPS (srcpad)); /* push to srcpad */ ret = gst_pad_push (srcpad, buf); return ret; /* ERRORS */ invalid_buffer: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } no_caps: { GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Could not get caps for payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstRtpPtDemux *rtpdemux; guint8 pt; GstPad *srcpad; GstCaps *caps; GstRTPBuffer rtp = { NULL }; rtpdemux = GST_RTP_PT_DEMUX (parent); if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) goto invalid_buffer; pt = gst_rtp_buffer_get_payload_type (&rtp); gst_rtp_buffer_unmap (&rtp); GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt); srcpad = find_pad_for_pt (rtpdemux, pt); if (srcpad == NULL) { /* new PT, create a src pad */ GstRtpPtDemuxPad *rtpdemuxpad; GstElementClass *klass; GstPadTemplate *templ; gchar *padname; caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; klass = GST_ELEMENT_GET_CLASS (rtpdemux); templ = gst_element_class_get_pad_template (klass, "src_%u"); padname = g_strdup_printf ("src_%u", pt); srcpad = gst_pad_new_from_template (templ, padname); gst_pad_use_fixed_caps (srcpad); g_free (padname); gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event); GST_DEBUG ("Adding pt=%d to the list.", pt); rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad); rtpdemuxpad->pt = pt; rtpdemuxpad->newcaps = FALSE; rtpdemuxpad->pad = srcpad; gst_object_ref (srcpad); GST_OBJECT_LOCK (rtpdemux); rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad); GST_OBJECT_UNLOCK (rtpdemux); gst_pad_set_active (srcpad, TRUE); /* First push the stream-start event, it must always come first */ gst_pad_push_event (srcpad, gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0)); /* Then caps event is sent */ caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); /* First sticky events on sink pad are forwarded to the new src pad */ gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events, srcpad); gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad); GST_DEBUG ("emitting new-payload-type for pt %d", pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad); } if (pt != rtpdemux->last_pt) { gint emit_pt = pt; /* our own signal with an extra flag that this is the only pad */ rtpdemux->last_pt = pt; GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt); } while (need_caps_for_pt (rtpdemux, pt)) { GST_DEBUG ("need new caps for %d", pt); caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; clear_newcaps_for_pt (rtpdemux, pt); caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); } /* push to srcpad */ ret = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_buffer: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } no_caps: { GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Could not get caps for payload")); gst_buffer_unref (buf); if (srcpad) gst_object_unref (srcpad); return GST_FLOW_ERROR; } }