rtpsv3vdepay: Properly fill codec_data and cleanup code a bite more.
authorEdward Hervey <bilboed@bilboed.com>
Mon, 3 Aug 2009 19:24:44 +0000 (21:24 +0200)
committerEdward Hervey <bilboed@bilboed.com>
Mon, 3 Aug 2009 19:26:30 +0000 (21:26 +0200)
gst/rtp/gstrtpsv3vdepay.c

index ae7cf57c34d8838118a2db1e795481c4b660ee73..b9b03c244740d1b5ff537027e6a2c18b9ace4597 100644 (file)
@@ -139,128 +139,143 @@ static GstBuffer *
 gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 {
   GstRtpSV3VDepay *rtpsv3vdepay;
-  GstBuffer *outbuf;
+  static struct
+  {
+    guint width, height;
+  } resolutions[7] = {
+    {
+    160, 128}, {
+    128, 96}, {
+    176, 144}, {
+    352, 288}, {
+    704, 576}, {
+    240, 180}, {
+    320, 240}
+  };
+  gint payload_len;
+  guint8 *payload;
+  gboolean M;
+  gboolean C, S, E;
+  GstBuffer *outbuf = NULL;
   guint16 seq;
 
   rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload);
 
   /* flush on sequence number gaps */
   seq = gst_rtp_buffer_get_seq (buf);
+
+  GST_DEBUG ("timestamp %" GST_TIME_FORMAT ", sequence number:%d",
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), seq);
+
   if (seq != rtpsv3vdepay->nextseq) {
+    GST_DEBUG ("Sequence discontinuity, clearing adapter");
     gst_adapter_clear (rtpsv3vdepay->adapter);
   }
   rtpsv3vdepay->nextseq = seq + 1;
 
-  {
-    static struct
-    {
-      guint width, height;
-    } resolutions[7] = {
-      {
-      160, 128}, {
-      128, 96}, {
-      176, 144}, {
-      352, 288}, {
-      704, 576}, {
-      240, 180}, {
-      320, 240}
-    };
-    gint payload_len;
-    guint8 *payload;
-    gboolean M;
-    gboolean C, S, E;
-
-    payload_len = gst_rtp_buffer_get_payload_len (buf);
-    if (payload_len < 3)
-      goto bad_packet;
-
-    payload = gst_rtp_buffer_get_payload (buf);
-
-    M = gst_rtp_buffer_get_marker (buf);
-
-    /* This is all a guess:
-     *                      1 1 1 1 1 1
-     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
-     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-     * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0|
-     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-     *
-     * C: config, packet contains config info
-     * S: start, packet contains start of frame
-     * E: end, packet contains end of frame
-     */
-    /* this seems to indicate a packet with a config string sent before each
-     * keyframe */
-    C = (payload[0] & 0x40) == 0x40;
-
-    /* redundant with the RTP marker bit */
-    S = (payload[0] & 0x20) == 0x20;
-    E = (payload[0] & 0x10) == 0x10;
-
-    GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E);
-
-    GST_MEMDUMP ("incoming buffer", payload, payload_len);
-
-    if (C) {
-      GstCaps *caps;
-      GstBuffer *codec_data;
-      GValue value = { 0 };
-      guint8 res;
-
-      /* if we already have caps, we don't need to do anything. FIXME, check if
-       * something changed. */
-      if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload)))
-        return NULL;
-
-      res = payload[2] >> 5;
-
-      /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */
-      if (res < 7) {
-        rtpsv3vdepay->width = resolutions[res].width;
-        rtpsv3vdepay->height = resolutions[res].height;
-      } else {
-        /* extended width/height, they're contained in the following 24bit */
-        rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1);
-        rtpsv3vdepay->height =
-            (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5);
-      }
-
-      /* we need a dummy empty codec data */
-      g_value_init (&value, GST_TYPE_BUFFER);
-      gst_value_deserialize (&value, "");
-      codec_data = gst_value_get_buffer (&value);
-
-      caps = gst_caps_new_simple ("video/x-svq",
-          "svqversion", G_TYPE_INT, 3,
-          "width", G_TYPE_INT, rtpsv3vdepay->width,
-          "height", G_TYPE_INT, rtpsv3vdepay->height,
-          "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
-      gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps);
-      gst_caps_unref (caps);
-      g_value_unset (&value);
-
-      rtpsv3vdepay->configured = TRUE;
-
-      return NULL;
+  payload_len = gst_rtp_buffer_get_payload_len (buf);
+  if (payload_len < 3)
+    goto bad_packet;
+
+  payload = gst_rtp_buffer_get_payload (buf);
+
+  M = gst_rtp_buffer_get_marker (buf);
+
+  /* This is all a guess:
+   *                      1 1 1 1 1 1
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0|
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * C: config, packet contains config info
+   * S: start, packet contains start of frame
+   * E: end, packet contains end of frame
+   */
+  /* this seems to indicate a packet with a config string sent before each
+   * keyframe */
+  C = (payload[0] & 0x40) == 0x40;
+
+  /* redundant with the RTP marker bit */
+  S = (payload[0] & 0x20) == 0x20;
+  E = (payload[0] & 0x10) == 0x10;
+
+  GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E);
+
+  GST_MEMDUMP ("incoming buffer", payload, payload_len);
+
+  if (G_UNLIKELY (C)) {
+    GstCaps *caps;
+    GstBuffer *codec_data;
+    guint8 res;
+
+    GST_DEBUG ("Configuration packet");
+
+    /* if we already have caps, we don't need to do anything. FIXME, check if
+     * something changed. */
+    if (G_UNLIKELY (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload)))) {
+      GST_DEBUG ("Already configured, skipping config parsing");
+      goto beach;
+    }
+
+    res = payload[2] >> 5;
+
+    /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */
+    if (G_LIKELY (res < 7)) {
+      rtpsv3vdepay->width = resolutions[res].width;
+      rtpsv3vdepay->height = resolutions[res].height;
+    } else {
+      /* extended width/height, they're contained in the following 24bit */
+      rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1);
+      rtpsv3vdepay->height =
+          (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5);
     }
 
