g726depay: implement RFC3551 packing
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 15 Apr 2009 11:56:17 +0000 (13:56 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 15 Apr 2009 11:56:17 +0000 (13:56 +0200)
We implemented the AAL2 packing, add the encoding-name for those to the caps and
a property to force AAL2 decoding (always TRUE for now).
Implement RFC3551 unpacking for regular G726.
See #567140.

gst/rtp/gstrtpg726depay.c
gst/rtp/gstrtpg726depay.h

index 1420a11..45bec1c 100644 (file)
@@ -49,9 +49,13 @@ enum
   LAST_SIGNAL
 };
 
+#define DEFAULT_FORCE_AAL2     TRUE
+
 enum
 {
-  ARG_0
+  PROP_0,
+  PROP_FORCE_AAL2,
+  PROP_LAST
 };
 
 static GstStaticPadTemplate gst_rtp_g726_depay_sink_template =
@@ -61,7 +65,8 @@ static GstStaticPadTemplate gst_rtp_g726_depay_sink_template =
     GST_STATIC_CAPS ("application/x-rtp, "
         "media = (string) \"audio\", "
         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
-        "encoding-name = (string) { \"G726\", \"G726-16\", \"G726-24\", \"G726-32\", \"G726-40\"}, "
+        "encoding-name = (string) { \"G726\", \"G726-16\", \"G726-24\", \"G726-32\", \"G726-40\", "
+        "\"AAL2-G726-16\", \"AAL2-G726-24\", \"AAL2-G726-32\", \"AAL2-G726-40\" }, "
         "clock-rate = (int) 8000;")
     );
 
@@ -122,6 +127,8 @@ gst_rtp_g726_depay_init (GstRtpG726Depay * rtpG726depay,
   depayload = GST_BASE_RTP_DEPAYLOAD (rtpG726depay);
 
   gst_pad_use_fixed_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload));
+
+  rtpG726depay->force_aal2 = DEFAULT_FORCE_AAL2;
 }
 
 static gboolean
@@ -132,7 +139,9 @@ gst_rtp_g726_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
   gboolean ret;
   gint clock_rate;
   const gchar *encoding_name;
-  gint bitrate;
+  GstRtpG726Depay *depay;
+
+  depay = GST_RTP_G726_DEPAY (depayload);
 
   structure = gst_caps_get_structure (caps, 0);
 
@@ -140,52 +149,173 @@ gst_rtp_g726_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
     clock_rate = 8000;          /* default */
   depayload->clock_rate = clock_rate;
 
+  depay->aal2 = FALSE;
   encoding_name = gst_structure_get_string (structure, "encoding-name");
   if (encoding_name == NULL || g_ascii_strcasecmp (encoding_name, "G726") == 0) {
-    bitrate = DEFAULT_BIT_RATE;
-  } else if (g_ascii_strcasecmp (encoding_name, "G726-16") == 0) {
-    bitrate = 16000;
-  } else if (g_ascii_strcasecmp (encoding_name, "G726-24") == 0) {
-    bitrate = 24000;
-  } else if (g_ascii_strcasecmp (encoding_name, "G726-32") == 0) {
-    bitrate = 32000;
-  } else if (g_ascii_strcasecmp (encoding_name, "G726-40") == 0) {
-    bitrate = 40000;
+    depay->bitrate = DEFAULT_BIT_RATE;
   } else {
-    GST_WARNING ("Could not determine bitrate from encoding-name (%s)",
-        encoding_name);
-    ret = FALSE;
-    goto done;
+    if (g_str_has_prefix (encoding_name, "AAL2-")) {
+      depay->aal2 = TRUE;
+      encoding_name += 5;
+    }
+    if (g_ascii_strcasecmp (encoding_name, "G726-16") == 0) {
+      depay->bitrate = 16000;
+    } else if (g_ascii_strcasecmp (encoding_name, "G726-24") == 0) {
+      depay->bitrate = 24000;
+    } else if (g_ascii_strcasecmp (encoding_name, "G726-32") == 0) {
+      depay->bitrate = 32000;
+    } else if (g_ascii_strcasecmp (encoding_name, "G726-40") == 0) {
+      depay->bitrate = 40000;
+    } else
+      goto unknown_encoding;
   }
-  GST_DEBUG ("RTP G.726 depayloader, bitrate set to %d\n", bitrate);
+
+  GST_DEBUG ("RTP G.726 depayloader, bitrate set to %d\n", depay->bitrate);
 
   srccaps = gst_caps_new_simple ("audio/x-adpcm",
       "channels", G_TYPE_INT, 1,
       "rate", G_TYPE_INT, clock_rate,
-      "bitrate", G_TYPE_INT, bitrate,
+      "bitrate", G_TYPE_INT, depay->bitrate,
       "layout", G_TYPE_STRING, LAYOUT_G726, NULL);
 
   ret = gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps);
   gst_caps_unref (srccaps);
 
-done:
   return ret;
