rtpmux: remove rtpmux plugin, moved to -good

Move rtpmux and rtpdtmfmux into rtpmanager plugin in -good.

https://bugzilla.gnome.org/show_bug.cgi?id=629117
This commit is contained in:
Tim-Philipp Müller 2012-12-16 17:35:07 +00:00
parent 7ab936fa7e
commit 02ab609c11
19 changed files with 0 additions and 1824 deletions

View file

@ -56,7 +56,6 @@ GST_PLUGINS_BAD_BUILT_SOURCES := \
gst/sdi/Android.mk \
gst/festival/Android.mk \
gst/y4m/Android.mk \
gst/rtpmux/Android.mk \
gst/pcapparse/Android.mk \
gst/nuvdemux/Android.mk \
gst/colorspace/Android.mk \
@ -148,7 +147,6 @@ CONFIGURE_TARGETS += gst-plugins-bad-configure
-include $(GST_PLUGINS_BAD_TOP)/gst/sdi/Android.mk
-include $(GST_PLUGINS_BAD_TOP)/gst/festival/Android.mk
-include $(GST_PLUGINS_BAD_TOP)/gst/y4m/Android.mk
-include $(GST_PLUGINS_BAD_TOP)/gst/rtpmux/Android.mk
-include $(GST_PLUGINS_BAD_TOP)/gst/pcapparse/Android.mk
-include $(GST_PLUGINS_BAD_TOP)/gst/nuvdemux/Android.mk
-include $(GST_PLUGINS_BAD_TOP)/gst/colorspace/Android.mk

View file

@ -377,7 +377,6 @@ AG_GST_CHECK_PLUGIN(pnm)
AG_GST_CHECK_PLUGIN(rawparse)
AG_GST_CHECK_PLUGIN(real)
AG_GST_CHECK_PLUGIN(removesilence)
AG_GST_CHECK_PLUGIN(rtpmux)
AG_GST_CHECK_PLUGIN(sdi)
AG_GST_CHECK_PLUGIN(sdp)
AG_GST_CHECK_PLUGIN(segmentclip)
@ -2120,7 +2119,6 @@ gst/pnm/Makefile
gst/rawparse/Makefile
gst/real/Makefile
gst/removesilence/Makefile
gst/rtpmux/Makefile
gst/sdi/Makefile
gst/sdp/Makefile
gst/segmentclip/Makefile

View file

@ -164,8 +164,6 @@ EXTRA_HFILES = \
$(top_srcdir)/gst/pcapparse/gstpcapparse.h \
$(top_srcdir)/gst/rawparse/gstaudioparse.h \
$(top_srcdir)/gst/rawparse/gstvideoparse.h \
$(top_srcdir)/gst/rtpmux/gstrtpmux.h \
$(top_srcdir)/gst/rtpmux/gstrtpdtmfmux.h \
$(top_srcdir)/gst/sdp/gstsdpdemux.h \
$(top_srcdir)/gst/speed/gstspeed.h \
$(top_srcdir)/gst/stereo/gststereo.h \

View file

@ -71,10 +71,7 @@
<xi:include href="xml/element-pyramidsegment.xml" />
<xi:include href="xml/element-rtmpsink.xml" />
<xi:include href="xml/element-rtmpsrc.xml" />
<xi:include href="xml/element-rtpmux.xml" />
<xi:include href="xml/element-rtpdtmfsrc.xml" />
<xi:include href="xml/element-rtpdtmfmux.xml" />
<xi:include href="xml/element-rtpmux.xml" />
<xi:include href="xml/element-shmsink.xml" />
<xi:include href="xml/element-shmsrc.xml" />
<xi:include href="xml/element-sdpdemux.xml" />
@ -135,7 +132,6 @@
<xi:include href="xml/plugin-pcapparse.xml" />
<xi:include href="xml/plugin-rawparse.xml" />
<xi:include href="xml/plugin-rtmp.xml" />
<xi:include href="xml/plugin-rtpmux.xml" />
<xi:include href="xml/plugin-sdp.xml" />
<xi:include href="xml/plugin-shm.xml" />
<xi:include href="xml/plugin-soundtouch.xml" />

View file

@ -1187,21 +1187,6 @@ GST_RTP_DTMF_DEPAY_CLASS
gst_rtp_dtmf_depay_plugin_init
</SECTION>
<SECTION>
<FILE>element-rtpdtmfmux</FILE>
<TITLE>rtpdtmfmux</TITLE>
GstRTPDTMFMux
<SUBSECTION Standard>
GST_IS_RTP_DTMF_MUX
GST_IS_RTP_DTMF_MUX_CLASS
GST_TYPE_RTP_DTMF_MUX
GstRTPDTMFMuxClass
GST_RTP_DTMF_MUX
GST_RTP_DTMF_MUX_CLASS
gst_rtp_dtmf_mux_get_type
gst_rtp_dtmf_mux_plugin_init
</SECTION>
<SECTION>
<FILE>element-rtpdtmfsrc</FILE>
<TITLE>rtpdtmfsrc</TITLE>
@ -1222,22 +1207,6 @@ GstRTPDTMFSrcEvent
GstRTPDTMFEventType
</SECTION>
<SECTION>
<FILE>element-rtpmux</FILE>
<TITLE>rtpmux</TITLE>
GstRTPMux
<SUBSECTION Standard>
GST_IS_RTP_MUX
GST_IS_RTP_MUX_CLASS
GST_RTP_MUX
GST_RTP_MUX_CLASS
GST_RTP_MUX_GET_CLASS
GST_TYPE_RTP_MUX
GstRTPMuxClass
gst_rtp_mux_get_type
gst_rtp_mux_plugin_init
</SECTION>
<SECTION>
<FILE>element-sdlaudiosink</FILE>
<TITLE>sdlaudiosink</TITLE>

View file

@ -23653,46 +23653,6 @@
<DEFAULT>60</DEFAULT>
</ARG>
<ARG>
<NAME>GstRTPMux::seqnum</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>r</FLAGS>
<NICK>Sequence number</NICK>
<BLURB>The RTP sequence number of the last processed packet.</BLURB>
<DEFAULT>0</DEFAULT>
</ARG>
<ARG>
<NAME>GstRTPMux::seqnum-offset</NAME>
<TYPE>gint</TYPE>
<RANGE>>= G_MAXULONG</RANGE>
<FLAGS>rw</FLAGS>
<NICK>Sequence number Offset</NICK>
<BLURB>Offset to add to all outgoing seqnum (-1 = random).</BLURB>
<DEFAULT>-1</DEFAULT>
</ARG>
<ARG>
<NAME>GstRTPMux::ssrc</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SSRC</NICK>
<BLURB>The SSRC of the packets (-1 == random).</BLURB>
<DEFAULT>4294967295</DEFAULT>
</ARG>
<ARG>
<NAME>GstRTPMux::timestamp-offset</NAME>
<TYPE>gint</TYPE>
<RANGE>>= G_MAXULONG</RANGE>
<FLAGS>rw</FLAGS>
<NICK>Timestamp Offset</NICK>
<BLURB>Offset to add to all outgoing timestamps (-1 = random).</BLURB>
<DEFAULT>-1</DEFAULT>
</ARG>
<ARG>
<NAME>GstAutoConvert::factories</NAME>
<TYPE>gpointer</TYPE>

View file

@ -208,8 +208,6 @@ GObject
GstRtpAsfPay
GstRtpOPUSPay
GstRtpVP8Pay
GstRTPMux
GstRTPDTMFMux
GstRawParse
GstAudioParse
GstVideoParse

View file

@ -184,22 +184,6 @@ GstCameraBin *gstcamerabin
GstCameraBin *gstcamerabin
</SIGNAL>
<SIGNAL>
<NAME>GstRTPDTMFMux::locking</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRTPDTMFMux *gstrtpdtmfmux
GstPad *arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRTPDTMFMux::unlocked</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRTPDTMFMux *gstrtpdtmfmux
GstPad *arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::clear-pt-map</NAME>
<RETURNS>void</RETURNS>

View file

@ -1,61 +0,0 @@
<plugin>
<name>rtpmux</name>
<description>RTP Muxer plugins</description>
<filename>../../gst/rtpmux/.libs/libgstrtpmux.so</filename>
<basename>libgstrtpmux.so</basename>
<version>1.1.0.1</version>
<license>LGPL</license>
<source>gst-plugins-bad</source>
<package>GStreamer Bad Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>
<name>rtpdtmfmux</name>
<longname>RTP muxer</longname>
<class>Codec/Muxer</class>
<description>mixes RTP DTMF streams into other RTP streams</description>
<author>Zeeshan Ali &lt;first.last@nokia.com&gt;</author>
<pads>
<caps>
<name>priority_sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
<element>
<name>rtpmux</name>
<longname>RTP muxer</longname>
<class>Codec/Muxer</class>
<description>multiplex N rtp streams into one</description>
<author>Zeeshan Ali &lt;first.last@nokia.com&gt;</author>
<pads>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
</elements>
</plugin>

View file

@ -230,7 +230,6 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS=''
%{_libdir}/gstreamer-%{majorminor}/libgstpcapparse.so
%{_libdir}/gstreamer-%{majorminor}/libgstpnm.so
# %{_libdir}/gstreamer-%{majorminor}/libgstrfbsrc.so
%{_libdir}/gstreamer-%{majorminor}/libgstrtpmux.so
%{_libdir}/gstreamer-%{majorminor}/libgstsegmentclip.so
%{_libdir}/gstreamer-%{majorminor}/libgstrawparse.so
%{_libdir}/gstreamer-%{majorminor}/libgstshm.so

View file

@ -1,25 +0,0 @@
plugin_LTLIBRARIES = libgstrtpmux.la
libgstrtpmux_la_SOURCES = gstrtpmuxer.c gstrtpmux.c gstrtpdtmfmux.c
libgstrtpmux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstrtpmux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_API_VERSION@ \
$(GST_BASE_LIBS) $(GST_LIBS)
libgstrtpmux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstrtpmux_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstrtpmux.h gstrtpdtmfmux.h
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
-:PROJECT libgstrtpmux -:SHARED libgstrtpmux \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstrtpmux_la_SOURCES) \
-:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstrtpmux_la_CFLAGS) \
-:LDFLAGS $(libgstrtpmux_la_LDFLAGS) \
$(libgstrtpmux_la_LIBADD) \
-ldl \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-@GST_API_VERSION@' \
> $@

View file

@ -1,233 +0,0 @@
/* RTP DTMF muxer element for GStreamer
*
* gstrtpdtmfmux.c:
*
* Copyright (C) <2007-2010> Nokia Corporation.
* Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
* Copyright (C) <2007-2010> Collabora Ltd
* Contact: Olivier Crete <olivier.crete@collabora.co.uk>
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* 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-rtpdtmfmux
* @see_also: rtpdtmfsrc, dtmfsrc, rtpmux
*
* The RTP "DTMF" Muxer muxes multiple RTP streams into a valid RTP
* stream. It does exactly what it's parent (#rtpmux) does, except
* that it prevent buffers coming over a regular sink_%%u pad from going through
* for the duration of buffers that came in a priority_sink_%%u pad.
*
* This is especially useful if a discontinuous source like dtmfsrc or
* rtpdtmfsrc are connected to the priority sink pads. This way, the generated
* DTMF signal can replace the recorded audio while the tone is being sent.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <string.h>
#include "gstrtpdtmfmux.h"
GST_DEBUG_CATEGORY_STATIC (gst_rtp_dtmf_mux_debug);
#define GST_CAT_DEFAULT gst_rtp_dtmf_mux_debug
static GstStaticPadTemplate priority_sink_factory =
GST_STATIC_PAD_TEMPLATE ("priority_sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtp"));
static GstPad *gst_rtp_dtmf_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static GstStateChangeReturn gst_rtp_dtmf_mux_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer);
static gboolean gst_rtp_dtmf_mux_src_event (GstRTPMux * rtp_mux,
GstEvent * event);
G_DEFINE_TYPE (GstRTPDTMFMux, gst_rtp_dtmf_mux, GST_TYPE_RTP_MUX);
static void
gst_rtp_dtmf_mux_init (GstRTPDTMFMux * mux)
{
}
static void
gst_rtp_dtmf_mux_class_init (GstRTPDTMFMuxClass * klass)
{
GstElementClass *gstelement_class;
GstRTPMuxClass *gstrtpmux_class;
gstelement_class = (GstElementClass *) klass;
gstrtpmux_class = (GstRTPMuxClass *) klass;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&priority_sink_factory));
gst_element_class_set_static_metadata (gstelement_class, "RTP muxer",
"Codec/Muxer",
"mixes RTP DTMF streams into other RTP streams",
"Zeeshan Ali <first.last@nokia.com>");
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_request_new_pad);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_dtmf_mux_change_state);
gstrtpmux_class->accept_buffer_locked = gst_rtp_dtmf_mux_accept_buffer_locked;
gstrtpmux_class->src_event = gst_rtp_dtmf_mux_src_event;
}
static gboolean
gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux,
GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer)
{
GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (rtp_mux);
GstClockTime running_ts;
running_ts = GST_BUFFER_PTS (rtpbuffer->buffer);
if (GST_CLOCK_TIME_IS_VALID (running_ts)) {
if (padpriv && padpriv->segment.format == GST_FORMAT_TIME)
running_ts = gst_segment_to_running_time (&padpriv->segment,
GST_FORMAT_TIME, GST_BUFFER_PTS (rtpbuffer->buffer));
if (padpriv && padpriv->priority) {
if (GST_BUFFER_PTS_IS_VALID (rtpbuffer->buffer)) {
if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end))
mux->last_priority_end =
MAX (running_ts + GST_BUFFER_DURATION (rtpbuffer->buffer),
mux->last_priority_end);
else
mux->last_priority_end = running_ts +
GST_BUFFER_DURATION (rtpbuffer->buffer);
GST_LOG_OBJECT (mux, "Got buffer %p on priority pad, "
" blocking regular pads until %" GST_TIME_FORMAT, rtpbuffer->buffer,
GST_TIME_ARGS (mux->last_priority_end));
} else {
GST_WARNING_OBJECT (mux, "Buffer %p has an invalid duration,"
" not blocking other pad", rtpbuffer->buffer);
}
} else {
if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end) &&
running_ts < mux->last_priority_end) {
GST_LOG_OBJECT (mux, "Dropping buffer %p because running time"
" %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT, rtpbuffer->buffer,
GST_TIME_ARGS (running_ts), GST_TIME_ARGS (mux->last_priority_end));
return FALSE;
}
}
} else {
GST_LOG_OBJECT (mux, "Buffer %p has an invalid timestamp,"
" letting through", rtpbuffer->buffer);
}
return TRUE;
}
static GstPad *
gst_rtp_dtmf_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * name, const GstCaps * caps)
{
GstPad *pad;
pad =
GST_ELEMENT_CLASS (gst_rtp_dtmf_mux_parent_class)->request_new_pad
(element, templ, name, caps);
if (pad) {
GstRTPMuxPadPrivate *padpriv;
GST_OBJECT_LOCK (element);
padpriv = gst_pad_get_element_private (pad);
if (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element),
"priority_sink_%u") == gst_pad_get_pad_template (pad))
padpriv->priority = TRUE;
GST_OBJECT_UNLOCK (element);
}
return pad;
}
static gboolean
gst_rtp_dtmf_mux_src_event (GstRTPMux * rtp_mux, GstEvent * event)
{
if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) {
const GstStructure *s = gst_event_get_structure (event);
if (s && gst_structure_has_name (s, "dtmf-event")) {
GST_OBJECT_LOCK (rtp_mux);
if (GST_CLOCK_TIME_IS_VALID (rtp_mux->last_stop)) {
event = (GstEvent *)
gst_mini_object_make_writable (GST_MINI_OBJECT_CAST (event));
s = gst_event_get_structure (event);
gst_structure_set ((GstStructure *) s,
"last-stop", G_TYPE_UINT64, rtp_mux->last_stop, NULL);
}
GST_OBJECT_UNLOCK (rtp_mux);
}
}
return GST_RTP_MUX_CLASS (gst_rtp_dtmf_mux_parent_class)->src_event (rtp_mux,
event);
}
static GstStateChangeReturn
gst_rtp_dtmf_mux_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
{
GST_OBJECT_LOCK (mux);
mux->last_priority_end = GST_CLOCK_TIME_NONE;
GST_OBJECT_UNLOCK (mux);
break;
}
default:
break;
}
ret =
GST_ELEMENT_CLASS (gst_rtp_dtmf_mux_parent_class)->change_state (element,
transition);
return ret;
}
gboolean
gst_rtp_dtmf_mux_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_rtp_dtmf_mux_debug, "rtpdtmfmux", 0,
"rtp dtmf muxer");
return gst_element_register (plugin, "rtpdtmfmux", GST_RANK_NONE,
GST_TYPE_RTP_DTMF_MUX);
}

View file

@ -1,67 +0,0 @@
/* RTP muxer element for GStreamer
*
* gstrtpdtmfmux.h:
*
* Copyright (C) <2007> Nokia Corporation.
* Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* 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_DTMF_MUX_H__
#define __GST_RTP_DTMF_MUX_H__
#include <gst/gst.h>
#include "gstrtpmux.h"
G_BEGIN_DECLS
#define GST_TYPE_RTP_DTMF_MUX (gst_rtp_dtmf_mux_get_type())
#define GST_RTP_DTMF_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DTMF_MUX, GstRTPDTMFMux))
#define GST_RTP_DTMF_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DTMF_MUX, GstRTPDTMFMux))
#define GST_IS_RTP_DTMF_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DTMF_MUX))
#define GST_IS_RTP_DTMF_MUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DTMF_MUX))
typedef struct _GstRTPDTMFMux GstRTPDTMFMux;
typedef struct _GstRTPDTMFMuxClass GstRTPDTMFMuxClass;
/**
* GstRTPDTMFMux:
*
* The opaque #GstRTPDTMFMux structure.
*/
struct _GstRTPDTMFMux
{
GstRTPMux mux;
/* Protected by object lock */
GstClockTime last_priority_end;
};
struct _GstRTPDTMFMuxClass
{
GstRTPMuxClass parent_class;
/* signals */
void (*locking) (GstElement * element, GstPad * pad);
void (*unlocked) (GstElement * element, GstPad * pad);
};
GType gst_rtp_dtmf_mux_get_type (void);
gboolean gst_rtp_dtmf_mux_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_RTP_DTMF_MUX_H__ */

View file