-    if (G_LIKELY (rtpsv3vdepay->configured)) {
-      /* store data in adapter, stip off 2 bytes header */
-      outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1);
-      gst_adapter_push (rtpsv3vdepay->adapter, outbuf);
+    /* CodecData needs to be 'SEQH' + len (32bit) + data according to
+     * ffmpeg's libavcodec/svq3.c:svq3_decode_init */
+    codec_data = gst_buffer_new_and_alloc (payload_len + 6);
+    memcpy (GST_BUFFER_DATA (codec_data), "SEQH", 4);
+    GST_WRITE_UINT32_LE (GST_BUFFER_DATA (codec_data) + 4, payload_len - 2);
+    memcpy (GST_BUFFER_DATA (codec_data) + 8, payload + 2, payload_len - 2);
 
-      if (M) {
-        /* frame is completed: push contents of adapter */
-        guint avail;
+    GST_MEMDUMP ("codec_data", GST_BUFFER_DATA (codec_data),
+        GST_BUFFER_SIZE (codec_data));
 
-        avail = gst_adapter_available (rtpsv3vdepay->adapter);
-        outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail);
+    caps = gst_caps_new_simple ("video/x-svq",
+        "svqversion", G_TYPE_INT, 3,
+        "width", G_TYPE_INT, rtpsv3vdepay->width,
+        "height", G_TYPE_INT, rtpsv3vdepay->height,
+        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+    gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps);
+    gst_caps_unref (caps);
 
-        return outbuf;
-      }
+    GST_DEBUG ("Depayloader now configured");
+
+    rtpsv3vdepay->configured = TRUE;
+
+    goto beach;
+  }
+
+  if (G_LIKELY (rtpsv3vdepay->configured)) {
+    GstBuffer *tmpbuf;
+
+    GST_DEBUG ("Storing incoming payload");
+    /* store data in adapter, stip off 2 bytes header */
+    tmpbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1);
+    gst_adapter_push (rtpsv3vdepay->adapter, tmpbuf);
+
+    if (G_UNLIKELY (M)) {
+      /* frame is completed: push contents of adapter */
+      guint avail;
+
+      avail = gst_adapter_available (rtpsv3vdepay->adapter);
+      GST_DEBUG ("Returning completed output buffer [%d bytes]", avail);
+      outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail);
     }
   }
-  return NULL;
+
+beach:
+  return outbuf;
 
   /* ERRORS */
 bad_packet: