gst/rtp/: Add support for AMR-WB.

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.
This commit is contained in:
Daniel Charles 2007-06-01 11:16:17 +00:00 committed by Wim Taymans
parent 0b2e6f1c90
commit 89ae9b40f9
5 changed files with 168 additions and 54 deletions

View file

@ -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> 2007-05-31 Wim Taymans <wim@fluendo.com>
* gst/rtsp/rtspextwms.c: (rtsp_ext_wms_configure_stream): * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_configure_stream):

View file

@ -38,7 +38,7 @@
static const GstElementDetails gst_rtp_amrdepay_details = static const GstElementDetails gst_rtp_amrdepay_details =
GST_ELEMENT_DETAILS ("RTP packet depayloader", GST_ELEMENT_DETAILS ("RTP packet depayloader",
"Codec/Depayloader/Network", "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>"); "Wim Taymans <wim@fluendo.com>");
/* RtpAMRDepay signals and args */ /* RtpAMRDepay signals and args */
@ -71,6 +71,25 @@ GST_STATIC_PAD_TEMPLATE ("sink",
* GstCaps mapping. */ * GstCaps mapping. */
"octet-align = (string) \"1\", " "octet-align = (string) \"1\", "
"crc = (string) { \"0\", \"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\"" "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder /* following options are not needed for a decoder
* *
@ -87,7 +106,8 @@ static GstStaticPadTemplate gst_rtp_amr_depay_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, 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, static gboolean gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload,
@ -146,13 +166,28 @@ gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
GstCaps *srccaps; GstCaps *srccaps;
GstRtpAMRDepay *rtpamrdepay; GstRtpAMRDepay *rtpamrdepay;
const gchar *params; const gchar *params;
const gchar *str; const gchar *str, *type;
gint clock_rate = 8000; /* default */ gint clock_rate, need_clock_rate;
rtpamrdepay = GST_RTP_AMR_DEPAY (depayload); rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
structure = gst_caps_get_structure (caps, 0); 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"))) if (!(str = gst_structure_get_string (structure, "octet-align")))
rtpamrdepay->octet_align = FALSE; rtpamrdepay->octet_align = FALSE;
else else
@ -201,7 +236,7 @@ gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
* no robust sorting, no interleaving for now */ * no robust sorting, no interleaving for now */
if (rtpamrdepay->channels != 1) if (rtpamrdepay->channels != 1)
return FALSE; return FALSE;
if (clock_rate != 8000) if (clock_rate != need_clock_rate)
return FALSE; return FALSE;
if (rtpamrdepay->octet_align != TRUE) if (rtpamrdepay->octet_align != TRUE)
return FALSE; return FALSE;
@ -210,22 +245,34 @@ gst_rtp_amr_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
if (rtpamrdepay->interleaving != FALSE) if (rtpamrdepay->interleaving != FALSE)
return FALSE; return FALSE;
srccaps = gst_caps_new_simple ("audio/AMR", srccaps = gst_caps_new_simple (type,
"channels", G_TYPE_INT, rtpamrdepay->channels, "channels", G_TYPE_INT, rtpamrdepay->channels,
"rate", G_TYPE_INT, clock_rate, NULL); "rate", G_TYPE_INT, clock_rate, NULL);
gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps);
gst_caps_unref (srccaps); gst_caps_unref (srccaps);
rtpamrdepay->negotiated = TRUE; rtpamrdepay->negotiated = TRUE;
return TRUE; return TRUE;
/* ERRORS */
invalid_mode:
{
GST_ERROR_OBJECT (rtpamrdepay, "invalid encoding-name");
return FALSE;
}
} }
/* -1 is invalid */ /* -1 is invalid */
static gint frame_size[16] = { static gint nb_frame_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31, 12, 13, 15, 17, 19, 20, 26, 31,
5, -1, -1, -1, -1, -1, -1, 0 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 * static GstBuffer *
gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
@ -233,6 +280,7 @@ gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
GstRtpAMRDepay *rtpamrdepay; GstRtpAMRDepay *rtpamrdepay;
GstBuffer *outbuf = NULL; GstBuffer *outbuf = NULL;
gint payload_len; gint payload_len;
gint *frame_size;
rtpamrdepay = GST_RTP_AMR_DEPAY (depayload); 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)) if (!gst_rtp_buffer_validate (buf))
goto invalid_packet; 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 */ * no robust sorting, no interleaving data is to be depayloaded */
{ {
guint8 *payload, *p, *dp; guint8 *payload, *p, *dp;

View file

@ -39,11 +39,18 @@ G_BEGIN_DECLS
typedef struct _GstRtpAMRDepay GstRtpAMRDepay; typedef struct _GstRtpAMRDepay GstRtpAMRDepay;
typedef struct _GstRtpAMRDepayClass GstRtpAMRDepayClass; 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 struct _GstRtpAMRDepay
{ {
GstBaseRTPDepayload depayload; GstBaseRTPDepayload depayload;
gboolean negotiated; gboolean negotiated;
GstRtpAMRDepayMode mode;
gboolean octet_align; gboolean octet_align;
guint8 mode_set; guint8 mode_set;

View file

@ -35,20 +35,27 @@ GST_DEBUG_CATEGORY_STATIC (rtpamrpay_debug);
* RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
* Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive * Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive
* Multi-Rate Wideband (AMR-WB) Audio Codecs. * 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 */ /* elementfactory information */
static const GstElementDetails gst_rtp_amrpay_details = static const GstElementDetails gst_rtp_amrpay_details =
GST_ELEMENT_DETAILS ("RTP packet payloader", GST_ELEMENT_DETAILS ("RTP packet payloader",
"Codec/Payloader/Network", "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>"); "Wim Taymans <wim@fluendo.com>");
static GstStaticPadTemplate gst_rtp_amr_pay_sink_template = static GstStaticPadTemplate gst_rtp_amr_pay_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, 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 = static GstStaticPadTemplate gst_rtp_amr_pay_src_template =
@ -57,7 +64,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp, " GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"audio\", " "media = (string) \"audio\", "
"payload = (int) [ 96, 127 ], " "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
"clock-rate = (int) 8000, " "clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", " "encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", " "encoding-params = (string) \"1\", "
@ -68,47 +75,33 @@ GST_STATIC_PAD_TEMPLATE ("src",
"mode-set = (int) [ 0, 7 ], " "mode-set = (int) [ 0, 7 ], "
"mode-change-period = (int) [ 1, MAX ], " "mode-change-period = (int) [ 1, MAX ], "
"mode-change-neighbor = (string) { \"0\", \"1\" }, " "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 ]") "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, static gboolean gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload,
GstCaps * caps); GstCaps * caps);
static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * pad, static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * pad,
GstBuffer * buffer); GstBuffer * buffer);
static GstBaseRTPPayloadClass *parent_class = NULL; GST_BOILERPLATE (GstRtpAMRPay, gst_rtp_amr_pay, GstBaseRTPPayload,
GST_TYPE_BASE_RTP_PAYLOAD);
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;
}
static void 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); 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; gstbasertppayload_class->handle_buffer = gst_rtp_amr_pay_handle_buffer;
GST_DEBUG_CATEGORY_INIT (rtpamrpay_debug, "rtpamrpay", 0, GST_DEBUG_CATEGORY_INIT (rtpamrpay_debug, "rtpamrpay", 0,
"AMR RTP Payloader"); "AMR/AMR-WB RTP Payloader");
} }
static void 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) gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
{ {
GstRtpAMRPay *rtpamrpay; GstRtpAMRPay *rtpamrpay;
const GstStructure *s;
const gchar *str;
rtpamrpay = GST_RTP_AMR_PAY (basepayload); rtpamrpay = GST_RTP_AMR_PAY (basepayload);
/* 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); 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, gst_basertppayload_set_outcaps (basepayload,
"encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1", "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
/* don't set the defaults /* don't set the defaults
@ -165,13 +176,25 @@ gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
NULL); NULL);
return TRUE; return TRUE;
/* ERRORS */
wrong_type:
{
GST_ERROR_OBJECT (rtpamrpay, "unsupported media type '%s'",
GST_STR_NULL (str));
return FALSE;
}
} }
/* -1 is invalid */ /* -1 is invalid */
static gint frame_size[16] = { static gint nb_frame_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31, 12, 13, 15, 17, 19, 20, 26, 31,
5, -1, -1, -1, -1, -1, -1, 0 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 static GstFlowReturn
gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload, gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
@ -186,6 +209,7 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
guint packet_len, mtu; guint packet_len, mtu;
gint i, num_packets, num_nonempty_packets; gint i, num_packets, num_nonempty_packets;
gint amr_len; gint amr_len;
gint *frame_size;
rtpamrpay = GST_RTP_AMR_PAY (basepayload); rtpamrpay = GST_RTP_AMR_PAY (basepayload);
mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpamrpay); mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpamrpay);
@ -194,12 +218,19 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
data = GST_BUFFER_DATA (buffer); data = GST_BUFFER_DATA (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer);
/* FIXME, only /* setup frame size pointer */
* octet aligned, no interleaving, single channel, no CRC, if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
* no robust-sorting. */ frame_size = nb_frame_size;
else
frame_size = wb_frame_size;
GST_DEBUG_OBJECT (basepayload, "got %d bytes", 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 */ /* first count number of packets and total amr frame size */
amr_len = num_packets = num_nonempty_packets = 0; amr_len = num_packets = num_nonempty_packets = 0;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {

View file

@ -40,9 +40,17 @@ G_BEGIN_DECLS
typedef struct _GstRtpAMRPay GstRtpAMRPay; typedef struct _GstRtpAMRPay GstRtpAMRPay;
typedef struct _GstRtpAMRPayClass GstRtpAMRPayClass; 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 struct _GstRtpAMRPay
{ {
GstBaseRTPPayload payload; GstBaseRTPPayload payload;
GstRtpAMRPayMode mode;
}; };
struct _GstRtpAMRPayClass struct _GstRtpAMRPayClass