gstdepay: add support for events
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 1 Nov 2012 17:44:11 +0000 (17:44 +0000)
committerWim Taymans <wim.taymans@collabora.co.uk>
Thu, 1 Nov 2012 18:18:19 +0000 (18:18 +0000)
Conflicts:
gst/rtp/gstrtpgstdepay.c

gst/rtp/gstrtpgstdepay.c

index 49a3d73..9bc5d45 100644 (file)
@@ -183,6 +183,121 @@ gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * 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)
+{
+  guint offset, length;
+  GstCaps *caps;
+  GstMapInfo map;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %u", map.size);
+
+  if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
+    goto too_small;
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &map.data[offset]);
+
+  /* parse and store in cache */
+  caps = gst_caps_from_string ((gchar *) & map.data[offset]);
+  gst_buffer_unmap (buf, &map);
+
+  *skip = length + offset;
+
+  return caps;
+
+too_small:
+  {
+    GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+        ("Buffer too small."), (NULL));
+    gst_buffer_unmap (buf, &map);
+    return NULL;
+  }
+}
+
+static GstEvent *
+read_event (GstRtpGSTDepay * rtpgstdepay, guint type,
+    GstBuffer * buf, guint * skip)
+{
+  guint offset, length;
+  GstStructure *s;
+  GstEvent *event;
+  GstEventType etype;
+  gchar *end;
+  GstMapInfo map;
+
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %u", map.size);
+
+  if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
+    goto too_small;
+
+  GST_DEBUG_OBJECT (rtpgstdepay, "parsing event %s", &map.data[offset]);
+
+  /* parse */
+  s = gst_structure_from_string ((gchar *) & map.data[offset], &end);
+  gst_buffer_unmap (buf, &map);
+
+  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));
+    gst_buffer_unmap (buf, &map);
+    return NULL;
+  }
+unknown_event:
+  {
+    GST_DEBUG_OBJECT (rtpgstdepay, "unknown event type");
+    return NULL;
+  }
+}
+
 static GstBuffer *
 gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
 {
@@ -190,7 +305,7 @@ gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
   GstBuffer *subbuf, *outbuf = NULL;
   gint payload_len;
   guint8 *payload;
-  guint CV, frag_offset, avail;
+  guint CV, frag_offset, avail, offset;
   GstRTPBuffer rtp = { NULL };
 
   rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
@@ -214,7 +329,7 @@ gst_rtp_gst_depay_process (GstRTPBaseDepayload * 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|0|0|0|                  MBZ                          |
+   * |C| CV  |D|0|0|0|     ETYPE     |  MBZ                          |
    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    * |                          Frag_offset                          |
    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -230,6 +345,7 @@ gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
   subbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 8, -1);
   gst_adapter_push (rtpgstdepay->adapter, subbuf);
 
+  offset = 0;
   if (gst_rtp_buffer_get_marker (&rtp)) {
     guint avail;
     GstCaps *outcaps;
@@ -241,82 +357,78 @@ gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
     CV = (payload[0] >> 4) & 0x7;
 
     if (payload[0] & 0x80) {
-      guint b, csize, left, offset;
-      GstMapInfo map;
-      GstBuffer *subbuf;
+      guint size;
 
       /* C bit, we have inline caps */
-      gst_buffer_map (outbuf, &map, GST_MAP_READ);
-
-      GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %u", map.size);
-
-      /* start reading the length, we need this to skip to the data later */
-      csize = offset = 0;
-      left = map.size;
-      do {
-        if (offset >= left) {
-          gst_buffer_unmap (outbuf, &map);
-          goto too_small;
-        }
-        b = map.data[offset++];
-        csize = (csize << 7) | (b & 0x7f);
-      } while (b & 0x80);
-
-      /* we have read csize, reduce remaining buffer size */
-      left -= offset;
-      if (left < csize) {
-        gst_buffer_unmap (outbuf, &map);
-        goto too_small;
-      }
+      outcaps = read_caps (rtpgstdepay, outbuf, &size);
+      if (outcaps == NULL)
+        goto no_caps;
 
-      GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &map.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 *) & map.data[offset]);
       store_cache (rtpgstdepay, CV, outcaps);
 
       /* skip caps */
-      offset += csize;
-      left -= csize;
-
-      GST_DEBUG_OBJECT (rtpgstdepay,
-          "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, csize, outcaps);
-
-      GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset,
-          left);
-      /* create real data buffer when needed */
-      if (left)
-        subbuf =
-            gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, offset, left);
-      else
-        subbuf = NULL;
-
-      gst_buffer_unmap (outbuf, &map);
-      gst_buffer_unref (outbuf);
-      outbuf = subbuf;
+      offset += size;
+      avail -= size;
     }
+    if (payload[1]) {
+      guint size;
+      GstEvent *event;
 
-    /* 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;
+      /* we have an event */
+      event = read_event (rtpgstdepay, payload[1], outbuf, &size);
+      if (event == NULL)
+        goto no_event;
 
       GST_DEBUG_OBJECT (rtpgstdepay,
-          "need caps switch from %u to %u, %" GST_PTR_FORMAT,
-          rtpgstdepay->current_CV, CV, outcaps);
+          "inline event, length %u, %" GST_PTR_FORMAT, size, event);
+
+      gst_pad_push_event (depayload->srcpad, event);
 
-      /* and set caps */
-      if (gst_pad_set_caps (depayload->srcpad, outcaps))
-        rtpgstdepay->current_CV = CV;
+      /* no buffer after event */
+      avail = 0;
     }
 
-    if (outbuf) {
+    if (avail) {
+      if (offset != 0) {
+        GstBuffer *temp;
+
+        GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset,
+            avail);
+
+        temp =
+            gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, 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 (payload[0] & 0x8)
         GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+    } else {
+      gst_buffer_unref (outbuf);
+      outbuf = NULL;
     }
   }
   gst_rtp_buffer_unmap (&rtp);
+
   return outbuf;
 
   /* ERRORS */
@@ -334,12 +446,17 @@ 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);
+    gst_rtp_buffer_unmap (&rtp);
+    return NULL;
+  }
+no_event:
+  {
+    GST_WARNING_OBJECT (rtpgstdepay, "failed to parse event");
+    gst_buffer_unref (outbuf);
     gst_rtp_buffer_unmap (&rtp);
     return NULL;
   }
@@ -347,8 +464,7 @@ missing_caps:
   {
     GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
         ("Missing caps %u.", CV), (NULL));
-    if (outbuf)
-      gst_buffer_unref (outbuf);
+    gst_buffer_unref (outbuf);
     gst_rtp_buffer_unmap (&rtp);
     return NULL;
   }