From c12772c616d48bd98a5e49507cdd10d894720dfb Mon Sep 17 00:00:00 2001 From: Flavio Oliveira Date: Tue, 25 Oct 2005 19:19:38 +0000 Subject: [PATCH] G711 payloader and depayloader created by Edgard Lima (it supports mulaw and alaw (dec)encoders) Original commit message from CVS: G711 payloader and depayloader created by Edgard Lima (it supports mulaw and alaw (dec)encoders) --- ChangeLog | 11 ++ gst/rtp/Makefile.am | 4 + gst/rtp/gstrtp.c | 8 + gst/rtp/gstrtpg711dec.c | 307 ++++++++++++++++++++++++++++++++++++++ gst/rtp/gstrtpg711dec.h | 53 +++++++ gst/rtp/gstrtpg711depay.c | 307 ++++++++++++++++++++++++++++++++++++++ gst/rtp/gstrtpg711depay.h | 53 +++++++ gst/rtp/gstrtpg711enc.c | 198 ++++++++++++++++++++++++ gst/rtp/gstrtpg711enc.h | 54 +++++++ gst/rtp/gstrtpg711pay.c | 198 ++++++++++++++++++++++++ gst/rtp/gstrtpg711pay.h | 54 +++++++ 11 files changed, 1247 insertions(+) create mode 100644 gst/rtp/gstrtpg711dec.c create mode 100644 gst/rtp/gstrtpg711dec.h create mode 100644 gst/rtp/gstrtpg711depay.c create mode 100644 gst/rtp/gstrtpg711depay.h create mode 100644 gst/rtp/gstrtpg711enc.c create mode 100644 gst/rtp/gstrtpg711enc.h create mode 100644 gst/rtp/gstrtpg711pay.c create mode 100644 gst/rtp/gstrtpg711pay.h diff --git a/ChangeLog b/ChangeLog index d6e245a75e..dd257090cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-10-25 Edgard Lima + + * gst/rtp/Makefile.am + * gst/rtp/gstrtp.c + * gst/rtp/gstrtpg711enc.c + * gst/rtp/gstrtpg711enc.h + * gst/rtp/gstrtpg711dec.c + * gst/rtp/gstrtpg711dec.h + Created G711 payloader and depayloader (it supports mulaw and alaw + (dec)encoders) + 2005-10-25 Julien MOUTTE * gst/videobox/gstvideobox.c: (gst_video_box_class_init), diff --git a/gst/rtp/Makefile.am b/gst/rtp/Makefile.am index 753b8c1051..b5639d727a 100644 --- a/gst/rtp/Makefile.am +++ b/gst/rtp/Makefile.am @@ -4,6 +4,8 @@ libgstrtp_la_SOURCES = gstrtp.c \ gstrtpdec.c \ gstrtpmpadec.c \ gstrtpmpaenc.c \ + gstrtpg711enc.c \ + gstrtpg711dec.c \ gstrtpgsmenc.c \ gstrtpgsmparse.c \ gstrtpamrdec.c \ @@ -26,6 +28,8 @@ noinst_HEADERS = gstrtpL16enc.h \ gstrtpL16parse.h \ gstrtpamrdec.h \ gstrtpamrenc.h \ + gstrtpg711enc.h \ + gstrtpg711dec.h \ gstrtpgsmenc.h \ gstrtpgsmparse.h \ gstrtpmpadec.h \ diff --git a/gst/rtp/gstrtp.c b/gst/rtp/gstrtp.c index a967495cb7..dd8457b4d9 100644 --- a/gst/rtp/gstrtp.c +++ b/gst/rtp/gstrtp.c @@ -22,6 +22,8 @@ #endif #include "gstrtpdec.h" +#include "gstrtpg711enc.h" +#include "gstrtpg711dec.h" #include "gstrtpgsmenc.h" #include "gstrtpgsmparse.h" #include "gstrtpamrenc.h" @@ -53,6 +55,12 @@ plugin_init (GstPlugin * plugin) if (!gst_rtpamrenc_plugin_init (plugin)) return FALSE; + if (!gst_rtpg711dec_plugin_init (plugin)) + return FALSE; + + if (!gst_rtpg711enc_plugin_init (plugin)) + return FALSE; + if (!gst_rtpmpadec_plugin_init (plugin)) return FALSE; diff --git a/gst/rtp/gstrtpg711dec.c b/gst/rtp/gstrtpg711dec.c new file mode 100644 index 0000000000..6456f72c46 --- /dev/null +++ b/gst/rtp/gstrtpg711dec.c @@ -0,0 +1,307 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include "gstrtpg711dec.h" + +/* elementfactory information */ +static GstElementDetails gst_rtp_g711dec_details = { + "RTP packet parser", + "Codec/Parser/Network", + "Extracts PCMU/PCMA audio from RTP packets", + "Edgard Lima " +}; + +/* RtpG711Dec signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0 +}; + +static GstStaticPadTemplate gst_rtpg711dec_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 0, " + "clock-rate = (int) 8000, " + "encoding-name = (string) \"PCMU\"; " + "application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 8, " + "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\"") + + ); + +static GstStaticPadTemplate gst_rtpg711dec_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-mulaw, channels = (int) 1; " + "audio/x-alaw, channels = (int) 1") + ); + +static void gst_rtpg711dec_class_init (GstRtpG711DecClass * klass); +static void gst_rtpg711dec_base_init (GstRtpG711DecClass * klass); +static void gst_rtpg711dec_init (GstRtpG711Dec * rtpg711dec); +static gboolean gst_rtpg711dec_sink_setcaps (GstPad * pad, GstCaps * caps); +static GstFlowReturn gst_rtpg711dec_chain (GstPad * pad, GstBuffer * buffer); + +static void gst_rtpg711dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_rtpg711dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstStateChangeReturn gst_rtpg711dec_change_state (GstElement * element, + GstStateChange transition); + +static GstElementClass *parent_class = NULL; + +static GType +gst_rtpg711dec_get_type (void) +{ + static GType rtpg711dec_type = 0; + + if (!rtpg711dec_type) { + static const GTypeInfo rtpg711dec_info = { + sizeof (GstRtpG711DecClass), + (GBaseInitFunc) gst_rtpg711dec_base_init, + NULL, + (GClassInitFunc) gst_rtpg711dec_class_init, + NULL, + NULL, + sizeof (GstRtpG711Dec), + 0, + (GInstanceInitFunc) gst_rtpg711dec_init, + }; + + rtpg711dec_type = + g_type_register_static (GST_TYPE_ELEMENT, "GstRtpG711Dec", + &rtpg711dec_info, 0); + } + return rtpg711dec_type; +} + +static void +gst_rtpg711dec_base_init (GstRtpG711DecClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711dec_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711dec_sink_template)); + gst_element_class_set_details (element_class, &gst_rtp_g711dec_details); +} + +static void +gst_rtpg711dec_class_init (GstRtpG711DecClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_rtpg711dec_set_property; + gobject_class->get_property = gst_rtpg711dec_get_property; + + gstelement_class->change_state = gst_rtpg711dec_change_state; +} + +static void +gst_rtpg711dec_init (GstRtpG711Dec * rtpg711dec) +{ + rtpg711dec->srcpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&gst_rtpg711dec_src_template), "src"); + rtpg711dec->sinkpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&gst_rtpg711dec_sink_template), "sink"); + gst_element_add_pad (GST_ELEMENT (rtpg711dec), rtpg711dec->srcpad); + + gst_pad_set_setcaps_function (rtpg711dec->sinkpad, + gst_rtpg711dec_sink_setcaps); + gst_element_add_pad (GST_ELEMENT (rtpg711dec), rtpg711dec->sinkpad); + gst_pad_set_chain_function (rtpg711dec->sinkpad, gst_rtpg711dec_chain); +} + +static gboolean +gst_rtpg711dec_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstCaps *srccaps; + GstRtpG711Dec *rtpg711dec; + const gchar *enc_name; + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + + enc_name = gst_structure_get_name (structure); + + enc_name = gst_structure_get_string (structure, "encoding-name"); + + if (NULL == enc_name) { + return FALSE; + } + + if (0 == strcmp ("PCMU", enc_name)) { + srccaps = gst_caps_new_simple ("audio/x-mulaw", + "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); + } else if (0 == strcmp ("PCMA", enc_name)) { + srccaps = gst_caps_new_simple ("audio/x-alaw", + "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); + } else { + return FALSE; + } + + rtpg711dec = GST_RTP_G711_DEC (GST_OBJECT_PARENT (pad)); + + srccaps = gst_caps_new_simple ("audio/x-mulaw", + "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); + gst_pad_set_caps (rtpg711dec->srcpad, srccaps); + gst_caps_unref (srccaps); + + return TRUE; +} + +static GstFlowReturn +gst_rtpg711dec_chain (GstPad * pad, GstBuffer * buf) +{ + GstRtpG711Dec *rtpg711dec; + GstBuffer *outbuf; + GstFlowReturn ret; + + rtpg711dec = GST_RTP_G711_DEC (gst_pad_get_parent (pad)); + + if (!gst_rtpbuffer_validate (buf)) + goto bad_packet; + + { + gint payload_len; + guint8 *payload; + guint32 timestamp; + static guint32 firstTS = -1; + + payload_len = gst_rtpbuffer_get_payload_len (buf); + payload = gst_rtpbuffer_get_payload (buf); + + timestamp = gst_rtpbuffer_get_timestamp (buf); + + if (firstTS == -1) { + firstTS = gst_rtpbuffer_get_timestamp (buf); + } + timestamp = gst_rtpbuffer_get_timestamp (buf) - firstTS; + + outbuf = gst_buffer_new_and_alloc (payload_len); + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000; + + memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len); + + GST_DEBUG ("pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); + + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpg711dec->srcpad)); + gst_buffer_unref (buf); + + ret = gst_pad_push (rtpg711dec->srcpad, outbuf); + } + + return ret; + +bad_packet: + { + GST_DEBUG ("Packet did not validate"); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } +} + +static void +gst_rtpg711dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRtpG711Dec *rtpg711dec; + + rtpg711dec = GST_RTP_G711_DEC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtpg711dec_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstRtpG711Dec *rtpg711dec; + + rtpg711dec = GST_RTP_G711_DEC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_rtpg711dec_change_state (GstElement * element, GstStateChange transition) +{ + GstRtpG711Dec *rtpg711dec; + GstStateChangeReturn ret; + + rtpg711dec = GST_RTP_G711_DEC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + return ret; +} + +gboolean +gst_rtpg711dec_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpg711dec", + GST_RANK_NONE, GST_TYPE_RTP_G711_DEC); +} diff --git a/gst/rtp/gstrtpg711dec.h b/gst/rtp/gstrtpg711dec.h new file mode 100644 index 0000000000..4be76e38b8 --- /dev/null +++ b/gst/rtp/gstrtpg711dec.h @@ -0,0 +1,53 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + +#ifndef __GST_RTP_G711_DEC_H__ +#define __GST_RTP_G711_DEC_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _GstRtpG711Dec GstRtpG711Dec; +typedef struct _GstRtpG711DecClass GstRtpG711DecClass; + +#define GST_TYPE_RTP_G711_DEC \ + (gst_rtpg711dec_get_type()) +#define GST_RTP_G711_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G711_DEC,GstRtpG711Dec)) +#define GST_RTP_G711_DEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G711_DEC,GstRtpG711Dec)) +#define GST_IS_RTP_G711_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G711_DEC)) +#define GST_IS_RTP_G711_DEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G711_DEC)) + +struct _GstRtpG711Dec +{ + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; +}; + +struct _GstRtpG711DecClass +{ + GstElementClass parent_class; +}; + +gboolean gst_rtpg711dec_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_RTP_G711_DEC_H__ */ diff --git a/gst/rtp/gstrtpg711depay.c b/gst/rtp/gstrtpg711depay.c new file mode 100644 index 0000000000..6456f72c46 --- /dev/null +++ b/gst/rtp/gstrtpg711depay.c @@ -0,0 +1,307 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include "gstrtpg711dec.h" + +/* elementfactory information */ +static GstElementDetails gst_rtp_g711dec_details = { + "RTP packet parser", + "Codec/Parser/Network", + "Extracts PCMU/PCMA audio from RTP packets", + "Edgard Lima " +}; + +/* RtpG711Dec signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0 +}; + +static GstStaticPadTemplate gst_rtpg711dec_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 0, " + "clock-rate = (int) 8000, " + "encoding-name = (string) \"PCMU\"; " + "application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 8, " + "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\"") + + ); + +static GstStaticPadTemplate gst_rtpg711dec_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-mulaw, channels = (int) 1; " + "audio/x-alaw, channels = (int) 1") + ); + +static void gst_rtpg711dec_class_init (GstRtpG711DecClass * klass); +static void gst_rtpg711dec_base_init (GstRtpG711DecClass * klass); +static void gst_rtpg711dec_init (GstRtpG711Dec * rtpg711dec); +static gboolean gst_rtpg711dec_sink_setcaps (GstPad * pad, GstCaps * caps); +static GstFlowReturn gst_rtpg711dec_chain (GstPad * pad, GstBuffer * buffer); + +static void gst_rtpg711dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_rtpg711dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstStateChangeReturn gst_rtpg711dec_change_state (GstElement * element, + GstStateChange transition); + +static GstElementClass *parent_class = NULL; + +static GType +gst_rtpg711dec_get_type (void) +{ + static GType rtpg711dec_type = 0; + + if (!rtpg711dec_type) { + static const GTypeInfo rtpg711dec_info = { + sizeof (GstRtpG711DecClass), + (GBaseInitFunc) gst_rtpg711dec_base_init, + NULL, + (GClassInitFunc) gst_rtpg711dec_class_init, + NULL, + NULL, + sizeof (GstRtpG711Dec), + 0, + (GInstanceInitFunc) gst_rtpg711dec_init, + }; + + rtpg711dec_type = + g_type_register_static (GST_TYPE_ELEMENT, "GstRtpG711Dec", + &rtpg711dec_info, 0); + } + return rtpg711dec_type; +} + +static void +gst_rtpg711dec_base_init (GstRtpG711DecClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711dec_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711dec_sink_template)); + gst_element_class_set_details (element_class, &gst_rtp_g711dec_details); +} + +static void +gst_rtpg711dec_class_init (GstRtpG711DecClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_rtpg711dec_set_property; + gobject_class->get_property = gst_rtpg711dec_get_property; + + gstelement_class->change_state = gst_rtpg711dec_change_state; +} + +static void +gst_rtpg711dec_init (GstRtpG711Dec * rtpg711dec) +{ + rtpg711dec->srcpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&gst_rtpg711dec_src_template), "src"); + rtpg711dec->sinkpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&gst_rtpg711dec_sink_template), "sink"); + gst_element_add_pad (GST_ELEMENT (rtpg711dec), rtpg711dec->srcpad); + + gst_pad_set_setcaps_function (rtpg711dec->sinkpad, + gst_rtpg711dec_sink_setcaps); + gst_element_add_pad (GST_ELEMENT (rtpg711dec), rtpg711dec->sinkpad); + gst_pad_set_chain_function (rtpg711dec->sinkpad, gst_rtpg711dec_chain); +} + +static gboolean +gst_rtpg711dec_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstCaps *srccaps; + GstRtpG711Dec *rtpg711dec; + const gchar *enc_name; + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + + enc_name = gst_structure_get_name (structure); + + enc_name = gst_structure_get_string (structure, "encoding-name"); + + if (NULL == enc_name) { + return FALSE; + } + + if (0 == strcmp ("PCMU", enc_name)) { + srccaps = gst_caps_new_simple ("audio/x-mulaw", + "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); + } else if (0 == strcmp ("PCMA", enc_name)) { + srccaps = gst_caps_new_simple ("audio/x-alaw", + "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); + } else { + return FALSE; + } + + rtpg711dec = GST_RTP_G711_DEC (GST_OBJECT_PARENT (pad)); + + srccaps = gst_caps_new_simple ("audio/x-mulaw", + "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); + gst_pad_set_caps (rtpg711dec->srcpad, srccaps); + gst_caps_unref (srccaps); + + return TRUE; +} + +static GstFlowReturn +gst_rtpg711dec_chain (GstPad * pad, GstBuffer * buf) +{ + GstRtpG711Dec *rtpg711dec; + GstBuffer *outbuf; + GstFlowReturn ret; + + rtpg711dec = GST_RTP_G711_DEC (gst_pad_get_parent (pad)); + + if (!gst_rtpbuffer_validate (buf)) + goto bad_packet; + + { + gint payload_len; + guint8 *payload; + guint32 timestamp; + static guint32 firstTS = -1; + + payload_len = gst_rtpbuffer_get_payload_len (buf); + payload = gst_rtpbuffer_get_payload (buf); + + timestamp = gst_rtpbuffer_get_timestamp (buf); + + if (firstTS == -1) { + firstTS = gst_rtpbuffer_get_timestamp (buf); + } + timestamp = gst_rtpbuffer_get_timestamp (buf) - firstTS; + + outbuf = gst_buffer_new_and_alloc (payload_len); + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000; + + memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len); + + GST_DEBUG ("pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); + + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpg711dec->srcpad)); + gst_buffer_unref (buf); + + ret = gst_pad_push (rtpg711dec->srcpad, outbuf); + } + + return ret; + +bad_packet: + { + GST_DEBUG ("Packet did not validate"); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } +} + +static void +gst_rtpg711dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRtpG711Dec *rtpg711dec; + + rtpg711dec = GST_RTP_G711_DEC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtpg711dec_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstRtpG711Dec *rtpg711dec; + + rtpg711dec = GST_RTP_G711_DEC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_rtpg711dec_change_state (GstElement * element, GstStateChange transition) +{ + GstRtpG711Dec *rtpg711dec; + GstStateChangeReturn ret; + + rtpg711dec = GST_RTP_G711_DEC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + return ret; +} + +gboolean +gst_rtpg711dec_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpg711dec", + GST_RANK_NONE, GST_TYPE_RTP_G711_DEC); +} diff --git a/gst/rtp/gstrtpg711depay.h b/gst/rtp/gstrtpg711depay.h new file mode 100644 index 0000000000..4be76e38b8 --- /dev/null +++ b/gst/rtp/gstrtpg711depay.h @@ -0,0 +1,53 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + +#ifndef __GST_RTP_G711_DEC_H__ +#define __GST_RTP_G711_DEC_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _GstRtpG711Dec GstRtpG711Dec; +typedef struct _GstRtpG711DecClass GstRtpG711DecClass; + +#define GST_TYPE_RTP_G711_DEC \ + (gst_rtpg711dec_get_type()) +#define GST_RTP_G711_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G711_DEC,GstRtpG711Dec)) +#define GST_RTP_G711_DEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G711_DEC,GstRtpG711Dec)) +#define GST_IS_RTP_G711_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G711_DEC)) +#define GST_IS_RTP_G711_DEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G711_DEC)) + +struct _GstRtpG711Dec +{ + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; +}; + +struct _GstRtpG711DecClass +{ + GstElementClass parent_class; +}; + +gboolean gst_rtpg711dec_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_RTP_G711_DEC_H__ */ diff --git a/gst/rtp/gstrtpg711enc.c b/gst/rtp/gstrtpg711enc.c new file mode 100644 index 0000000000..2067ffd6cc --- /dev/null +++ b/gst/rtp/gstrtpg711enc.c @@ -0,0 +1,198 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "gstrtpg711enc.h" + +/* elementfactory information */ +static GstElementDetails gst_rtpg711enc_details = { + "RTP packet parser", + "Codec/Encoder/Network", + "Encodes PCMU/PCMA audio into a RTP packet", + "Edgard Lima " +}; + +static GstStaticPadTemplate gst_rtpg711enc_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-mulaw, channels=(int)1, rate=(int)8000 ;" + "audio/x-alaw, channels=(int)1, rate=(int)8000") + ); + +static GstStaticPadTemplate gst_rtpg711enc_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 0, " + "clock-rate = (int) 8000, " + "encoding-name = (string) \"PCMU\"; " + "application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 8, " + "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\"") + ); + + +static void gst_rtpg711enc_class_init (GstRtpG711EncClass * klass); +static void gst_rtpg711enc_base_init (GstRtpG711EncClass * klass); +static void gst_rtpg711enc_init (GstRtpG711Enc * rtpg711enc); + +static gboolean gst_rtpg711enc_setcaps (GstBaseRTPPayload * payload, + GstCaps * caps); +static GstFlowReturn gst_rtpg711enc_handle_buffer (GstBaseRTPPayload * payload, + GstBuffer * buffer); + +static GstBaseRTPPayloadClass *parent_class = NULL; + +static GType +gst_rtpg711enc_get_type (void) +{ + static GType rtpg711enc_type = 0; + + if (!rtpg711enc_type) { + static const GTypeInfo rtpg711enc_info = { + sizeof (GstRtpG711EncClass), + (GBaseInitFunc) gst_rtpg711enc_base_init, + NULL, + (GClassInitFunc) gst_rtpg711enc_class_init, + NULL, + NULL, + sizeof (GstRtpG711Enc), + 0, + (GInstanceInitFunc) gst_rtpg711enc_init, + }; + + rtpg711enc_type = + g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpG711Enc", + &rtpg711enc_info, 0); + } + return rtpg711enc_type; +} + +static void +gst_rtpg711enc_base_init (GstRtpG711EncClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711enc_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711enc_src_template)); + gst_element_class_set_details (element_class, &gst_rtpg711enc_details); +} + +static void +gst_rtpg711enc_class_init (GstRtpG711EncClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseRTPPayloadClass *gstbasertppayload_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD); + + gstbasertppayload_class->set_caps = gst_rtpg711enc_setcaps; + gstbasertppayload_class->handle_buffer = gst_rtpg711enc_handle_buffer; +} + +static void +gst_rtpg711enc_init (GstRtpG711Enc * rtpg711enc) +{ +} + +static gboolean +gst_rtpg711enc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) +{ + + const char *stname; + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + + stname = gst_structure_get_name (structure); + + if (0 == strcmp ("audio/x-mulaw", stname)) { + gst_basertppayload_set_options (payload, "audio", TRUE, "PCMU", 8000); + } else if (0 == strcmp ("audio/x-alaw", stname)) { + gst_basertppayload_set_options (payload, "audio", TRUE, "PCMA", 8000); + } else { + return FALSE; + } + + gst_basertppayload_set_outcaps (payload, NULL); + + return TRUE; +} + +static GstFlowReturn +gst_rtpg711enc_handle_buffer (GstBaseRTPPayload * basepayload, + GstBuffer * buffer) +{ + GstRtpG711Enc *rtpg711enc; + guint size, payload_len; + GstBuffer *outbuf; + guint8 *payload, *data; + GstClockTime timestamp; + GstFlowReturn ret; + + rtpg711enc = GST_RTP_G711_ENC (basepayload); + + size = GST_BUFFER_SIZE (buffer); + timestamp = GST_BUFFER_TIMESTAMP (buffer); + + /* FIXME, only one G711 frame per RTP packet for now */ + payload_len = size; + + outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0); + /* FIXME, assert for now */ + g_assert (GST_BUFFER_SIZE (outbuf) < GST_BASE_RTP_PAYLOAD_MTU (rtpg711enc)); + + gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND); + + /* copy timestamp */ + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + /* get payload */ + payload = gst_rtpbuffer_get_payload (outbuf); + + data = GST_BUFFER_DATA (buffer); + + /* copy data in payload */ + memcpy (&payload[0], data, size); + + gst_buffer_unref (buffer); + + ret = gst_basertppayload_push (basepayload, outbuf); + + return ret; +} + +gboolean +gst_rtpg711enc_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpg711enc", + GST_RANK_NONE, GST_TYPE_RTP_G711_ENC); +} diff --git a/gst/rtp/gstrtpg711enc.h b/gst/rtp/gstrtpg711enc.h new file mode 100644 index 0000000000..e3ab1fe5c6 --- /dev/null +++ b/gst/rtp/gstrtpg711enc.h @@ -0,0 +1,54 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + + +#ifndef __GST_RTP_G711_ENC_H__ +#define __GST_RTP_G711_ENC_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstRtpG711Enc GstRtpG711Enc; +typedef struct _GstRtpG711EncClass GstRtpG711EncClass; + +#define GST_TYPE_RTP_G711_ENC \ + (gst_rtpg711enc_get_type()) +#define GST_RTP_G711_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G711_ENC,GstRtpG711Enc)) +#define GST_RTP_G711_ENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G711_ENC,GstRtpG711Enc)) +#define GST_IS_RTP_G711_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G711_ENC)) +#define GST_IS_RTP_G711_ENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G711_ENC)) + +struct _GstRtpG711Enc +{ + GstBaseRTPPayload payload; + + gint frequency; +}; + +struct _GstRtpG711EncClass +{ + GstBaseRTPPayloadClass parent_class; +}; + +gboolean gst_rtpg711enc_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_RTP_G711_ENC_H__ */ diff --git a/gst/rtp/gstrtpg711pay.c b/gst/rtp/gstrtpg711pay.c new file mode 100644 index 0000000000..2067ffd6cc --- /dev/null +++ b/gst/rtp/gstrtpg711pay.c @@ -0,0 +1,198 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "gstrtpg711enc.h" + +/* elementfactory information */ +static GstElementDetails gst_rtpg711enc_details = { + "RTP packet parser", + "Codec/Encoder/Network", + "Encodes PCMU/PCMA audio into a RTP packet", + "Edgard Lima " +}; + +static GstStaticPadTemplate gst_rtpg711enc_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-mulaw, channels=(int)1, rate=(int)8000 ;" + "audio/x-alaw, channels=(int)1, rate=(int)8000") + ); + +static GstStaticPadTemplate gst_rtpg711enc_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 0, " + "clock-rate = (int) 8000, " + "encoding-name = (string) \"PCMU\"; " + "application/x-rtp, " + "media = (string) \"audio\", " + "payload = (int) 8, " + "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\"") + ); + + +static void gst_rtpg711enc_class_init (GstRtpG711EncClass * klass); +static void gst_rtpg711enc_base_init (GstRtpG711EncClass * klass); +static void gst_rtpg711enc_init (GstRtpG711Enc * rtpg711enc); + +static gboolean gst_rtpg711enc_setcaps (GstBaseRTPPayload * payload, + GstCaps * caps); +static GstFlowReturn gst_rtpg711enc_handle_buffer (GstBaseRTPPayload * payload, + GstBuffer * buffer); + +static GstBaseRTPPayloadClass *parent_class = NULL; + +static GType +gst_rtpg711enc_get_type (void) +{ + static GType rtpg711enc_type = 0; + + if (!rtpg711enc_type) { + static const GTypeInfo rtpg711enc_info = { + sizeof (GstRtpG711EncClass), + (GBaseInitFunc) gst_rtpg711enc_base_init, + NULL, + (GClassInitFunc) gst_rtpg711enc_class_init, + NULL, + NULL, + sizeof (GstRtpG711Enc), + 0, + (GInstanceInitFunc) gst_rtpg711enc_init, + }; + + rtpg711enc_type = + g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpG711Enc", + &rtpg711enc_info, 0); + } + return rtpg711enc_type; +} + +static void +gst_rtpg711enc_base_init (GstRtpG711EncClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711enc_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtpg711enc_src_template)); + gst_element_class_set_details (element_class, &gst_rtpg711enc_details); +} + +static void +gst_rtpg711enc_class_init (GstRtpG711EncClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseRTPPayloadClass *gstbasertppayload_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD); + + gstbasertppayload_class->set_caps = gst_rtpg711enc_setcaps; + gstbasertppayload_class->handle_buffer = gst_rtpg711enc_handle_buffer; +} + +static void +gst_rtpg711enc_init (GstRtpG711Enc * rtpg711enc) +{ +} + +static gboolean +gst_rtpg711enc_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) +{ + + const char *stname; + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + + stname = gst_structure_get_name (structure); + + if (0 == strcmp ("audio/x-mulaw", stname)) { + gst_basertppayload_set_options (payload, "audio", TRUE, "PCMU", 8000); + } else if (0 == strcmp ("audio/x-alaw", stname)) { + gst_basertppayload_set_options (payload, "audio", TRUE, "PCMA", 8000); + } else { + return FALSE; + } + + gst_basertppayload_set_outcaps (payload, NULL); + + return TRUE; +} + +static GstFlowReturn +gst_rtpg711enc_handle_buffer (GstBaseRTPPayload * basepayload, + GstBuffer * buffer) +{ + GstRtpG711Enc *rtpg711enc; + guint size, payload_len; + GstBuffer *outbuf; + guint8 *payload, *data; + GstClockTime timestamp; + GstFlowReturn ret; + + rtpg711enc = GST_RTP_G711_ENC (basepayload); + + size = GST_BUFFER_SIZE (buffer); + timestamp = GST_BUFFER_TIMESTAMP (buffer); + + /* FIXME, only one G711 frame per RTP packet for now */ + payload_len = size; + + outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0); + /* FIXME, assert for now */ + g_assert (GST_BUFFER_SIZE (outbuf) < GST_BASE_RTP_PAYLOAD_MTU (rtpg711enc)); + + gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND); + + /* copy timestamp */ + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + /* get payload */ + payload = gst_rtpbuffer_get_payload (outbuf); + + data = GST_BUFFER_DATA (buffer); + + /* copy data in payload */ + memcpy (&payload[0], data, size); + + gst_buffer_unref (buffer); + + ret = gst_basertppayload_push (basepayload, outbuf); + + return ret; +} + +gboolean +gst_rtpg711enc_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpg711enc", + GST_RANK_NONE, GST_TYPE_RTP_G711_ENC); +} diff --git a/gst/rtp/gstrtpg711pay.h b/gst/rtp/gstrtpg711pay.h new file mode 100644 index 0000000000..e3ab1fe5c6 --- /dev/null +++ b/gst/rtp/gstrtpg711pay.h @@ -0,0 +1,54 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima + * + * 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 + */ + + +#ifndef __GST_RTP_G711_ENC_H__ +#define __GST_RTP_G711_ENC_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstRtpG711Enc GstRtpG711Enc; +typedef struct _GstRtpG711EncClass GstRtpG711EncClass; + +#define GST_TYPE_RTP_G711_ENC \ + (gst_rtpg711enc_get_type()) +#define GST_RTP_G711_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G711_ENC,GstRtpG711Enc)) +#define GST_RTP_G711_ENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G711_ENC,GstRtpG711Enc)) +#define GST_IS_RTP_G711_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G711_ENC)) +#define GST_IS_RTP_G711_ENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G711_ENC)) + +struct _GstRtpG711Enc +{ + GstBaseRTPPayload payload; + + gint frequency; +}; + +struct _GstRtpG711EncClass +{ + GstBaseRTPPayloadClass parent_class; +}; + +gboolean gst_rtpg711enc_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_RTP_G711_ENC_H__ */