@ -1,879 +0,0 @@
/* RTP muxer element for GStreamer
*
* gstrtpmux.c:
*
* Copyright (C) <2007-2010> Nokia Corporation.
* Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
* Copyright (C) <2007-2010> Collabora Ltd
* Contact: Olivier Crete <olivier.crete@collabora.co.uk>
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* 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-rtpmux
* @see_also: rtpdtmfmux
*
* The rtp muxer takes multiple RTP streams having the same clock-rate and
* muxes into a single stream with a single SSRC.
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch rtpmux name=mux ! udpsink host=127.0.0.1 port=8888 \
* alsasrc ! alawenc ! rtppcmapay ! \
* application/x-rtp, payload=8, rate=8000 ! mux.sink_0 \
* audiotestsrc is-live=1 ! \
* mulawenc ! rtppcmupay ! \
* application/x-rtp, payload=0, rate=8000 ! mux.sink_1
* ]|
* In this example, an audio stream is captured from ALSA and another is
* generated, both are encoded into different payload types and muxed together
* so they can be sent on the same port.
* </refsect2>
*
* Last reviewed on 2010-09-30 (0.10.21)
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <string.h>
#include "gstrtpmux.h"
GST_DEBUG_CATEGORY_STATIC (gst_rtp_mux_debug);
#define GST_CAT_DEFAULT gst_rtp_mux_debug
enum
{
ARG_0,
PROP_TIMESTAMP_OFFSET,
PROP_SEQNUM_OFFSET,
PROP_SEQNUM,
PROP_SSRC
};
#define DEFAULT_TIMESTAMP_OFFSET -1
#define DEFAULT_SEQNUM_OFFSET -1
#define DEFAULT_SSRC -1
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp")
);
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtp")
);
static GstPad *gst_rtp_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_rtp_mux_release_pad (GstElement * element, GstPad * pad);
static GstFlowReturn gst_rtp_mux_chain (GstPad * pad, GstObject * parent,
GstBuffer * buffer);
static GstFlowReturn gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
GstBufferList * bufferlist);
static gboolean gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux,
GstCaps * caps);
static gboolean gst_rtp_mux_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static gboolean gst_rtp_mux_sink_query (GstPad * pad, GstObject * parent,
GstQuery * query);
static GstStateChangeReturn gst_rtp_mux_change_state (GstElement *
element, GstStateChange transition);
static void gst_rtp_mux_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_rtp_mux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_rtp_mux_dispose (GObject * object);
static gboolean gst_rtp_mux_src_event_real (GstRTPMux * rtp_mux,
GstEvent * event);
G_DEFINE_TYPE (GstRTPMux, gst_rtp_mux, GST_TYPE_ELEMENT);
static void
gst_rtp_mux_class_init (GstRTPMuxClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_static_metadata (gstelement_class, "RTP muxer",
"Codec/Muxer",
"multiplex N rtp streams into one", "Zeeshan Ali <first.last@nokia.com>");
gobject_class->get_property = gst_rtp_mux_get_property;
gobject_class->set_property = gst_rtp_mux_set_property;
gobject_class->dispose = gst_rtp_mux_dispose;
klass->src_event = gst_rtp_mux_src_event_real;
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_TIMESTAMP_OFFSET, g_param_spec_int ("timestamp-offset",
"Timestamp Offset",
"Offset to add to all outgoing timestamps (-1 = random)", -1,
G_MAXINT, DEFAULT_TIMESTAMP_OFFSET,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
g_param_spec_int ("seqnum-offset", "Sequence number Offset",
"Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXINT,
DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
g_param_spec_uint ("seqnum", "Sequence number",
"The RTP sequence number of the last processed packet",
0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
g_param_spec_uint ("ssrc", "SSRC",
"The SSRC of the packets (-1 == random)",
0, G_MAXUINT, DEFAULT_SSRC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_rtp_mux_request_new_pad);
gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_mux_release_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_mux_change_state);
}
static void
gst_rtp_mux_dispose (GObject * object)
{
GstRTPMux *rtp_mux = GST_RTP_MUX (object);
GList *item;
g_clear_object (&rtp_mux->last_pad);
restart:
for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
GstPad *pad = GST_PAD (item->data);
if (GST_PAD_IS_SINK (pad)) {
gst_element_release_request_pad (GST_ELEMENT (object), pad);
goto restart;
}
}
G_OBJECT_CLASS (gst_rtp_mux_parent_class)->dispose (object);
}
static gboolean
gst_rtp_mux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstRTPMux *rtp_mux = GST_RTP_MUX (parent);
GstRTPMuxClass *klass;
gboolean ret = FALSE;
klass = GST_RTP_MUX_GET_CLASS (rtp_mux);
ret = klass->src_event (rtp_mux, event);
return ret;
}
static gboolean
gst_rtp_mux_src_event_real (GstRTPMux * rtp_mux, GstEvent * event)
{
GstIterator *iter;
gboolean result = FALSE;
gboolean done = FALSE;
iter = gst_element_iterate_sink_pads (GST_ELEMENT (rtp_mux));
while (!done) {
GValue item = { 0, };
switch (gst_iterator_next (iter, &item)) {
case GST_ITERATOR_OK:
gst_event_ref (event);
result |= gst_pad_push_event (g_value_get_object (&item), event);
g_value_reset (&item);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (iter);
result = FALSE;
break;
case GST_ITERATOR_ERROR:
GST_WARNING_OBJECT (rtp_mux, "Error iterating sinkpads");
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (iter);
gst_event_unref (event);
return result;
}
static void
gst_rtp_mux_init (GstRTPMux * rtp_mux)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (rtp_mux);
rtp_mux->srcpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"src"), "src");
gst_pad_set_event_function (rtp_mux->srcpad,
GST_DEBUG_FUNCPTR (gst_rtp_mux_src_event));
gst_element_add_pad (GST_ELEMENT (rtp_mux), rtp_mux->srcpad);
rtp_mux->ssrc = DEFAULT_SSRC;
rtp_mux->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
rtp_mux->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
}
static void
gst_rtp_mux_setup_sinkpad (GstRTPMux * rtp_mux, GstPad * sinkpad)
{
GstRTPMuxPadPrivate *padpriv = g_slice_new0 (GstRTPMuxPadPrivate);
/* setup some pad functions */
gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (gst_rtp_mux_chain));
gst_pad_set_chain_list_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_rtp_mux_chain_list));
gst_pad_set_event_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_rtp_mux_sink_event));
gst_pad_set_query_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_rtp_mux_sink_query));
gst_segment_init (&padpriv->segment, GST_FORMAT_UNDEFINED);
gst_pad_set_element_private (sinkpad, padpriv);
gst_pad_set_active (sinkpad, TRUE);
gst_element_add_pad (GST_ELEMENT (rtp_mux), sinkpad);
}
static GstPad *
gst_rtp_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
{
GstRTPMux *rtp_mux;
GstPad *newpad;
g_return_val_if_fail (templ != NULL, NULL);
g_return_val_if_fail (GST_IS_RTP_MUX (element), NULL);
rtp_mux = GST_RTP_MUX (element);
if (templ->direction != GST_PAD_SINK) {
GST_WARNING_OBJECT (rtp_mux, "request pad that is not a SINK pad");
return NULL;
}
newpad = gst_pad_new_from_template (templ, req_name);
if (newpad)
gst_rtp_mux_setup_sinkpad (rtp_mux, newpad);
else
GST_WARNING_OBJECT (rtp_mux, "failed to create request pad");
return newpad;
}
static void
gst_rtp_mux_release_pad (GstElement * element, GstPad * pad)
{
GstRTPMuxPadPrivate *padpriv;
GST_OBJECT_LOCK (element);
padpriv = gst_pad_get_element_private (pad);
gst_pad_set_element_private (pad, NULL);
GST_OBJECT_UNLOCK (element);
gst_element_remove_pad (element, pad);
if (padpriv) {
g_slice_free (GstRTPMuxPadPrivate, padpriv);
}
}
/* Put our own clock-base on the buffer */
static void
gst_rtp_mux_readjust_rtp_timestamp_locked (GstRTPMux * rtp_mux,
GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer)
{
guint32 ts;
guint32 sink_ts_base = 0;
if (padpriv && padpriv->have_clock_base)
sink_ts_base = padpriv->clock_base;
ts = gst_rtp_buffer_get_timestamp (rtpbuffer) - sink_ts_base +
rtp_mux->ts_base;
GST_LOG_OBJECT (rtp_mux, "Re-adjusting RTP ts %u to %u",
gst_rtp_buffer_get_timestamp (rtpbuffer), ts);
gst_rtp_buffer_set_timestamp (rtpbuffer, ts);
}
static gboolean
process_buffer_locked (GstRTPMux * rtp_mux, GstRTPMuxPadPrivate * padpriv,
GstRTPBuffer * rtpbuffer)
{
GstRTPMuxClass *klass = GST_RTP_MUX_GET_CLASS (rtp_mux);
if (klass->accept_buffer_locked)
if (!klass->accept_buffer_locked (rtp_mux, padpriv, rtpbuffer))
return FALSE;
rtp_mux->seqnum++;
gst_rtp_buffer_set_seq (rtpbuffer, rtp_mux->seqnum);
gst_rtp_buffer_set_ssrc (rtpbuffer, rtp_mux->current_ssrc);
gst_rtp_mux_readjust_rtp_timestamp_locked (rtp_mux, padpriv, rtpbuffer);
GST_LOG_OBJECT (rtp_mux,
"Pushing packet size %" G_GSIZE_FORMAT ", seq=%d, ts=%u",
rtpbuffer->map[0].size, rtp_mux->seqnum,
gst_rtp_buffer_get_timestamp (rtpbuffer));
if (padpriv) {
if (padpriv->segment.format == GST_FORMAT_TIME)
GST_BUFFER_PTS (rtpbuffer->buffer) =
gst_segment_to_running_time (&padpriv->segment, GST_FORMAT_TIME,
GST_BUFFER_PTS (rtpbuffer->buffer));
}
return TRUE;
}
struct BufferListData
{
GstRTPMux *rtp_mux;
GstRTPMuxPadPrivate *padpriv;
gboolean drop;
};
static gboolean
process_list_item (GstBuffer ** buffer, guint idx, gpointer user_data)
{
struct BufferListData *bd = user_data;
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
*buffer = gst_buffer_make_writable (*buffer);
gst_rtp_buffer_map (*buffer, GST_MAP_READWRITE, &rtpbuffer);
bd->drop = !process_buffer_locked (bd->rtp_mux, bd->padpriv, &rtpbuffer);
gst_rtp_buffer_unmap (&rtpbuffer);
if (bd->drop)
return FALSE;
if (GST_BUFFER_DURATION_IS_VALID (*buffer) &&
GST_BUFFER_TIMESTAMP_IS_VALID (*buffer))
bd->rtp_mux->last_stop = GST_BUFFER_TIMESTAMP (*buffer) +
GST_BUFFER_DURATION (*buffer);
else
bd->rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
return TRUE;
}
static GstFlowReturn
gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
GstBufferList * bufferlist)
{
GstRTPMux *rtp_mux;
GstFlowReturn ret;
GstRTPMuxPadPrivate *padpriv;
gboolean drop = TRUE;
struct BufferListData bd;
rtp_mux = GST_RTP_MUX (parent);
GST_OBJECT_LOCK (rtp_mux);
padpriv = gst_pad_get_element_private (pad);
if (!padpriv) {
GST_OBJECT_UNLOCK (rtp_mux);
ret = GST_FLOW_NOT_LINKED;
gst_buffer_list_unref (bufferlist);
goto out;
}
bd.rtp_mux = rtp_mux;
bd.padpriv = padpriv;
bd.drop = FALSE;
bufferlist = gst_buffer_list_make_writable (bufferlist);
gst_buffer_list_foreach (bufferlist, process_list_item, &bd);
GST_OBJECT_UNLOCK (rtp_mux);
if (drop) {
gst_buffer_list_unref (bufferlist);
ret = GST_FLOW_OK;
} else {
ret = gst_pad_push_list (rtp_mux->srcpad, bufferlist);
}
out:
return ret;
}
static gboolean
resend_events (GstPad * pad, GstEvent ** event, gpointer user_data)
{
GstRTPMux *rtp_mux = user_data;
if (GST_EVENT_TYPE (*event) == GST_EVENT_CAPS) {
GstCaps *caps;
gst_event_parse_caps (*event, &caps);
gst_rtp_mux_setcaps (pad, rtp_mux, caps);
} else {
gst_pad_push_event (rtp_mux->srcpad, gst_event_ref (*event));
}
return TRUE;
}
static GstFlowReturn
gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
GstRTPMux *rtp_mux;
GstFlowReturn ret;
GstRTPMuxPadPrivate *padpriv;
gboolean drop;
gboolean changed = FALSE;
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
rtp_mux = GST_RTP_MUX (GST_OBJECT_PARENT (pad));
GST_OBJECT_LOCK (rtp_mux);
padpriv = gst_pad_get_element_private (pad);
if (!padpriv) {
GST_OBJECT_UNLOCK (rtp_mux);
gst_buffer_unref (buffer);
return GST_FLOW_NOT_LINKED;
}
buffer = gst_buffer_make_writable (buffer);
if (!gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtpbuffer)) {
GST_OBJECT_UNLOCK (rtp_mux);
gst_buffer_unref (buffer);
GST_ERROR_OBJECT (rtp_mux, "Invalid RTP buffer");
return GST_FLOW_ERROR;
}
drop = !process_buffer_locked (rtp_mux, padpriv, &rtpbuffer);
gst_rtp_buffer_unmap (&rtpbuffer);
if (!drop) {
if (pad != rtp_mux->last_pad) {
changed = TRUE;
g_clear_object (&rtp_mux->last_pad);
rtp_mux->last_pad = g_object_ref (pad);
}
if (GST_BUFFER_DURATION_IS_VALID (buffer) &&
GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
rtp_mux->last_stop = GST_BUFFER_TIMESTAMP (buffer) +
GST_BUFFER_DURATION (buffer);
else
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
}
GST_OBJECT_UNLOCK (rtp_mux);
if (changed)
gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux);
if (drop) {
gst_buffer_unref (buffer);
ret = GST_FLOW_OK;
} else {
ret = gst_pad_push (rtp_mux->srcpad, buffer);
}
return ret;
}
static gboolean
gst_rtp_mux_setcaps (GstPad * pad, GstRTPMux * rtp_mux, GstCaps * caps)
{
GstStructure *structure;
gboolean ret = FALSE;
GstRTPMuxPadPrivate *padpriv;
structure = gst_caps_get_structure (caps, 0);
if (!structure)
return FALSE;
GST_OBJECT_LOCK (rtp_mux);
padpriv = gst_pad_get_element_private (pad);
if (padpriv &&
gst_structure_get_uint (structure, "clock-base", &padpriv->clock_base)) {
padpriv->have_clock_base = TRUE;
}
GST_OBJECT_UNLOCK (rtp_mux);
caps = gst_caps_copy (caps);
gst_caps_set_simple (caps,
"clock-base", G_TYPE_UINT, rtp_mux->ts_base,
"seqnum-base", G_TYPE_UINT, rtp_mux->seqnum_base, NULL);
GST_DEBUG_OBJECT (rtp_mux,
"setting caps %" GST_PTR_FORMAT " on src pad..", caps);
ret = gst_pad_set_caps (rtp_mux->srcpad, caps);
if (rtp_mux->ssrc == -1) {
if (gst_structure_has_field_typed (structure, "ssrc", G_TYPE_UINT)) {
rtp_mux->current_ssrc = g_value_get_uint
(gst_structure_get_value (structure, "ssrc"));
}
}
gst_caps_unref (caps);
return ret;
}
static void
clear_caps (GstCaps * caps, gboolean only_clock_rate)
{
gint i, j;
/* Lets only match on the clock-rate */
for (i = 0; i < gst_caps_get_size (caps); i++) {
GstStructure *s = gst_caps_get_structure (caps, i);
for (j = 0; j < gst_structure_n_fields (s); j++) {
const gchar *name = gst_structure_nth_field_name (s, j);
if (strcmp (name, "clock-rate") && (only_clock_rate ||
(strcmp (name, "ssrc")))) {
gst_structure_remove_field (s, name);
j--;
}
}
}
}
static gboolean
same_clock_rate_fold (const GValue * item, GValue * ret, gpointer user_data)
{
GstPad *mypad = user_data;
GstPad *pad = g_value_get_object (item);
GstCaps *peercaps;
GstCaps *accumcaps;
GstCaps *intersect;
if (pad == mypad)
return TRUE;
accumcaps = g_value_get_boxed (ret);
peercaps = gst_pad_peer_query_caps (pad, accumcaps);
if (!peercaps) {
g_warning ("no peercaps");
return TRUE;
}
peercaps = gst_caps_make_writable (peercaps);
clear_caps (peercaps, TRUE);
intersect = gst_caps_intersect (accumcaps, peercaps);
g_value_take_boxed (ret, intersect);
gst_caps_unref (peercaps);
return !gst_caps_is_empty (intersect);
}
static GstCaps *
gst_rtp_mux_getcaps (GstPad * pad, GstRTPMux * mux, GstCaps * filter)
{
GstCaps *caps = NULL;
GstIterator *iter = NULL;
GValue v = { 0 };
GstIteratorResult res;
GstCaps *peercaps;
GstCaps *othercaps = NULL;
GstCaps *filtered_caps;
peercaps = gst_pad_peer_query_caps (mux->srcpad, filter);
if (peercaps) {
othercaps = gst_caps_intersect (peercaps,
gst_pad_get_pad_template_caps (pad));
gst_caps_unref (peercaps);
} else {
othercaps = gst_caps_copy (gst_pad_get_pad_template_caps (mux->srcpad));
}
if (filter) {
filtered_caps = gst_caps_intersect (othercaps, filter);
gst_caps_unref (othercaps);
} else {
filtered_caps = othercaps;
}
filtered_caps = gst_caps_make_writable (filtered_caps);
clear_caps (filtered_caps, FALSE);
g_value_init (&v, GST_TYPE_CAPS);
iter = gst_element_iterate_sink_pads (GST_ELEMENT (mux));
do {
gst_value_set_caps (&v, filtered_caps);
res = gst_iterator_fold (iter, same_clock_rate_fold, &v, pad);
gst_iterator_resync (iter);
} while (res == GST_ITERATOR_RESYNC);
gst_iterator_free (iter);
caps = (GstCaps *) gst_value_get_caps (&v);
if (res == GST_ITERATOR_ERROR) {
gst_caps_unref (caps);
caps = gst_caps_new_empty ();
}
gst_caps_unref (filtered_caps);
return caps;
}
static gboolean
gst_rtp_mux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstRTPMux *mux = GST_RTP_MUX (parent);
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:
{
GstCaps *filter, *caps;
gst_query_parse_caps (query, &filter);
caps = gst_rtp_mux_getcaps (pad, mux, filter);
gst_query_set_caps_result (query, caps);
gst_caps_unref (caps);
res = TRUE;
break;
}
default:
res = gst_pad_query_default (pad, parent, query);
break;
}
return res;
}
static void
gst_rtp_mux_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstRTPMux *rtp_mux;
rtp_mux = GST_RTP_MUX (object);
switch (prop_id) {
case PROP_TIMESTAMP_OFFSET:
g_value_set_int (value, rtp_mux->ts_offset);
break;
case PROP_SEQNUM_OFFSET:
g_value_set_int (value, rtp_mux->seqnum_offset);
break;
case PROP_SEQNUM:
GST_OBJECT_LOCK (rtp_mux);
g_value_set_uint (value, rtp_mux->seqnum);
GST_OBJECT_UNLOCK (rtp_mux);
break;
case PROP_SSRC:
g_value_set_uint (value, rtp_mux->ssrc);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_rtp_mux_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstRTPMux *rtp_mux;
rtp_mux = GST_RTP_MUX (object);
switch (prop_id) {
case PROP_TIMESTAMP_OFFSET:
rtp_mux->ts_offset = g_value_get_int (value);
break;
case PROP_SEQNUM_OFFSET:
rtp_mux->seqnum_offset = g_value_get_int (value);
break;
case PROP_SSRC:
rtp_mux->ssrc = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_rtp_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstRTPMux *mux = GST_RTP_MUX (parent);
gboolean is_pad;
gboolean ret;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
GstCaps *caps;
gst_event_parse_caps (event, &caps);
ret = gst_rtp_mux_setcaps (pad, mux, caps);
gst_event_unref (event);
return ret;
}
case GST_EVENT_FLUSH_STOP:
{
GST_OBJECT_LOCK (mux);
mux->last_stop = GST_CLOCK_TIME_NONE;
GST_OBJECT_UNLOCK (mux);
break;
}
case GST_EVENT_SEGMENT:
{
GstRTPMuxPadPrivate *padpriv;
GST_OBJECT_LOCK (mux);
padpriv = gst_pad_get_element_private (pad);
if (padpriv) {
gst_event_copy_segment (event, &padpriv->segment);
}
GST_OBJECT_UNLOCK (mux);
break;
}
default:
break;
}
GST_OBJECT_LOCK (mux);
is_pad = (pad == mux->last_pad);
GST_OBJECT_UNLOCK (mux);
if (is_pad) {
return gst_pad_push_event (mux->srcpad, event);
} else {
gst_event_unref (event);
return TRUE;
}
}
static void
gst_rtp_mux_ready_to_paused (GstRTPMux * rtp_mux)
{
GST_OBJECT_LOCK (rtp_mux);
g_clear_object (&rtp_mux->last_pad);
if (rtp_mux->ssrc == -1)
rtp_mux->current_ssrc = g_random_int ();
else
rtp_mux->current_ssrc = rtp_mux->ssrc;
if (rtp_mux->seqnum_offset == -1)
rtp_mux->seqnum_base = g_random_int_range (0, G_MAXUINT16);
else
rtp_mux->seqnum_base = rtp_mux->seqnum_offset;
rtp_mux->seqnum = rtp_mux->seqnum_base;
if (rtp_mux->ts_offset == -1)
rtp_mux->ts_base = g_random_int ();
else
rtp_mux->ts_base = rtp_mux->ts_offset;
rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
GST_DEBUG_OBJECT (rtp_mux, "set clock-base to %u", rtp_mux->ts_base);
GST_OBJECT_UNLOCK (rtp_mux);
}
static GstStateChangeReturn
gst_rtp_mux_change_state (GstElement * element, GstStateChange transition)
{
GstRTPMux *rtp_mux;
GstStateChangeReturn ret;
rtp_mux = GST_RTP_MUX (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_rtp_mux_ready_to_paused (rtp_mux);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (gst_rtp_mux_parent_class)->change_state (element,
transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
g_clear_object (&rtp_mux->last_pad);
break;
default:
break;
}
return ret;
}
gboolean
gst_rtp_mux_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_rtp_mux_debug, "rtpmux", 0, "rtp muxer");
return gst_element_register (plugin, "rtpmux", GST_RANK_NONE,
GST_TYPE_RTP_MUX);
}

