ext/amrnb/: Update caps with audio/AMR.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 19 Aug 2005 12:44:35 +0000 (12:44 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 19 Aug 2005 12:44:35 +0000 (12:44 +0000)
Original commit message from CVS:
* ext/amrnb/amrnbdec.c:
* ext/amrnb/amrnbenc.c: (gst_amrnbenc_setcaps):
* ext/amrnb/amrnbparse.c:
Update caps with audio/AMR.

* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
(gst_rtpamrdec_sink_setcaps), (gst_rtpamrdec_chain),
(gst_rtpamrdec_change_state):
* gst/rtp/gstrtpamrdec.h:
* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_class_init),
(gst_rtpamrenc_init), (gst_rtpamrenc_chain):
Dont set FT headers twice, it was already in the encoded
bitstream.

* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open),
(gst_rtspsrc_close), (gst_rtspsrc_play):
* gst/rtsp/rtspconnection.c: (parse_line):
Cleanups

* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
(gst_udpsrc_create), (gst_udpsrc_set_property),
(gst_udpsrc_get_property):
* gst/udp/gstudpsrc.h:
Added caps property, we need this soon to type the buffers.

ChangeLog
gst/rtp/gstrtpamrdec.c
gst/rtp/gstrtpamrdec.h
gst/rtp/gstrtpamrdepay.c
gst/rtp/gstrtpamrdepay.h
gst/rtp/gstrtpamrenc.c
gst/rtp/gstrtpamrpay.c
gst/rtsp/gstrtspsrc.c
gst/rtsp/rtspconnection.c
gst/udp/gstudpsrc.c
gst/udp/gstudpsrc.h

index 96edad2..296fc02 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2005-08-19  Wim Taymans  <wim@fluendo.com>
+
+       * ext/amrnb/amrnbdec.c:
+       * ext/amrnb/amrnbenc.c: (gst_amrnbenc_setcaps):
+       * ext/amrnb/amrnbparse.c:
+       Update caps with audio/AMR.
+       
+       * gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
+       (gst_rtpamrdec_sink_setcaps), (gst_rtpamrdec_chain),
+       (gst_rtpamrdec_change_state):
+       * gst/rtp/gstrtpamrdec.h:
+       * gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_class_init),
+       (gst_rtpamrenc_init), (gst_rtpamrenc_chain):
+       Dont set FT headers twice, it was already in the encoded
+       bitstream.
+       
+       * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send), (gst_rtspsrc_open),
+       (gst_rtspsrc_close), (gst_rtspsrc_play):
+       * gst/rtsp/rtspconnection.c: (parse_line):
+       Cleanups
+       
+       * gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
+       (gst_udpsrc_create), (gst_udpsrc_set_property),
+       (gst_udpsrc_get_property):
+       * gst/udp/gstudpsrc.h:
+       Added caps property, we need this soon to type the buffers.
+
 2005-08-18  Wim Taymans  <wim@fluendo.com>
 
        * gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init),
index 25dff88..c3d0604 100644 (file)
@@ -42,25 +42,43 @@ enum
   ARG_FREQUENCY
 };
 
-static GstStaticPadTemplate gst_rtpamrdec_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
-    GST_PAD_SRC,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-amr-nb")
-    );
-
+/* input is an RTP packet 
+ *
+ * params see RFC 3267, section 8.1
+ */
 static GstStaticPadTemplate gst_rtpamrdec_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("application/x-rtp")
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "octet-align = (boolean) TRUE, "
+        "crc = (boolean) FALSE, "
+        "robust-sorting = (boolean) FALSE, "
+        "interleaving = (boolean) FALSE, "
+        "channels = (int) 1, " "rate = (int) 8000"
+        /* 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 ]"
+         */
+    )
     );
 
+static GstStaticPadTemplate gst_rtpamrdec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000")
+    );
 
 static void gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass);
 static void gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass);
 static void gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec);
 
+static gboolean gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps);
 static GstFlowReturn gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buffer);
 
 static void gst_rtpamrdec_set_property (GObject * object, guint prop_id,
@@ -130,25 +148,104 @@ gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
 static void
 gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
 {
-  GstCaps *caps;
+  GstCaps *srccaps;
 
   rtpamrdec->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&gst_rtpamrdec_src_template), "src");
