gst/rtp/: Add support for AMR-WB.
authorDaniel Charles <dcharles@ti.com>
Fri, 1 Jun 2007 11:16:17 +0000 (11:16 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 1 Jun 2007 11:16:17 +0000 (11:16 +0000)
Original commit message from CVS:
Based on Patch by: Daniel Charles <dcharles at ti dot com>
* gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_setcaps),
(gst_rtp_amr_depay_process):
* gst/rtp/gstrtpamrdepay.h:
* gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_base_init),
(gst_rtp_amr_pay_class_init), (gst_rtp_amr_pay_init),
(gst_rtp_amr_pay_setcaps), (gst_rtp_amr_pay_handle_buffer):
* gst/rtp/gstrtpamrpay.h:
Add support for AMR-WB.
Small cleanups such as using BOILERPLATE.

ChangeLog
gst/rtp/gstrtpamrdepay.c
gst/rtp/gstrtpamrdepay.h
gst/rtp/gstrtpamrpay.c
gst/rtp/gstrtpamrpay.h

index 6a6116e..00ed607 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2007-06-01  Wim Taymans  <wim@fluendo.com>
+
+       Based on Patch by: Daniel Charles <dcharles at ti dot com>
+
+       * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_setcaps),
+       (gst_rtp_amr_depay_process):
+       * gst/rtp/gstrtpamrdepay.h:
+       * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_base_init),
+       (gst_rtp_amr_pay_class_init), (gst_rtp_amr_pay_init),
+       (gst_rtp_amr_pay_setcaps), (gst_rtp_amr_pay_handle_buffer):
+       * gst/rtp/gstrtpamrpay.h:
+       Add support for AMR-WB.
+       Small cleanups such as using BOILERPLATE.
+
 2007-05-31  Wim Taymans  <wim@fluendo.com>
 
        * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_configure_stream):
index 74800a2..6daad65 100644 (file)
@@ -38,7 +38,7 @@
 static const GstElementDetails gst_rtp_amrdepay_details =
 GST_ELEMENT_DETAILS ("RTP packet depayloader",
     "Codec/Depayloader/Network",
-    "Extracts AMR audio from RTP packets (RFC 3267)",
+    "Extracts AMR or AMR-WB audio from RTP packets (RFC 3267)",
     "Wim Taymans <wim@fluendo.com>");
 
 /* RtpAMRDepay signals and args */
@@ -58,7 +58,7 @@ enum
  * params see RFC 3267, section 8.1
  */
 static GstStaticPadTemplate gst_rtp_amr_depay_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("application/x-rtp, "
@@ -71,6 +71,25 @@ GST_STATIC_PAD_TEMPLATE ("sink",
          * GstCaps mapping. */
         "octet-align = (string) \"1\", "
         "crc = (string) { \"0\", \"1\" }, "
+        "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\";"
+        /* following options are not needed for a decoder
+         *
+         "mode-set = (int) [ 0, 7 ], "
+         "mode-change-period = (int) [ 1, MAX ], "
+         "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+         "maxptime = (int) [ 20, MAX ], "
+         "ptime = (int) [ 20, MAX ]"
+         */
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 16000, "
+        "encoding-name = (string) \"AMR-WB\", "
+        "encoding-params = (string) \"1\", "
+        /* NOTE that all values must be strings in orde to be able to do SDP <->
+         * GstCaps mapping. */
+        "octet-align = (string) \"1\", "
+        "crc = (string) { \"0\", \"1\" }, "
         "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
         /* following options are not needed for a decoder
          *
@@ -84,10 +103,11 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     );
 
 static GstStaticPadTemplate gst_rtp_amr_depay_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
+    GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000")
+    GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000;"
+        "audio/AMR-WB, " "channels = (int) 1," "rate = (int) 16000")
     );
 
 static gboolean gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload,
@@ -146,13 +166,28 @@ gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
   GstCaps *srccaps;
   GstRtpAMRDepay *rtpamrdepay;
   const gchar *params;
-  const gchar *str;
-  gint clock_rate = 8000;       /* default */
+  const gchar *str, *type;
+  gint clock_rate, need_clock_rate;
 
   rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
 
   structure = gst_caps_get_structure (caps, 0);
 
+  /* figure out the mode first and set the clock rates */
+  if ((str = gst_structure_get_string (structure, "encoding-name"))) {
+    if (strcmp (str, "AMR") == 0) {
+      rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_NB;
+      clock_rate = need_clock_rate = 8000;
+      type = "audio/AMR";
+    } else if (strcmp (str, "AMR-WB") == 0) {
+      rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_WB;
+      clock_rate = need_clock_rate = 16000;
+      type = "audio/AMR-WB";
+    } else
+      goto invalid_mode;
+  } else
+    goto invalid_mode;
+
   if (!(str = gst_structure_get_string (structure, "octet-align")))
     rtpamrdepay->octet_align = FALSE;
   else
@@ -201,7 +236,7 @@ gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
    * no robust sorting, no interleaving for now */
   if (rtpamrdepay->channels != 1)
     return FALSE;
-  if (clock_rate != 8000)
+  if (clock_rate != need_clock_rate)
     return FALSE;
   if (rtpamrdepay->octet_align != TRUE)
     return FALSE;
@@ -210,22 +245,34 @@ gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
   if (rtpamrdepay->interleaving != FALSE)
     return FALSE;
 
-  srccaps = gst_caps_new_simple ("audio/AMR",
+  srccaps = gst_caps_new_simple (type,
       "channels", G_TYPE_INT, rtpamrdepay->channels,
       "rate", G_TYPE_INT, clock_rate, NULL);
+
   gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps);
   gst_caps_unref (srccaps);
 
   rtpamrdepay->negotiated = TRUE;
 
   return TRUE;
+
+  /* ERRORS */
+invalid_mode:
+  {
+    GST_ERROR_OBJECT (rtpamrdepay, "invalid encoding-name");
+    return FALSE;
+  }
 }
 
 /* -1 is invalid */
-static gint frame_size[16] = {
+static gint nb_frame_size[16] = {
   12, 13, 15, 17, 19, 20, 26, 31,
   5, -1, -1, -1, -1, -1, -1, 0
 };
+static gint wb_frame_size[16] = {
+  17, 23, 32, 36, 40, 46, 50, 58,
+  60, -1, -1, -1, -1, -1, -1, 0
+};
 
 static GstBuffer *
 gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
@@ -233,6 +280,7 @@ gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   GstRtpAMRDepay *rtpamrdepay;
   GstBuffer *outbuf = NULL;
   gint payload_len;
+  gint *frame_size;
 
   rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
 
@@ -242,7 +290,13 @@ gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
   if (!gst_rtp_buffer_validate (buf))
     goto invalid_packet;
 
-  /* when we get here, 1 channel, 8000 Hz, octet aligned, no CRC, 
+  /* setup frame size pointer */
+  if (rtpamrdepay->mode == GST_RTP_AMR_DP_MODE_NB)
+    frame_size = nb_frame_size;
+  else
+    frame_size = wb_frame_size;
+
+  /* when we get here, 1 channel, 8000/16000 Hz, octet aligned, no CRC, 
    * no robust sorting, no interleaving data is to be depayloaded */
   {
     guint8 *payload, *p, *dp;
index 9b9424f..022c8cb 100644 (file)
@@ -39,11 +39,18 @@ G_BEGIN_DECLS
 typedef struct _GstRtpAMRDepay GstRtpAMRDepay;
 typedef struct _GstRtpAMRDepayClass GstRtpAMRDepayClass;
 
+typedef enum {
+  GST_RTP_AMR_DP_MODE_INVALID = 0,
+  GST_RTP_AMR_DP_MODE_NB      = 1,
+  GST_RTP_AMR_DP_MODE_WB      = 2
+} GstRtpAMRDepayMode;
+
 struct _GstRtpAMRDepay
 {
   GstBaseRTPDepayload depayload;
 
   gboolean negotiated;
+  GstRtpAMRDepayMode mode;
 
   gboolean octet_align;
   guint8   mode_set;
index 9fac30b..e32b11f 100644 (file)
@@ -35,29 +35,36 @@ GST_DEBUG_CATEGORY_STATIC (rtpamrpay_debug);
  * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File 
  *    Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive 
  *    Multi-Rate Wideband (AMR-WB) Audio Codecs.
+ *    
+ * ETSI TS 126 201 V6.0.0 (2004-12) - Digital cellular telecommunications system (Phase 2+);
+ *                 Universal Mobile Telecommunications System (UMTS);
+ *                          AMR speech codec, wideband;
+ *                                 Frame structure
+ *                    (3GPP TS 26.201 version 6.0.0 Release 6)
  */
 
 /* elementfactory information */
 static const GstElementDetails gst_rtp_amrpay_details =
 GST_ELEMENT_DETAILS ("RTP packet payloader",
     "Codec/Payloader/Network",
-    "Payload-encode AMR audio into RTP packets (RFC 3267)",
+    "Payload-encode AMR or AMR-WB audio into RTP packets (RFC 3267)",
     "Wim Taymans <wim@fluendo.com>");
 
 static GstStaticPadTemplate gst_rtp_amr_pay_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000")
+    GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000; "
+        "audio/AMR-WB, channels=(int)1, rate=(int)16000")
     );
 
 static GstStaticPadTemplate gst_rtp_amr_pay_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
+    GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("application/x-rtp, "
         "media = (string) \"audio\", "
-        "payload = (int) [ 96, 127 ], "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
         "clock-rate = (int) 8000, "
         "encoding-name = (string) \"AMR\", "
         "encoding-params = (string) \"1\", "
@@ -68,47 +75,33 @@ GST_STATIC_PAD_TEMPLATE ("src",
         "mode-set = (int) [ 0, 7 ], "
         "mode-change-period = (int) [ 1, MAX ], "
         "mode-change-neighbor = (string) { \"0\", \"1\" }, "
+        "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ];"
+        "application/x-rtp, "
+        "media = (string) \"audio\", "
+        "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+        "clock-rate = (int) 16000, "
+        "encoding-name = (string) \"AMR-WB\", "
+        "encoding-params = (string) \"1\", "
+        "octet-align = (string) \"1\", "
+        "crc = (string) \"0\", "
+        "robust-sorting = (string) \"0\", "
+        "interleaving = (string) \"0\", "
+        "mode-set = (int) [ 0, 7 ], "
+        "mode-change-period = (int) [ 1, MAX ], "
+        "mode-change-neighbor = (string) { \"0\", \"1\" }, "
         "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
     );
 
-static void gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass);
-static void gst_rtp_amr_pay_base_init (GstRtpAMRPayClass * klass);
-static void gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay);
-
 static gboolean gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload,
     GstCaps * caps);
 static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * pad,
     GstBuffer * buffer);
 
