Move rtpmanager from -bad to -good.

This commit is contained in:
Tim-Philipp Müller 2009-08-11 02:46:54 +01:00
parent ae388318cc
commit a6912096cd
35 changed files with 0 additions and 15481 deletions

View file

@ -284,7 +284,6 @@ AG_GST_CHECK_PLUGIN(pcapparse)
AG_GST_CHECK_PLUGIN(qtmux) AG_GST_CHECK_PLUGIN(qtmux)
AG_GST_CHECK_PLUGIN(rawparse) AG_GST_CHECK_PLUGIN(rawparse)
AG_GST_CHECK_PLUGIN(real) AG_GST_CHECK_PLUGIN(real)
AG_GST_CHECK_PLUGIN(rtpmanager)
AG_GST_CHECK_PLUGIN(rtpmux) AG_GST_CHECK_PLUGIN(rtpmux)
AG_GST_CHECK_PLUGIN(scaletempo) AG_GST_CHECK_PLUGIN(scaletempo)
AG_GST_CHECK_PLUGIN(sdp) AG_GST_CHECK_PLUGIN(sdp)
@ -1696,7 +1695,6 @@ gst/pcapparse/Makefile
gst/qtmux/Makefile gst/qtmux/Makefile
gst/rawparse/Makefile gst/rawparse/Makefile
gst/real/Makefile gst/real/Makefile
gst/rtpmanager/Makefile
gst/rtpmux/Makefile gst/rtpmux/Makefile
gst/scaletempo/Makefile gst/scaletempo/Makefile
gst/sdp/Makefile gst/sdp/Makefile

View file

@ -142,11 +142,6 @@ EXTRA_HFILES = \
$(top_srcdir)/gst/pcapparse/gstpcapparse.h \ $(top_srcdir)/gst/pcapparse/gstpcapparse.h \
$(top_srcdir)/gst/rawparse/gstaudioparse.h \ $(top_srcdir)/gst/rawparse/gstaudioparse.h \
$(top_srcdir)/gst/rawparse/gstvideoparse.h \ $(top_srcdir)/gst/rawparse/gstvideoparse.h \
$(top_srcdir)/gst/rtpmanager/gstrtpbin.h \
$(top_srcdir)/gst/rtpmanager/gstrtpjitterbuffer.h \
$(top_srcdir)/gst/rtpmanager/gstrtpptdemux.h \
$(top_srcdir)/gst/rtpmanager/gstrtpsession.h \
$(top_srcdir)/gst/rtpmanager/gstrtpssrcdemux.h \
$(top_srcdir)/gst/rtpmux/gstrtpmux.h \ $(top_srcdir)/gst/rtpmux/gstrtpmux.h \
$(top_srcdir)/gst/rtpmux/gstrtpdtmfmux.h \ $(top_srcdir)/gst/rtpmux/gstrtpdtmfmux.h \
$(top_srcdir)/gst/scaletempo/gstscaletempo.h \ $(top_srcdir)/gst/scaletempo/gstscaletempo.h \

View file

@ -38,11 +38,6 @@
<xi:include href="xml/element-dvdspu.xml" /> <xi:include href="xml/element-dvdspu.xml" />
<xi:include href="xml/element-festival.xml" /> <xi:include href="xml/element-festival.xml" />
<xi:include href="xml/element-fpsdisplaysink.xml" /> <xi:include href="xml/element-fpsdisplaysink.xml" />
<xi:include href="xml/element-gstrtpbin.xml" />
<xi:include href="xml/element-gstrtpjitterbuffer.xml" />
<xi:include href="xml/element-gstrtpptdemux.xml" />
<xi:include href="xml/element-gstrtpsession.xml" />
<xi:include href="xml/element-gstrtpssrcdemux.xml" />
<xi:include href="xml/element-input-selector.xml" /> <xi:include href="xml/element-input-selector.xml" />
<xi:include href="xml/element-ivorbisdec.xml" /> <xi:include href="xml/element-ivorbisdec.xml" />
<xi:include href="xml/element-jackaudiosrc.xml" /> <xi:include href="xml/element-jackaudiosrc.xml" />
@ -122,7 +117,6 @@
<xi:include href="xml/plugin-freeze.xml" /> <xi:include href="xml/plugin-freeze.xml" />
<xi:include href="xml/plugin-frei0r.xml" /> <xi:include href="xml/plugin-frei0r.xml" />
<xi:include href="xml/plugin-gsm.xml" /> <xi:include href="xml/plugin-gsm.xml" />
<xi:include href="xml/plugin-gstrtpmanager.xml" />
<xi:include href="xml/plugin-h264parse.xml" /> <xi:include href="xml/plugin-h264parse.xml" />
<xi:include href="xml/plugin-jack.xml" /> <xi:include href="xml/plugin-jack.xml" />
<xi:include href="xml/plugin-kate.xml" /> <xi:include href="xml/plugin-kate.xml" />

View file

@ -780,82 +780,6 @@ gst_rtp_mux_plugin_init
gst_rtp_session_set_ssrc gst_rtp_session_set_ssrc
</SECTION> </SECTION>
<SECTION>
<FILE>element-gstrtpbin</FILE>
<TITLE>gstrtpbin</TITLE>
GstRtpBin
<SUBSECTION Standard>
GstRtpBinPrivate
GstRtpBinClass
GST_RTP_BIN
GST_IS_RTP_BIN
GST_TYPE_RTP_BIN
gst_rtp_bin_get_type
GST_RTP_BIN_CLASS
GST_IS_RTP_BIN_CLASS
</SECTION>
<SECTION>
<FILE>element-gstrtpjitterbuffer</FILE>
<TITLE>gstrtpjitterbuffer</TITLE>
GstRtpJitterBuffer
<SUBSECTION Standard>
GstRtpJitterBufferClass
GstRtpJitterBufferPrivate
GST_RTP_JITTER_BUFFER
GST_IS_RTP_JITTER_BUFFER
GST_TYPE_RTP_JITTER_BUFFER
gst_rtp_jitter_buffer_get_type
GST_RTP_JITTER_BUFFER_CLASS
GST_IS_RTP_JITTER_BUFFER_CLASS
</SECTION>
<SECTION>
<FILE>element-gstrtpptdemux</FILE>
<TITLE>gstrtpptdemux</TITLE>
GstRtpPtDemux
<SUBSECTION Standard>
GstRtpPtDemuxClass
GstRtpPtDemuxPad
GST_RTP_PT_DEMUX
GST_IS_RTP_PT_DEMUX
GST_TYPE_RTP_PT_DEMUX
gst_rtp_pt_demux_get_type
GST_RTP_PT_DEMUX_CLASS
GST_IS_RTP_PT_DEMUX_CLASS
</SECTION>
<SECTION>
<FILE>element-gstrtpsession</FILE>
<TITLE>gstrtpsession</TITLE>
GstRtpSession
<SUBSECTION Standard>
GstRtpSessionClass
GstRtpSessionPrivate
GST_RTP_SESSION
GST_IS_RTP_SESSION
GST_TYPE_RTP_SESSION
gst_rtp_session_get_type
GST_RTP_SESSION_CLASS
GST_IS_RTP_SESSION_CLASS
GST_RTP_SESSION_CAST
</SECTION>
<SECTION>
<FILE>element-gstrtpssrcdemux</FILE>
<TITLE>gstrtpssrcdemux</TITLE>
GstRtpSsrcDemux
<SUBSECTION Standard>
GstRtpSsrcDemuxClass
GstRtpSsrcDemuxPad
GST_RTP_SSRC_DEMUX
GST_IS_RTP_SSRC_DEMUX
GST_TYPE_RTP_SSRC_DEMUX
gst_rtp_ssrc_demux_get_type
GST_RTP_SSRC_DEMUX_CLASS
GST_IS_RTP_SSRC_DEMUX_CLASS
</SECTION>
<SECTION> <SECTION>
<FILE>element-scaletempo</FILE> <FILE>element-scaletempo</FILE>
<TITLE>scaletempo</TITLE> <TITLE>scaletempo</TITLE>

View file

@ -17558,36 +17558,6 @@
<DEFAULT>25</DEFAULT> <DEFAULT>25</DEFAULT>
</ARG> </ARG>
<ARG>
<NAME>GstRTPJitterBuffer::drop-on-latency</NAME>
<TYPE>gboolean</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Drop buffers when maximum latency is reached</NICK>
<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB>
<DEFAULT>FALSE</DEFAULT>
</ARG>
<ARG>
<NAME>GstRTPJitterBuffer::latency</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Buffer latency in ms</NICK>
<BLURB>Amount of ms to buffer.</BLURB>
<DEFAULT>200</DEFAULT>
</ARG>
<ARG>
<NAME>GstRTPBin::latency</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Buffer latency in ms</NICK>
<BLURB>Default amount of ms to buffer in the jitterbuffers.</BLURB>
<DEFAULT>200</DEFAULT>
</ARG>
<ARG> <ARG>
<NAME>GstOSXVideoSink::embed</NAME> <NAME>GstOSXVideoSink::embed</NAME>
<TYPE>gboolean</TYPE> <TYPE>gboolean</TYPE>
@ -18108,286 +18078,6 @@
<DEFAULT>0</DEFAULT> <DEFAULT>0</DEFAULT>
</ARG> </ARG>
<ARG>
<NAME>GstRtpSession::ntp-ns-base</NAME>
<TYPE>guint64</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>NTP base time</NICK>
<BLURB>The NTP base time corresponding to running_time 0.</BLURB>
<DEFAULT>0</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::bandwidth</NAME>
<TYPE>gdouble</TYPE>
<RANGE>>= 0</RANGE>
<FLAGS>rw</FLAGS>
<NICK>Bandwidth</NICK>
<BLURB>The bandwidth of the session.</BLURB>
<DEFAULT>64000</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::num-active-sources</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>r</FLAGS>
<NICK>Num Active Sources</NICK>
<BLURB>The number of active sources in the session.</BLURB>
<DEFAULT>0</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::num-sources</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>r</FLAGS>
<NICK>Num Sources</NICK>
<BLURB>The number of sources in the session.</BLURB>
<DEFAULT>0</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::rtcp-fraction</NAME>
<TYPE>gdouble</TYPE>
<RANGE>>= 0</RANGE>
<FLAGS>rw</FLAGS>
<NICK>RTCP Fraction</NICK>
<BLURB>The fraction of the bandwidth used for RTCP.</BLURB>
<DEFAULT>3000</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-cname</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES CNAME</NICK>
<BLURB>The CNAME to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-email</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES EMAIL</NICK>
<BLURB>The EMAIL to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-location</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES LOCATION</NICK>
<BLURB>The LOCATION to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-name</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES NAME</NICK>
<BLURB>The NAME to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-note</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES NOTE</NICK>
<BLURB>The NOTE to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-phone</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES PHONE</NICK>
<BLURB>The PHONE to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes-tool</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES TOOL</NICK>
<BLURB>The TOOL to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::internal-session</NAME>
<TYPE>RTPSession*</TYPE>
<RANGE></RANGE>
<FLAGS>r</FLAGS>
<NICK>Internal Session</NICK>
<BLURB>The internal RTPSession object.</BLURB>
<DEFAULT></DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpSession::sdes</NAME>
<TYPE>GstStructure*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES</NICK>
<BLURB>The SDES items of this session.</BLURB>
<DEFAULT></DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpJitterBuffer::drop-on-latency</NAME>
<TYPE>gboolean</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Drop buffers when maximum latency is reached</NICK>
<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB>
<DEFAULT>FALSE</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpJitterBuffer::latency</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Buffer latency in ms</NICK>
<BLURB>Amount of ms to buffer.</BLURB>
<DEFAULT>200</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpJitterBuffer::ts-offset</NAME>
<TYPE>gint64</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Timestamp Offset</NICK>
<BLURB>Adjust buffer timestamps with offset in nanoseconds.</BLURB>
<DEFAULT>0</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpJitterBuffer::do-lost</NAME>
<TYPE>gboolean</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Do Lost</NICK>
<BLURB>Send an event downstream when a packet is lost.</BLURB>
<DEFAULT>FALSE</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::latency</NAME>
<TYPE>guint</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Buffer latency in ms</NICK>
<BLURB>Default amount of ms to buffer in the jitterbuffers.</BLURB>
<DEFAULT>200</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-cname</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES CNAME</NICK>
<BLURB>The CNAME to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-email</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES EMAIL</NICK>
<BLURB>The EMAIL to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-location</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES LOCATION</NICK>
<BLURB>The LOCATION to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-name</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES NAME</NICK>
<BLURB>The NAME to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-note</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES NOTE</NICK>
<BLURB>The NOTE to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-phone</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES PHONE</NICK>
<BLURB>The PHONE to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes-tool</NAME>
<TYPE>gchar*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES TOOL</NICK>
<BLURB>The TOOL to put in SDES messages of this session.</BLURB>
<DEFAULT>NULL</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::do-lost</NAME>
<TYPE>gboolean</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Do Lost</NICK>
<BLURB>Send an event downstream when a packet is lost.</BLURB>
<DEFAULT>FALSE</DEFAULT>
</ARG>
<ARG>
<NAME>GstRtpBin::sdes</NAME>
<TYPE>GstStructure*</TYPE>
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>SDES</NICK>
<BLURB>The SDES items of this session.</BLURB>
<DEFAULT></DEFAULT>
</ARG>
<ARG> <ARG>
<NAME>GstGioSrc::location</NAME> <NAME>GstGioSrc::location</NAME>
<TYPE>gchar*</TYPE> <TYPE>gchar*</TYPE>

View file

@ -16,7 +16,6 @@ GObject
GstFPSDisplaySink GstFPSDisplaySink
GstAutoConvert GstAutoConvert
GstSDPDemux GstSDPDemux
GstRtpBin
GstSignalProcessor GstSignalProcessor
http---calf-sourceforge-net-plugins-Compressor http---calf-sourceforge-net-plugins-Compressor
http---calf-sourceforge-net-plugins-Filter http---calf-sourceforge-net-plugins-Filter
@ -466,10 +465,6 @@ GObject
GstSpeed GstSpeed
GstInputSelector GstInputSelector
GstOutputSelector GstOutputSelector
GstRtpJitterBuffer
GstRtpPtDemux
GstRtpSession
GstRtpSsrcDemux
GstRealVideoDec GstRealVideoDec
GstRealAudioDec GstRealAudioDec
GstRawParse GstRawParse

View file

@ -50,302 +50,6 @@ gint64 arg2
gint64 arg3 gint64 arg3
</SIGNAL> </SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::clear-pt-map</NAME>
<RETURNS>void</RETURNS>
<FLAGS>la</FLAGS>
GstRtpBin *gstrtpbin
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-bye-ssrc</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-bye-timeout</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-new-ssrc</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-ssrc-active</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-ssrc-collision</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-ssrc-sdes</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-ssrc-validated</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-timeout</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::request-pt-map</NAME>
<RETURNS>GstCaps*</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::get-internal-session</NAME>
<RETURNS>RTPSession*</RETURNS>
<FLAGS>la</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-sender-timeout</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::reset-sync</NAME>
<RETURNS>void</RETURNS>
<FLAGS>la</FLAGS>
GstRtpBin *gstrtpbin
</SIGNAL>
<SIGNAL>
<NAME>GstRtpBin::on-npt-stop</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpBin *gstrtpbin
guint arg1
guint arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpJitterBuffer::clear-pt-map</NAME>
<RETURNS>void</RETURNS>
<FLAGS>la</FLAGS>
GstRtpJitterBuffer *gstrtpjitterbuffer
</SIGNAL>
<SIGNAL>
<NAME>GstRtpJitterBuffer::request-pt-map</NAME>
<RETURNS>GstCaps*</RETURNS>
<FLAGS>l</FLAGS>
GstRtpJitterBuffer *gstrtpjitterbuffer
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpJitterBuffer::handle-sync</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpJitterBuffer *gstrtpjitterbuffer
GstStructure *arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpJitterBuffer::on-npt-stop</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpJitterBuffer *gstrtpjitterbuffer
</SIGNAL>
<SIGNAL>
<NAME>GstRtpPtDemux::clear-pt-map</NAME>
<RETURNS>void</RETURNS>
<FLAGS>la</FLAGS>
GstRtpPtDemux *gstrtpptdemux
</SIGNAL>
<SIGNAL>
<NAME>GstRtpPtDemux::new-payload-type</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpPtDemux *gstrtpptdemux
guint arg1
GstPad *arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpPtDemux::payload-type-change</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpPtDemux *gstrtpptdemux
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpPtDemux::request-pt-map</NAME>
<RETURNS>GstCaps*</RETURNS>
<FLAGS>l</FLAGS>
GstRtpPtDemux *gstrtpptdemux
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::clear-pt-map</NAME>
<RETURNS>void</RETURNS>
<FLAGS>a</FLAGS>
GstRtpSession *gstrtpsession
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-bye-ssrc</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-bye-timeout</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-new-ssrc</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-ssrc-active</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-ssrc-collision</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-ssrc-sdes</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-ssrc-validated</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-timeout</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::request-pt-map</NAME>
<RETURNS>GstCaps*</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSession::on-sender-timeout</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSession *gstrtpsession
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSsrcDemux::new-ssrc-pad</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSsrcDemux *gstrtpssrcdemux
guint arg1
GstPad *arg2
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSsrcDemux::clear-ssrc</NAME>
<RETURNS>void</RETURNS>
<FLAGS>la</FLAGS>
GstRtpSsrcDemux *gstrtpssrcdemux
guint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstRtpSsrcDemux::removed-ssrc-pad</NAME>
<RETURNS>void</RETURNS>
<FLAGS>l</FLAGS>
GstRtpSsrcDemux *gstrtpssrcdemux
guint arg1
GstPad *arg2
</SIGNAL>
<SIGNAL> <SIGNAL>
<NAME>GstCDAudio::track-change</NAME> <NAME>GstCDAudio::track-change</NAME>
<RETURNS>void</RETURNS> <RETURNS>void</RETURNS>