-  gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
 
-  caps = gst_caps_new_simple ("audio/x-amr-nb",
+  /* FIXME */
+  srccaps = gst_caps_new_simple ("audio/AMR",
       "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+  gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
+  gst_caps_unref (srccaps);
 
-  gst_pad_set_caps (rtpamrdec->srcpad, caps);
+  gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
 
   rtpamrdec->sinkpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&gst_rtpamrdec_sink_template), "sink");
+  gst_pad_set_setcaps_function (rtpamrdec->sinkpad, gst_rtpamrdec_sink_setcaps);
   gst_pad_set_chain_function (rtpamrdec->sinkpad, gst_rtpamrdec_chain);
   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->sinkpad);
 }
 
+static gboolean
+gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *srccaps;
+  GstRtpAMRDec *rtpamrdec;
+
+  rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_boolean (structure, "octet-align",
+          &rtpamrdec->octet_align))
+    rtpamrdec->octet_align = FALSE;
+
+  /* FIXME, force octect align for now until all elements negotiate 
+   * correctly*/
+  rtpamrdec->octet_align = TRUE;
+
+  if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
+    rtpamrdec->crc = FALSE;
+
+  if (rtpamrdec->crc) {
+    /* crc mode implies octet aligned mode */
+    rtpamrdec->octet_align = TRUE;
+  }
+
+  if (!gst_structure_get_boolean (structure, "robust-sorting",
+          &rtpamrdec->robust_sorting))
+    rtpamrdec->robust_sorting = FALSE;
+
+  if (rtpamrdec->robust_sorting) {
+    /* robust_sorting mode implies octet aligned mode */
+    rtpamrdec->octet_align = TRUE;
+  }
+
+  if (!gst_structure_get_boolean (structure, "interleaving",
+          &rtpamrdec->interleaving))
+    rtpamrdec->interleaving = FALSE;
+
+  if (rtpamrdec->interleaving) {
+    /* interleaving mode implies octet aligned mode */
+    rtpamrdec->octet_align = TRUE;
+  }
+
+  if (!gst_structure_get_int (structure, "channels", &rtpamrdec->channels))
+    rtpamrdec->channels = 1;
+  if (!gst_structure_get_int (structure, "rate", &rtpamrdec->rate))
+    rtpamrdec->rate = 8000;
+
+  /* we require 1 channel, 8000 Hz, octet aligned, no CRC, 
+   * no robust sorting, no interleaving for now */
+  if (rtpamrdec->channels != 1)
+    return FALSE;
+  if (rtpamrdec->rate != 8000)
+    return FALSE;
+  if (rtpamrdec->octet_align != TRUE)
+    return FALSE;
+  if (rtpamrdec->crc != FALSE)
+    return FALSE;
+  if (rtpamrdec->robust_sorting != FALSE)
+    return FALSE;
+  if (rtpamrdec->interleaving != FALSE)
+    return FALSE;
+
+  srccaps = gst_caps_new_simple ("audio/AMR",
+      "channels", G_TYPE_INT, rtpamrdec->channels,
+      "rate", G_TYPE_INT, rtpamrdec->rate, NULL);
+  gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  rtpamrdec->negotiated = TRUE;
+
+  return TRUE;
+}
+
 static GstFlowReturn
 gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
 {
@@ -158,26 +255,58 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
 
   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
 
+  if (!rtpamrdec->negotiated)
+    goto not_negotiated;
+
   if (!gst_rtpbuffer_validate (buf))
     goto bad_packet;
 
+  /* when we get here, 1 channel, 8000 Hz, octet aligned, no CRC, 
+   * no robust sorting, no interleaving data is to be parsed */
   {
     gint payload_len;
     guint8 *payload;
     guint32 timestamp;
+    guint8 CMR, F, FT, Q;
 
     payload_len = gst_rtpbuffer_get_payload_len (buf);
+
+    /* need at least 2 bytes for the header */
+    if (payload_len < 2)
+      goto bad_packet;
+
     payload = gst_rtpbuffer_get_payload (buf);
 
-    /* strip off header */
-    payload_len -= 2;
-    payload += 2;
+    /* parse header 
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
+     * | CMR=6 |R|R|R|R|0|FT#1=5 |Q|P|P|
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
+     */
+    CMR = (payload[0] & 0xf0) >> 4;
+    F = (payload[1] & 0x80) >> 7;
+    /* we only support 1 packet per RTP packet for now */
+    if (F != 0)
+      goto one_packet_only;
+
+    FT = (payload[1] & 0x78) >> 3;
+    Q = (payload[1] & 0x04) >> 2;
+
+    /* skip packet */
+    if (FT > 9 && FT < 15) {
+      ret = GST_FLOW_OK;
+      goto skip;
+    }
+
+    /* strip header now, leave FT in the data for the decoder */
+    payload_len -= 1;
+    payload += 1;
 
     timestamp = gst_rtpbuffer_get_timestamp (buf);
 
     outbuf = gst_buffer_new_and_alloc (payload_len);
 
-    //GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 90000;
+    GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
 
     memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
 
@@ -185,20 +314,32 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
 
     GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
         GST_BUFFER_SIZE (outbuf));
+    ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
 
+  skip:
     gst_buffer_unref (buf);
-
-    ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
   }
 
   return ret;
 