View file

@ -1,95 +0,0 @@
/* RTP muxer element for GStreamer
*
* gstrtpmux.h:
*
* Copyright (C) <2007> Nokia Corporation.
* Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* 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_MUX_H__
#define __GST_RTP_MUX_H__
#include <gst/gst.h>
#include <gst/rtp/gstrtpbuffer.h>
G_BEGIN_DECLS
#define GST_TYPE_RTP_MUX (gst_rtp_mux_get_type())
#define GST_RTP_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MUX, GstRTPMux))
#define GST_RTP_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MUX, GstRTPMuxClass))
#define GST_RTP_MUX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_MUX, GstRTPMuxClass))
#define GST_IS_RTP_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MUX))
#define GST_IS_RTP_MUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MUX))
typedef struct _GstRTPMux GstRTPMux;
typedef struct _GstRTPMuxClass GstRTPMuxClass;
typedef struct
{
gboolean have_clock_base;
guint clock_base;
GstSegment segment;
gboolean priority;
} GstRTPMuxPadPrivate;
/**
* GstRTPMux:
*
* The opaque #GstRTPMux structure.
*/
struct _GstRTPMux
{
GstElement element;
/* pad */
GstPad *srcpad;
guint32 ts_base;
guint16 seqnum_base;
gint32 ts_offset;
gint16 seqnum_offset;
guint16 seqnum; /* protected by object lock */
guint ssrc;
guint current_ssrc;
GstPad *last_pad; /* protected by object lock */
GstClockTime last_stop;
};
struct _GstRTPMuxClass
{
GstElementClass parent_class;
gboolean (*accept_buffer_locked) (GstRTPMux *rtp_mux,
GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * buffer);
gboolean (*src_event) (GstRTPMux *rtp_mux, GstEvent *event);
};
GType gst_rtp_mux_get_type (void);
gboolean gst_rtp_mux_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_RTP_MUX_H__ */

