diff --git a/ChangeLog b/ChangeLog index 6a6116e2b8..00ed607b93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2007-06-01 Wim Taymans + + Based on Patch by: Daniel Charles + + * 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 * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_configure_stream): diff --git a/gst/rtp/gstrtpamrdepay.c b/gst/rtp/gstrtpamrdepay.c index 74800a2d28..6daad65920 100644 --- a/gst/rtp/gstrtpamrdepay.c +++ b/gst/rtp/gstrtpamrdepay.c @@ -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 "); /* 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; diff --git a/gst/rtp/gstrtpamrdepay.h b/gst/rtp/gstrtpamrdepay.h index 9b9424f5f4..022c8cb20c 100644 --- a/gst/rtp/gstrtpamrdepay.h +++ b/gst/rtp/gstrtpamrdepay.h @@ -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; diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c index 9fac30bd66..e32b11f3f4 100644 --- a/gst/rtp/gstrtpamrpay.c +++ b/gst/rtp/gstrtpamrpay.c @@ -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 "); 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++) { diff --git a/gst/rtp/gstrtpamrpay.h b/gst/rtp/gstrtpamrpay.h index bd924d62d9..5e32ddbcd9 100644 --- a/gst/rtp/gstrtpamrpay.h +++ b/gst/rtp/gstrtpamrpay.h @@ -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