+not_negotiated:
+  {
+    GST_DEBUG ("not_negotiated");
+    gst_buffer_unref (buf);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
 bad_packet:
   {
     GST_DEBUG ("Packet did not validate");
     gst_buffer_unref (buf);
     return GST_FLOW_ERROR;
   }
+one_packet_only:
+  {
+    GST_DEBUG ("One packet per RTP packet only");
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
 }
 
 static void
@@ -244,6 +385,11 @@ gst_rtpamrdec_change_state (GstElement * element)
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
       break;
+    case GST_STATE_READY_TO_PAUSED:
+      /* FIXME, don't require negotiation until all elements
+       * do */
+      rtpamrdec->negotiated = TRUE;
+      break;
     default:
       break;
   }
index dd14792..265b5fe 100644 (file)
@@ -45,7 +45,19 @@ struct _GstRtpAMRDec
   GstPad *sinkpad;
   GstPad *srcpad;
 
-  guint frequency;
+  gboolean negotiated;
+
+  gboolean octet_align;
+  guint8   mode_set;
+  gint     mode_change_period;
+  gboolean mode_change_neighbor;
+  gint     maxptime;
+  gboolean crc;
+  gboolean robust_sorting;
+  gboolean interleaving;
+  gint     ptime;
+  gint     channels;
+  gint     rate;
 };
 
 struct _GstRtpAMRDecClass
index 25dff88..c3d0604 100644 (file)
@@ -42,25 +42,43 @@ enum
   ARG_FREQUENCY
 };
 
-static GstStaticPadTemplate gst_rtpamrdec_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
-    GST_PAD_SRC,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-amr-nb")
-    );
-
+/* input is an RTP packet 
+ *
+ * params see RFC 3267, section 8.1
+ */
 static GstStaticPadTemplate gst_rtpamrdec_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("application/x-rtp")
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "octet-align = (boolean) TRUE, "
+        "crc = (boolean) FALSE, "
+        "robust-sorting = (boolean) FALSE, "
+        "interleaving = (boolean) FALSE, "
+        "channels = (int) 1, " "rate = (int) 8000"
+        /* 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 ]"
+         */
+    )
     );
 
+static GstStaticPadTemplate gst_rtpamrdec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000")
+    );
 
 static void gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass);
 static void gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass);
 static void gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec);
 
+static gboolean gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps);
 static GstFlowReturn gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buffer);
 
 static void gst_rtpamrdec_set_property (GObject * object, guint prop_id,
@@ -130,25 +148,104 @@ gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
 static void
 gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
 {
-  GstCaps *caps;
+  GstCaps *srccaps;
 
   rtpamrdec->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&gst_rtpamrdec_src_template), "src");
-  gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
 
-  caps = gst_caps_new_simple ("audio/x-amr-nb",
+  /* FIXME */
+  srccaps = gst_caps_new_simple ("audio/AMR",
       "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+  gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
+  gst_caps_unref (srccaps);
 
-  gst_pad_set_caps (rtpamrdec->srcpad, caps);
+  gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
 
   rtpamrdec->sinkpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&gst_rtpamrdec_sink_template), "sink");