View file

@ -1,190 +0,0 @@
<plugin>
<name>gstrtpmanager</name>
<description>RTP session management plugin library</description>
<filename>../../gst/rtpmanager/.libs/libgstrtpmanager.so</filename>
<basename>libgstrtpmanager.so</basename>
<version>0.10.13.1</version>
<license>LGPL</license>
<source>gst-plugins-bad</source>
<package>GStreamer Bad Plug-ins git/prerelease</package>
<origin>http://gstreamer.freedesktop.org</origin>
<elements>
<element>
<name>gstrtpbin</name>
<longname>RTP Bin</longname>
<class>Filter/Network/RTP</class>
<description>Implement an RTP bin</description>
<author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
<pads>
<caps>
<name>send_rtp_src_%d</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>send_rtcp_src_%d</name>
<direction>source</direction>
<presence>request</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>recv_rtp_src_%d_%d_%d</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>send_rtp_sink_%d</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>recv_rtcp_sink_%d</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>recv_rtp_sink_%d</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
<element>
<name>gstrtpjitterbuffer</name>
<longname>RTP packet jitter-buffer</longname>
<class>Filter/Network/RTP</class>
<description>A buffer that deals with network jitter and other transmission faults</description>
<author>Philippe Kalaf &lt;philippe.kalaf@collabora.co.uk&gt;, Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
<pads>
<caps>
<name>sink_rtcp</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>application/x-rtp, clock-rate=(int)[ 1, 2147483647 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
<element>
<name>gstrtpptdemux</name>
<longname>RTP Demux</longname>
<class>Demux/Network/RTP</class>
<description>Parses codec streams transmitted in the same RTP session</description>
<author>Kai Vehmanen &lt;kai.vehmanen@nokia.com&gt;</author>
<pads>
<caps>
<name>src_%d</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtp, payload=(int)[ 0, 255 ]</details>
</caps>
<caps>
<name>sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
<element>
<name>gstrtpsession</name>
<longname>RTP Session</longname>
<class>Filter/Network/RTP</class>
<description>Implement an RTP session</description>
<author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
<pads>
<caps>
<name>send_rtcp_src</name>
<direction>source</direction>
<presence>request</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>send_rtp_src</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>sync_src</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>recv_rtp_src</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>send_rtp_sink</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>recv_rtcp_sink</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>recv_rtp_sink</name>
<direction>sink</direction>
<presence>request</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
<element>
<name>gstrtpssrcdemux</name>
<longname>RTP SSRC Demux</longname>
<class>Demux/Network/RTP</class>
<description>Splits RTP streams based on the SSRC</description>
<author>Wim Taymans &lt;wim.taymans@gmail.com&gt;</author>
<pads>
<caps>
<name>rtcp_src_%d</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>src_%d</name>
<direction>source</direction>
<presence>sometimes</presence>
<details>application/x-rtp</details>
</caps>
<caps>
<name>rtcp_sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>application/x-rtcp</details>
</caps>
<caps>
<name>sink</name>
<direction>sink</direction>
<presence>always</presence>
<details>application/x-rtp</details>
</caps>
</pads>
</element>
</elements>
</plugin>

View file

@ -83,7 +83,6 @@ rm -rf $RPM_BUILD_ROOT
%{_libdir}/gstreamer-%{majorminor}/libgstreal.so %{_libdir}/gstreamer-%{majorminor}/libgstreal.so
%{_libdir}/gstreamer-%{majorminor}/libgstmve.so %{_libdir}/gstreamer-%{majorminor}/libgstmve.so
%{_libdir}/gstreamer-%{majorminor}/libgstmpegvideoparse.so %{_libdir}/gstreamer-%{majorminor}/libgstmpegvideoparse.so
%{_libdir}/gstreamer-%{majorminor}/libgstrtpmanager.so
%{_libdir}/gstreamer-%{majorminor}/libgstbayer.so %{_libdir}/gstreamer-%{majorminor}/libgstbayer.so
%{_libdir}/gstreamer-%{majorminor}/libgstdvdspu.so %{_libdir}/gstreamer-%{majorminor}/libgstdvdspu.so
%{_libdir}/gstreamer-%{majorminor}/libgstfestival.so %{_libdir}/gstreamer-%{majorminor}/libgstfestival.so

View file

@ -1,2 +0,0 @@
gstrtpbin-marshal.h
gstrtpbin-marshal.c

View file

@ -1,49 +0,0 @@
plugin_LTLIBRARIES = libgstrtpmanager.la
glib_enum_define = GST_RTP_BIN
glib_enum_prefix = gst_rtp_bin
include $(top_srcdir)/common/glib-gen.mak
built_sources = gstrtpbin-marshal.c
built_headers = gstrtpbin-marshal.h
BUILT_SOURCES = $(built_sources) $(built_headers)
libgstrtpmanager_la_SOURCES = gstrtpmanager.c \
gstrtpbin.c \
gstrtpjitterbuffer.c \
gstrtpptdemux.c \
gstrtpssrcdemux.c \
rtpjitterbuffer.c \
rtpsession.c \
rtpsource.c \
rtpstats.c \
gstrtpsession.c
nodist_libgstrtpmanager_la_SOURCES = \
$(built_sources)
noinst_HEADERS = gstrtpbin.h \
gstrtpjitterbuffer.h \
gstrtpptdemux.h \
gstrtpssrcdemux.h \
rtpjitterbuffer.h \
rtpsession.h \
rtpsource.h \
rtpstats.h \
gstrtpsession.h
libgstrtpmanager_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
$(ERROR_CFLAGS)
libgstrtpmanager_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstnetbuffer-@GST_MAJORMINOR@ -lgstrtp-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) $(GST_LIBS_LIBS)
libgstrtpmanager_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstrtpmanager_la_LIBTOOLFLAGS = --tag=disable-static
CLEANFILES = $(BUILT_SOURCES)
EXTRA_DIST = gstrtpbin-marshal.list

View file

@ -1,8 +0,0 @@
UINT:UINT
BOXED:UINT
BOXED:UINT,UINT
OBJECT:UINT
VOID:UINT,OBJECT
VOID:UINT
VOID:UINT,UINT
VOID:OBJECT,OBJECT

File diff suppressed because it is too large Load diff

View file

@ -1,88 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_RTP_BIN_H__
#define __GST_RTP_BIN_H__
#include <gst/gst.h>
#include "rtpsession.h"
#define GST_TYPE_RTP_BIN \
(gst_rtp_bin_get_type())
#define GST_RTP_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_BIN,GstRtpBin))
#define GST_RTP_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_BIN,GstRtpBinClass))
#define GST_IS_RTP_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_BIN))
#define GST_IS_RTP_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_BIN))
typedef struct _GstRtpBin GstRtpBin;
typedef struct _GstRtpBinClass GstRtpBinClass;
typedef struct _GstRtpBinPrivate GstRtpBinPrivate;
struct _GstRtpBin {
GstBin bin;
/*< private >*/
/* default latency for sessions */
guint latency;
gboolean do_lost;
/* a list of session */
GSList *sessions;
/* a list of clients, these are streams with the same CNAME */
GSList *clients;
/* the default SDES items for sessions */
GstStructure *sdes;
/*< private >*/
GstRtpBinPrivate *priv;
};
struct _GstRtpBinClass {
GstBinClass parent_class;
/* get the caps for pt */
GstCaps* (*request_pt_map) (GstRtpBin *rtpbin, guint session, guint pt);
/* action signals */
void (*clear_pt_map) (GstRtpBin *rtpbin);
void (*reset_sync) (GstRtpBin *rtpbin);
RTPSession* (*get_internal_session) (GstRtpBin *rtpbin, guint session_id);
/* session manager signals */
void (*on_new_ssrc) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_ssrc_collision) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_ssrc_validated) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_ssrc_active) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_ssrc_sdes) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_bye_ssrc) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_bye_timeout) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_timeout) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_sender_timeout) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
void (*on_npt_stop) (GstRtpBin *rtpbin, guint session, guint32 ssrc);
};
GType gst_rtp_bin_get_type (void);
#endif /* __GST_RTP_BIN_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,88 +0,0 @@
/*
* Farsight Voice+Video library
*
* Copyright 2007 Collabora Ltd,
* Copyright 2007 Nokia Corporation
* @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
* Copyright 2007 Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __GST_RTP_JITTER_BUFFER_H__
#define __GST_RTP_JITTER_BUFFER_H__
#include <gst/gst.h>
#include <gst/rtp/gstrtpbuffer.h>
G_BEGIN_DECLS
/* #define's don't like whitespacey bits */
#define GST_TYPE_RTP_JITTER_BUFFER \
(gst_rtp_jitter_buffer_get_type())
#define GST_RTP_JITTER_BUFFER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), \
GST_TYPE_RTP_JITTER_BUFFER,GstRtpJitterBuffer))
#define GST_RTP_JITTER_BUFFER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), \
GST_TYPE_RTP_JITTER_BUFFER,GstRtpJitterBufferClass))
#define GST_IS_RTP_JITTER_BUFFER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JITTER_BUFFER))
#define GST_IS_RTP_JITTER_BUFFER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JITTER_BUFFER))
typedef struct _GstRtpJitterBuffer GstRtpJitterBuffer;
typedef struct _GstRtpJitterBufferClass GstRtpJitterBufferClass;
typedef struct _GstRtpJitterBufferPrivate GstRtpJitterBufferPrivate;
/**
* GstRtpJitterBuffer:
*
* Opaque jitterbuffer structure.
*/
struct _GstRtpJitterBuffer
{
GstElement parent;
/*< private >*/
GstRtpJitterBufferPrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstRtpJitterBufferClass
{
GstElementClass parent_class;
/* signals */
GstCaps* (*request_pt_map) (GstRtpJitterBuffer *buffer, guint pt);
void (*handle_sync) (GstRtpJitterBuffer *buffer, GstStructure *s);
void (*on_npt_stop) (GstRtpJitterBuffer *buffer);
/* actions */
void (*clear_pt_map) (GstRtpJitterBuffer *buffer);
/*< private > */
gpointer _gst_reserved[GST_PADDING];
};
GType gst_rtp_jitter_buffer_get_type (void);
G_END_DECLS
#endif /* __GST_RTP_JITTER_BUFFER_H__ */

View file

@ -1,60 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstrtpbin.h"
#include "gstrtpjitterbuffer.h"
#include "gstrtpptdemux.h"
#include "gstrtpsession.h"
#include "gstrtpssrcdemux.h"
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "gstrtpbin", GST_RANK_NONE,
GST_TYPE_RTP_BIN))
return FALSE;
if (!gst_element_register (plugin, "gstrtpjitterbuffer", GST_RANK_NONE,
GST_TYPE_RTP_JITTER_BUFFER))
return FALSE;
if (!gst_element_register (plugin, "gstrtpptdemux", GST_RANK_NONE,
GST_TYPE_RTP_PT_DEMUX))
return FALSE;
if (!gst_element_register (plugin, "gstrtpsession", GST_RANK_NONE,
GST_TYPE_RTP_SESSION))
return FALSE;
if (!gst_element_register (plugin, "gstrtpssrcdemux", GST_RANK_NONE,
GST_TYPE_RTP_SSRC_DEMUX))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gstrtpmanager",
"RTP session management plugin library",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,492 +0,0 @@
/*
* RTP Demux element
*
* Copyright (C) 2005 Nokia Corporation.
* @author Kai Vehmanen <kai.vehmanen@nokia.com>
*
* Loosely based on GStreamer gstdecodebin
* Copyright (C) <2004> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:element-gstrtpptdemux
*
* gstrtpptdemux acts as a demuxer for RTP packets based on the payload type of
* the packets. Its main purpose is to allow an application to easily receive
* and decode an RTP stream with multiple payload types.
*
* For each payload type that is detected, a new pad will be created and the
* #GstRtpPtDemux::new-payload-type signal will be emitted. When the payload for
* the RTP stream changes, the #GstRtpPtDemux::payload-type-change signal will be
* emitted.
*
* The element will try to set complete and unique application/x-rtp caps on the
* outgoing buffers and pads based on the result of the
* #GstRtpPtDemux::request-pt-map signal.
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch udpsrc caps="application/x-rtp" ! gstrtpptdemux ! fakesink
* ]| Takes an RTP stream and send the RTP packets with the first detected
* payload type to fakesink, discarding the other payload types.
* </refsect2>
*
* Last reviewed on 2007-05-28 (0.10.5)
*/
/*
* Contributors:
* Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
*/
/*
* Status:
* - works with the test_rtpdemux.c tool
*
* Check:
* - is emitting a signal enough, or should we
* use GstEvent to notify downstream elements
* of the new packet... no?
*
* Notes:
* - emits event both for new PTs, and whenever
* a PT is changed
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/rtp/gstrtpbuffer.h>
#include "gstrtpbin-marshal.h"
#include "gstrtpptdemux.h"
/* generic templates */
static GstStaticPadTemplate rtp_pt_demux_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp")
);
static GstStaticPadTemplate rtp_pt_demux_src_template =
GST_STATIC_PAD_TEMPLATE ("src_%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("application/x-rtp, " "payload = (int) [ 0, 255 ]")
);
GST_DEBUG_CATEGORY_STATIC (gst_rtp_pt_demux_debug);
#define GST_CAT_DEFAULT gst_rtp_pt_demux_debug
/**
* Item for storing GstPad<->pt pairs.
*/
struct _GstRtpPtDemuxPad
{
GstPad *pad; /**< pointer to the actual pad */
gint pt; /**< RTP payload-type attached to pad */
gboolean newcaps;
};
/* signals */
enum
{
SIGNAL_REQUEST_PT_MAP,
SIGNAL_NEW_PAYLOAD_TYPE,
SIGNAL_PAYLOAD_TYPE_CHANGE,
SIGNAL_CLEAR_PT_MAP,
LAST_SIGNAL
};
GST_BOILERPLATE (GstRtpPtDemux, gst_rtp_pt_demux, GstElement, GST_TYPE_ELEMENT);
static void gst_rtp_pt_demux_finalize (GObject * object);
static void gst_rtp_pt_demux_release (GstRtpPtDemux * ptdemux);
static gboolean gst_rtp_pt_demux_setup (GstRtpPtDemux * ptdemux);
static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_rtp_pt_demux_change_state (GstElement * element,
GstStateChange transition);
static void gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux);
static GstRtpPtDemuxPad *find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt);
static guint gst_rtp_pt_demux_signals[LAST_SIGNAL] = { 0 };
static GstElementDetails gst_rtp_pt_demux_details = {
"RTP Demux",
"Demux/Network/RTP",
"Parses codec streams transmitted in the same RTP session",
"Kai Vehmanen <kai.vehmanen@nokia.com>"
};
static void
gst_rtp_pt_demux_base_init (gpointer g_class)
{
GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_pt_demux_sink_template));
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_pt_demux_src_template));
gst_element_class_set_details (gstelement_klass, &gst_rtp_pt_demux_details);
}
static void
gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
{
GObjectClass *gobject_klass;
GstElementClass *gstelement_klass;
gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass;
/**
* GstRtpPtDemux::request-pt-map:
* @demux: the object which received the signal
* @pt: the payload type
*
* Request the payload type as #GstCaps for @pt.
*/
gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP] =
g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, request_pt_map),
NULL, NULL, gst_rtp_bin_marshal_BOXED__UINT, GST_TYPE_CAPS, 1,
G_TYPE_UINT);
/**
* GstRtpPtDemux::new-payload-type:
* @demux: the object which received the signal
* @pt: the payload type
* @pad: the pad with the new payload
*
* Emited when a new payload type pad has been created in @demux.
*/
gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE] =
g_signal_new ("new-payload-type", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, new_payload_type),
NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT, G_TYPE_NONE, 2,
G_TYPE_UINT, GST_TYPE_PAD);
/**
* GstRtpPtDemux::payload-type-change:
* @demux: the object which received the signal
* @pt: the new payload type
*
* Emited when the payload type changed.
*/
gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
payload_type_change), NULL, NULL, g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1, G_TYPE_UINT);
/**
* GstRtpPtDemux::clear-pt-map:
* @demux: the object which received the signal
*
* The application can call this signal to instruct the element to discard the
* currently cached payload type map.
*/
gst_rtp_pt_demux_signals[SIGNAL_CLEAR_PT_MAP] =
g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, G_TYPE_NONE);
gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_finalize);
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_change_state);
klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_clear_pt_map);
GST_DEBUG_CATEGORY_INIT (gst_rtp_pt_demux_debug,
"rtpptdemux", 0, "RTP codec demuxer");
}
static void
gst_rtp_pt_demux_init (GstRtpPtDemux * ptdemux, GstRtpPtDemuxClass * g_class)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (ptdemux);
ptdemux->sink =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"sink"), "sink");
g_assert (ptdemux->sink != NULL);
gst_pad_set_chain_function (ptdemux->sink, gst_rtp_pt_demux_chain);
gst_element_add_pad (GST_ELEMENT (ptdemux), ptdemux->sink);
}
static void
gst_rtp_pt_demux_finalize (GObject * object)
{
gst_rtp_pt_demux_release (GST_RTP_PT_DEMUX (object));
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstCaps *
gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt)
{
GstCaps *caps;
GValue ret = { 0 };
GValue args[2] = { {0}, {0} };
/* figure out the caps */
g_value_init (&args[0], GST_TYPE_ELEMENT);
g_value_set_object (&args[0], rtpdemux);
g_value_init (&args[1], G_TYPE_UINT);
g_value_set_uint (&args[1], pt);
g_value_init (&ret, GST_TYPE_CAPS);
g_value_set_boxed (&ret, NULL);
g_signal_emitv (args, gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP], 0,
&ret);
g_value_unset (&args[0]);
g_value_unset (&args[1]);
caps = g_value_dup_boxed (&ret);
g_value_unset (&ret);
if (caps == NULL) {
caps = GST_PAD_CAPS (rtpdemux->sink);
if (caps)
gst_caps_ref (caps);
}
GST_DEBUG ("pt %d, got caps %" GST_PTR_FORMAT, pt, caps);
return caps;
}
static void
gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux)
{
GSList *walk;
GST_OBJECT_LOCK (rtpdemux);
GST_DEBUG ("clearing pt map");
for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpPtDemuxPad *pad = walk->data;
pad->newcaps = TRUE;
}
GST_OBJECT_UNLOCK (rtpdemux);
}
static GstFlowReturn
gst_rtp_pt_demux_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn ret = GST_FLOW_OK;
GstRtpPtDemux *rtpdemux;
GstElement *element = GST_ELEMENT (GST_OBJECT_PARENT (pad));
guint8 pt;
GstPad *srcpad;
GstRtpPtDemuxPad *rtpdemuxpad;
GstCaps *caps;
rtpdemux = GST_RTP_PT_DEMUX (GST_OBJECT_PARENT (pad));
if (!gst_rtp_buffer_validate (buf))
goto invalid_buffer;
pt = gst_rtp_buffer_get_payload_type (buf);
GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);
rtpdemuxpad = find_pad_for_pt (rtpdemux, pt);
if (rtpdemuxpad == NULL) {
/* new PT, create a src pad */
GstElementClass *klass;
GstPadTemplate *templ;
gchar *padname;
klass = GST_ELEMENT_GET_CLASS (rtpdemux);
templ = gst_element_class_get_pad_template (klass, "src_%d");
padname = g_strdup_printf ("src_%d", pt);
srcpad = gst_pad_new_from_template (templ, padname);
gst_pad_use_fixed_caps (srcpad);
g_free (padname);
caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
if (!caps)
goto no_caps;
caps = gst_caps_make_writable (caps);
gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
gst_pad_set_caps (srcpad, caps);
gst_caps_unref (caps);
GST_DEBUG ("Adding pt=%d to the list.", pt);
rtpdemuxpad = g_new0 (GstRtpPtDemuxPad, 1);
rtpdemuxpad->pt = pt;
rtpdemuxpad->newcaps = FALSE;
rtpdemuxpad->pad = srcpad;
GST_OBJECT_LOCK (rtpdemux);
rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
GST_OBJECT_UNLOCK (rtpdemux);
gst_pad_set_active (srcpad, TRUE);
gst_element_add_pad (element, srcpad);
GST_DEBUG ("emitting new-payload-type for pt %d", pt);
g_signal_emit (G_OBJECT (rtpdemux),
gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
}
srcpad = rtpdemuxpad->pad;
if (pt != rtpdemux->last_pt) {
gint emit_pt = pt;
/* our own signal with an extra flag that this is the only pad */
rtpdemux->last_pt = pt;
GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
g_signal_emit (G_OBJECT (rtpdemux),
gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
}
if (rtpdemuxpad->newcaps) {
GST_DEBUG ("need new caps");
caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
if (!caps)
goto no_caps;
caps = gst_caps_make_writable (caps);
gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
gst_pad_set_caps (srcpad, caps);
gst_caps_unref (caps);
rtpdemuxpad->newcaps = FALSE;
}
gst_buffer_set_caps (buf, GST_PAD_CAPS (srcpad));
/* push to srcpad */
ret = gst_pad_push (srcpad, buf);
return ret;
/* ERRORS */
invalid_buffer:
{
/* this is fatal and should be filtered earlier */
GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
("Dropping invalid RTP payload"));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
no_caps:
{
GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
("Could not get caps for payload"));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
}
static GstRtpPtDemuxPad *
find_pad_for_pt (GstRtpPtDemux * rtpdemux, guint8 pt)
{
GstRtpPtDemuxPad *respad = NULL;
GSList *walk;
for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpPtDemuxPad *pad = walk->data;
if (pad->pt == pt) {
respad = pad;
break;
}
}
return respad;
}
/**
* Reserves resources for the object.
*/
static gboolean
gst_rtp_pt_demux_setup (GstRtpPtDemux * ptdemux)
{
ptdemux->srcpads = NULL;
ptdemux->last_pt = 0xFFFF;
return TRUE;
}
/**
* Free resources for the object.
*/
static void
gst_rtp_pt_demux_release (GstRtpPtDemux * ptdemux)
{
GSList *walk;
for (walk = ptdemux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpPtDemuxPad *pad = walk->data;
gst_pad_set_active (pad->pad, FALSE);
gst_element_remove_pad (GST_ELEMENT_CAST (ptdemux), pad->pad);
g_free (pad);
}
g_slist_free (ptdemux->srcpads);
ptdemux->srcpads = NULL;
}
static GstStateChangeReturn
gst_rtp_pt_demux_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
GstRtpPtDemux *ptdemux;
ptdemux = GST_RTP_PT_DEMUX (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (gst_rtp_pt_demux_setup (ptdemux) != TRUE)
ret = GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
case GST_STATE_CHANGE_PAUSED_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_rtp_pt_demux_release (ptdemux);
break;
default:
break;
}
return ret;
}

