diff --git a/ChangeLog b/ChangeLog index 96edad2a0c..296fc02f76 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2005-08-19 Wim Taymans + + * 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 * gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_init), diff --git a/gst/rtp/gstrtpamrdec.c b/gst/rtp/gstrtpamrdec.c index 25dff88edc..c3d0604cc5 100644 --- a/gst/rtp/gstrtpamrdec.c +++ b/gst/rtp/gstrtpamrdec.c @@ -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)); - - gst_buffer_unref (buf); - ret = gst_pad_push (rtpamrdec->srcpad, outbuf); + + skip: + gst_buffer_unref (buf); } 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; } diff --git a/gst/rtp/gstrtpamrdec.h b/gst/rtp/gstrtpamrdec.h index dd1479225e..265b5fe02a 100644 --- a/gst/rtp/gstrtpamrdec.h +++ b/gst/rtp/gstrtpamrdec.h @@ -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 diff --git a/gst/rtp/gstrtpamrdepay.c b/gst/rtp/gstrtpamrdepay.c index 25dff88edc..c3d0604cc5 100644 --- a/gst/rtp/gstrtpamrdepay.c +++ b/gst/rtp/gstrtpamrdepay.c @@ -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)); - - gst_buffer_unref (buf); - ret = gst_pad_push (rtpamrdec->srcpad, outbuf); + + skip: + gst_buffer_unref (buf); } 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; } diff --git a/gst/rtp/gstrtpamrdepay.h b/gst/rtp/gstrtpamrdepay.h index dd1479225e..265b5fe02a 100644 --- a/gst/rtp/gstrtpamrdepay.h +++ b/gst/rtp/gstrtpamrdepay.h @@ -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 diff --git a/gst/rtp/gstrtpamrenc.c b/gst/rtp/gstrtpamrenc.c index d5986e355e..a1e5ed864c 100644 --- a/gst/rtp/gstrtpamrenc.c +++ b/gst/rtp/gstrtpamrenc.c @@ -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); diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c index d5986e355e..a1e5ed864c 100644 --- a/gst/rtp/gstrtpamrpay.c +++ b/gst/rtp/gstrtpamrpay.c @@ -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); diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 5ac136a6f5..655641e9f1 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -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 */ diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c index 69557f053c..11268e4a91 100644 --- a/gst/rtsp/rtspconnection.c +++ b/gst/rtsp/rtspconnection.c @@ -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); diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c index 445c144496..61fadcd4a4 100644 --- a/gst/udp/gstudpsrc.c +++ b/gst/udp/gstudpsrc.c @@ -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; diff --git a/gst/udp/gstudpsrc.h b/gst/udp/gstudpsrc.h index cbdfa7caaa..85209d5d98 100644 --- a/gst/udp/gstudpsrc.h +++ b/gst/udp/gstudpsrc.h @@ -65,6 +65,8 @@ struct _GstUDPSrc { struct sockaddr_in myaddr; struct ip_mreq multi_addr; + + GstCaps *caps; }; struct _GstUDPSrcClass {