+  gst_pad_set_setcaps_function (rtpamrdec->sinkpad, gst_rtpamrdec_sink_setcaps);
   gst_pad_set_chain_function (rtpamrdec->sinkpad, gst_rtpamrdec_chain);
   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->sinkpad);
 }
 
+static gboolean
+gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstCaps *srccaps;
+  GstRtpAMRDec *rtpamrdec;
+
+  rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (!gst_structure_get_boolean (structure, "octet-align",
+          &rtpamrdec->octet_align))
+    rtpamrdec->octet_align = FALSE;
+
+  /* FIXME, force octect align for now until all elements negotiate 
+   * correctly*/
+  rtpamrdec->octet_align = TRUE;
+
+  if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
+    rtpamrdec->crc = FALSE;
+
+  if (rtpamrdec->crc) {
+    /* crc mode implies octet aligned mode */
+    rtpamrdec->octet_align = TRUE;
+  }
+
+  if (!gst_structure_get_boolean (structure, "robust-sorting",
+          &rtpamrdec->robust_sorting))
+    rtpamrdec->robust_sorting = FALSE;
+
+  if (rtpamrdec->robust_sorting) {
+    /* robust_sorting mode implies octet aligned mode */
+    rtpamrdec->octet_align = TRUE;
+  }
+
+  if (!gst_structure_get_boolean (structure, "interleaving",
+          &rtpamrdec->interleaving))
+    rtpamrdec->interleaving = FALSE;
+
+  if (rtpamrdec->interleaving) {
+    /* interleaving mode implies octet aligned mode */
+    rtpamrdec->octet_align = TRUE;
+  }
+
+  if (!gst_structure_get_int (structure, "channels", &rtpamrdec->channels))
+    rtpamrdec->channels = 1;
+  if (!gst_structure_get_int (structure, "rate", &rtpamrdec->rate))
+    rtpamrdec->rate = 8000;
+
+  /* we require 1 channel, 8000 Hz, octet aligned, no CRC, 
+   * no robust sorting, no interleaving for now */
+  if (rtpamrdec->channels != 1)
+    return FALSE;
+  if (rtpamrdec->rate != 8000)
+    return FALSE;
+  if (rtpamrdec->octet_align != TRUE)
+    return FALSE;
+  if (rtpamrdec->crc != FALSE)
+    return FALSE;
+  if (rtpamrdec->robust_sorting != FALSE)
+    return FALSE;
+  if (rtpamrdec->interleaving != FALSE)
+    return FALSE;
+
+  srccaps = gst_caps_new_simple ("audio/AMR",
+      "channels", G_TYPE_INT, rtpamrdec->channels,
+      "rate", G_TYPE_INT, rtpamrdec->rate, NULL);
+  gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
+  gst_caps_unref (srccaps);
+
+  rtpamrdec->negotiated = TRUE;
+
+  return TRUE;
+}
+
 static GstFlowReturn
 gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
 {
@@ -158,26 +255,58 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
 
   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
 
+  if (!rtpamrdec->negotiated)
+    goto not_negotiated;
+
   if (!gst_rtpbuffer_validate (buf))
     goto bad_packet;
 
+  /* when we get here, 1 channel, 8000 Hz, octet aligned, no CRC, 
+   * no robust sorting, no interleaving data is to be parsed */
   {
     gint payload_len;
     guint8 *payload;
     guint32 timestamp;
+    guint8 CMR, F, FT, Q;
 
     payload_len = gst_rtpbuffer_get_payload_len (buf);
+
+    /* need at least 2 bytes for the header */
+    if (payload_len < 2)
+      goto bad_packet;
+
     payload = gst_rtpbuffer_get_payload (buf);
 
-    /* strip off header */
-    payload_len -= 2;
-    payload += 2;
+    /* parse header 
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
+     * | CMR=6 |R|R|R|R|0|FT#1=5 |Q|P|P|
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
+     */
+    CMR = (payload[0] & 0xf0) >> 4;
+    F = (payload[1] & 0x80) >> 7;
+    /* we only support 1 packet per RTP packet for now */
+    if (F != 0)
+      goto one_packet_only;
+
+    FT = (payload[1] & 0x78) >> 3;
+    Q = (payload[1] & 0x04) >> 2;
+
+    /* skip packet */
+    if (FT > 9 && FT < 15) {
+      ret = GST_FLOW_OK;
+      goto skip;
+    }
+
+    /* strip header now, leave FT in the data for the decoder */
+    payload_len -= 1;
+    payload += 1;
 
     timestamp = gst_rtpbuffer_get_timestamp (buf);
 
     outbuf = gst_buffer_new_and_alloc (payload_len);
 
-    //GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 90000;
+    GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
 
     memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
 
@@ -185,20 +314,32 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
 
     GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
         GST_BUFFER_SIZE (outbuf));
+    ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
 
+  skip:
     gst_buffer_unref (buf);
-
-    ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
   }
 
   return ret;
 