View file

@ -1,62 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_RTP_PT_DEMUX_H__
#define __GST_RTP_PT_DEMUX_H__
#include <gst/gst.h>
#define GST_TYPE_RTP_PT_DEMUX (gst_rtp_pt_demux_get_type())
#define GST_RTP_PT_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PT_DEMUX,GstRtpPtDemux))
#define GST_RTP_PT_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PT_DEMUX,GstRtpPtDemuxClass))
#define GST_IS_RTP_PT_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PT_DEMUX))
#define GST_IS_RTP_PT_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PT_DEMUX))
typedef struct _GstRtpPtDemux GstRtpPtDemux;
typedef struct _GstRtpPtDemuxClass GstRtpPtDemuxClass;
typedef struct _GstRtpPtDemuxPad GstRtpPtDemuxPad;
struct _GstRtpPtDemux
{
GstElement parent; /**< parent class */
GstPad *sink; /**< the sink pad */
guint16 last_pt; /**< pt of the last packet 0xFFFF if none */
GSList *srcpads; /**< a linked list of GstRtpPtDemuxPad objects */
};
struct _GstRtpPtDemuxClass
{
GstElementClass parent_class;
/* get the caps for pt */
GstCaps* (*request_pt_map) (GstRtpPtDemux *demux, guint pt);
/* signal emmited when a new PT is found from the incoming stream */
void (*new_payload_type) (GstRtpPtDemux *demux, guint pt, GstPad * pad);
/* signal emitted when the payload type changes */
void (*payload_type_change) (GstRtpPtDemux *demux, guint pt);
void (*clear_pt_map) (GstRtpPtDemux *demux);
};
GType gst_rtp_pt_demux_get_type (void);
#endif /* __GST_RTP_PT_DEMUX_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,81 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_RTP_SESSION_H__
#define __GST_RTP_SESSION_H__
#include <gst/gst.h>
#define GST_TYPE_RTP_SESSION \
(gst_rtp_session_get_type())
#define GST_RTP_SESSION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SESSION,GstRtpSession))
#define GST_RTP_SESSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SESSION,GstRtpSessionClass))
#define GST_IS_RTP_SESSION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SESSION))
#define GST_IS_RTP_SESSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SESSION))
#define GST_RTP_SESSION_CAST(obj) ((GstRtpSession *)(obj))
typedef struct _GstRtpSession GstRtpSession;
typedef struct _GstRtpSessionClass GstRtpSessionClass;
typedef struct _GstRtpSessionPrivate GstRtpSessionPrivate;
struct _GstRtpSession {
GstElement element;
/*< private >*/
GstPad *recv_rtp_sink;
GstSegment recv_rtp_seg;
GstPad *recv_rtcp_sink;
GstPad *send_rtp_sink;
GstSegment send_rtp_seg;
GstPad *recv_rtp_src;
GstPad *sync_src;
GstPad *send_rtp_src;
GstPad *send_rtcp_src;
GstRtpSessionPrivate *priv;
};
struct _GstRtpSessionClass {
GstElementClass parent_class;
/* signals */
GstCaps* (*request_pt_map) (GstRtpSession *sess, guint pt);
void (*clear_pt_map) (GstRtpSession *sess);
void (*on_new_ssrc) (GstRtpSession *sess, guint32 ssrc);
void (*on_ssrc_collision) (GstRtpSession *sess, guint32 ssrc);
void (*on_ssrc_validated) (GstRtpSession *sess, guint32 ssrc);
void (*on_ssrc_active) (GstRtpSession *sess, guint32 ssrc);
void (*on_ssrc_sdes) (GstRtpSession *sess, guint32 ssrc);
void (*on_bye_ssrc) (GstRtpSession *sess, guint32 ssrc);
void (*on_bye_timeout) (GstRtpSession *sess, guint32 ssrc);
void (*on_timeout) (GstRtpSession *sess, guint32 ssrc);
void (*on_sender_timeout) (GstRtpSession *sess, guint32 ssrc);
};
GType gst_rtp_session_get_type (void);
void gst_rtp_session_set_ssrc (GstRtpSession *sess, guint32 ssrc);
#endif /* __GST_RTP_SESSION_H__ */

View file