View file

@ -1,48 +0,0 @@
/* GStreamer RTP Muxer Plugins
*
* gstrtpdtmf.c:
*
* Copyright (C) <2007> Nokia Corporation.
* Contact: Zeeshan Ali <zeeshan.ali@nokia.com>
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstrtpmux.h"
#include "gstrtpdtmfmux.h"
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_rtp_mux_plugin_init (plugin))
return FALSE;
if (!gst_rtp_dtmf_mux_plugin_init (plugin))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
rtpmux,
"RTP Muxer plugins",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -224,7 +224,6 @@ check_PROGRAMS = \
elements/id3mux \
pipelines/mxf \
$(check_mimic) \
elements/rtpmux \
libs/mpegvideoparser \
libs/h264parser \
$(check_uvch264) \
@ -349,9 +348,6 @@ elements_timidity_LDADD = $(GST_BASE_LIBS) $(LDADD)
elements_kate_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_kate_LDADD = $(GST_BASE_LIBS) $(LDADD)
elements_rtpmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_rtpmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
elements_assrender_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_assrender_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) -lgstapp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)

View file

@ -40,7 +40,6 @@ opus
rganalysis
rglimiter
rgvolume
rtpmux
schroenc
spectrum
timidity

View file

@ -1,311 +0,0 @@
/* GStreamer
*
* unit test for rtpmux elements
*
* Copyright 2009 Collabora Ltd.
* @author: Olivier Crete <olivier.crete@collabora.co.uk>
* Copyright 2009 Nokia Corp.
*
* 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.
*/
#include <gst/check/gstcheck.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/gst.h>
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp"));
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp"));
typedef void (*check_cb) (GstPad * pad, int i);
static gboolean
query_func (GstPad * pad, GstObject * noparent, GstQuery * query)
{
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:
{
GstCaps **caps = g_object_get_data (G_OBJECT (pad), "caps");
fail_unless (caps != NULL && *caps != NULL);
gst_query_set_caps_result (query, *caps);
break;
}
case GST_QUERY_ACCEPT_CAPS:
gst_query_set_accept_caps_result (query, TRUE);
break;
default:
break;
}
return TRUE;
}
static gboolean
event_func (GstPad * pad, GstObject * noparent, GstEvent * event)
{
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
GstCaps *caps;
GstCaps **caps2 = g_object_get_data (G_OBJECT (pad), "caps");
gst_event_parse_caps (event, &caps);
fail_unless (caps2 != NULL && *caps2 != NULL);
fail_unless (gst_caps_is_fixed (caps));
fail_unless (gst_caps_is_fixed (*caps2));
fail_unless (gst_caps_is_equal_fixed (caps, *caps2));
break;
}
default:
break;
}
gst_event_unref (event);
return TRUE;
}
static void
test_basic (const gchar * elem_name, const gchar * sink2, int count,
check_cb cb)
{
GstElement *rtpmux = NULL;
GstPad *reqpad1 = NULL;
GstPad *reqpad2 = NULL;
GstPad *src1 = NULL;
GstPad *src2 = NULL;
GstPad *sink = NULL;
GstBuffer *inbuf = NULL;
GstCaps *src1caps = NULL;
GstCaps *src2caps = NULL;
GstCaps *sinkcaps = NULL;
GstCaps *caps;
GstSegment segment;
int i;
rtpmux = gst_check_setup_element (elem_name);
reqpad1 = gst_element_get_request_pad (rtpmux, "sink_1");
fail_unless (reqpad1 != NULL);
reqpad2 = gst_element_get_request_pad (rtpmux, sink2);
fail_unless (reqpad2 != NULL);
sink = gst_check_setup_sink_pad_by_name (rtpmux, &sinktemplate, "src");
src1 = gst_pad_new_from_static_template (&srctemplate, "src");
src2 = gst_pad_new_from_static_template (&srctemplate, "src");
fail_unless (gst_pad_link (src1, reqpad1) == GST_PAD_LINK_OK);
fail_unless (gst_pad_link (src2, reqpad2) == GST_PAD_LINK_OK);
gst_pad_set_query_function (src1, query_func);
gst_pad_set_query_function (src2, query_func);
gst_pad_set_query_function (sink, query_func);
gst_pad_set_event_function (sink, event_func);
g_object_set_data (G_OBJECT (src1), "caps", &src1caps);
g_object_set_data (G_OBJECT (src2), "caps", &src2caps);
g_object_set_data (G_OBJECT (sink), "caps", &sinkcaps);
src1caps = gst_caps_new_simple ("application/x-rtp",
"clock-rate", G_TYPE_INT, 1, "ssrc", G_TYPE_UINT, 11, NULL);
src2caps = gst_caps_new_simple ("application/x-rtp",
"clock-rate", G_TYPE_INT, 2, "ssrc", G_TYPE_UINT, 12, NULL);
sinkcaps = gst_caps_new_simple ("application/x-rtp",
"clock-rate", G_TYPE_INT, 3, "ssrc", G_TYPE_UINT, 13, NULL);
caps = gst_pad_peer_query_caps (src1, NULL);
fail_unless (gst_caps_is_empty (caps));
gst_caps_unref (caps);
gst_caps_set_simple (src2caps, "clock-rate", G_TYPE_INT, 3, NULL);
caps = gst_pad_peer_query_caps (src1, NULL);
fail_unless (gst_caps_is_equal (caps, sinkcaps));
gst_caps_unref (caps);
g_object_set (rtpmux, "seqnum-offset", 100, "timestamp-offset", 1000,
"ssrc", 55, NULL);
fail_unless (gst_element_set_state (rtpmux,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
gst_pad_set_active (sink, TRUE);
gst_pad_set_active (src1, TRUE);
gst_pad_set_active (src2, TRUE);
gst_caps_set_simple (sinkcaps,
"payload", G_TYPE_INT, 98, "seqnum-base", G_TYPE_UINT, 100,
"clock-base", G_TYPE_UINT, 1000, "ssrc", G_TYPE_UINT, 66, NULL);
caps = gst_caps_new_simple ("application/x-rtp",
"payload", G_TYPE_INT, 98, "clock-rate", G_TYPE_INT, 3,
"seqnum-base", G_TYPE_UINT, 56, "clock-base", G_TYPE_UINT, 57,
"ssrc", G_TYPE_UINT, 66, NULL);
fail_unless (gst_pad_set_caps (src1, caps));
gst_segment_init (&segment, GST_FORMAT_TIME);
segment.start = 100000;
fail_unless (gst_pad_push_event (src1, gst_event_new_segment (&segment)));
segment.start = 0;
fail_unless (gst_pad_push_event (src2, gst_event_new_segment (&segment)));
for (i = 0; i < count; i++) {
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
GST_BUFFER_PTS (inbuf) = i * 1000 + 100000;
GST_BUFFER_DURATION (inbuf) = 1000;
gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
gst_rtp_buffer_set_version (&rtpbuffer, 2);
gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
gst_rtp_buffer_unmap (&rtpbuffer);
fail_unless (gst_pad_push (src1, inbuf) == GST_FLOW_OK);
if (buffers)
fail_unless (GST_BUFFER_PTS (buffers->data) == i * 1000, "%lld",
GST_BUFFER_PTS (buffers->data));
cb (src2, i);
g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
g_list_free (buffers);
buffers = NULL;
}
gst_pad_set_active (sink, FALSE);
gst_pad_set_active (src1, FALSE);
gst_pad_set_active (src2, FALSE);
fail_unless (gst_element_set_state (rtpmux,
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
gst_check_teardown_pad_by_name (rtpmux, "src");
gst_object_unref (reqpad1);
gst_object_unref (reqpad2);
gst_check_teardown_pad_by_name (rtpmux, "sink_1");
gst_check_teardown_pad_by_name (rtpmux, sink2);
gst_element_release_request_pad (rtpmux, reqpad1);
gst_element_release_request_pad (rtpmux, reqpad2);
gst_caps_unref (caps);
gst_caps_replace (&src1caps, NULL);
gst_caps_replace (&src2caps, NULL);
gst_caps_replace (&sinkcaps, NULL);
gst_check_teardown_element (rtpmux);
}
static void
basic_check_cb (GstPad * pad, int i)
{
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
fail_unless (buffers && g_list_length (buffers) == 1);
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 55);
fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) ==
200 - 57 + 1000 + i);
fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i);
gst_rtp_buffer_unmap (&rtpbuffer);
}
GST_START_TEST (test_rtpmux_basic)
{
test_basic ("rtpmux", "sink_2", 10, basic_check_cb);
}
GST_END_TEST;
GST_START_TEST (test_rtpdtmfmux_basic)
{
test_basic ("rtpdtmfmux", "sink_2", 10, basic_check_cb);
}
GST_END_TEST;
static void
lock_check_cb (GstPad * pad, int i)
{
GstBuffer *inbuf;
if (i % 2) {
fail_unless (buffers == NULL);
} else {
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
fail_unless (buffers && g_list_length (buffers) == 1);
gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer);
fail_unless (gst_rtp_buffer_get_ssrc (&rtpbuffer) == 55);
fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) ==
200 - 57 + 1000 + i);
fail_unless (gst_rtp_buffer_get_seq (&rtpbuffer) == 100 + 1 + i);
gst_rtp_buffer_unmap (&rtpbuffer);
inbuf = gst_rtp_buffer_new_allocate (10, 0, 0);
GST_BUFFER_PTS (inbuf) = i * 1000 + 500;
GST_BUFFER_DURATION (inbuf) = 1000;
gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer);
gst_rtp_buffer_set_version (&rtpbuffer, 2);
gst_rtp_buffer_set_payload_type (&rtpbuffer, 98);
gst_rtp_buffer_set_ssrc (&rtpbuffer, 44);
gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i);
gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i);
gst_rtp_buffer_unmap (&rtpbuffer);
fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK);
g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
g_list_free (buffers);
buffers = NULL;
}
}
GST_START_TEST (test_rtpdtmfmux_lock)
{
test_basic ("rtpdtmfmux", "priority_sink_2", 10, lock_check_cb);
}
GST_END_TEST;
static Suite *
rtpmux_suite (void)
{
Suite *s = suite_create ("rtpmux");
TCase *tc_chain;
tc_chain = tcase_create ("rtpmux_basic");
tcase_add_test (tc_chain, test_rtpmux_basic);
suite_add_tcase (s, tc_chain);
tc_chain = tcase_create ("rtpdtmfmux_basic");
tcase_add_test (tc_chain, test_rtpdtmfmux_basic);
suite_add_tcase (s, tc_chain);
tc_chain = tcase_create ("rtpdtmfmux_lock");
tcase_add_test (tc_chain, test_rtpdtmfmux_lock);
suite_add_tcase (s, tc_chain);
return s;
}
GST_CHECK_MAIN (rtpmux)