+not_negotiated:
+  {
+    GST_DEBUG ("not_negotiated");
+    gst_buffer_unref (buf);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
 bad_packet:
   {
     GST_DEBUG ("Packet did not validate");
     gst_buffer_unref (buf);
     return GST_FLOW_ERROR;
   }
+one_packet_only:
+  {
+    GST_DEBUG ("One packet per RTP packet only");
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
 }
 
 static void
@@ -244,6 +385,11 @@ gst_rtpamrdec_change_state (GstElement * element)
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
       break;
+    case GST_STATE_READY_TO_PAUSED:
+      /* FIXME, don't require negotiation until all elements
+       * do */
+      rtpamrdec->negotiated = TRUE;
+      break;
     default:
       break;
   }
index dd14792..265b5fe 100644 (file)
@@ -45,7 +45,19 @@ struct _GstRtpAMRDec
   GstPad *sinkpad;
   GstPad *srcpad;
 
-  guint frequency;
+  gboolean negotiated;
+
+  gboolean octet_align;
+  guint8   mode_set;
+  gint     mode_change_period;
+  gboolean mode_change_neighbor;
+  gint     maxptime;
+  gboolean crc;
+  gboolean robust_sorting;
+  gboolean interleaving;
+  gint     ptime;
+  gint     channels;
+  gint     rate;
 };
 
 struct _GstRtpAMRDecClass
index d5986e3..a1e5ed8 100644 (file)
@@ -53,14 +53,24 @@ static GstStaticPadTemplate gst_rtpamrenc_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-amr-nb, channels=(int)1, rate=(int)8000")
+    GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000")
     );
 
 static GstStaticPadTemplate gst_rtpamrenc_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("application/x-rtp")
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "octet-align = (boolean) TRUE, "
+        "crc = (boolean) FALSE, "
+        "robust-sorting = (boolean) FALSE, "
+        "interleaving = (boolean) FALSE, "
+        "channels = (int) 1, "
+        "rate = (int) 8000, "
+        "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 ]")
     );
 
 
@@ -150,9 +160,21 @@ gst_rtpamrenc_class_init (GstRtpAMREncClass * klass)
 static void
 gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
 {
+  GstCaps *caps;
+
   rtpamrenc->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&gst_rtpamrenc_src_template), "src");
+
+  caps = gst_caps_new_simple ("application/x-rtp",
+      "octet-align", G_TYPE_BOOLEAN, TRUE,
+      "crc", G_TYPE_BOOLEAN, FALSE,
+      "robust-sorting", G_TYPE_BOOLEAN, FALSE,
+      "interleaving", G_TYPE_BOOLEAN, FALSE,
+      "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+
+  gst_pad_set_caps (rtpamrenc->srcpad, caps);
+  gst_caps_unref (caps);
   gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->srcpad);
 
   rtpamrenc->sinkpad =
@@ -173,7 +195,7 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
   GstFlowReturn ret;
   guint size, payload_len;
   GstBuffer *outbuf;
-  guint8 *payload;
+  guint8 *payload, *data;
   GstClockTime timestamp;
 
   rtpamrenc = GST_RTP_AMR_ENC (gst_pad_get_parent (pad));