@ -1,722 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
*
* RTP SSRC demuxer
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:element-gstrtpssrcdemux
*
* gstrtpssrcdemux acts as a demuxer for RTP packets based on the SSRC of the
* packets. Its main purpose is to allow an application to easily receive and
* decode an RTP stream with multiple SSRCs.
*
* For each SSRC that is detected, a new pad will be created and the
* #GstRtpSsrcDemux::new-ssrc-pad signal will be emitted.
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch udpsrc caps="application/x-rtp" ! gstrtpssrcdemux ! fakesink
* ]| Takes an RTP stream and send the RTP packets with the first detected SSRC
* to fakesink, discarding the other SSRCs.
* </refsect2>
*
* Last reviewed on 2007-05-28 (0.10.5)
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/rtp/gstrtcpbuffer.h>
#include "gstrtpbin-marshal.h"
#include "gstrtpssrcdemux.h"
GST_DEBUG_CATEGORY_STATIC (gst_rtp_ssrc_demux_debug);
#define GST_CAT_DEFAULT gst_rtp_ssrc_demux_debug
/* generic templates */
static GstStaticPadTemplate rtp_ssrc_demux_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp")
);
static GstStaticPadTemplate rtp_ssrc_demux_rtcp_sink_template =
GST_STATIC_PAD_TEMPLATE ("rtcp_sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtcp")
);
static GstStaticPadTemplate rtp_ssrc_demux_src_template =
GST_STATIC_PAD_TEMPLATE ("src_%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("application/x-rtp")
);
static GstStaticPadTemplate rtp_ssrc_demux_rtcp_src_template =
GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("application/x-rtcp")
);
static GstElementDetails gst_rtp_ssrc_demux_details = {
"RTP SSRC Demux",
"Demux/Network/RTP",
"Splits RTP streams based on the SSRC",
"Wim Taymans <wim.taymans@gmail.com>"
};
#define GST_PAD_LOCK(obj) (g_mutex_lock ((obj)->padlock))
#define GST_PAD_UNLOCK(obj) (g_mutex_unlock ((obj)->padlock))
/* signals */
enum
{
SIGNAL_NEW_SSRC_PAD,
SIGNAL_REMOVED_SSRC_PAD,
SIGNAL_CLEAR_SSRC,
LAST_SIGNAL
};
GST_BOILERPLATE (GstRtpSsrcDemux, gst_rtp_ssrc_demux, GstElement,
GST_TYPE_ELEMENT);
/* GObject vmethods */
static void gst_rtp_ssrc_demux_dispose (GObject * object);
static void gst_rtp_ssrc_demux_finalize (GObject * object);
/* GstElement vmethods */
static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement *
element, GstStateChange transition);
static void gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux,
guint32 ssrc);
/* sinkpad stuff */
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad,
GstBuffer * buf);
static gboolean gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad,
GstEvent * event);
/* srcpad stuff */
static gboolean gst_rtp_ssrc_demux_src_event (GstPad * pad, GstEvent * event);
static GList *gst_rtp_ssrc_demux_internal_links (GstPad * pad);
static gboolean gst_rtp_ssrc_demux_src_query (GstPad * pad, GstQuery * query);
static guint gst_rtp_ssrc_demux_signals[LAST_SIGNAL] = { 0 };
/*
* Item for storing GstPad <-> SSRC pairs.
*/
struct _GstRtpSsrcDemuxPad
{
guint32 ssrc;
GstPad *rtp_pad;
GstCaps *caps;
GstPad *rtcp_pad;
};
/* find a src pad for a given SSRC, returns NULL if the SSRC was not found
*/
static GstRtpSsrcDemuxPad *
find_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
{
GSList *walk;
for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
if (pad->ssrc == ssrc)
return pad;
}
return NULL;
}
/* with PAD_LOCK */
static GstRtpSsrcDemuxPad *
create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc,
GstClockTime timestamp)
{
GstPad *rtp_pad, *rtcp_pad;
GstElementClass *klass;
GstPadTemplate *templ;
gchar *padname;
GstRtpSsrcDemuxPad *demuxpad;
GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
klass = GST_ELEMENT_GET_CLASS (demux);
templ = gst_element_class_get_pad_template (klass, "src_%d");
padname = g_strdup_printf ("src_%d", ssrc);
rtp_pad = gst_pad_new_from_template (templ, padname);
g_free (padname);
templ = gst_element_class_get_pad_template (klass, "rtcp_src_%d");
padname = g_strdup_printf ("rtcp_src_%d", ssrc);
rtcp_pad = gst_pad_new_from_template (templ, padname);
g_free (padname);
/* we use the first timestamp received to calculate the difference between
* timestamps on all streams */
GST_DEBUG_OBJECT (demux, "SSRC %08x, first timestamp %" GST_TIME_FORMAT,
ssrc, GST_TIME_ARGS (timestamp));
/* wrap in structure and add to list */
demuxpad = g_new0 (GstRtpSsrcDemuxPad, 1);
demuxpad->ssrc = ssrc;
demuxpad->rtp_pad = rtp_pad;
demuxpad->rtcp_pad = rtcp_pad;
GST_DEBUG_OBJECT (demux, "first timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
gst_pad_set_element_private (rtp_pad, demuxpad);
gst_pad_set_element_private (rtcp_pad, demuxpad);
demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad);
/* copy caps from input */
gst_pad_set_caps (rtp_pad, GST_PAD_CAPS (demux->rtp_sink));
gst_pad_use_fixed_caps (rtp_pad);
gst_pad_set_caps (rtcp_pad, GST_PAD_CAPS (demux->rtcp_sink));
gst_pad_use_fixed_caps (rtcp_pad);
gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event);
gst_pad_set_query_function (rtp_pad, gst_rtp_ssrc_demux_src_query);
gst_pad_set_internal_link_function (rtp_pad,
gst_rtp_ssrc_demux_internal_links);
gst_pad_set_active (rtp_pad, TRUE);
gst_pad_set_internal_link_function (rtcp_pad,
gst_rtp_ssrc_demux_internal_links);
gst_pad_set_active (rtcp_pad, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (demux), rtp_pad);
gst_element_add_pad (GST_ELEMENT_CAST (demux), rtcp_pad);
g_signal_emit (G_OBJECT (demux),
gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad);
return demuxpad;
}
static void
gst_rtp_ssrc_demux_base_init (gpointer g_class)
{
GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_ssrc_demux_sink_template));
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_ssrc_demux_rtcp_sink_template));
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_ssrc_demux_src_template));
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&rtp_ssrc_demux_rtcp_src_template));
gst_element_class_set_details (gstelement_klass, &gst_rtp_ssrc_demux_details);
}
static void
gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass)
{
GObjectClass *gobject_klass;
GstElementClass *gstelement_klass;
GstRtpSsrcDemuxClass *gstrtpssrcdemux_klass;
gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass;
gstrtpssrcdemux_klass = (GstRtpSsrcDemuxClass *) klass;
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_dispose);
gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_finalize);
/**
* GstRtpSsrcDemux::new-ssrc-pad:
* @demux: the object which received the signal
* @ssrc: the SSRC of the pad
* @pad: the new pad.
*
* Emited when a new SSRC pad has been created.
*/
gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD] =
g_signal_new ("new-ssrc-pad",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, new_ssrc_pad),
NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
/**
* GstRtpSsrcDemux::removed-ssrc-pad:
* @demux: the object which received the signal
* @ssrc: the SSRC of the pad
* @pad: the removed pad.
*
* Emited when a SSRC pad has been removed.
*/
gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD] =
g_signal_new ("removed-ssrc-pad",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, removed_ssrc_pad),
NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
/**
* GstRtpSsrcDemux::clear-ssrc:
* @demux: the object which received the signal
* @ssrc: the SSRC of the pad
*
* Action signal to remove the pad for SSRC.
*/
gst_rtp_ssrc_demux_signals[SIGNAL_CLEAR_SSRC] =
g_signal_new ("clear-ssrc",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, clear_ssrc),
NULL, NULL, gst_rtp_bin_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_change_state);
gstrtpssrcdemux_klass->clear_ssrc =
GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_clear_ssrc);
GST_DEBUG_CATEGORY_INIT (gst_rtp_ssrc_demux_debug,
"rtpssrcdemux", 0, "RTP SSRC demuxer");
}
static void
gst_rtp_ssrc_demux_init (GstRtpSsrcDemux * demux,
GstRtpSsrcDemuxClass * g_class)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
demux->rtp_sink =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"sink"), "sink");
gst_pad_set_chain_function (demux->rtp_sink, gst_rtp_ssrc_demux_chain);
gst_pad_set_event_function (demux->rtp_sink, gst_rtp_ssrc_demux_sink_event);
gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtp_sink);
demux->rtcp_sink =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"rtcp_sink"), "rtcp_sink");
gst_pad_set_chain_function (demux->rtcp_sink, gst_rtp_ssrc_demux_rtcp_chain);
gst_pad_set_event_function (demux->rtcp_sink,
gst_rtp_ssrc_demux_rtcp_sink_event);
gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtcp_sink);
demux->padlock = g_mutex_new ();
gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
}
static void
gst_rtp_ssrc_demux_reset (GstRtpSsrcDemux * demux)
{
GSList *walk;
for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data;
gst_pad_set_active (dpad->rtp_pad, FALSE);
gst_pad_set_active (dpad->rtcp_pad, FALSE);
gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);
g_free (dpad);
}
g_slist_free (demux->srcpads);
demux->srcpads = NULL;
}
static void
gst_rtp_ssrc_demux_dispose (GObject * object)
{
GstRtpSsrcDemux *demux;
demux = GST_RTP_SSRC_DEMUX (object);
gst_rtp_ssrc_demux_reset (demux);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_rtp_ssrc_demux_finalize (GObject * object)
{
GstRtpSsrcDemux *demux;
demux = GST_RTP_SSRC_DEMUX (object);
g_mutex_free (demux->padlock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
{
GstRtpSsrcDemuxPad *dpad;
GST_PAD_LOCK (demux);
dpad = find_demux_pad_for_ssrc (demux, ssrc);
if (dpad != NULL)
goto unknown_pad;
GST_DEBUG_OBJECT (demux, "clearing pad for SSRC %08x", ssrc);
demux->srcpads = g_slist_remove (demux->srcpads, dpad);
GST_PAD_UNLOCK (demux);
gst_pad_set_active (dpad->rtp_pad, FALSE);
gst_pad_set_active (dpad->rtcp_pad, FALSE);
g_signal_emit (G_OBJECT (demux),
gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD], 0, ssrc,
dpad->rtp_pad);
gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);
g_free (dpad);
return;
/* ERRORS */
unknown_pad:
{
g_warning ("unknown SSRC %08x", ssrc);
return;
}
}
static gboolean
gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event)
{
GstRtpSsrcDemux *demux;
gboolean res = FALSE;
demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
case GST_EVENT_NEWSEGMENT:
default:
{
GSList *walk;
res = TRUE;
GST_PAD_LOCK (demux);
for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
gst_event_ref (event);
res &= gst_pad_push_event (pad->rtp_pad, event);
}
GST_PAD_UNLOCK (demux);
gst_event_unref (event);
break;
}
}
gst_object_unref (demux);
return res;
}
static gboolean
gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad, GstEvent * event)
{
GstRtpSsrcDemux *demux;
gboolean res = FALSE;
demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:
default:
{
GSList *walk;
res = TRUE;
GST_PAD_LOCK (demux);
for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;
gst_event_ref (event);
res &= gst_pad_push_event (pad->rtcp_pad, event);
}
GST_PAD_UNLOCK (demux);
gst_event_unref (event);
break;
}
}
gst_object_unref (demux);
return res;
}
static GstFlowReturn
gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn ret;
GstRtpSsrcDemux *demux;
guint32 ssrc;
GstRtpSsrcDemuxPad *dpad;
demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));
if (!gst_rtp_buffer_validate (buf))
goto invalid_payload;
ssrc = gst_rtp_buffer_get_ssrc (buf);
GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc);
GST_PAD_LOCK (demux);
dpad = find_demux_pad_for_ssrc (demux, ssrc);
if (dpad == NULL) {
if (!(dpad =
create_demux_pad_for_ssrc (demux, ssrc,
GST_BUFFER_TIMESTAMP (buf))))
goto create_failed;
}
GST_PAD_UNLOCK (demux);
/* push to srcpad */
ret = gst_pad_push (dpad->rtp_pad, buf);
return ret;
/* ERRORS */
invalid_payload:
{
/* this is fatal and should be filtered earlier */
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
("Dropping invalid RTP payload"));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
create_failed:
{
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
("Could not create new pad"));
GST_PAD_UNLOCK (demux);
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn ret;
GstRtpSsrcDemux *demux;
guint32 ssrc;
GstRtpSsrcDemuxPad *dpad;
GstRTCPPacket packet;
demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));
if (!gst_rtcp_buffer_validate (buf))
goto invalid_rtcp;
if (!gst_rtcp_buffer_get_first_packet (buf, &packet))
goto invalid_rtcp;
/* first packet must be SR or RR or else the validate would have failed */
switch (gst_rtcp_packet_get_type (&packet)) {
case GST_RTCP_TYPE_SR:
/* get the ssrc so that we can route it to the right source pad */
gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
NULL);
break;
default:
goto unexpected_rtcp;
}
GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);
GST_PAD_LOCK (demux);
dpad = find_demux_pad_for_ssrc (demux, ssrc);
if (dpad == NULL) {
GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
if (!(dpad = create_demux_pad_for_ssrc (demux, ssrc, -1)))
goto create_failed;
}
GST_PAD_UNLOCK (demux);
/* push to srcpad */
ret = gst_pad_push (dpad->rtcp_pad, buf);
return ret;
/* ERRORS */
invalid_rtcp:
{
/* this is fatal and should be filtered earlier */
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
("Dropping invalid RTCP packet"));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
unexpected_rtcp:
{
GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
create_failed:
{
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
("Could not create new pad"));
GST_PAD_UNLOCK (demux);
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
}
static gboolean
gst_rtp_ssrc_demux_src_event (GstPad * pad, GstEvent * event)
{
GstRtpSsrcDemux *demux;
gboolean res = FALSE;
demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (demux);
return res;
}
static GList *
gst_rtp_ssrc_demux_internal_links (GstPad * pad)
{
GstRtpSsrcDemux *demux;
GList *res = NULL;
GSList *walk;
demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
GST_PAD_LOCK (demux);
for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data;
if (pad == demux->rtp_sink) {
res = g_list_prepend (res, dpad->rtp_pad);
} else if (pad == demux->rtcp_sink) {
res = g_list_prepend (res, dpad->rtcp_pad);
} else if (pad == dpad->rtp_pad) {
res = g_list_prepend (res, demux->rtp_sink);
break;
} else if (pad == dpad->rtcp_pad) {
res = g_list_prepend (res, demux->rtcp_sink);
break;
}
}
GST_PAD_UNLOCK (demux);
gst_object_unref (demux);
return res;
}
static gboolean
gst_rtp_ssrc_demux_src_query (GstPad * pad, GstQuery * query)
{
GstRtpSsrcDemux *demux;
gboolean res = FALSE;
demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:
{
if ((res = gst_pad_peer_query (demux->rtp_sink, query))) {
gboolean live;
GstClockTime min_latency, max_latency;
GstRtpSsrcDemuxPad *demuxpad;
demuxpad = gst_pad_get_element_private (pad);
gst_query_parse_latency (query, &live, &min_latency, &max_latency);
GST_DEBUG_OBJECT (demux, "peer min latency %" GST_TIME_FORMAT,
GST_TIME_ARGS (min_latency));
GST_DEBUG_OBJECT (demux, "latency for SSRC %08x", demuxpad->ssrc);
gst_query_set_latency (query, live, min_latency, max_latency);
}
break;
}
default:
res = gst_pad_query_default (pad, query);
break;
}
gst_object_unref (demux);
return res;
}
static GstStateChangeReturn
gst_rtp_ssrc_demux_change_state (GstElement * element,
GstStateChange transition)
{
GstStateChangeReturn ret;
GstRtpSsrcDemux *demux;
demux = GST_RTP_SSRC_DEMUX (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
case GST_STATE_CHANGE_READY_TO_PAUSED:
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_rtp_ssrc_demux_reset (demux);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
default:
break;
}
return ret;
}

View file

