From af632d3bfd548e705a902dcd79b9a906679ef482 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 1 Nov 2012 17:44:11 +0000 Subject: gstdepay: add support for events --- gst/rtp/gstrtpgstdepay.c | 232 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 174 insertions(+), 58 deletions(-) diff --git a/gst/rtp/gstrtpgstdepay.c b/gst/rtp/gstrtpgstdepay.c index 7978a39f5..20e17989b 100644 --- a/gst/rtp/gstrtpgstdepay.c +++ b/gst/rtp/gstrtpgstdepay.c @@ -190,6 +190,119 @@ gst_rtp_gst_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) return res; } +static gboolean +read_length (GstRtpGSTDepay * rtpgstdepay, guint8 * data, guint size, + guint * length, guint * skip) +{ + guint b, len, offset; + + /* start reading the length, we need this to skip to the data later */ + len = offset = 0; + do { + if (offset >= size) + return FALSE; + b = data[offset++]; + len = (len << 7) | (b & 0x7f); + } while (b & 0x80); + + /* check remaining buffer size */ + if (size - offset < len) + return FALSE; + + *length = len; + *skip = offset; + + return TRUE; +} + +static GstCaps * +read_caps (GstRtpGSTDepay * rtpgstdepay, GstBuffer * buf, guint * skip) +{ + guint8 *data; + guint size, offset, length; + GstCaps *caps; + + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %u", size); + + if (!read_length (rtpgstdepay, data, size, &length, &offset)) + goto too_small; + + GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &data[offset]); + + /* parse and store in cache */ + caps = gst_caps_from_string ((gchar *) & data[offset]); + + *skip = length + offset; + + return caps; + +too_small: + { + GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE, + ("Buffer too small."), (NULL)); + return NULL; + } +} + +static GstEvent * +read_event (GstRtpGSTDepay * rtpgstdepay, guint type, + GstBuffer * buf, guint * skip) +{ + guint8 *data; + guint size, offset, length; + GstStructure *s; + GstEvent *event; + GstEventType etype; + gchar *end; + + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %u", size); + + if (!read_length (rtpgstdepay, data, size, &length, &offset)) + goto too_small; + + GST_DEBUG_OBJECT (rtpgstdepay, "parsing event %s", &data[offset]); + + /* parse */ + s = gst_structure_from_string ((gchar *) & data[offset], &end); + + switch (type) { + case 1: + etype = GST_EVENT_TAG; + break; + case 2: + etype = GST_EVENT_CUSTOM_DOWNSTREAM; + break; + case 3: + etype = GST_EVENT_CUSTOM_BOTH; + break; + default: + goto unknown_event; + } + event = gst_event_new_custom (etype, s); + + *skip = length + offset; + + return event; + +too_small: + { + GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE, + ("Buffer too small."), (NULL)); + return NULL; + } +unknown_event: + { + GST_DEBUG_OBJECT (rtpgstdepay, "unknown event type"); + return NULL; + } +} + static GstBuffer * gst_rtp_gst_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { @@ -197,7 +310,7 @@ gst_rtp_gst_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) GstBuffer *subbuf, *outbuf = NULL; gint payload_len; guint8 *payload; - guint CV, frag_offset, avail; + guint CV, frag_offset, avail, offset; rtpgstdepay = GST_RTP_GST_DEPAY (depayload); @@ -218,7 +331,7 @@ gst_rtp_gst_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |C| CV |D|X|Y|Z| MBZ | + * |C| CV |D|X|Y|Z| ETYPE | MBZ | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Frag_offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -234,6 +347,7 @@ gst_rtp_gst_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) subbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 8, -1); gst_adapter_push (rtpgstdepay->adapter, subbuf); + offset = 0; if (gst_rtp_buffer_get_marker (buf)) { guint avail; GstCaps *outcaps; @@ -245,71 +359,67 @@ gst_rtp_gst_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) CV = (payload[0] >> 4) & 0x7; if (payload[0] & 0x80) { - guint b, csize, size, offset; - guint8 *data; - GstBuffer *subbuf; + guint size; /* C bit, we have inline caps */ - data = GST_BUFFER_DATA (outbuf); - size = GST_BUFFER_SIZE (outbuf); + outcaps = read_caps (rtpgstdepay, outbuf, &size); + if (outcaps == NULL) + goto no_caps; - GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %u", size); - - /* start reading the length, we need this to skip to the data later */ - csize = offset = 0; - do { - if (offset >= size) - goto too_small; - b = data[offset++]; - csize = (csize << 7) | (b & 0x7f); - } while (b & 0x80); - - /* we have read csize, reduce remaining buffer size */ - size -= offset; - if (size < csize) - goto too_small; - - GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &data[offset]); + GST_DEBUG_OBJECT (rtpgstdepay, + "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, size, outcaps); - /* parse and store in cache */ - outcaps = gst_caps_from_string ((gchar *) & data[offset]); store_cache (rtpgstdepay, CV, outcaps); /* skip caps */ - offset += csize; - size -= csize; + offset += size; + avail -= size; + } + if (payload[1]) { + guint size; + GstEvent *event; + + /* we have an event */ + event = read_event (rtpgstdepay, payload[1], outbuf, &size); + if (event == NULL) + goto no_event; GST_DEBUG_OBJECT (rtpgstdepay, - "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, csize, outcaps); + "inline event, length %u, %" GST_PTR_FORMAT, size, event); - GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset, - size); - /* create real data buffer when needed */ - if (size) - subbuf = gst_buffer_create_sub (outbuf, offset, size); - else - subbuf = NULL; + gst_pad_push_event (depayload->srcpad, event); - gst_buffer_unref (outbuf); - outbuf = subbuf; + /* no buffer after event */ + avail = 0; } - /* see what caps we need */ - if (CV != rtpgstdepay->current_CV) { - /* we need to switch caps, check if we have the caps */ - if ((outcaps = rtpgstdepay->CV_cache[CV]) == NULL) - goto missing_caps; + if (avail) { + if (offset != 0) { + GstBuffer *temp; - GST_DEBUG_OBJECT (rtpgstdepay, - "need caps switch from %u to %u, %" GST_PTR_FORMAT, - rtpgstdepay->current_CV, CV, outcaps); + GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset, + avail); - /* and set caps */ - if (gst_pad_set_caps (depayload->srcpad, outcaps)) - rtpgstdepay->current_CV = CV; - } + temp = gst_buffer_create_sub (outbuf, offset, avail); + gst_buffer_unref (outbuf); + outbuf = temp; + } + + /* see what caps we need */ + if (CV != rtpgstdepay->current_CV) { + /* we need to switch caps, check if we have the caps */ + if ((outcaps = rtpgstdepay->CV_cache[CV]) == NULL) + goto missing_caps; + + GST_DEBUG_OBJECT (rtpgstdepay, + "need caps switch from %u to %u, %" GST_PTR_FORMAT, + rtpgstdepay->current_CV, CV, outcaps); + + /* and set caps */ + if (gst_pad_set_caps (depayload->srcpad, outcaps)) + rtpgstdepay->current_CV = CV; + } - if (outbuf) { if (payload[0] & 0x8) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); if (payload[0] & 0x4) @@ -318,6 +428,9 @@ gst_rtp_gst_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_MEDIA2); if (payload[0] & 0x1) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_MEDIA3); + } else { + gst_buffer_unref (outbuf); + outbuf = NULL; } } return outbuf; @@ -335,20 +448,23 @@ wrong_frag: GST_LOG_OBJECT (rtpgstdepay, "wrong fragment, skipping"); return NULL; } -too_small: +no_caps: { - GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE, - ("Buffer too small."), (NULL)); - if (outbuf) - gst_buffer_unref (outbuf); + GST_WARNING_OBJECT (rtpgstdepay, "failed to parse caps"); + gst_buffer_unref (outbuf); + return NULL; + } +no_event: + { + GST_WARNING_OBJECT (rtpgstdepay, "failed to parse event"); + gst_buffer_unref (outbuf); return NULL; } missing_caps: { GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE, ("Missing caps %u.", CV), (NULL)); - if (outbuf) - gst_buffer_unref (outbuf); + gst_buffer_unref (outbuf); return NULL; } } -- cgit v1.2.1