@@ -184,7 +206,10 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
   /* FIXME, only one AMR frame per RTP packet for now, 
    * octet aligned, no interleaving, single channel, no CRC,
    * no robust-sorting. */
-  payload_len = size + 2;
+
+  /* we need one extra byte for the CMR, the ToC is in the input
+   * data */
+  payload_len = size + 1;
 
   outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
   /* FIXME, assert for now */
@@ -207,18 +232,24 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
    *  +-+-+-+-+-+-+-+-+
    */
   payload[0] = 0xF0;            /* CMR, no specific mode requested */
+
+  data = GST_BUFFER_DATA (buffer);
+
+  /* copy data in payload */
+  memcpy (&payload[1], data, size);
+
   /*   0 1 2 3 4 5 6 7
    *  +-+-+-+-+-+-+-+-+
    *  |F|  FT   |Q|P|P|
    *  +-+-+-+-+-+-+-+-+
    */
-  payload[1] = 0x04;            /* ToC, no damage (Q=1) */
-
-  /* copy data in payload */
-  memcpy (&payload[2], GST_BUFFER_DATA (buffer), size);
+  /* clear F flag */
+  payload[1] = payload[1] & 0x7f;
 
   gst_buffer_unref (buffer);
 
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrenc->srcpad));
+
   ret = gst_pad_push (rtpamrenc->srcpad, outbuf);
 
   gst_object_unref (rtpamrenc);
index d5986e3..a1e5ed8 100644 (file)
@@ -53,14 +53,24 @@ static GstStaticPadTemplate gst_rtpamrenc_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-amr-nb, channels=(int)1, rate=(int)8000")
+    GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000")
     );
 
 static GstStaticPadTemplate gst_rtpamrenc_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("application/x-rtp")
+    GST_STATIC_CAPS ("application/x-rtp, "
+        "octet-align = (boolean) TRUE, "
+        "crc = (boolean) FALSE, "
+        "robust-sorting = (boolean) FALSE, "
+        "interleaving = (boolean) FALSE, "
+        "channels = (int) 1, "
+        "rate = (int) 8000, "
+        "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 ]")
     );
 
 
@@ -150,9 +160,21 @@ gst_rtpamrenc_class_init (GstRtpAMREncClass * klass)
 static void
 gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
 {
+  GstCaps *caps;
+
   rtpamrenc->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get
       (&gst_rtpamrenc_src_template), "src");
+
+  caps = gst_caps_new_simple ("application/x-rtp",
+      "octet-align", G_TYPE_BOOLEAN, TRUE,
+      "crc", G_TYPE_BOOLEAN, FALSE,
+      "robust-sorting", G_TYPE_BOOLEAN, FALSE,
+      "interleaving", G_TYPE_BOOLEAN, FALSE,
+      "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+
+  gst_pad_set_caps (rtpamrenc->srcpad, caps);
+  gst_caps_unref (caps);
   gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->srcpad);
 
   rtpamrenc->sinkpad =
@@ -173,7 +195,7 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
   GstFlowReturn ret;
   guint size, payload_len;
   GstBuffer *outbuf;
-  guint8 *payload;
+  guint8 *payload, *data;
   GstClockTime timestamp;
 
   rtpamrenc = GST_RTP_AMR_ENC (gst_pad_get_parent (pad));
@@ -184,7 +206,10 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
   /* FIXME, only one AMR frame per RTP packet for now, 
    * octet aligned, no interleaving, single channel, no CRC,
    * no robust-sorting. */
-  payload_len = size + 2;
+
+  /* we need one extra byte for the CMR, the ToC is in the input
+   * data */
+  payload_len = size + 1;
 
   outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
   /* FIXME, assert for now */
@@ -207,18 +232,24 @@ gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
    *  +-+-+-+-+-+-+-+-+
    */
   payload[0] = 0xF0;            /* CMR, no specific mode requested */
+
+  data = GST_BUFFER_DATA (buffer);
+
+  /* copy data in payload */
+  memcpy (&payload[1], data, size);
+
   /*   0 1 2 3 4 5 6 7
    *  +-+-+-+-+-+-+-+-+
    *  |F|  FT   |Q|P|P|
    *  +-+-+-+-+-+-+-+-+
    */