@ -1,62 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_RTP_SSRC_DEMUX_H__
#define __GST_RTP_SSRC_DEMUX_H__
#include <gst/gst.h>
#define GST_TYPE_RTP_SSRC_DEMUX (gst_rtp_ssrc_demux_get_type())
#define GST_RTP_SSRC_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SSRC_DEMUX,GstRtpSsrcDemux))
#define GST_RTP_SSRC_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SSRC_DEMUX,GstRtpSsrcDemuxClass))
#define GST_IS_RTP_SSRC_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SSRC_DEMUX))
#define GST_IS_RTP_SSRC_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SSRC_DEMUX))
typedef struct _GstRtpSsrcDemux GstRtpSsrcDemux;
typedef struct _GstRtpSsrcDemuxClass GstRtpSsrcDemuxClass;
typedef struct _GstRtpSsrcDemuxPad GstRtpSsrcDemuxPad;
struct _GstRtpSsrcDemux
{
GstElement parent;
GstSegment segment;
GstPad *rtp_sink;
GstPad *rtcp_sink;
GMutex *padlock;
GSList *srcpads;
};
struct _GstRtpSsrcDemuxClass
{
GstElementClass parent_class;
/* signals */
void (*new_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
void (*removed_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
/* actions */
void (*clear_ssrc) (GstRtpSsrcDemux *demux, guint32 ssrc);
};
GType gst_rtp_ssrc_demux_get_type (void);
#endif /* __GST_RTP_SSRC_DEMUX_H__ */

View file

@ -1,593 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/rtp/gstrtcpbuffer.h>
#include "rtpjitterbuffer.h"
GST_DEBUG_CATEGORY_STATIC (rtp_jitter_buffer_debug);
#define GST_CAT_DEFAULT rtp_jitter_buffer_debug
#define MAX_WINDOW RTP_JITTER_BUFFER_MAX_WINDOW
#define MAX_TIME (2 * GST_SECOND)
/* signals and args */
enum
{
LAST_SIGNAL
};
enum
{
PROP_0
};
/* GObject vmethods */
static void rtp_jitter_buffer_finalize (GObject * object);
/* static guint rtp_jitter_buffer_signals[LAST_SIGNAL] = { 0 }; */
G_DEFINE_TYPE (RTPJitterBuffer, rtp_jitter_buffer, G_TYPE_OBJECT);
static void
rtp_jitter_buffer_class_init (RTPJitterBufferClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gobject_class->finalize = rtp_jitter_buffer_finalize;
GST_DEBUG_CATEGORY_INIT (rtp_jitter_buffer_debug, "rtpjitterbuffer", 0,
"RTP Jitter Buffer");
}
static void
rtp_jitter_buffer_init (RTPJitterBuffer * jbuf)
{
jbuf->packets = g_queue_new ();
rtp_jitter_buffer_reset_skew (jbuf);
}
static void
rtp_jitter_buffer_finalize (GObject * object)
{
RTPJitterBuffer *jbuf;
jbuf = RTP_JITTER_BUFFER_CAST (object);
rtp_jitter_buffer_flush (jbuf);
g_queue_free (jbuf->packets);
G_OBJECT_CLASS (rtp_jitter_buffer_parent_class)->finalize (object);
}
/**
* rtp_jitter_buffer_new:
*
* Create an #RTPJitterBuffer.
*
* Returns: a new #RTPJitterBuffer. Use g_object_unref() after usage.
*/
RTPJitterBuffer *
rtp_jitter_buffer_new (void)
{
RTPJitterBuffer *jbuf;
jbuf = g_object_new (RTP_TYPE_JITTER_BUFFER, NULL);
return jbuf;
}
void
rtp_jitter_buffer_reset_skew (RTPJitterBuffer * jbuf)
{
jbuf->base_time = -1;
jbuf->base_rtptime = -1;
jbuf->base_extrtp = -1;
jbuf->clock_rate = -1;
jbuf->ext_rtptime = -1;
jbuf->last_rtptime = -1;
jbuf->window_pos = 0;
jbuf->window_filling = TRUE;
jbuf->window_min = 0;
jbuf->skew = 0;
jbuf->prev_send_diff = -1;
jbuf->prev_out_time = -1;
GST_DEBUG ("reset skew correction");
}
/* For the clock skew we use a windowed low point averaging algorithm as can be
* found in http://www.grame.fr/pub/TR-050601.pdf. The idea is that the jitter is
* composed of:
*
* J = N + n
*
* N : a constant network delay.
* n : random added noise. The noise is concentrated around 0
*
* In the receiver we can track the elapsed time at the sender with:
*
* send_diff(i) = (Tsi - Ts0);
*
* Tsi : The time at the sender at packet i
* Ts0 : The time at the sender at the first packet
*
* This is the difference between the RTP timestamp in the first received packet
* and the current packet.
*
* At the receiver we have to deal with the jitter introduced by the network.
*
* recv_diff(i) = (Tri - Tr0)
*
* Tri : The time at the receiver at packet i
* Tr0 : The time at the receiver at the first packet
*
* Both of these values contain a jitter Ji, a jitter for packet i, so we can
* write:
*
* recv_diff(i) = (Cri + D + ni) - (Cr0 + D + n0))
*
* Cri : The time of the clock at the receiver for packet i
* D + ni : The jitter when receiving packet i
*
* We see that the network delay is irrelevant here as we can elliminate D:
*
* recv_diff(i) = (Cri + ni) - (Cr0 + n0))
*
* The drift is now expressed as:
*
* Drift(i) = recv_diff(i) - send_diff(i);
*
* We now keep the W latest values of Drift and find the minimum (this is the
* one with the lowest network jitter and thus the one which is least affected
* by it). We average this lowest value to smooth out the resulting network skew.
*
* Both the window and the weighting used for averaging influence the accuracy
* of the drift estimation. Finding the correct parameters turns out to be a
* compromise between accuracy and inertia.
*
* We use a 2 second window or up to 512 data points, which is statistically big
* enough to catch spikes (FIXME, detect spikes).
* We also use a rather large weighting factor (125) to smoothly adapt. During
* startup, when filling the window, we use a parabolic weighting factor, the
* more the window is filled, the faster we move to the detected possible skew.
*
* Returns: @time adjusted with the clock skew.
*/
static GstClockTime
calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
guint32 clock_rate)
{
guint64 ext_rtptime;
guint64 send_diff, recv_diff;
gint64 delta;
gint64 old;
gint pos, i;
GstClockTime gstrtptime, out_time;
ext_rtptime = gst_rtp_buffer_ext_timestamp (&jbuf->ext_rtptime, rtptime);
gstrtptime = gst_util_uint64_scale_int (ext_rtptime, GST_SECOND, clock_rate);
/* keep track of the last extended rtptime */
jbuf->last_rtptime = ext_rtptime;
if (jbuf->clock_rate != clock_rate) {
GST_WARNING ("Clock rate changed from %" G_GUINT32_FORMAT " to %"
G_GUINT32_FORMAT, jbuf->clock_rate, clock_rate);
jbuf->base_time = -1;
jbuf->base_rtptime = -1;
jbuf->clock_rate = clock_rate;
jbuf->prev_out_time = -1;
jbuf->prev_send_diff = -1;
}
/* first time, lock on to time and gstrtptime */
if (G_UNLIKELY (jbuf->base_time == -1)) {
jbuf->base_time = time;
jbuf->prev_out_time = -1;
GST_DEBUG ("Taking new base time %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
}
if (G_UNLIKELY (jbuf->base_rtptime == -1)) {
jbuf->base_rtptime = gstrtptime;
jbuf->base_extrtp = ext_rtptime;
jbuf->prev_send_diff = -1;
GST_DEBUG ("Taking new base rtptime %" GST_TIME_FORMAT,
GST_TIME_ARGS (gstrtptime));
}
if (G_LIKELY (gstrtptime >= jbuf->base_rtptime))
send_diff = gstrtptime - jbuf->base_rtptime;
else {
/* elapsed time at sender, timestamps can go backwards and thus be smaller
* than our base time, take a new base time in that case. */
GST_WARNING ("backward timestamps at server, taking new base time");
jbuf->base_time = time;
jbuf->base_rtptime = gstrtptime;
jbuf->base_extrtp = ext_rtptime;
jbuf->prev_out_time = -1;
jbuf->prev_send_diff = -1;
send_diff = 0;
}
GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
GST_TIME_ARGS (send_diff));
/* we don't have an arrival timestamp so we can't do skew detection. we
* should still apply a timestamp based on RTP timestamp and base_time */
if (time == -1 || jbuf->base_time == -1)
goto no_skew;
/* elapsed time at receiver, includes the jitter */
recv_diff = time - jbuf->base_time;
GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", recv_diff %"
GST_TIME_FORMAT, GST_TIME_ARGS (time), GST_TIME_ARGS (jbuf->base_time),
GST_TIME_ARGS (recv_diff));
/* measure the diff */
delta = ((gint64) recv_diff) - ((gint64) send_diff);
/* if the difference between the sender timeline and the receiver timeline
* changed too quickly we have to resync because the server likely restarted
* its timestamps. */
if (ABS (delta - jbuf->skew) > GST_SECOND) {
GST_WARNING ("delta %" GST_TIME_FORMAT " too big, reset skew",
GST_TIME_ARGS (delta - jbuf->skew));
jbuf->base_time = time;
jbuf->base_rtptime = gstrtptime;
jbuf->base_extrtp = ext_rtptime;
jbuf->prev_out_time = -1;
jbuf->prev_send_diff = -1;
send_diff = 0;
delta = 0;
}
pos = jbuf->window_pos;
if (G_UNLIKELY (jbuf->window_filling)) {
/* we are filling the window */
GST_DEBUG ("filling %d, delta %" G_GINT64_FORMAT, pos, delta);
jbuf->window[pos++] = delta;
/* calc the min delta we observed */
if (G_UNLIKELY (pos == 1 || delta < jbuf->window_min))
jbuf->window_min = delta;
if (G_UNLIKELY (send_diff >= MAX_TIME || pos >= MAX_WINDOW)) {
jbuf->window_size = pos;
/* window filled */
GST_DEBUG ("min %" G_GINT64_FORMAT, jbuf->window_min);
/* the skew is now the min */
jbuf->skew = jbuf->window_min;
jbuf->window_filling = FALSE;
} else {
gint perc_time, perc_window, perc;
/* figure out how much we filled the window, this depends on the amount of
* time we have or the max number of points we keep. */
perc_time = send_diff * 100 / MAX_TIME;
perc_window = pos * 100 / MAX_WINDOW;
perc = MAX (perc_time, perc_window);
/* make a parabolic function, the closer we get to the MAX, the more value
* we give to the scaling factor of the new value */
perc = perc * perc;
/* quickly go to the min value when we are filling up, slowly when we are
* just starting because we're not sure it's a good value yet. */
jbuf->skew =
(perc * jbuf->window_min + ((10000 - perc) * jbuf->skew)) / 10000;
jbuf->window_size = pos + 1;
}
} else {
/* pick old value and store new value. We keep the previous value in order
* to quickly check if the min of the window changed */
old = jbuf->window[pos];
jbuf->window[pos++] = delta;
if (G_UNLIKELY (delta <= jbuf->window_min)) {
/* if the new value we inserted is smaller or equal to the current min,
* it becomes the new min */
jbuf->window_min = delta;
} else if (G_UNLIKELY (old == jbuf->window_min)) {
gint64 min = G_MAXINT64;
/* if we removed the old min, we have to find a new min */
for (i = 0; i < jbuf->window_size; i++) {
/* we found another value equal to the old min, we can stop searching now */
if (jbuf->window[i] == old) {
min = old;
break;
}
if (jbuf->window[i] < min)
min = jbuf->window[i];
}
jbuf->window_min = min;
}
/* average the min values */
jbuf->skew = (jbuf->window_min + (124 * jbuf->skew)) / 125;
GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT,
delta, jbuf->window_min);
}
/* wrap around in the window */
if (G_UNLIKELY (pos >= jbuf->window_size))
pos = 0;
jbuf->window_pos = pos;
no_skew:
/* the output time is defined as the base timestamp plus the RTP time
* adjusted for the clock skew .*/
if (jbuf->base_time != -1) {
out_time = jbuf->base_time + send_diff + jbuf->skew;
/* check if timestamps are not going backwards, we can only check this if we
* have a previous out time and a previous send_diff */
if (G_LIKELY (jbuf->prev_out_time != -1 && jbuf->prev_send_diff != -1)) {
/* now check for backwards timestamps */
if (G_UNLIKELY (
/* if the server timestamps went up and the out_time backwards */
(send_diff > jbuf->prev_send_diff
&& out_time < jbuf->prev_out_time) ||
/* if the server timestamps went backwards and the out_time forwards */
(send_diff < jbuf->prev_send_diff
&& out_time > jbuf->prev_out_time) ||
/* if the server timestamps did not change */
send_diff == jbuf->prev_send_diff)) {
GST_DEBUG ("backwards timestamps, using previous time");
out_time = jbuf->prev_out_time;
}
}
} else
out_time = -1;
jbuf->prev_out_time = out_time;
jbuf->prev_send_diff = send_diff;
GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
jbuf->skew, GST_TIME_ARGS (out_time));
return out_time;
}
/**
* rtp_jitter_buffer_insert:
* @jbuf: an #RTPJitterBuffer
* @buf: a buffer
* @time: a running_time when this buffer was received in nanoseconds
* @clock_rate: the clock-rate of the payload of @buf
* @tail: TRUE when the tail element changed.
*
* Inserts @buf into the packet queue of @jbuf. The sequence number of the
* packet will be used to sort the packets. This function takes ownerhip of
* @buf when the function returns %TRUE.
* @buf should have writable metadata when calling this function.
*
* Returns: %FALSE if a packet with the same number already existed.
*/
gboolean
rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
GstClockTime time, guint32 clock_rate, gboolean * tail)
{
GList *list;
guint32 rtptime;
guint16 seqnum;
g_return_val_if_fail (jbuf != NULL, FALSE);
g_return_val_if_fail (buf != NULL, FALSE);
seqnum = gst_rtp_buffer_get_seq (buf);
/* loop the list to skip strictly smaller seqnum buffers */
for (list = jbuf->packets->head; list; list = g_list_next (list)) {
guint16 qseq;
gint gap;
qseq = gst_rtp_buffer_get_seq (GST_BUFFER_CAST (list->data));
/* compare the new seqnum to the one in the buffer */
gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq);
/* we hit a packet with the same seqnum, notify a duplicate */
if (G_UNLIKELY (gap == 0))
goto duplicate;
/* seqnum > qseq, we can stop looking */
if (G_LIKELY (gap < 0))
break;
}
/* do skew calculation by measuring the difference between rtptime and the
* receive time, this function will retimestamp @buf with the skew corrected
* running time. */
rtptime = gst_rtp_buffer_get_timestamp (buf);
time = calculate_skew (jbuf, rtptime, time, clock_rate);
GST_BUFFER_TIMESTAMP (buf) = time;
/* It's more likely that the packet was inserted in the front of the buffer */
if (G_LIKELY (list))
g_queue_insert_before (jbuf->packets, list, buf);
else
g_queue_push_tail (jbuf->packets, buf);
/* tail was changed when we did not find a previous packet, we set the return
* flag when requested. */
if (G_LIKELY (tail))
*tail = (list == NULL);
return TRUE;
/* ERRORS */
duplicate:
{
GST_WARNING ("duplicate packet %d found", (gint) seqnum);
return FALSE;
}
}
/**
* rtp_jitter_buffer_pop:
* @jbuf: an #RTPJitterBuffer
*
* Pops the oldest buffer from the packet queue of @jbuf. The popped buffer will
* have its timestamp adjusted with the incomming running_time and the detected
* clock skew.
*
* Returns: a #GstBuffer or %NULL when there was no packet in the queue.
*/
GstBuffer *
rtp_jitter_buffer_pop (RTPJitterBuffer * jbuf)
{
GstBuffer *buf;
g_return_val_if_fail (jbuf != NULL, FALSE);
buf = g_queue_pop_tail (jbuf->packets);
return buf;
}
/**
* rtp_jitter_buffer_peek:
* @jbuf: an #RTPJitterBuffer
*
* Peek the oldest buffer from the packet queue of @jbuf. Register a callback
* with rtp_jitter_buffer_set_tail_changed() to be notified when an older packet
* was inserted in the queue.
*
* Returns: a #GstBuffer or %NULL when there was no packet in the queue.
*/
GstBuffer *
rtp_jitter_buffer_peek (RTPJitterBuffer * jbuf)
{
GstBuffer *buf;
g_return_val_if_fail (jbuf != NULL, FALSE);
buf = g_queue_peek_tail (jbuf->packets);
return buf;
}
/**
* rtp_jitter_buffer_flush:
* @jbuf: an #RTPJitterBuffer
*
* Flush all packets from the jitterbuffer.
*/
void
rtp_jitter_buffer_flush (RTPJitterBuffer * jbuf)
{
GstBuffer *buffer;
g_return_if_fail (jbuf != NULL);
while ((buffer = g_queue_pop_head (jbuf->packets)))
gst_buffer_unref (buffer);
}
/**
* rtp_jitter_buffer_num_packets:
* @jbuf: an #RTPJitterBuffer
*
* Get the number of packets currently in "jbuf.
*
* Returns: The number of packets in @jbuf.
*/
guint
rtp_jitter_buffer_num_packets (RTPJitterBuffer * jbuf)
{
g_return_val_if_fail (jbuf != NULL, 0);
return jbuf->packets->length;
}
/**
* rtp_jitter_buffer_get_ts_diff:
* @jbuf: an #RTPJitterBuffer
*
* Get the difference between the timestamps of first and last packet in the
* jitterbuffer.
*
* Returns: The difference expressed in the timestamp units of the packets.
*/
guint32
rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer * jbuf)
{
guint64 high_ts, low_ts;
GstBuffer *high_buf, *low_buf;
guint32 result;
g_return_val_if_fail (jbuf != NULL, 0);
high_buf = g_queue_peek_head (jbuf->packets);
low_buf = g_queue_peek_tail (jbuf->packets);
if (!high_buf || !low_buf || high_buf == low_buf)
return 0;
high_ts = gst_rtp_buffer_get_timestamp (high_buf);
low_ts = gst_rtp_buffer_get_timestamp (low_buf);
/* it needs to work if ts wraps */
if (high_ts >= low_ts) {
result = (guint32) (high_ts - low_ts);
} else {
result = (guint32) (high_ts + G_MAXUINT32 + 1 - low_ts);
}
return result;
}
/**
* rtp_jitter_buffer_get_sync:
* @jbuf: an #RTPJitterBuffer
* @rtptime: result RTP time
* @timestamp: result GStreamer timestamp
* @clock_rate: clock-rate of @rtptime
* @last_rtptime: last seen rtptime.
*
* Calculates the relation between the RTP timestamp and the GStreamer timestamp
* used for constructing timestamps.
*
* For extended RTP timestamp @rtptime with a clock-rate of @clock_rate,
* the GStreamer timestamp is currently @timestamp.
*
* The last seen extended RTP timestamp with clock-rate @clock-rate is returned in
* @last_rtptime.
*/
void
rtp_jitter_buffer_get_sync (RTPJitterBuffer * jbuf, guint64 * rtptime,
guint64 * timestamp, guint32 * clock_rate, guint64 * last_rtptime)
{
if (rtptime)
*rtptime = jbuf->base_extrtp;
if (timestamp)
*timestamp = jbuf->base_time + jbuf->skew;
if (clock_rate)
*clock_rate = jbuf->clock_rate;
if (last_rtptime)
*last_rtptime = jbuf->last_rtptime;
}

View file