+
+  /* ERRORS */
+unknown_encoding:
+  {
+    GST_WARNING ("Could not determine bitrate from encoding-name (%s)",
+        encoding_name);
+    return FALSE;
+  }
 }
 
 
 static GstBuffer *
 gst_rtp_g726_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 {
+  GstRtpG726Depay *depay;
   GstBuffer *outbuf = NULL;
   gboolean marker;
 
+  depay = GST_RTP_G726_DEPAY (depayload);
+
   marker = gst_rtp_buffer_get_marker (buf);
 
   GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d",
       GST_BUFFER_SIZE (buf), marker,
       gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf));
 
-  outbuf = gst_rtp_buffer_get_payload_buffer (buf);
+  if (depay->aal2 || depay->force_aal2) {
+    /* AAL2, we can just copy the bytes */
+    outbuf = gst_rtp_buffer_get_payload_buffer (buf);
+  } else {
+    guint8 *in, *out, tmp;
+    guint len;
+
+    in = gst_rtp_buffer_get_payload (buf);
+    len = gst_rtp_buffer_get_payload_len (buf);
+
+    if (gst_buffer_is_writable (buf)) {
+      outbuf = gst_rtp_buffer_get_payload_buffer (buf);
+    } else {
+      GstBuffer *copy;
+
+      /* copy buffer */
+      copy = gst_buffer_copy (buf);
+      outbuf = gst_rtp_buffer_get_payload_buffer (copy);
+      gst_buffer_unref (copy);
+    }
+    out = GST_BUFFER_DATA (outbuf);
+
+    /* we need to reshuffle the bytes */
+    switch (depay->bitrate) {
+      case 16000:
+      {
+        /*  0               
+         *  0 1 2 3 4 5 6 7 
+         * +-+-+-+-+-+-+-+-+-
+         * |D D|C C|B B|A A| ...
+         * |0 1|0 1|0 1|0 1|
+         * +-+-+-+-+-+-+-+-+-
+         */
+        while (len > 0) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x30) >> 2) | ((tmp & 0x0c) << 2) | ((tmp & 0x03) << 6);
+          len--;
+        }
+        break;
+      }
+      case 24000:
+      {
+        /*  0                   1                   2
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |C C|B B B|A A A|F|E E E|D D D|C|H H H|G G G|F F| ...
+         * |1 2|0 1 2|0 1 2|2|0 1 2|0 1 2|0|0 1 2|0 1 2|0 1|
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (len > 2) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xe0) >> 5) |
+              ((tmp & 0x1c) << 1) | ((tmp & 0x03) << 6);
+          tmp = *in++;
+          *out++ = ((tmp & 0x80) >> 7) |
+              ((tmp & 0x70) >> 3) | ((tmp & 0x0e) << 4) | ((tmp & 0x01) << 7);
+          tmp = *in++;
+          *out++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x38) >> 1) | ((tmp & 0x07) << 5);
+          len -= 3;
+        }
+        break;
+      }
+      case 32000:
+      {
+        /*  0                   1
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |B B B B|A A A A|D D D D|C C C C| ...
+         * |0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3|
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (len > 0) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+          len--;
+        }
+        break;
+      }
+      case 40000:
+      {
+        /*  0                   1                   2                   3                   4
+         *  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 2 3 4 5 6 7 8 9 0
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         * |B B B|A A A A A|D|C C C C C|B B|E E E E|D D D D|G G|F F F F F|E|H H H H H|G G G|
+         * |2 3 4|0 1 2 3 4|4|0 1 2 3 4|0 1|1 2 3 4|0 1 2 3|3 4|0 1 2 3 4|0|0 1 2 3 4|0 1 2|   
+         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+         */
+        while (len > 4) {
+          tmp = *in++;
+          *out++ = ((tmp & 0xf8) >> 3) | ((tmp & 0x07) << 5);
+          tmp = *in++;
+          *out++ = ((tmp & 0xc0) >> 6) |
+              ((tmp & 0x3e) << 1) | ((tmp & 0x01) << 7);
+          tmp = *in++;
+          *out++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+          tmp = *in++;
+          *out++ = ((tmp & 0x80) >> 7) |
+              ((tmp & 0x7c) >> 1) | ((tmp & 0x03) << 6);
+          tmp = *in++;
+          *out++ = ((tmp & 0xe0) >> 5) | ((tmp & 0x1f) << 3);
+          len -= 5;
+        }
+        break;
+      }
+    }
+  }
 
   if (marker) {
     /* mark start of talkspurt with discont */
index e62252c..992644e 100644 (file)
@@ -38,6 +38,10 @@ typedef struct _GstRtpG726DepayClass GstRtpG726DepayClass;
 struct _GstRtpG726Depay
 {
   GstBaseRTPDepayload depayload;
+
+  gboolean aal2;
+  gboolean force_aal2;
+  gint bitrate;
 };
 
 struct _GstRtpG726DepayClass