-  payload[1] = 0x04;            /* ToC, no damage (Q=1) */
-
-  /* copy data in payload */
-  memcpy (&payload[2], GST_BUFFER_DATA (buffer), size);
+  /* clear F flag */
+  payload[1] = payload[1] & 0x7f;
 
   gst_buffer_unref (buffer);
 
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrenc->srcpad));
+
   ret = gst_pad_push (rtpamrenc->srcpad, outbuf);
 
   gst_object_unref (rtpamrenc);
index 5ac136a..655641e 100644 (file)
@@ -652,6 +652,9 @@ gst_rtspsrc_open (GstRTSPSrc * src)
   sdp_message_init (&sdp);
   sdp_message_parse_buffer (data, size, &sdp);
 
+  if (src->debug)
+    sdp_message_dump (&sdp);
+
   /* we allow all configured protocols */
   protocols = src->protocols;
   /* setup streams */
index 69557f0..11268e4 100644 (file)
@@ -339,9 +339,7 @@ parse_line (gchar * buffer, RTSPMessage * msg)
   bptr++;
 
   field = rtsp_find_header_field (key);
-  if (field == -1) {
-    g_warning ("ignoring unknown header field '%s'\n", key);
-  } else {
+  if (field != -1) {
     while (g_ascii_isspace (*bptr))
       bptr++;
     rtsp_message_add_header (msg, field, bptr);
index 445c144..61fadcd 100644 (file)
@@ -75,6 +75,7 @@ enum
 #define UDP_DEFAULT_PORT               4951
 #define UDP_DEFAULT_MULTICAST_GROUP    "0.0.0.0"
 #define UDP_DEFAULT_URI                        "udp://0.0.0.0:4951"
+#define UDP_DEFAULT_CAPS               NULL
 
 enum
 {
@@ -82,6 +83,7 @@ enum
   PROP_PORT,
   PROP_MULTICAST_GROUP,
   PROP_URI,
+  PROP_CAPS,
   /* FILL ME */
 };
 
@@ -180,6 +182,9 @@ gst_udpsrc_class_init (GstUDPSrc * klass)
       g_param_spec_string ("uri", "URI",
           "URI in the form of udp://hostname:port", UDP_DEFAULT_URI,
           G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_CAPS,
+      g_param_spec_boxed ("caps", "Caps",
+          "The caps of the source pad", GST_TYPE_CAPS, G_PARAM_READWRITE));
 
   gstbasesrc_class->start = gst_udpsrc_start;
   gstbasesrc_class->stop = gst_udpsrc_stop;
@@ -297,6 +302,8 @@ gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
   gst_netaddress_set_ip4_address (&outbuf->from, tmpaddr.sin_addr.s_addr,
       tmpaddr.sin_port);
 
+  gst_buffer_set_caps (GST_BUFFER (outbuf), udpsrc->caps);
+
   GST_LOG_OBJECT (udpsrc, "read %d bytes", readsize);
 
   *buf = GST_BUFFER (outbuf);
@@ -386,6 +393,23 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
     case PROP_URI:
       gst_udpsrc_set_uri (udpsrc, g_value_get_string (value));
       break;
+    case PROP_CAPS:
+    {
+      const GstCaps *new_caps_val = gst_value_get_caps (value);
+      GstCaps *new_caps;
+      GstCaps *old_caps;
+
+      if (new_caps_val == NULL) {
+        new_caps = gst_caps_new_any ();
+      } else {
+        new_caps = gst_caps_copy (new_caps_val);
+      }
+
+      old_caps = udpsrc->caps;
+      udpsrc->caps = new_caps;
+      gst_caps_unref (old_caps);
+      break;
+    }
     default:
       break;
   }
@@ -409,6 +433,9 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_URI:
       g_value_set_string (value, udpsrc->uri);
       break;
+    case PROP_CAPS:
+      gst_value_set_caps (value, udpsrc->caps);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index cbdfa7c..85209d5 100644 (file)
@@ -65,6 +65,8 @@ struct _GstUDPSrc {
 
   struct sockaddr_in myaddr;
   struct ip_mreq multi_addr;
+
+  GstCaps *caps;
 };
 
 struct _GstUDPSrcClass {