@ -1,101 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __RTP_JITTER_BUFFER_H__
#define __RTP_JITTER_BUFFER_H__
#include <gst/gst.h>
#include <gst/rtp/gstrtcpbuffer.h>
typedef struct _RTPJitterBuffer RTPJitterBuffer;
typedef struct _RTPJitterBufferClass RTPJitterBufferClass;
#define RTP_TYPE_JITTER_BUFFER (rtp_jitter_buffer_get_type())
#define RTP_JITTER_BUFFER(src) (G_TYPE_CHECK_INSTANCE_CAST((src),RTP_TYPE_JITTER_BUFFER,RTPJitterBuffer))
#define RTP_JITTER_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RTP_TYPE_JITTER_BUFFER,RTPJitterBufferClass))
#define RTP_IS_JITTER_BUFFER(src) (G_TYPE_CHECK_INSTANCE_TYPE((src),RTP_TYPE_JITTER_BUFFER))
#define RTP_IS_JITTER_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RTP_TYPE_JITTER_BUFFER))
#define RTP_JITTER_BUFFER_CAST(src) ((RTPJitterBuffer *)(src))
/**
* RTPTailChanged:
* @jbuf: an #RTPJitterBuffer
* @user_data: user data specified when registering
*
* This callback will be called when the tail buffer of @jbuf changed.
*/
typedef void (*RTPTailChanged) (RTPJitterBuffer *jbuf, gpointer user_data);
#define RTP_JITTER_BUFFER_MAX_WINDOW 512
/**
* RTPJitterBuffer:
*
* A JitterBuffer in the #RTPSession
*/
struct _RTPJitterBuffer {
GObject object;
GQueue *packets;
/* for calculating skew */
GstClockTime base_time;
GstClockTime base_rtptime;
guint32 clock_rate;
GstClockTime base_extrtp;
GstClockTime prev_out_time;
guint64 ext_rtptime;
guint64 last_rtptime;
gint64 window[RTP_JITTER_BUFFER_MAX_WINDOW];
guint window_pos;
guint window_size;
gboolean window_filling;
gint64 window_min;
gint64 skew;
gint64 prev_send_diff;
};
struct _RTPJitterBufferClass {
GObjectClass parent_class;
};
GType rtp_jitter_buffer_get_type (void);
/* managing lifetime */
RTPJitterBuffer* rtp_jitter_buffer_new (void);
void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf);
gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf, GstBuffer *buf,
GstClockTime time,
guint32 clock_rate,
gboolean *tail);
GstBuffer * rtp_jitter_buffer_peek (RTPJitterBuffer *jbuf);
GstBuffer * rtp_jitter_buffer_pop (RTPJitterBuffer *jbuf);
void rtp_jitter_buffer_flush (RTPJitterBuffer *jbuf);
guint rtp_jitter_buffer_num_packets (RTPJitterBuffer *jbuf);
guint32 rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer *jbuf);
void rtp_jitter_buffer_get_sync (RTPJitterBuffer *jbuf, guint64 *rtptime,
guint64 *timestamp, guint32 *clock_rate,
guint64 *last_rtptime);
#endif /* __RTP_JITTER_BUFFER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,306 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __RTP_SESSION_H__
#define __RTP_SESSION_H__
#include <gst/gst.h>
#include <gst/netbuffer/gstnetbuffer.h>
#include "rtpsource.h"
typedef struct _RTPSession RTPSession;
typedef struct _RTPSessionClass RTPSessionClass;
#define RTP_TYPE_SESSION (rtp_session_get_type())
#define RTP_SESSION(sess) (G_TYPE_CHECK_INSTANCE_CAST((sess),RTP_TYPE_SESSION,RTPSession))
#define RTP_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RTP_TYPE_SESSION,RTPSessionClass))
#define RTP_IS_SESSION(sess) (G_TYPE_CHECK_INSTANCE_TYPE((sess),RTP_TYPE_SESSION))
#define RTP_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RTP_TYPE_SESSION))
#define RTP_SESSION_CAST(sess) ((RTPSession *)(sess))
#define RTP_SESSION_LOCK(sess) (g_mutex_lock ((sess)->lock))
#define RTP_SESSION_UNLOCK(sess) (g_mutex_unlock ((sess)->lock))
/**
* RTPSessionProcessRTP:
* @sess: an #RTPSession
* @src: the #RTPSource
* @buffer: the RTP buffer ready for processing
* @user_data: user data specified when registering
*
* This callback will be called when @sess has @buffer ready for further
* processing. Processing the buffer typically includes decoding and displaying
* the buffer.
*
* Returns: a #GstFlowReturn.
*/
typedef GstFlowReturn (*RTPSessionProcessRTP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer, gpointer user_data);
/**
* RTPSessionSendRTP:
* @sess: an #RTPSession
* @src: the #RTPSource
* @buffer: the RTP buffer ready for sending
* @user_data: user data specified when registering
*
* This callback will be called when @sess has @buffer ready for sending to
* all listening participants in this session.
*
* Returns: a #GstFlowReturn.
*/
typedef GstFlowReturn (*RTPSessionSendRTP) (RTPSession *sess, RTPSource *src, gpointer data, gpointer user_data);
/**
* RTPSessionSendRTCP:
* @sess: an #RTPSession
* @src: the #RTPSource
* @buffer: the RTCP buffer ready for sending
* @eos: if an EOS event should be pushed
* @user_data: user data specified when registering
*
* This callback will be called when @sess has @buffer ready for sending to
* all listening participants in this session.
*
* Returns: a #GstFlowReturn.
*/
typedef GstFlowReturn (*RTPSessionSendRTCP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer,
gboolean eos, gpointer user_data);
/**
* RTPSessionSyncRTCP:
* @sess: an #RTPSession
* @src: the #RTPSource
* @buffer: the RTCP buffer ready for synchronisation
* @user_data: user data specified when registering
*
* This callback will be called when @sess has an SR @buffer ready for doing
* synchronisation between streams.
*
* Returns: a #GstFlowReturn.
*/
typedef GstFlowReturn (*RTPSessionSyncRTCP) (RTPSession *sess, RTPSource *src, GstBuffer *buffer, gpointer user_data);
/**
* RTPSessionClockRate:
* @sess: an #RTPSession
* @payload: the payload
* @user_data: user data specified when registering
*
* This callback will be called when @sess needs the clock-rate of @payload.
*
* Returns: the clock-rate of @pt.
*/
typedef gint (*RTPSessionClockRate) (RTPSession *sess, guint8 payload, gpointer user_data);
/**
* RTPSessionReconsider:
* @sess: an #RTPSession
* @user_data: user data specified when registering
*
* This callback will be called when @sess needs to cancel the current timeout.
* The currently running timeout should be canceled and a new reporting interval
* should be requested from @sess.
*/
typedef void (*RTPSessionReconsider) (RTPSession *sess, gpointer user_data);
/**
* RTPSessionCallbacks:
* @RTPSessionProcessRTP: callback to process RTP packets
* @RTPSessionSendRTP: callback for sending RTP packets
* @RTPSessionSendRTCP: callback for sending RTCP packets
* @RTPSessionSyncRTCP: callback for handling SR packets
* @RTPSessionReconsider: callback for reconsidering the timeout
*
* These callbacks can be installed on the session manager to get notification
* when RTP and RTCP packets are ready for further processing. These callbacks
* are not implemented with signals for performance reasons.
*/
typedef struct {
RTPSessionProcessRTP process_rtp;
RTPSessionSendRTP send_rtp;
RTPSessionSyncRTCP sync_rtcp;
RTPSessionSendRTCP send_rtcp;
RTPSessionClockRate clock_rate;
RTPSessionReconsider reconsider;
} RTPSessionCallbacks;
/**
* RTPConflictingAddress:
* @address: #GstNetAddress which conflicted
* @last_conflict_time: time when the last conflict was seen
*
* This structure is used to account for addresses that have conflicted to find
* loops.
*/
typedef struct {
GstNetAddress address;
GstClockTime time;
} RTPConflictingAddress;
/**
* RTPSession:
* @lock: lock to protect the session
* @source: the source of this session
* @ssrcs: Hashtable of sources indexed by SSRC
* @cnames: Hashtable of sources indexed by CNAME
* @num_sources: the number of sources
* @activecount: the number of active sources
* @callbacks: callbacks
* @user_data: user data passed in callbacks
* @stats: session statistics
* @conflicting_addresses: GList of conflicting addresses
*
* The RTP session manager object
*/
struct _RTPSession {
GObject object;
GMutex *lock;
guint header_len;
guint mtu;
RTPSource *source;
/* for sender/receiver counting */
guint32 key;
guint32 mask_idx;
guint32 mask;
GHashTable *ssrcs[32];
GHashTable *cnames;
guint total_sources;
GstClockTime next_rtcp_check_time;
GstClockTime last_rtcp_send_time;
gboolean first_rtcp;
gchar *bye_reason;
gboolean sent_bye;
RTPSessionCallbacks callbacks;
gpointer process_rtp_user_data;
gpointer send_rtp_user_data;
gpointer send_rtcp_user_data;
gpointer sync_rtcp_user_data;
gpointer clock_rate_user_data;
gpointer reconsider_user_data;
RTPSessionStats stats;
GList *conflicting_addresses;
gboolean change_ssrc;
};
/**
* RTPSessionClass:
* @on_new_ssrc: emited when a new source is found
* @on_bye_ssrc: emited when a source is gone
*
* The session class.
*/
struct _RTPSessionClass {
GObjectClass parent_class;
/* action signals */
RTPSource* (*get_source_by_ssrc) (RTPSession *sess, guint32 ssrc);
/* signals */
void (*on_new_ssrc) (RTPSession *sess, RTPSource *source);
void (*on_ssrc_collision) (RTPSession *sess, RTPSource *source);
void (*on_ssrc_validated) (RTPSession *sess, RTPSource *source);
void (*on_ssrc_active) (RTPSession *sess, RTPSource *source);
void (*on_ssrc_sdes) (RTPSession *sess, RTPSource *source);
void (*on_bye_ssrc) (RTPSession *sess, RTPSource *source);
void (*on_bye_timeout) (RTPSession *sess, RTPSource *source);
void (*on_timeout) (RTPSession *sess, RTPSource *source);
void (*on_sender_timeout) (RTPSession *sess, RTPSource *source);
};
GType rtp_session_get_type (void);
/* create and configure */
RTPSession* rtp_session_new (void);
void rtp_session_set_callbacks (RTPSession *sess,
RTPSessionCallbacks *callbacks,
gpointer user_data);
void rtp_session_set_process_rtp_callback (RTPSession * sess,
RTPSessionProcessRTP callback,
gpointer user_data);
void rtp_session_set_send_rtp_callback (RTPSession * sess,
RTPSessionSendRTP callback,
gpointer user_data);
void rtp_session_set_send_rtcp_callback (RTPSession * sess,
RTPSessionSendRTCP callback,
gpointer user_data);
void rtp_session_set_sync_rtcp_callback (RTPSession * sess,
RTPSessionSyncRTCP callback,
gpointer user_data);
void rtp_session_set_clock_rate_callback (RTPSession * sess,
RTPSessionClockRate callback,
gpointer user_data);
void rtp_session_set_reconsider_callback (RTPSession * sess,
RTPSessionReconsider callback,
gpointer user_data);
void rtp_session_set_bandwidth (RTPSession *sess, gdouble bandwidth);
gdouble rtp_session_get_bandwidth (RTPSession *sess);
void rtp_session_set_rtcp_fraction (RTPSession *sess, gdouble fraction);
gdouble rtp_session_get_rtcp_fraction (RTPSession *sess);
gboolean rtp_session_set_sdes_string (RTPSession *sess, GstRTCPSDESType type,
const gchar *cname);
gchar* rtp_session_get_sdes_string (RTPSession *sess, GstRTCPSDESType type);
GstStructure * rtp_session_get_sdes_struct (RTPSession *sess);
void rtp_session_set_sdes_struct (RTPSession *sess, const GstStructure *sdes);
/* handling sources */
RTPSource* rtp_session_get_internal_source (RTPSession *sess);
void rtp_session_set_internal_ssrc (RTPSession *sess, guint32 ssrc);
guint32 rtp_session_get_internal_ssrc (RTPSession *sess);
gboolean rtp_session_add_source (RTPSession *sess, RTPSource *src);
guint rtp_session_get_num_sources (RTPSession *sess);
guint rtp_session_get_num_active_sources (RTPSession *sess);
RTPSource* rtp_session_get_source_by_ssrc (RTPSession *sess, guint32 ssrc);
RTPSource* rtp_session_get_source_by_cname (RTPSession *sess, const gchar *cname);
RTPSource* rtp_session_create_source (RTPSession *sess);
/* processing packets from receivers */
GstFlowReturn rtp_session_process_rtp (RTPSession *sess, GstBuffer *buffer,
GstClockTime current_time,
GstClockTime running_time, guint64 ntpnstime);
GstFlowReturn rtp_session_process_rtcp (RTPSession *sess, GstBuffer *buffer,
GstClockTime current_time);
/* processing packets for sending */
GstFlowReturn rtp_session_send_rtp (RTPSession *sess, gpointer data, gboolean is_list,
GstClockTime current_time, guint64 ntpnstime);
/* stopping the session */
GstFlowReturn rtp_session_schedule_bye (RTPSession *sess, const gchar *reason,
GstClockTime current_time);
/* get interval for next RTCP interval */
GstClockTime rtp_session_next_timeout (RTPSession *sess, GstClockTime current_time);
GstFlowReturn rtp_session_on_timeout (RTPSession *sess, GstClockTime current_time,
guint64 ntpnstime);
#endif /* __RTP_SESSION_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,226 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __RTP_SOURCE_H__
#define __RTP_SOURCE_H__
#include <gst/gst.h>
#include <gst/rtp/gstrtcpbuffer.h>
#include <gst/netbuffer/gstnetbuffer.h>
#include "rtpstats.h"
/* the default number of consecutive RTP packets we need to receive before the
* source is considered valid */
#define RTP_NO_PROBATION 0
#define RTP_DEFAULT_PROBATION 2
#define RTP_SEQ_MOD (1 << 16)
typedef struct _RTPSource RTPSource;
typedef struct _RTPSourceClass RTPSourceClass;
#define RTP_TYPE_SOURCE (rtp_source_get_type())
#define RTP_SOURCE(src) (G_TYPE_CHECK_INSTANCE_CAST((src),RTP_TYPE_SOURCE,RTPSource))
#define RTP_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RTP_TYPE_SOURCE,RTPSourceClass))
#define RTP_IS_SOURCE(src) (G_TYPE_CHECK_INSTANCE_TYPE((src),RTP_TYPE_SOURCE))
#define RTP_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RTP_TYPE_SOURCE))
#define RTP_SOURCE_CAST(src) ((RTPSource *)(src))
/**
* RTP_SOURCE_IS_ACTIVE:
* @src: an #RTPSource
*
* Check if @src is active. A source is active when it has been validated
* and has not yet received a BYE packet.
*/
#define RTP_SOURCE_IS_ACTIVE(src) (src->validated && !src->received_bye)
/**
* RTP_SOURCE_IS_SENDER:
* @src: an #RTPSource
*
* Check if @src is a sender.
*/
#define RTP_SOURCE_IS_SENDER(src) (src->is_sender)
/**
* RTPSourcePushRTP:
* @src: an #RTPSource
* @buffer: the RTP buffer ready for processing
* @user_data: user data specified when registering
*
* This callback will be called when @src has @buffer ready for further
* processing.
*
* Returns: a #GstFlowReturn.
*/
typedef GstFlowReturn (*RTPSourcePushRTP) (RTPSource *src, GstBuffer *buffer,
gpointer user_data);
/**
* RTPSourceClockRate:
* @src: an #RTPSource
* @payload: a payload type
* @user_data: user data specified when registering
*
* This callback will be called when @src needs the clock-rate of the
* @payload.
*
* Returns: a clock-rate for @payload.
*/
typedef gint (*RTPSourceClockRate) (RTPSource *src, guint8 payload, gpointer user_data);
/**
* RTPSourceCallbacks:
* @push_rtp: a packet becomes available for handling
* @clock_rate: a clock-rate is requested
* @get_time: the current clock time is requested
*
* Callbacks performed by #RTPSource when actions need to be performed.
*/
typedef struct {
RTPSourcePushRTP push_rtp;
RTPSourceClockRate clock_rate;
} RTPSourceCallbacks;
/**
* RTPSource:
*
* A source in the #RTPSession
*/
struct _RTPSource {
GObject object;
/*< private >*/
guint32 ssrc;
gint probation;
gboolean validated;
gboolean internal;
gboolean is_csrc;
gboolean is_sender;
guint8 *sdes[9];
guint sdes_len[9];
gboolean received_bye;
gchar *bye_reason;
gboolean have_rtp_from;
GstNetAddress rtp_from;
gboolean have_rtcp_from;
GstNetAddress rtcp_from;
gint payload;
GstCaps *caps;
gint clock_rate;
gint32 seqnum_base;
GstClockTime bye_time;
GstClockTime last_activity;
GstClockTime last_rtp_activity;
GstClockTime last_rtptime;
GstClockTime last_ntpnstime;
/* for bitrate estimation */
guint64 bitrate;
GstClockTime prev_ntpnstime;
guint64 bytes_sent;
GQueue *packets;
RTPSourceCallbacks callbacks;
gpointer user_data;
RTPSourceStats stats;
};
struct _RTPSourceClass {
GObjectClass parent_class;
};
GType rtp_source_get_type (void);
/* managing lifetime of sources */
RTPSource* rtp_source_new (guint32 ssrc);
void rtp_source_set_callbacks (RTPSource *src, RTPSourceCallbacks *cb, gpointer data);
/* properties */
guint32 rtp_source_get_ssrc (RTPSource *src);
void rtp_source_set_as_csrc (RTPSource *src);
gboolean rtp_source_is_as_csrc (RTPSource *src);
gboolean rtp_source_is_active (RTPSource *src);
gboolean rtp_source_is_validated (RTPSource *src);
gboolean rtp_source_is_sender (RTPSource *src);
gboolean rtp_source_received_bye (RTPSource *src);
gchar * rtp_source_get_bye_reason (RTPSource *src);
void rtp_source_update_caps (RTPSource *src, GstCaps *caps);
/* SDES info */
gboolean rtp_source_set_sdes (RTPSource *src, GstRTCPSDESType type,
const guint8 *data, guint len);
gboolean rtp_source_set_sdes_string (RTPSource *src, GstRTCPSDESType type,
const gchar *data);
gboolean rtp_source_get_sdes (RTPSource *src, GstRTCPSDESType type,
guint8 **data, guint *len);
gchar* rtp_source_get_sdes_string (RTPSource *src, GstRTCPSDESType type);
GstStructure * rtp_source_get_sdes_struct (RTPSource * src);
void rtp_source_set_sdes_struct (RTPSource * src, const GstStructure *sdes);
/* handling network address */
void rtp_source_set_rtp_from (RTPSource *src, GstNetAddress *address);
void rtp_source_set_rtcp_from (RTPSource *src, GstNetAddress *address);
/* handling RTP */
GstFlowReturn rtp_source_process_rtp (RTPSource *src, GstBuffer *buffer, RTPArrivalStats *arrival);
GstFlowReturn rtp_source_send_rtp (RTPSource *src, gpointer data, gboolean is_list, guint64 ntpnstime);
/* RTCP messages */
void rtp_source_process_bye (RTPSource *src, const gchar *reason);
void rtp_source_process_sr (RTPSource *src, GstClockTime time, guint64 ntptime,
guint32 rtptime, guint32 packet_count, guint32 octet_count);
void rtp_source_process_rb (RTPSource *src, GstClockTime time, guint8 fractionlost,
gint32 packetslost, guint32 exthighestseq, guint32 jitter,
guint32 lsr, guint32 dlsr);
gboolean rtp_source_get_new_sr (RTPSource *src, guint64 ntpnstime, guint64 *ntptime,
guint32 *rtptime, guint32 *packet_count,
guint32 *octet_count);
gboolean rtp_source_get_new_rb (RTPSource *src, GstClockTime time, guint8 *fractionlost,
gint32 *packetslost, guint32 *exthighestseq, guint32 *jitter,
guint32 *lsr, guint32 *dlsr);
gboolean rtp_source_get_last_sr (RTPSource *src, GstClockTime *time, guint64 *ntptime,
guint32 *rtptime, guint32 *packet_count,
guint32 *octet_count);
gboolean rtp_source_get_last_rb (RTPSource *src, guint8 *fractionlost, gint32 *packetslost,
guint32 *exthighestseq, guint32 *jitter,
guint32 *lsr, guint32 *dlsr, guint32 *round_trip);
void rtp_source_reset (RTPSource * src);
#endif /* __RTP_SOURCE_H__ */