-static GstBaseRTPPayloadClass *parent_class = NULL;
-
-static GType
-gst_rtp_amr_pay_get_type (void)
-{
-  static GType rtpamrpay_type = 0;
-
-  if (!rtpamrpay_type) {
-    static const GTypeInfo rtpamrpay_info = {
-      sizeof (GstRtpAMRPayClass),
-      (GBaseInitFunc) gst_rtp_amr_pay_base_init,
-      NULL,
-      (GClassInitFunc) gst_rtp_amr_pay_class_init,
-      NULL,
-      NULL,
-      sizeof (GstRtpAMRPay),
-      0,
-      (GInstanceInitFunc) gst_rtp_amr_pay_init,
-    };
-
-    rtpamrpay_type =
-        g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpAMRPay",
-        &rtpamrpay_info, 0);
-  }
-  return rtpamrpay_type;
-}
+GST_BOILERPLATE (GstRtpAMRPay, gst_rtp_amr_pay, GstBaseRTPPayload,
+    GST_TYPE_BASE_RTP_PAYLOAD);
 
 static void
-gst_rtp_amr_pay_base_init (GstRtpAMRPayClass * klass)
+gst_rtp_amr_pay_base_init (gpointer klass)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
@@ -137,12 +130,11 @@ gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass)
   gstbasertppayload_class->handle_buffer = gst_rtp_amr_pay_handle_buffer;
 
   GST_DEBUG_CATEGORY_INIT (rtpamrpay_debug, "rtpamrpay", 0,
-      "AMR RTP Payloader");
-
+      "AMR/AMR-WB RTP Payloader");
 }
 
 static void
-gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay)
+gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay, GstRtpAMRPayClass * klass)
 {
 }
 
@@ -150,10 +142,29 @@ static gboolean
 gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
 {
   GstRtpAMRPay *rtpamrpay;
+  const GstStructure *s;
+  const gchar *str;
 
   rtpamrpay = GST_RTP_AMR_PAY (basepayload);
 
-  gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
+  /* figure out the mode Narrow or Wideband */
+  s = gst_caps_get_structure (caps, 0);
+  if ((str = gst_structure_get_name (s))) {
+    if (strcmp (str, "audio/AMR") == 0)
+      rtpamrpay->mode = GST_RTP_AMR_P_MODE_NB;
+    else if (strcmp (str, "audio/AMR-WB") == 0)
+      rtpamrpay->mode = GST_RTP_AMR_P_MODE_WB;
+    else
+      goto wrong_type;
+  } else
+    goto wrong_type;
+
+  if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
+    gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
+  else
+    gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR-WB",
+        16000);
+
   gst_basertppayload_set_outcaps (basepayload,
       "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
       /* don't set the defaults 
@@ -165,13 +176,25 @@ gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
       NULL);
 
   return TRUE;
+
+  /* ERRORS */
+wrong_type:
+  {
+    GST_ERROR_OBJECT (rtpamrpay, "unsupported media type '%s'",
+        GST_STR_NULL (str));
+    return FALSE;
+  }
 }
 
 /* -1 is invalid */
-static gint frame_size[16] = {
+static gint nb_frame_size[16] = {
   12, 13, 15, 17, 19, 20, 26, 31,
   5, -1, -1, -1, -1, -1, -1, 0
 };
+static gint wb_frame_size[16] = {
+  17, 23, 32, 36, 40, 46, 50, 58,
+  60, -1, -1, -1, -1, -1, -1, 0
+};
 
 static GstFlowReturn
 gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
@@ -186,6 +209,7 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
   guint packet_len, mtu;
   gint i, num_packets, num_nonempty_packets;
   gint amr_len;
+  gint *frame_size;
 
   rtpamrpay = GST_RTP_AMR_PAY (basepayload);
   mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpamrpay);
@@ -194,12 +218,19 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
   data = GST_BUFFER_DATA (buffer);
   timestamp = GST_BUFFER_TIMESTAMP (buffer);
 
-  /* FIXME, only 
-   * octet aligned, no interleaving, single channel, no CRC,
-   * no robust-sorting. */
+  /* setup frame size pointer */
+  if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
+    frame_size = nb_frame_size;
+  else
+    frame_size = wb_frame_size;
 
   GST_DEBUG_OBJECT (basepayload, "got %d bytes", size);
 
+  /* FIXME, only 
+   * octet aligned, no interleaving, single channel, no CRC,
+   * no robust-sorting. To fix this you need to implement the downstream
+   * negotiation function. */
+
   /* first count number of packets and total amr frame size */
   amr_len = num_packets = num_nonempty_packets = 0;
   for (i = 0; i < size; i++) {
index bd924d6..5e32ddb 100644 (file)
@@ -40,9 +40,17 @@ G_BEGIN_DECLS
 typedef struct _GstRtpAMRPay GstRtpAMRPay;
 typedef struct _GstRtpAMRPayClass GstRtpAMRPayClass;
 
+typedef enum {
+  GST_RTP_AMR_P_MODE_INVALID = 0,
+  GST_RTP_AMR_P_MODE_NB      = 1,
+  GST_RTP_AMR_P_MODE_WB      = 2
+} GstRtpAMRPayMode;
+
 struct _GstRtpAMRPay
 {
   GstBaseRTPPayload payload;
+
+  GstRtpAMRPayMode mode;
 };
 
 struct _GstRtpAMRPayClass