mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
Move rtpmanager from -bad to -good.
This commit is contained in:
parent
ae388318cc
commit
a6912096cd
35 changed files with 0 additions and 15481 deletions
|
@ -284,7 +284,6 @@ AG_GST_CHECK_PLUGIN(pcapparse)
|
|||
AG_GST_CHECK_PLUGIN(qtmux)
|
||||
AG_GST_CHECK_PLUGIN(rawparse)
|
||||
AG_GST_CHECK_PLUGIN(real)
|
||||
AG_GST_CHECK_PLUGIN(rtpmanager)
|
||||
AG_GST_CHECK_PLUGIN(rtpmux)
|
||||
AG_GST_CHECK_PLUGIN(scaletempo)
|
||||
AG_GST_CHECK_PLUGIN(sdp)
|
||||
|
@ -1696,7 +1695,6 @@ gst/pcapparse/Makefile
|
|||
gst/qtmux/Makefile
|
||||
gst/rawparse/Makefile
|
||||
gst/real/Makefile
|
||||
gst/rtpmanager/Makefile
|
||||
gst/rtpmux/Makefile
|
||||
gst/scaletempo/Makefile
|
||||
gst/sdp/Makefile
|
||||
|
|
|
@ -142,11 +142,6 @@ EXTRA_HFILES = \
|
|||
$(top_srcdir)/gst/pcapparse/gstpcapparse.h \
|
||||
$(top_srcdir)/gst/rawparse/gstaudioparse.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/gstrtpdtmfmux.h \
|
||||
$(top_srcdir)/gst/scaletempo/gstscaletempo.h \
|
||||
|
|
|
@ -38,11 +38,6 @@
|
|||
<xi:include href="xml/element-dvdspu.xml" />
|
||||
<xi:include href="xml/element-festival.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-ivorbisdec.xml" />
|
||||
<xi:include href="xml/element-jackaudiosrc.xml" />
|
||||
|
@ -122,7 +117,6 @@
|
|||
<xi:include href="xml/plugin-freeze.xml" />
|
||||
<xi:include href="xml/plugin-frei0r.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-jack.xml" />
|
||||
<xi:include href="xml/plugin-kate.xml" />
|
||||
|
|
|
@ -780,82 +780,6 @@ gst_rtp_mux_plugin_init
|
|||
gst_rtp_session_set_ssrc
|
||||
</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>
|
||||
<FILE>element-scaletempo</FILE>
|
||||
<TITLE>scaletempo</TITLE>
|
||||
|
|
|
@ -17558,36 +17558,6 @@
|
|||
<DEFAULT>25</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>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>GstOSXVideoSink::embed</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
|
@ -18108,286 +18078,6 @@
|
|||
<DEFAULT>0</DEFAULT>
|
||||
</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>
|
||||
<NAME>GstGioSrc::location</NAME>
|
||||
<TYPE>gchar*</TYPE>
|
||||
|
|
|
@ -16,7 +16,6 @@ GObject
|
|||
GstFPSDisplaySink
|
||||
GstAutoConvert
|
||||
GstSDPDemux
|
||||
GstRtpBin
|
||||
GstSignalProcessor
|
||||
http---calf-sourceforge-net-plugins-Compressor
|
||||
http---calf-sourceforge-net-plugins-Filter
|
||||
|
@ -466,10 +465,6 @@ GObject
|
|||
GstSpeed
|
||||
GstInputSelector
|
||||
GstOutputSelector
|
||||
GstRtpJitterBuffer
|
||||
GstRtpPtDemux
|
||||
GstRtpSession
|
||||
GstRtpSsrcDemux
|
||||
GstRealVideoDec
|
||||
GstRealAudioDec
|
||||
GstRawParse
|
||||
|
|
|
@ -50,302 +50,6 @@ gint64 arg2
|
|||
gint64 arg3
|
||||
</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>
|
||||
<NAME>GstCDAudio::track-change</NAME>
|
||||
<RETURNS>void</RETURNS>
|
||||
|
|
|
@ -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 <wim.taymans@gmail.com></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 <philippe.kalaf@collabora.co.uk>, Wim Taymans <wim.taymans@gmail.com></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 <kai.vehmanen@nokia.com></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 <wim.taymans@gmail.com></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 <wim.taymans@gmail.com></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>
|
|
@ -83,7 +83,6 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%{_libdir}/gstreamer-%{majorminor}/libgstreal.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstmve.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstmpegvideoparse.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstrtpmanager.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstbayer.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstdvdspu.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstfestival.so
|
||||
|
|
2
gst/rtpmanager/.gitignore
vendored
2
gst/rtpmanager/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
gstrtpbin-marshal.h
|
||||
gstrtpbin-marshal.c
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
@ -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
|
@ -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__ */
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -99,8 +99,6 @@ check_PROGRAMS = \
|
|||
elements/asfmux \
|
||||
elements/legacyresample \
|
||||
elements/qtmux \
|
||||
elements/rtpbin \
|
||||
elements/rtpbin_buffer_list \
|
||||
elements/selector \
|
||||
elements/shapewipe \
|
||||
elements/mxfdemux \
|
||||
|
@ -125,13 +123,6 @@ elements_camerabin_LDADD = \
|
|||
-lgstinterfaces-@GST_MAJORMINOR@
|
||||
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_LDADD = $(GST_BASE_LIBS) $(LDADD)
|
||||
|
||||
|
|
2
tests/check/elements/.gitignore
vendored
2
tests/check/elements/.gitignore
vendored
|
@ -20,8 +20,6 @@ souphttpsrc
|
|||
rganalysis
|
||||
rglimiter
|
||||
rgvolume
|
||||
rtpbin
|
||||
rtpbin_buffer_list
|
||||
selector
|
||||
shapewipe
|
||||
spectrum
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
Loading…
Reference in a new issue