View file

@ -1,176 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "rtpstats.h"
/**
* rtp_stats_init_defaults:
* @stats: an #RTPSessionStats struct
*
* Initialize @stats with its default values.
*/
void
rtp_stats_init_defaults (RTPSessionStats * stats)
{
stats->bandwidth = RTP_STATS_BANDWIDTH;
stats->sender_fraction = RTP_STATS_SENDER_FRACTION;
stats->receiver_fraction = RTP_STATS_RECEIVER_FRACTION;
stats->rtcp_bandwidth = RTP_STATS_RTCP_BANDWIDTH;
stats->min_interval = RTP_STATS_MIN_INTERVAL;
stats->bye_timeout = RTP_STATS_BYE_TIMEOUT;
}
/**
* rtp_stats_calculate_rtcp_interval:
* @stats: an #RTPSessionStats struct
* @sender: if we are a sender
* @first: if this is the first time
*
* Calculate the RTCP interval. The result of this function is the amount of
* time to wait (in nanoseconds) before sending a new RTCP message.
*
* Returns: the RTCP interval.
*/
GstClockTime
rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
gboolean first)
{
gdouble members, senders, n;
gdouble avg_rtcp_size, rtcp_bw;
gdouble interval;
gdouble rtcp_min_time;
/* Very first call at application start-up uses half the min
* delay for quicker notification while still allowing some time
* before reporting for randomization and to learn about other
* sources so the report interval will converge to the correct
* interval more quickly.
*/
rtcp_min_time = stats->min_interval;
if (first)
rtcp_min_time /= 2.0;
/* Dedicate a fraction of the RTCP bandwidth to senders unless
* the number of senders is large enough that their share is
* more than that fraction.
*/
n = members = stats->active_sources;
senders = (gdouble) stats->sender_sources;
rtcp_bw = stats->rtcp_bandwidth;
if (senders <= members * RTP_STATS_SENDER_FRACTION) {
if (we_send) {
rtcp_bw *= RTP_STATS_SENDER_FRACTION;
n = senders;
} else {
rtcp_bw *= RTP_STATS_RECEIVER_FRACTION;
n -= senders;
}
}
avg_rtcp_size = stats->avg_rtcp_packet_size / 16.0;
/*
* The effective number of sites times the average packet size is
* the total number of octets sent when each site sends a report.
* Dividing this by the effective bandwidth gives the time
* interval over which those packets must be sent in order to
* meet the bandwidth target, with a minimum enforced. In that
* time interval we send one report so this time is also our
* average time between reports.
*/
interval = avg_rtcp_size * n / rtcp_bw;
if (interval < rtcp_min_time)
interval = rtcp_min_time;
return interval * GST_SECOND;
}
/**
* rtp_stats_add_rtcp_jitter:
* @stats: an #RTPSessionStats struct
* @interval: an RTCP interval
*
* Apply a random jitter to the @interval. @interval is typically obtained with
* rtp_stats_calculate_rtcp_interval().
*
* Returns: the new RTCP interval.
*/
GstClockTime
rtp_stats_add_rtcp_jitter (RTPSessionStats * stats, GstClockTime interval)
{
gdouble temp;
/* see RFC 3550 p 30
* To compensate for "unconditional reconsideration" converging to a
* value below the intended average.
*/
#define COMPENSATION (2.71828 - 1.5);
temp = (interval * g_random_double_range (0.5, 1.5)) / COMPENSATION;
return (GstClockTime) temp;
}
/**
* rtp_stats_calculate_bye_interval:
* @stats: an #RTPSessionStats struct
*
* Calculate the BYE interval. The result of this function is the amount of
* time to wait (in nanoseconds) before sending a BYE message.
*
* Returns: the BYE interval.
*/
GstClockTime
rtp_stats_calculate_bye_interval (RTPSessionStats * stats)
{
gdouble members;
gdouble avg_rtcp_size, rtcp_bw;
gdouble interval;
gdouble rtcp_min_time;
/* no interval when we have less than 50 members */
if (stats->active_sources < 50)
return 0;
rtcp_min_time = (stats->min_interval) / 2.0;
/* Dedicate a fraction of the RTCP bandwidth to senders unless
* the number of senders is large enough that their share is
* more than that fraction.
*/
members = stats->bye_members;
rtcp_bw = stats->rtcp_bandwidth * RTP_STATS_RECEIVER_FRACTION;
avg_rtcp_size = stats->avg_rtcp_packet_size / 16.0;
/*
* The effective number of sites times the average packet size is
* the total number of octets sent when each site sends a report.
* Dividing this by the effective bandwidth gives the time
* interval over which those packets must be sent in order to
* meet the bandwidth target, with a minimum enforced. In that
* time interval we send one report so this time is also our
* average time between reports.
*/
interval = avg_rtcp_size * members / rtcp_bw;
if (interval < rtcp_min_time)
interval = rtcp_min_time;
return interval * GST_SECOND;
}

View file

@ -1,195 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __RTP_STATS_H__
#define __RTP_STATS_H__
#include <gst/gst.h>
#include <gst/netbuffer/gstnetbuffer.h>
/**
* RTPSenderReport:
*
* A sender report structure.
*/
typedef struct {
gboolean is_valid;
guint64 ntptime;
guint32 rtptime;
guint32 packet_count;
guint32 octet_count;
GstClockTime time;
} RTPSenderReport;
/**
* RTPReceiverReport:
*
* A receiver report structure.
*/
typedef struct {
gboolean is_valid;
guint32 ssrc; /* who the report is from */
guint8 fractionlost;
guint32 packetslost;
guint32 exthighestseq;
guint32 jitter;
guint32 lsr;
guint32 dlsr;
guint32 round_trip;
} RTPReceiverReport;
/**
* RTPArrivalStats:
* @time: arrival time of a packet according to the system clock
* @running_time: arrival time of a packet as buffer running_time
* @ntpnstime: arrival time of a packet as NTP time in nanoseconds
* @have_address: if the @address field contains a valid address
* @address: address of the sender of the packet
* @bytes: bytes of the packet including lowlevel overhead
* @payload_len: bytes of the RTP payload
*
* Structure holding information about the arrival stats of a packet.
*/
typedef struct {
GstClockTime time;
GstClockTime running_time;
guint64 ntpnstime;
gboolean have_address;
GstNetAddress address;
guint bytes;
guint payload_len;
} RTPArrivalStats;
/**
* RTPSourceStats:
* @packetsreceived: number of received packets in total
* @prevpacketsreceived: number of packets received in previous reporting
* interval
* @octetsreceived: number of payload bytes received
* @bytesreceived: number of total bytes received including headers and lower
* protocol level overhead
* @max_seqnr: highest sequence number received
* @transit: previous transit time used for calculating @jitter
* @jitter: current jitter
* @prev_rtptime: previous time when an RTP packet was received
* @prev_rtcptime: previous time when an RTCP packet was received
* @last_rtptime: time when last RTP packet received
* @last_rtcptime: time when last RTCP packet received
* @curr_rr: index of current @rr block
* @rr: previous and current receiver report block
* @curr_sr: index of current @sr block
* @sr: previous and current sender report block
*
* Stats about a source.
*/
typedef struct {
guint64 packets_received;
guint64 octets_received;
guint64 bytes_received;
guint32 prev_expected;
guint32 prev_received;
guint16 max_seq;
guint64 cycles;
guint32 base_seq;
guint32 bad_seq;
guint32 transit;
guint32 jitter;
guint64 packets_sent;
guint64 octets_sent;
/* when we received stuff */
GstClockTime prev_rtptime;
GstClockTime prev_rtcptime;
GstClockTime last_rtptime;
GstClockTime last_rtcptime;
/* sender and receiver reports */
gint curr_rr;
RTPReceiverReport rr[2];
gint curr_sr;
RTPSenderReport sr[2];
} RTPSourceStats;
#define RTP_STATS_BANDWIDTH 64000.0
#define RTP_STATS_RTCP_BANDWIDTH 3000.0
/*
* Minimum average time between RTCP packets from this site (in
* seconds). This time prevents the reports from `clumping' when
* sessions are small and the law of large numbers isn't helping
* to smooth out the traffic. It also keeps the report interval
* from becoming ridiculously small during transient outages like
* a network partition.
*/
#define RTP_STATS_MIN_INTERVAL 5.0
/*
* Fraction of the RTCP bandwidth to be shared among active
* senders. (This fraction was chosen so that in a typical
* session with one or two active senders, the computed report
* time would be roughly equal to the minimum report time so that
* we don't unnecessarily slow down receiver reports.) The
* receiver fraction must be 1 - the sender fraction.
*/
#define RTP_STATS_SENDER_FRACTION (0.25)
#define RTP_STATS_RECEIVER_FRACTION (1.0 - RTP_STATS_SENDER_FRACTION)
/*
* When receiving a BYE from a source, remove the source from the database
* after this timeout.
*/
#define RTP_STATS_BYE_TIMEOUT (2 * GST_SECOND)
/*
* The maximum number of missing packets we tollerate. These are packets with a
* sequence number bigger than the last seen packet.
*/
#define RTP_MAX_DROPOUT 3000
/*
* The maximum number of misordered packets we tollerate. These are packets with
* a sequence number smaller than the last seen packet.
*/
#define RTP_MAX_MISORDER 100
/**
* RTPSessionStats:
*
* Stats kept for a session and used to produce RTCP packet timeouts.
*/
typedef struct {
gdouble bandwidth;
gdouble sender_fraction;
gdouble receiver_fraction;
gdouble rtcp_bandwidth;
gdouble min_interval;
GstClockTime bye_timeout;
guint sender_sources;
guint active_sources;
guint avg_rtcp_packet_size;
guint bye_members;
} RTPSessionStats;
void rtp_stats_init_defaults (RTPSessionStats *stats);
GstClockTime rtp_stats_calculate_rtcp_interval (RTPSessionStats *stats, gboolean sender, gboolean first);
GstClockTime rtp_stats_add_rtcp_jitter (RTPSessionStats *stats, GstClockTime interval);
GstClockTime rtp_stats_calculate_bye_interval (RTPSessionStats *stats);
#endif /* __RTP_STATS_H__ */

View file

@ -99,8 +99,6 @@ check_PROGRAMS = \
elements/asfmux \ elements/asfmux \
elements/legacyresample \ elements/legacyresample \
elements/qtmux \ elements/qtmux \
elements/rtpbin \
elements/rtpbin_buffer_list \
elements/selector \ elements/selector \
elements/shapewipe \ elements/shapewipe \
elements/mxfdemux \ elements/mxfdemux \
@ -125,13 +123,6 @@ elements_camerabin_LDADD = \
-lgstinterfaces-@GST_MAJORMINOR@ -lgstinterfaces-@GST_MAJORMINOR@
elements_camerabin_SOURCES = elements/camerabin.c elements_camerabin_SOURCES = elements/camerabin.c
elements_rtpbin_buffer_list_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
$(ERROR_CFLAGS) $(GST_CHECK_CFLAGS)
elements_rtpbin_buffer_list_LDADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstnetbuffer-@GST_MAJORMINOR@ -lgstrtp-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) $(GST_LIBS_LIBS) $(GST_CHECK_LIBS)
elements_rtpbin_buffer_list_SOURCES = elements/rtpbin_buffer_list.c
elements_timidity_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) elements_timidity_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS)
elements_timidity_LDADD = $(GST_BASE_LIBS) $(LDADD) elements_timidity_LDADD = $(GST_BASE_LIBS) $(LDADD)

View file

@ -20,8 +20,6 @@ souphttpsrc
rganalysis rganalysis
rglimiter rglimiter
rgvolume rgvolume
rtpbin
rtpbin_buffer_list
selector selector
shapewipe shapewipe
spectrum spectrum

View file

