From c5284dc0475701aa3df7749e29a965c684727be2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 4 Dec 2013 10:12:46 +0100 Subject: [PATCH] rtpstreampay: Add RFC4571 RTP stream payloading element https://bugzilla.gnome.org/show_bug.cgi?id=719829 --- gst/rtp/Makefile.am | 6 +- gst/rtp/gstrtp.c | 4 + gst/rtp/gstrtpstreampay.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++ gst/rtp/gstrtpstreampay.h | 54 +++++++++ 4 files changed, 349 insertions(+), 2 deletions(-) create mode 100644 gst/rtp/gstrtpstreampay.c create mode 100644 gst/rtp/gstrtpstreampay.h diff --git a/gst/rtp/Makefile.am b/gst/rtp/Makefile.am index b863e01..3b5fd09 100644 --- a/gst/rtp/Makefile.am +++ b/gst/rtp/Makefile.am @@ -78,7 +78,8 @@ libgstrtp_la_SOURCES = \ gstrtpvp8depay.c \ gstrtpvp8pay.c \ gstrtpvrawdepay.c \ - gstrtpvrawpay.c + gstrtpvrawpay.c \ + gstrtpstreampay.c libgstrtp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \ $(GST_CFLAGS) -Dvp8_norm=gst_rtpvp8_vp8_norm \ @@ -173,7 +174,8 @@ noinst_HEADERS = \ gstrtpvp8depay.h \ gstrtpvp8pay.h \ gstrtpvrawdepay.h \ - gstrtpvrawpay.h + gstrtpvrawpay.h \ + gstrtpstreampay.c EXTRA_DIST = dboolhuff.LICENSE diff --git a/gst/rtp/gstrtp.c b/gst/rtp/gstrtp.c index 893dafd..aa3e592 100644 --- a/gst/rtp/gstrtp.c +++ b/gst/rtp/gstrtp.c @@ -97,6 +97,7 @@ #include "gstrtpvp8pay.h" #include "gstrtpvrawdepay.h" #include "gstrtpvrawpay.h" +#include "gstrtpstreampay.h" static gboolean plugin_init (GstPlugin * plugin) @@ -325,6 +326,9 @@ plugin_init (GstPlugin * plugin) if (!gst_rtp_vraw_pay_plugin_init (plugin)) return FALSE; + if (!gst_rtp_stream_pay_plugin_init (plugin)) + return FALSE; + return TRUE; } diff --git a/gst/rtp/gstrtpstreampay.c b/gst/rtp/gstrtpstreampay.c new file mode 100644 index 0000000..117f678 --- /dev/null +++ b/gst/rtp/gstrtpstreampay.c @@ -0,0 +1,287 @@ +/* + * GStreamer + * Copyright (C) 2013 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:element-rtpstreampay + * + * Implements stream payloading of RTP and RTCP packets for connection-oriented + * transport protocols according to RFC4571. + * + * Example launch line + * |[ + * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678 + * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink + * ]| + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstrtpstreampay.h" + +#define GST_CAT_DEFAULT gst_rtp_stream_pay_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp; application/x-rtcp; " + "application/x-srtp; application/x-srtcp") + ); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp-stream; application/x-rtcp-stream; " + "application/x-srtp-stream; application/x-srtcp-stream") + ); + +#define parent_class gst_rtp_stream_pay_parent_class +G_DEFINE_TYPE (GstRtpStreamPay, gst_rtp_stream_pay, GST_TYPE_ELEMENT); + +static gboolean gst_rtp_stream_pay_sink_query (GstPad * pad, GstObject * parent, + GstQuery * query); +static GstFlowReturn gst_rtp_stream_pay_sink_chain (GstPad * pad, + GstObject * parent, GstBuffer * inbuf); +static gboolean gst_rtp_stream_pay_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); + +static void +gst_rtp_stream_pay_class_init (GstRtpStreamPayClass * klass) +{ + GstElementClass *gstelement_class; + + GST_DEBUG_CATEGORY_INIT (gst_rtp_stream_pay_debug, "rtpstreampay", 0, + "RTP stream payloader"); + + gstelement_class = (GstElementClass *) klass; + + gst_element_class_set_static_metadata (gstelement_class, + "RTP Stream Payloading", "Codec/Payloader/Network", + "Payloads RTP/RTCP packets for streaming protocols according to RFC4571", + "Sebastian Dröge "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_template)); +} + +static void +gst_rtp_stream_pay_init (GstRtpStreamPay * self) +{ + self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_pad_set_chain_function (self->sinkpad, + GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_chain)); + gst_pad_set_event_function (self->sinkpad, + GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_event)); + gst_pad_set_query_function (self->sinkpad, + GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_query)); + gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); + + self->srcpad = gst_pad_new_from_static_template (&src_template, "src"); + gst_pad_use_fixed_caps (self->srcpad); + gst_element_add_pad (GST_ELEMENT (self), self->srcpad); +} + +static GstCaps * +gst_rtp_stream_pay_sink_get_caps (GstRtpStreamPay * self, GstCaps * filter) +{ + GstCaps *peerfilter = NULL, *peercaps, *templ; + GstCaps *res; + GstStructure *structure; + guint i, n; + + if (filter) { + peerfilter = gst_caps_copy (filter); + n = gst_caps_get_size (peerfilter); + for (i = 0; i < n; i++) { + structure = gst_caps_get_structure (peerfilter, i); + + if (gst_structure_has_name (structure, "application/x-rtp")) + gst_structure_set_name (structure, "application/x-rtp-stream"); + else if (gst_structure_has_name (structure, "application/x-rtcp")) + gst_structure_set_name (structure, "application/x-rtcp-stream"); + else if (gst_structure_has_name (structure, "application/x-srtp")) + gst_structure_set_name (structure, "application/x-srtp-stream"); + else + gst_structure_set_name (structure, "application/x-srtcp-stream"); + } + } + + templ = gst_pad_get_pad_template_caps (self->sinkpad); + peercaps = gst_pad_peer_query_caps (self->srcpad, peerfilter); + + if (peercaps) { + /* Rename structure names */ + peercaps = gst_caps_make_writable (peercaps); + n = gst_caps_get_size (peercaps); + for (i = 0; i < n; i++) { + structure = gst_caps_get_structure (peercaps, i); + + if (gst_structure_has_name (structure, "application/x-rtp-stream")) + gst_structure_set_name (structure, "application/x-rtp"); + else if (gst_structure_has_name (structure, "application/x-rtcp-stream")) + gst_structure_set_name (structure, "application/x-rtcp"); + else if (gst_structure_has_name (structure, "application/x-srtp-stream")) + gst_structure_set_name (structure, "application/x-srtp"); + else + gst_structure_set_name (structure, "application/x-srtcp"); + } + + res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (peercaps); + } else { + res = templ; + } + + if (filter) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (res); + res = intersection; + + gst_caps_unref (peerfilter); + } + + return res; +} + +static gboolean +gst_rtp_stream_pay_sink_query (GstPad * pad, GstObject * parent, + GstQuery * query) +{ + GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent); + gboolean ret; + + GST_LOG_OBJECT (pad, "Handling query of type '%s'", + gst_query_type_get_name (GST_QUERY_TYPE (query))); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS: + { + GstCaps *caps; + + gst_query_parse_caps (query, &caps); + caps = gst_rtp_stream_pay_sink_get_caps (self, caps); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + ret = TRUE; + break; + } + default: + ret = gst_pad_query_default (pad, parent, query); + } + + return ret; +} + +static gboolean +gst_rtp_stream_pay_sink_set_caps (GstRtpStreamPay * self, GstCaps * caps) +{ + GstCaps *othercaps; + GstStructure *structure; + gboolean ret; + + othercaps = gst_caps_copy (caps); + structure = gst_caps_get_structure (othercaps, 0); + + if (gst_structure_has_name (structure, "application/x-rtp")) + gst_structure_set_name (structure, "application/x-rtp-stream"); + else if (gst_structure_has_name (structure, "application/x-rtcp")) + gst_structure_set_name (structure, "application/x-rtcp-stream"); + else if (gst_structure_has_name (structure, "application/x-srtp")) + gst_structure_set_name (structure, "application/x-srtp-stream"); + else + gst_structure_set_name (structure, "application/x-srtcp-stream"); + + ret = gst_pad_set_caps (self->srcpad, othercaps); + gst_caps_unref (othercaps); + + return ret; +} + +static gboolean +gst_rtp_stream_pay_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event) +{ + GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent); + gboolean ret; + + GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + ret = gst_rtp_stream_pay_sink_set_caps (self, caps); + gst_event_unref (event); + break; + } + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + return ret; +} + +static GstFlowReturn +gst_rtp_stream_pay_sink_chain (GstPad * pad, GstObject * parent, + GstBuffer * inbuf) +{ + GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent); + GstBuffer *outbuf; + gsize size; + guint8 size16[2]; + + size = gst_buffer_get_size (inbuf); + if (size > G_MAXUINT16) { + GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL), + ("Only buffers up to %d bytes supported, got %" G_GSIZE_FORMAT, + G_MAXUINT16, size)); + gst_buffer_unref (inbuf); + return GST_FLOW_ERROR; + } + + outbuf = gst_buffer_new_and_alloc (2); + + GST_WRITE_UINT16_BE (size16, size); + gst_buffer_fill (outbuf, 0, size16, 2); + + gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_ALL, 0, -1); + + gst_buffer_unref (inbuf); + + return gst_pad_push (self->srcpad, outbuf); +} + +gboolean +gst_rtp_stream_pay_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpstreampay", + GST_RANK_NONE, GST_TYPE_RTP_STREAM_PAY); +} diff --git a/gst/rtp/gstrtpstreampay.h b/gst/rtp/gstrtpstreampay.h new file mode 100644 index 0000000..a9436a8 --- /dev/null +++ b/gst/rtp/gstrtpstreampay.h @@ -0,0 +1,54 @@ +/* + * GStreamer + * Copyright (C) 2013 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_RTP_STREAM_PAY_H__ +#define __GST_RTP_STREAM_PAY_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_RTP_STREAM_PAY (gst_rtp_stream_pay_get_type()) +#define GST_RTP_STREAM_PAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPay)) +#define GST_IS_RTP_STREAM_PAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_STREAM_PAY)) +#define GST_RTP_STREAM_PAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPayClass)) +#define GST_IS_RTP_STREAM_PAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_RTP_STREAM_PAY)) +#define GST_RTP_STREAM_PAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPayClass)) + +typedef struct _GstRtpStreamPay GstRtpStreamPay; +typedef struct _GstRtpStreamPayClass GstRtpStreamPayClass; + +struct _GstRtpStreamPay { + GstElement parent; + + GstPad *srcpad, *sinkpad; +}; + +struct _GstRtpStreamPayClass { + GstElementClass parent_class; +}; + +GType gst_rtp_stream_pay_get_type (void); + +gboolean gst_rtp_stream_pay_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_RTP_STREAM_PAY_H__ */ -- 2.7.4