@ -1,421 +0,0 @@
/* GStreamer
*
* unit test for gstrtpbin
*
* Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/check/gstcheck.h>
GST_START_TEST (test_cleanup_send)
{
GstElement *rtpbin;
GstPad *rtp_sink, *rtp_src, *rtcp_src;
GObject *session;
gint count = 2;
rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
while (count--) {
/* request session 0 */
rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
fail_unless (rtp_sink != NULL);
ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
/* request again */
rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
fail_unless (rtp_sink != NULL);
ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 3);
gst_object_unref (rtp_sink);
/* this static pad should be created automatically now */
rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
fail_unless (rtp_src != NULL);
ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 2);
/* we should be able to get an internal session 0 now */
g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
fail_unless (session != NULL);
g_object_unref (session);
/* get the send RTCP pad too */
rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
fail_unless (rtcp_src != NULL);
ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 2);
/* second time */
rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
fail_unless (rtcp_src != NULL);
ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 3);
gst_object_unref (rtcp_src);
gst_element_release_request_pad (rtpbin, rtp_sink);
/* we should only have our refs to the pads now */
ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 2);
/* the other pad should be gone now */
fail_unless (gst_element_get_static_pad (rtpbin, "send_rtp_src_0") == NULL);
/* internal session should still be there */
g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
fail_unless (session != NULL);
g_object_unref (session);
/* release the RTCP pad */
gst_element_release_request_pad (rtpbin, rtcp_src);
/* we should only have our refs to the pads now */
ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 1);
/* the session should be gone now */
g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
fail_unless (session == NULL);
/* unref the request pad and the static pad */
gst_object_unref (rtp_sink);
gst_object_unref (rtp_src);
gst_object_unref (rtcp_src);
}
gst_object_unref (rtpbin);
}
GST_END_TEST;
typedef struct
{
guint16 seqnum;
gboolean pad_added;
GstPad *pad;
GMutex *lock;
GCond *cond;
GstPad *sinkpad;
GList *pads;
} CleanupData;
static void
init_data (CleanupData * data)
{
data->seqnum = 10;
data->pad_added = FALSE;
data->lock = g_mutex_new ();
data->cond = g_cond_new ();
data->pads = NULL;
}
static void
clean_data (CleanupData * data)
{
g_list_foreach (data->pads, (GFunc) gst_object_unref, NULL);
g_list_free (data->pads);
g_mutex_free (data->lock);
g_cond_free (data->cond);
}
static guint8 rtp_packet[] = { 0x80, 0x60, 0x94, 0xbc, 0x8f, 0x37, 0x4e, 0xb8,
0x44, 0xa8, 0xf3, 0x7c, 0x06, 0x6a, 0x0c, 0xce,
0x13, 0x25, 0x19, 0x69, 0x1f, 0x93, 0x25, 0x9d,
0x2b, 0x82, 0x31, 0x3b, 0x36, 0xc1, 0x3c, 0x13
};
static GstBuffer *
make_rtp_packet (CleanupData * data)
{
static GstCaps *caps = NULL;
GstBuffer *result;
guint8 *datap;
if (caps == NULL) {
caps = gst_caps_from_string ("application/x-rtp,"
"media=(string)audio, clock-rate=(int)44100, "
"encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
data->seqnum = 0;
}
result = gst_buffer_new_and_alloc (sizeof (rtp_packet));
datap = GST_BUFFER_DATA (result);
memcpy (datap, rtp_packet, sizeof (rtp_packet));
datap[2] = (data->seqnum >> 8) & 0xff;
datap[3] = data->seqnum & 0xff;
data->seqnum++;
gst_buffer_set_caps (result, caps);
return result;
}
static GstFlowReturn
dummy_chain (GstPad * pad, GstBuffer * buffer)
{
gst_buffer_unref (buffer);
return GST_FLOW_OK;
}
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp"));
static GstPad *
make_sinkpad (CleanupData * data)
{
GstPad *pad;
pad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_chain_function (pad, dummy_chain);
gst_pad_set_active (pad, TRUE);
data->pads = g_list_prepend (data->pads, pad);
return pad;
}
static void
pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
{
GstPad *sinkpad;
GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
if (GST_PAD_IS_SINK (pad))
return;
fail_unless (data->pad_added == FALSE);
sinkpad = make_sinkpad (data);
fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
g_mutex_lock (data->lock);
data->pad_added = TRUE;
data->pad = pad;
g_cond_signal (data->cond);
g_mutex_unlock (data->lock);
}
static void
pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
{
GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
if (data->pad != pad)
return;
fail_unless (data->pad_added == TRUE);
g_mutex_lock (data->lock);
data->pad_added = FALSE;
g_cond_signal (data->cond);
g_mutex_unlock (data->lock);
}
GST_START_TEST (test_cleanup_recv)
{
GstElement *rtpbin;
GstPad *rtp_sink;
CleanupData data;
GstStateChangeReturn ret;
GstFlowReturn res;
GstBuffer *buffer;
gint count = 2;
init_data (&data);
rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
while (count--) {
/* request session 0 */
rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
fail_unless (rtp_sink != NULL);
ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
/* no sourcepads are created yet */
fail_unless (rtpbin->numsinkpads == 1);
fail_unless (rtpbin->numsrcpads == 0);
buffer = make_rtp_packet (&data);
res = gst_pad_chain (rtp_sink, buffer);
GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
fail_unless (res == GST_FLOW_OK);
buffer = make_rtp_packet (&data);
res = gst_pad_chain (rtp_sink, buffer);
GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
fail_unless (res == GST_FLOW_OK);
/* we wait for the new pad to appear now */
g_mutex_lock (data.lock);
while (!data.pad_added)
g_cond_wait (data.cond, data.lock);
g_mutex_unlock (data.lock);
/* sourcepad created now */
fail_unless (rtpbin->numsinkpads == 1);
fail_unless (rtpbin->numsrcpads == 1);
/* remove the session */
gst_element_release_request_pad (rtpbin, rtp_sink);
gst_object_unref (rtp_sink);
/* pad should be gone now */
g_mutex_lock (data.lock);
while (data.pad_added)
g_cond_wait (data.cond, data.lock);
g_mutex_unlock (data.lock);
/* nothing left anymore now */
fail_unless (rtpbin->numsinkpads == 0);
fail_unless (rtpbin->numsrcpads == 0);
}
ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
gst_object_unref (rtpbin);
clean_data (&data);
}
GST_END_TEST;
GST_START_TEST (test_cleanup_recv2)
{
GstElement *rtpbin;
GstPad *rtp_sink;
CleanupData data;
GstStateChangeReturn ret;
GstFlowReturn res;
GstBuffer *buffer;
gint count = 2;
init_data (&data);
rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
/* request session 0 */
rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
fail_unless (rtp_sink != NULL);
ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
while (count--) {
/* no sourcepads are created yet */
fail_unless (rtpbin->numsinkpads == 1);
fail_unless (rtpbin->numsrcpads == 0);
buffer = make_rtp_packet (&data);
res = gst_pad_chain (rtp_sink, buffer);
GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
fail_unless (res == GST_FLOW_OK);
buffer = make_rtp_packet (&data);
res = gst_pad_chain (rtp_sink, buffer);
GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
fail_unless (res == GST_FLOW_OK);
/* we wait for the new pad to appear now */
g_mutex_lock (data.lock);
while (!data.pad_added)
g_cond_wait (data.cond, data.lock);
g_mutex_unlock (data.lock);
/* sourcepad created now */
fail_unless (rtpbin->numsinkpads == 1);
fail_unless (rtpbin->numsrcpads == 1);
/* change state */
ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
/* pad should be gone now */
g_mutex_lock (data.lock);
while (data.pad_added)
g_cond_wait (data.cond, data.lock);
g_mutex_unlock (data.lock);
/* back to playing for the next round */
ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
}
/* remove the session */
gst_element_release_request_pad (rtpbin, rtp_sink);
gst_object_unref (rtp_sink);
/* nothing left anymore now */
fail_unless (rtpbin->numsinkpads == 0);
fail_unless (rtpbin->numsrcpads == 0);
ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
gst_object_unref (rtpbin);
clean_data (&data);
}
GST_END_TEST;
Suite *
gstrtpbin_suite (void)
{
Suite *s = suite_create ("gstrtpbin");
TCase *tc_chain = tcase_create ("general");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_cleanup_send);
tcase_add_test (tc_chain, test_cleanup_recv);
tcase_add_test (tc_chain, test_cleanup_recv2);
return s;
}
int
main (int argc, char **argv)
{
int nf;
Suite *s = gstrtpbin_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed (sr);
srunner_free (sr);
return nf;
}

View file

@ -1,331 +0,0 @@
/* GStreamer
*
* Unit test for gstrtpbin sending rtp packets using GstBufferList.
* Copyright (C) 2009 Branko Subasic <branko dot subasic at axis dot 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/check/gstcheck.h>
#include <gst/rtp/gstrtpbuffer.h>
/* This test makes sure that RTP packets sent as buffer lists are sent through
* the rtpbin as they are supposed to, and not corrupted in any way.
*/
#define TEST_CAPS \
"application/x-rtp, " \
"media=(string)video, " \
"clock-rate=(int)90000, " \
"encoding-name=(string)H264, " \
"profile-level-id=(string)4d4015, " \
"payload=(int)96, " \
"ssrc=(guint)2633237432, " \
"clock-base=(guint)1868267015, " \
"seqnum-base=(guint)54229"
/* RTP headers and the first 2 bytes of the payload (FU indicator and FU header)
*/
static const guint8 rtp_header[2][14] = {
{0x80, 0x60, 0xbb, 0xb7, 0x5c, 0xe9, 0x09,
0x0d, 0xf5, 0x9c, 0x43, 0x55, 0x1c, 0x86},
{0x80, 0x60, 0xbb, 0xb8, 0x5c, 0xe9, 0x09,
0x0d, 0xf5, 0x9c, 0x43, 0x55, 0x1c, 0x46}
};
static const guint rtp_header_len[] = {
sizeof rtp_header[0],
sizeof rtp_header[1]
};
static GstBuffer *header_buffer[2] = { NULL, NULL };
/* Some payload.
*/
static char *payload =
"0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
"0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
"0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
"0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
"0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
"0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF0123456789ABSDEF"
"0123456789ABSDEF0123456";
static const guint payload_offset[] = {
0, 498
};
static const guint payload_len[] = {
498, 5
};
static GstBuffer *original_buffer = NULL;
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"));
static GstBuffer *
_create_original_buffer (void)
{
GstCaps *caps;
if (original_buffer != NULL)
return original_buffer;
original_buffer = gst_buffer_new ();
fail_unless (original_buffer != NULL);
gst_buffer_set_data (original_buffer, (guint8 *) payload, strlen (payload));
GST_BUFFER_TIMESTAMP (original_buffer) =
gst_clock_get_internal_time (gst_system_clock_obtain ());
caps = gst_caps_from_string (TEST_CAPS);
fail_unless (caps != NULL);
gst_buffer_set_caps (original_buffer, caps);
gst_caps_unref (caps);
return original_buffer;
}
static GstBufferList *
_create_buffer_list (void)
{
GstBufferList *list;
GstBufferListIterator *it;
GstBuffer *orig_buffer;
GstBuffer *buffer;
orig_buffer = _create_original_buffer ();
fail_if (orig_buffer == NULL);
list = gst_buffer_list_new ();
fail_if (list == NULL);
it = gst_buffer_list_iterate (list);
fail_if (it == NULL);
/*** First group, i.e. first packet. **/
gst_buffer_list_iterator_add_group (it);
/* Create buffer with RTP header and add it to the 1st group */
buffer = gst_buffer_new ();
GST_BUFFER_MALLOCDATA (buffer) = g_memdup (&rtp_header[0], rtp_header_len[0]);
GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
GST_BUFFER_SIZE (buffer) = rtp_header_len[0];
gst_buffer_copy_metadata (buffer, orig_buffer, GST_BUFFER_COPY_ALL);
header_buffer[0] = buffer;
gst_buffer_list_iterator_add (it, buffer);
/* Create the payload buffer and add it to the 1st group
*/
buffer =
gst_buffer_create_sub (orig_buffer, payload_offset[0], payload_len[0]);
fail_if (buffer == NULL);
gst_buffer_list_iterator_add (it, buffer);
/*** Second group, i.e. second packet. ***/
/* Create a new group to hold the rtp header and the payload */
gst_buffer_list_iterator_add_group (it);
/* Create buffer with RTP header and add it to the 2nd group */
buffer = gst_buffer_new ();
GST_BUFFER_MALLOCDATA (buffer) = g_memdup (&rtp_header[1], rtp_header_len[1]);
GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
GST_BUFFER_SIZE (buffer) = rtp_header_len[1];
gst_buffer_copy_metadata (buffer, orig_buffer, GST_BUFFER_COPY_ALL);
header_buffer[1] = buffer;
/* Add the rtp header to the buffer list */
gst_buffer_list_iterator_add (it, buffer);
/* Create the payload buffer and add it to the 2d group
*/
buffer =
gst_buffer_create_sub (orig_buffer, payload_offset[1], payload_len[1]);
fail_if (buffer == NULL);
gst_buffer_list_iterator_add (it, buffer);
gst_buffer_list_iterator_free (it);
return list;
}
static void
_check_header (GstBuffer * buffer, guint index)
{
guint8 *data;
fail_if (buffer == NULL);
fail_unless (index < 2);
fail_unless (GST_BUFFER_SIZE (buffer) == rtp_header_len[index]);
/* Can't do a memcmp() on the whole header, cause the SSRC (bytes 8-11) will
* most likely be changed in gstrtpbin.
*/
fail_unless ((data = GST_BUFFER_DATA (buffer)) != NULL);
fail_unless_equals_uint64 (*(guint64 *) data, *(guint64 *) rtp_header[index]);
fail_unless (*(guint16 *) (data + 12) ==
*(guint16 *) (rtp_header[index] + 12));
}
static void
_check_payload (GstBuffer * buffer, guint index)
{
fail_if (buffer == NULL);
fail_unless (index < 2);
fail_unless (GST_BUFFER_SIZE (buffer) == payload_len[index]);
fail_if (GST_BUFFER_DATA (buffer) !=
(gpointer) (payload + payload_offset[index]));
fail_if (memcmp (GST_BUFFER_DATA (buffer), payload + payload_offset[index],
payload_len[index]));
}
static void
_check_group (GstBufferListIterator * it, guint index, GstCaps * caps)
{
GstBuffer *buffer;
fail_unless (it != NULL);
fail_unless (gst_buffer_list_iterator_n_buffers (it) == 2);
fail_unless (caps != NULL);
fail_unless ((buffer = gst_buffer_list_iterator_next (it)) != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (buffer) ==
GST_BUFFER_TIMESTAMP (original_buffer));
fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (original_buffer),
GST_BUFFER_CAPS (buffer)));
_check_header (buffer, index);
fail_unless ((buffer = gst_buffer_list_iterator_next (it)) != NULL);
_check_payload (buffer, index);
}
static GstFlowReturn
_sink_chain_list (GstPad * pad, GstBufferList * list)
{
GstCaps *caps;
GstBufferListIterator *it;
caps = gst_caps_from_string (TEST_CAPS);
fail_unless (caps != NULL);
fail_unless (GST_IS_BUFFER_LIST (list));
fail_unless (gst_buffer_list_n_groups (list) == 2);
it = gst_buffer_list_iterate (list);
fail_if (it == NULL);
fail_unless (gst_buffer_list_iterator_next_group (it));
_check_group (it, 0, caps);
fail_unless (gst_buffer_list_iterator_next_group (it));
_check_group (it, 1, caps);
gst_caps_unref (caps);
gst_buffer_list_iterator_free (it);
gst_buffer_list_unref (list);
return GST_FLOW_OK;
}
static void
_set_chain_functions (GstPad * pad)
{
gst_pad_set_chain_list_function (pad, _sink_chain_list);
}
GST_START_TEST (test_bufferlist)
{
GstElement *rtpbin;
GstPad *sinkpad;
GstPad *srcpad;
GstBufferList *list;
list = _create_buffer_list ();
fail_unless (list != NULL);
rtpbin = gst_check_setup_element ("gstrtpbin");
srcpad =
gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "send_rtp_sink_0");
fail_if (srcpad == NULL);
sinkpad =
gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate,
"send_rtp_src_0");
fail_if (sinkpad == NULL);
_set_chain_functions (sinkpad);
gst_pad_set_active (sinkpad, TRUE);
gst_element_set_state (rtpbin, GST_STATE_PLAYING);
fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK);
gst_pad_set_active (sinkpad, FALSE);
gst_check_teardown_pad_by_name (rtpbin, "send_rtp_src_0");
gst_check_teardown_pad_by_name (rtpbin, "send_rtp_sink_0");
gst_check_teardown_element (rtpbin);
}
GST_END_TEST;
static Suite *
bufferlist_suite (void)
{
Suite *s = suite_create ("BufferList");
TCase *tc_chain = tcase_create ("general");
/* time out after 30s. */
tcase_set_timeout (tc_chain, 10);
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_bufferlist);
return s;
}
GST_CHECK_MAIN (bufferlist);