...
 
Commits (17)
=== release 1.6.4 ===
2016-04-14 Tim-Philipp Müller <tim@centricular.com>
* configure.ac:
releasing 1.6.4
2016-01-05 13:10:36 +0100 Srimanta Panda <srimanta@axis.com>
* gst/rtsp-server/rtsp-stream.c:
rtsp-stream: fixed assert during update transport
When RTSP server trying update transport during multicast, it throws an
assert. The assert is thrown because it is trying to get the parent of
an non-existing funnel element.
https://bugzilla.gnome.org/show_bug.cgi?id=760150
2015-12-22 12:08:02 +0100 Sebastian Rasmussen <sebras@hotmail.com>
* gst/rtsp-server/rtsp-media.c:
rtsp-media: Do not prepare media after media times out
Deferred calls to start_prepare() can be deferred past the point until
which wait_preroll() and by proxy gst_rtsp_media_get_status() is
prepared to wait. Previously there was no lock and no check for this
situation. This meant that a media could be prepared and unprepared
simultaneously by two different threads. Now a lock is in place and a
suitable check is done.
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=759773
2015-11-17 22:30:54 -0500 Olivier Crête <olivier.crete@collabora.com>
* gst/rtsp-server/rtsp-session-pool.c:
rtsp-session-pool: Avoid dollar sign ($) in session ids
Live555 in VLC strips off dollar signs and then gets very confused,
we don't loose too much entropy by just skipping it.
2015-12-08 08:27:20 +0100 Srimanta Panda <srimanta@axis.com>
* gst/rtsp-server/rtsp-stream.c:
rtsp-stream: fixed valgrind error
Fixed the valgrind error in unit test. The UDP source created during
gst_rtsp_stream_join_bin() was not released while destroying the rtp
bin.
https://bugzilla.gnome.org/show_bug.cgi?id=759010
2015-11-18 11:14:39 +0100 Srimanta Panda <srimanta@axis.com>
* gst/rtsp-server/rtsp-client.c:
rtsp-client: suspend media during setup request
SETUP request from clients needs to suspend the media to clear the
prerolled buffers. Otherwise it will not affect the prerolled buffer
and the prerolled buffers will be incorrect (for example block-size
from setup request will not affect the prerolled buffer unless the
media is suspended).
https://bugzilla.gnome.org/show_bug.cgi?id=758268
2015-11-19 15:01:16 +0200 Sebastian Dröge <sebastian@centricular.com>
* gst/rtsp-server/rtsp-stream.c:
rtsp-stream: Only create RTP sending/receiving rtpbin pads if needed
Adding them when not needed will start some logic inside rtpbin that might be
problematic. Also if e.g. for a sender media we suddenly receive RTP data, we
would start up a rtpjitterbuffer and behave in weird ways.
We still set up the UDP sources for RTP receiving for a sender media to be
able to receive any packets sent by the client for NAT traversal. They will
all go to a fakesink though.
Having an rtpjitterbuffer in the media pipeline will cause the pipeline to be
NO_PREROLL, which will cause deadlocks when seeking the media as it will never
receive ASYNC_DONE after a seek.
https://bugzilla.gnome.org/show_bug.cgi?id=758319
2015-11-17 12:44:38 +0200 Sebastian Dröge <sebastian@centricular.com>
* gst/rtsp-server/rtsp-stream.c:
rtsp-stream: Disable multicast loopback for the multicast udp sources too
On POSIX this setting is for sender sockets, on Windows for receiver sockets.
Previously we were only setting this for sender sockets, which caused looped
back packets to be received on Windows if a multicast transport was used.
2015-11-17 01:12:28 +1100 Jan Schmidt <jan@centricular.com>
* gst/rtsp-server/rtsp-client.c:
* tests/check/gst/client.c:
rtsp-client: Report RECORD and ANNOUNCE as supported in the OPTIONS
2016-02-02 09:01:51 +0100 Steven Hoving <sh@bigbrother.nl>
* gst/rtsp-server/rtsp-media.c:
rtsp-media: fix state_lock not locked again when preroll fails
https://bugzilla.gnome.org/show_bug.cgi?id=761399
2016-01-28 09:22:18 +0100 Steven Hoving <sh@bigbrother.nl>
* gst/rtsp-server/rtsp-media.c:
rtsp-media: Fix mutex beeing unlocked while they should be locked
https://bugzilla.gnome.org/show_bug.cgi?id=761226
=== release 1.6.2 ===
2015-12-14 19:54:57 +0100 Sebastian Dröge <sebastian@centricular.com>
* ChangeLog:
* NEWS:
* RELEASE:
* configure.ac:
* gst-rtsp-server.doap:
Release 1.6.2
2015-11-11 14:58:33 +0100 Marcus Prebble <prebble@axis.com>
* gst/rtsp-server/rtsp-server.c:
rtsp-server: Change the logic so we don't pop a NULL context
When doing a port scan (e.g. with nmap) the call to GST_RTSP_CHECK()
will sometimes fail. This call is made before any context is pushed
resulting in an attempt to pop a NULL context.
https://bugzilla.gnome.org/show_bug.cgi?id=757949
=== release 1.6.1 ===
2015-10-30 17:04:16 +0200 Sebastian Dröge <sebastian@centricular.com>
* ChangeLog:
* NEWS:
* RELEASE:
* configure.ac:
* gst-rtsp-server.doap:
Release 1.6.1
2015-10-22 09:15:21 +0200 David Svensson Fors <davidsf@axis.com>
* gst/rtsp-server/rtsp-stream.c:
rtsp-stream: Always unref return value of gst_object_get_parent()
Fixes a leak of a GstBin in the udp-mcast case.
https://bugzilla.gnome.org/show_bug.cgi?id=756968
2015-09-29 13:04:53 +0100 Tim-Philipp Müller <tim@centricular.com>
* common:
common: update for new suppression
Makes check-valgrind pass with glib 2.46
2015-09-28 17:40:59 +0200 Sebastian Rasmussen <sebras@hotmail.com>
* gst/rtsp-server/rtsp-media.c:
rtsp-media: Take reference to media that will be prepared
default_prepare() takes a transfer-none reference GstRTSPMedia object.
Later on a g_idle_source_new() is created and a pointer to the media
object is passed as user data. If the media is freed before the idle
source is dispatched the media object pointer is invalid, but the idle
source callback expects it to still be valid. To fix this a reference to
the media object is taken when registering the source callback function
and a corresponding release of the reference is done when the souce is
destroyed.
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=755748
=== release 1.6.0 ===
2015-09-25 Sebastian Dröge <slomo@coaxion.net>
2015-09-25 23:32:52 +0200 Sebastian Dröge <sebastian@centricular.com>
* ChangeLog:
* NEWS:
* RELEASE:
* configure.ac:
releasing 1.6.0
* gst-rtsp-server.doap:
Release 1.6.0
=== release 1.5.91 ===
......
This is GStreamer 1.6.0
The GStreamer team is proud to announce a new major feature release in the
stable 1.x API series of your favourite cross-platform multimedia framework!
This release has been in the works for more than a year and is packed with new
features, bug fixes and other improvements.
See http://gstreamer.freedesktop.org/releases/1.6/ for the full list of
changes.
Highlights
- Stereoscopic 3D and multiview video support
- Trick mode API for key-frame only fast-forward/fast-reverse playback etc.
- Improved DTS (decoding timestamp) vs. PTS (presentation timestamp) handling
to account for negative DTS
- New GstVideoConverter API for more optimised and more correct conversion of
raw video frames between all supported formats, with rescaling
- v4l2src now supports renegotiation
- v4l2transform can now do scaling
- V4L2 Element now report Colorimetry properly
- Easier chunked recording of MP4, Matroska, Ogg, MPEG-TS: new splitmuxsink
and multifilesink improvements
- Content Protection signalling API and Common Encryption (CENC) support for
DASH/MP4
- Many adaptive streaming (DASH, HLS and MSS) improvements
- New PTP and NTP network client clocks and better remote clock tracking
stability
- High-quality text subtitle overlay at display resolutions with glimagesink
or gtkglsink
- RECORD support for the GStreamer RTSP Server
- Retransmissions (RTX) support in RTSP server and client
- RTSP seeking support in client and server has been fixed
- RTCP scheduling improvements and reduced size RTCP support
- MP4/MOV muxer acquired a new "robust" mode of operation which attempts to
keep the output file in a valid state at all times
- Live mixing support in aggregator, audiomixer and compositor was improved a
lot
- compositor now supports rescaling and converting inputs streams on the fly
- New audiointerleave element with proper input synchronisation and live input
support
- Blackmagic Design DeckLink capture and playback card support was rewritten
from scratch; 2k/4k support; mode sensing
- KLV metadata support in RTP and MPEG-TS
- H.265 video encoder (x265), decoders (libav, libde265) and RTP payloader and
depayloaders
- New DTLS plugin and SRTP/DTLS support
- OpenGL3 support, multiple contexts and context propagation, 3D video,
transfer/conversion separation, subtitle blending
- New OpenGL-based QML video sink, Gtk GL video sink, CoreAnimation
CAOpenGLLayerSink video sink
- gst-libav switched to ffmpeg as libav-provider, gains support for
3D/multiview video, trick modes, and the CAVS codec
- GstHarness API for unit tests
- gst-editing-services got a completely new ges-launch-1.0 interface, improved
mixing support and integration into gst-validate
- gnonlin has been deprecated in favor of nle (Non Linear Engine) in
gst-editing-services
- gst-validate has a new plugin system, an extensive default testsuite,
support for concurrent test runs and valgrind support
- cerbero build tool for SDK binary packages gains new 'bundle-source' command
- Various improvements to the Android, iOS, OS X and Windows platform support
s is GStreamer 1.6.4
The GStreamer team is pleased to announce the fourth and likely last
bugfix release in the old stable 1.6 release series of your favourite
cross-platform multimedia framework!
This release only contains bugfixes and it should be safe to update from 1.6.x.
This release maintains API/ABI backwards compatibility with the
GStreamer 1.0, 1.2, 1.4 and 1.6 release series.
For details about the GStreamer 1.6 series and the latest version of this
document see the GStreamer 1.6 release page:
http://gstreamer.freedesktop.org/releases/1.6/
Bug fix summary:
- audio parsers: make sure to send tags before pushing the first buffer,
so all metadata is available at preroll. Fixes metadata collection in
mopidy with certain FLAC files.
- fix decoding glitches at the beginning of some mp3 streams when streaming
- multiqueue eos handling fixes
- tcpserversink/multisocketsink: fix 100% cpu usage on client disconnect
- video4linux: colorimetry and colorspace handling fixes
- udpsrc: add option to enable/disable multicast loopback ("loop" property)
- RTP JPEG: depayloader robustness fixes; payloader now accepts different
quant tables for the chroma components
- directsoundsink: fix some issues around muting/unmuting the sound
- dvdreadsrc: don't jump to wrong title when seeking back to 0 for titles != 1
- adaptivedemux: fix race on shutdown that could result in deadlocks
in hlsdemux/dashdemux, especially when stopped before playback started
- decklink: various robustness fixes in decklinkaudiosrc and decklinkvideosrc
- mpeg4parser: prevent assertion when scanning for sync code
- fbdevsink: fix crash caused by wrong bpp calculation
- tsdemux: fix hang in preroll caused by bogus timestamp/wraparound
handling in some corner cases
- tsdemux: fix accurating seeking
- h265parse: fix crash converting from hevc format to nal-aligned bytestream
- h264parse, h265parse: fix handling of downstream force-key-unit events
- g-i annotation fixes for bindings for gst_element_query_convert(),
gst_pad_get_current_caps(), and gst_pad_peer_query_caps()
- gst-libav: update internal libav copy to n2.8.6
- rtsp-server: report RECORD and ANNOUNCE as supported in the OPTIONS
- rtsp-server: prevent receival of looped back packets on Windows if a
multicast transport is used
- various minor memory leak fixes
- miscellaneous other fixes
- fix crashes on newer windows versions when GTypes are passed through
vararg functions as is done in souphttpsrc or during ges_init(). This
would manifest itself if the application was compiled with MSVC
and /DYNAMICBASE (address space layout randomization) was used.
- Bug list: https://bugzilla.gnome.org/buglist.cgi?product=GStreamer&target_milestone=1.6.4
Release notes for GStreamer RTSP Server Library 1.6.0
Release notes for GStreamer RTSP Server Library 1.6.4
The GStreamer team is proud to announce a new major feature release in the
stable 1.x API series of your favourite cross-platform multimedia framework!
This release has been in the works for more than a year and is packed with new
features, bug fixes and other improvements.
See
http://gstreamer.freedesktop.org/releases/1.6/
for the full list of changes.
The GStreamer team is proud to announce a new bug-fix release
in the 1.x stable series of the GStreamer RTSP Server Library.
There were no bugs fixed in this release
Bugs fixed in this release
* 761226 : rtspmedia: Missing lock various functions (or the curious case of the duplicate unlocks)
* 761399 : rtspmedia: Missing lock in default_unsuspend, preroll_failed path
==== Download ====
You can find source releases of gst-rtsp-server in the download
directory: http://gstreamer.freedesktop.org/src/gst-rtsp-server/
directory: https://gstreamer.freedesktop.org/src/gst-rtsp-server/
The git repository and details how to clone it can be found at
http://cgit.freedesktop.org/gstreamer/gst-rtsp-server/
==== Homepage ====
The project's website is http://gstreamer.freedesktop.org/
The project's website is https://gstreamer.freedesktop.org/
==== Support and Bugs ====
......@@ -56,6 +49,9 @@ subscribe to the gstreamer-devel list.
Contributors to this release
* Jan Schmidt
* Olivier Crête
* Sebastian Dröge
* Tim-Philipp Müller
* Sebastian Rasmussen
* Srimanta Panda
* Steven Hoving
 
\ No newline at end of file
common @ 66235917
Subproject commit 9aed1d7a80a38b76f9441ecf181942df99f09c38
Subproject commit 66235917b47e6f933f8bd32376662a54f17eb609
......@@ -2,7 +2,7 @@ AC_PREREQ(2.69)
dnl initialize autoconf
dnl when going to/from release please set the nano (fourth number) right !
dnl releases only do Wall, cvs and prerelease does Werror too
AC_INIT([GStreamer RTSP Server Library], [1.6.0],
AC_INIT([GStreamer RTSP Server Library], [1.6.4],
[http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer],
[gst-rtsp-server])
AG_GST_INIT
......@@ -53,13 +53,13 @@ dnl 1.2.5 => 205
dnl 1.10.9 (who knows) => 1009
dnl
dnl sets GST_LT_LDFLAGS
AS_LIBTOOL(GST, 600, 0, 600)
AS_LIBTOOL(GST, 604, 0, 604)
dnl *** required versions of GStreamer stuff ***
GST_REQ=1.6.0
GSTPB_REQ=1.6.0
GSTPG_REQ=1.6.0
GSTPD_REQ=1.6.0
GST_REQ=1.6.4
GSTPB_REQ=1.6.4
GSTPG_REQ=1.6.4
GSTPD_REQ=1.6.4
dnl *** autotools stuff ****
......
......@@ -30,6 +30,36 @@ RTSP server library based on GStreamer
</GitRepository>
</repository>
<release>
<Version>
<revision>1.6.4</revision>
<branch>1.6</branch>
<name></name>
<created>2016-04-14</created>
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.6.4.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.6.2</revision>
<branch>1.6</branch>
<name></name>
<created>2015-12-14</created>
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.6.2.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.6.1</revision>
<branch>1.6</branch>
<name></name>
<created>2015-10-30</created>
<file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.6.1.tar.xz" />
</Version>
</release>
<release>
<Version>
<revision>1.6.0</revision>
......
......@@ -1823,6 +1823,9 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
if (sessmedia == NULL) {
/* get a handle to the configuration of the media in the session */
media = find_media (client, ctx, path, &matched);
/* need to suspend the media, if the protocol has changed */
if (media != NULL)
gst_rtsp_media_suspend (media);
} else {
if ((media = gst_rtsp_session_media_get_media (sessmedia)))
g_object_ref (media);
......@@ -2557,6 +2560,7 @@ handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
GST_RTSP_OPTIONS |
GST_RTSP_PAUSE |
GST_RTSP_PLAY |
GST_RTSP_RECORD | GST_RTSP_ANNOUNCE |
GST_RTSP_SETUP |
GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
......
......@@ -1217,7 +1217,7 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media)
priv = media->priv;
g_mutex_unlock (&priv->lock);
g_mutex_lock (&priv->lock);
res = priv->rtx_time;
g_mutex_unlock (&priv->lock);
......@@ -1267,7 +1267,7 @@ gst_rtsp_media_get_latency (GstRTSPMedia * media)
priv = media->priv;
g_mutex_unlock (&priv->lock);
g_mutex_lock (&priv->lock);
res = priv->latency;
g_mutex_unlock (&priv->lock);
......@@ -1315,7 +1315,7 @@ gst_rtsp_media_is_time_provider (GstRTSPMedia * media)
priv = media->priv;
g_mutex_unlock (&priv->lock);
g_mutex_lock (&priv->lock);
res = priv->time_provider;
g_mutex_unlock (&priv->lock);
......@@ -2487,6 +2487,10 @@ start_prepare (GstRTSPMedia * media)
guint i;
GList *walk;
g_rec_mutex_lock (&priv->state_lock);
if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
goto no_longer_preparing;
/* link streams we already have, other streams might appear when we have
* dynamic elements */
for (i = 0; i < priv->streams->len; i++) {
......@@ -2535,18 +2539,28 @@ start_prepare (GstRTSPMedia * media)
if (!start_preroll (media))
goto preroll_failed;
g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
no_longer_preparing:
{
GST_INFO ("media is no longer preparing");
g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
}
join_bin_failed:
{
GST_WARNING ("failed to join bin element");
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
}
preroll_failed:
{
GST_WARNING ("failed to preroll pipeline");
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
g_rec_mutex_unlock (&priv->state_lock);
return FALSE;
}
}
......@@ -2603,7 +2617,8 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
/* do remainder in context */
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL);
g_source_set_callback (source, (GSourceFunc) start_prepare,
g_object_ref (media), (GDestroyNotify) g_object_unref);
g_source_attach (source, context);
g_source_unref (source);
......@@ -3820,6 +3835,7 @@ static gboolean
default_unsuspend (GstRTSPMedia * media)
{
GstRTSPMediaPrivate *priv = media->priv;
gboolean preroll_ok;
switch (priv->suspend_mode) {
case GST_RTSP_SUSPEND_MODE_NONE:
......@@ -3833,12 +3849,13 @@ default_unsuspend (GstRTSPMedia * media)
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
if (!start_preroll (media))
goto start_failed;
g_rec_mutex_unlock (&priv->state_lock);
preroll_ok = wait_preroll (media);
g_rec_mutex_lock (&priv->state_lock);
if (!wait_preroll (media))
if (!preroll_ok)
goto preroll_failed;
g_rec_mutex_lock (&priv->state_lock);
}
default:
break;
......
......@@ -1191,9 +1191,11 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition,
manage_client (server, client);
} else {
GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
goto exit_no_ctx;
}
exit:
gst_rtsp_context_pop_current (&ctx);
exit_no_ctx:
return G_SOURCE_CONTINUE;
......@@ -1204,7 +1206,8 @@ accept_failed:
GST_ERROR_OBJECT (server, "Could not accept client on socket %p: %s",
socket, str);
g_free (str);
goto exit;
/* We haven't pushed the context yet, so just return */
goto exit_no_ctx;
}
connection_refused:
{
......
......@@ -67,7 +67,7 @@ static const gchar session_id_charset[] =
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '$', '-', '_', '.', '+'
'8', '9', '-', '_', '.', '+' /* '$' Live555 in VLC strips off $ chars */
};
enum
......
......@@ -2085,32 +2085,33 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
(GCallback) request_pt_map, stream);
}
/* get a pad for sending RTP */
name = g_strdup_printf ("send_rtp_sink_%u", idx);
priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
g_free (name);
/* get pads from the RTP session element for sending and receiving
* RTP/RTCP*/
if (priv->srcpad) {
/* get a pad for sending RTP */
name = g_strdup_printf ("send_rtp_sink_%u", idx);
priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
g_free (name);
/* link the RTP pad to the session manager, it should not really fail unless
* this is not really an RTP pad */
ret = gst_pad_link (priv->srcpad, priv->send_rtp_sink);
if (ret != GST_PAD_LINK_OK)
goto link_failed;
name = g_strdup_printf ("send_rtp_src_%u", idx);
priv->send_src[0] = gst_element_get_static_pad (rtpbin, name);
g_free (name);
} else {
/* Need to connect our sinkpad from here */
g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added, stream);
/* EOS */
g_signal_connect (rtpbin, "on-npt-stop", (GCallback) on_npt_stop, stream);
}
/* get pads from the RTP session element for sending and receiving
* RTP/RTCP*/
name = g_strdup_printf ("send_rtp_src_%u", idx);
priv->send_src[0] = gst_element_get_static_pad (rtpbin, name);
g_free (name);
name = g_strdup_printf ("recv_rtp_sink_%u", idx);
priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name);
g_free (name);
name = g_strdup_printf ("recv_rtp_sink_%u", idx);
priv->recv_sink[0] = gst_element_get_request_pad (rtpbin, name);
g_free (name);
}
name = g_strdup_printf ("send_rtcp_src_%u", idx);
priv->send_src[1] = gst_element_get_request_pad (rtpbin, name);
......@@ -2155,157 +2156,170 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
* When only UDP is allowed, we skip the tee, queue and appsink and link the
* udpsink directly to the session.
*/
/* add udpsink */
gst_bin_add (bin, priv->udpsink[i]);
sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink");
if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) {
/* make tee for RTP/RTCP */
priv->tee[i] = gst_element_factory_make ("tee", NULL);
gst_bin_add (bin, priv->tee[i]);
/* and link to rtpbin send pad */
pad = gst_element_get_static_pad (priv->tee[i], "sink");
gst_pad_link (priv->send_src[i], pad);
gst_object_unref (pad);
priv->udpqueue[i] = gst_element_factory_make ("queue", NULL);
g_object_set (priv->udpqueue[i], "max-size-buffers",
1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL);
gst_bin_add (bin, priv->udpqueue[i]);
/* link tee to udpqueue */
teepad = gst_element_get_request_pad (priv->tee[i], "src_%u");
pad = gst_element_get_static_pad (priv->udpqueue[i], "sink");
gst_pad_link (teepad, pad);
gst_object_unref (pad);
gst_object_unref (teepad);
/* link udpqueue to udpsink */
queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src");
gst_pad_link (queuepad, sinkpad);
gst_object_unref (queuepad);
/* make queue */
priv->appqueue[i] = gst_element_factory_make ("queue", NULL);
g_object_set (priv->appqueue[i], "max-size-buffers",
1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0), NULL);
gst_bin_add (bin, priv->appqueue[i]);
/* and link to tee */
teepad = gst_element_get_request_pad (priv->tee[i], "src_%u");
pad = gst_element_get_static_pad (priv->appqueue[i], "sink");
gst_pad_link (teepad, pad);
gst_object_unref (pad);
gst_object_unref (teepad);
/* make appsink */
priv->appsink[i] = gst_element_factory_make ("appsink", NULL);
g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL);
g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL);
gst_bin_add (bin, priv->appsink[i]);
gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]),
&sink_cb, stream, NULL);
/* and link to queue */
queuepad = gst_element_get_static_pad (priv->appqueue[i], "src");
pad = gst_element_get_static_pad (priv->appsink[i], "sink");
gst_pad_link (queuepad, pad);
gst_object_unref (pad);
gst_object_unref (queuepad);
} else {
/* else only udpsink needed, link it to the session */
gst_pad_link (priv->send_src[i], sinkpad);
}
gst_object_unref (sinkpad);
/* For the receiver we create this bit of pipeline for both
* RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
* and it is all funneled into the rtpbin receive pad.
*
* .--------. .--------. .--------.
* | udpsrc | | funnel | | rtpbin |
* | src->sink src->sink |
* '--------' | | '--------'
* .--------. | |
* | appsrc | | |
* | src->sink |
* '--------' '--------'
*/
/* make funnel for the RTP/RTCP receivers */
priv->funnel[i] = gst_element_factory_make ("funnel", NULL);
gst_bin_add (bin, priv->funnel[i]);
pad = gst_element_get_static_pad (priv->funnel[i], "src");
gst_pad_link (pad, priv->recv_sink[i]);
gst_object_unref (pad);
if (priv->udpsrc_v4[i]) {
if (priv->srcpad) {
/* we set and keep these to playing so that they don't cause NO_PREROLL return
* values. This is only relevant for PLAY pipelines */
gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING);
gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE);
/* Only link the RTP send src if we're going to send RTP, link
* the RTCP send src always */
if (priv->srcpad || i == 1) {
/* add udpsink */
gst_bin_add (bin, priv->udpsink[i]);
sinkpad = gst_element_get_static_pad (priv->udpsink[i], "sink");
if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) {
/* make tee for RTP/RTCP */
priv->tee[i] = gst_element_factory_make ("tee", NULL);
gst_bin_add (bin, priv->tee[i]);
/* and link to rtpbin send pad */
pad = gst_element_get_static_pad (priv->tee[i], "sink");
gst_pad_link (priv->send_src[i], pad);
gst_object_unref (pad);
priv->udpqueue[i] = gst_element_factory_make ("queue", NULL);
g_object_set (priv->udpqueue[i], "max-size-buffers",
1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0),
NULL);
gst_bin_add (bin, priv->udpqueue[i]);
/* link tee to udpqueue */
teepad = gst_element_get_request_pad (priv->tee[i], "src_%u");
pad = gst_element_get_static_pad (priv->udpqueue[i], "sink");
gst_pad_link (teepad, pad);
gst_object_unref (pad);
gst_object_unref (teepad);
/* link udpqueue to udpsink */
queuepad = gst_element_get_static_pad (priv->udpqueue[i], "src");
gst_pad_link (queuepad, sinkpad);
gst_object_unref (queuepad);
/* make queue */
priv->appqueue[i] = gst_element_factory_make ("queue", NULL);
g_object_set (priv->appqueue[i], "max-size-buffers",
1, "max-size-bytes", 0, "max-size-time", G_GINT64_CONSTANT (0),
NULL);
gst_bin_add (bin, priv->appqueue[i]);
/* and link to tee */
teepad = gst_element_get_request_pad (priv->tee[i], "src_%u");
pad = gst_element_get_static_pad (priv->appqueue[i], "sink");
gst_pad_link (teepad, pad);
gst_object_unref (pad);
gst_object_unref (teepad);
/* make appsink */
priv->appsink[i] = gst_element_factory_make ("appsink", NULL);
g_object_set (priv->appsink[i], "async", FALSE, "sync", FALSE, NULL);
g_object_set (priv->appsink[i], "emit-signals", FALSE, NULL);
gst_bin_add (bin, priv->appsink[i]);
gst_app_sink_set_callbacks (GST_APP_SINK_CAST (priv->appsink[i]),
&sink_cb, stream, NULL);
/* and link to queue */
queuepad = gst_element_get_static_pad (priv->appqueue[i], "src");
pad = gst_element_get_static_pad (priv->appsink[i], "sink");
gst_pad_link (queuepad, pad);
gst_object_unref (pad);
gst_object_unref (queuepad);
} else {
/* else only udpsink needed, link it to the session */
gst_pad_link (priv->send_src[i], sinkpad);
}
/* add udpsrc */
gst_bin_add (bin, priv->udpsrc_v4[i]);
gst_object_unref (sinkpad);
}
/* and link to the funnel v4 */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src");
gst_pad_link (pad, selpad);
/* Only connect recv RTP sink if we expect to receive RTP. Connect recv
* RTCP sink always */
if (priv->sinkpad || i == 1) {
/* For the receiver we create this bit of pipeline for both
* RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
* and it is all funneled into the rtpbin receive pad.
*
* .--------. .--------. .--------.
* | udpsrc | | funnel | | rtpbin |
* | src->sink src->sink |
* '--------' | | '--------'
* .--------. | |
* | appsrc | | |
* | src->sink |
* '--------' '--------'
*/
/* make funnel for the RTP/RTCP receivers */
priv->funnel[i] = gst_element_factory_make ("funnel", NULL);
gst_bin_add (bin, priv->funnel[i]);
pad = gst_element_get_static_pad (priv->funnel[i], "src");
gst_pad_link (pad, priv->recv_sink[i]);
gst_object_unref (pad);
gst_object_unref (selpad);
}
if (priv->udpsrc_v6[i]) {
if (priv->srcpad) {
gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING);
gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE);
if (priv->udpsrc_v4[i]) {
if (priv->srcpad) {
/* we set and keep these to playing so that they don't cause NO_PREROLL return
* values. This is only relevant for PLAY pipelines */
gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING);
gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE);
}
/* add udpsrc */
gst_bin_add (bin, priv->udpsrc_v4[i]);
/* and link to the funnel v4 */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
}
gst_bin_add (bin, priv->udpsrc_v6[i]);
/* and link to the funnel v6 */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
}
if (priv->udpsrc_v6[i]) {
if (priv->srcpad) {
gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING);
gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE);
}
gst_bin_add (bin, priv->udpsrc_v6[i]);
/* and link to the funnel v6 */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
}
if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) {
/* make and add appsrc */
priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
priv->appsrc_base_time[i] = -1;
g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL);
gst_bin_add (bin, priv->appsrc[i]);
/* and link to the funnel */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->appsrc[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
if (priv->protocols & GST_RTSP_LOWER_TRANS_TCP) {
/* make and add appsrc */
priv->appsrc[i] = gst_element_factory_make ("appsrc", NULL);
priv->appsrc_base_time[i] = -1;
g_object_set (priv->appsrc[i], "format", GST_FORMAT_TIME, NULL);
gst_bin_add (bin, priv->appsrc[i]);
/* and link to the funnel */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->appsrc[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
}
}
/* check if we need to set to a special state */
if (state != GST_STATE_NULL) {
if (priv->udpsink[i])
if (priv->udpsink[i] && (priv->srcpad || i == 1))
gst_element_set_state (priv->udpsink[i], state);
if (priv->appsink[i])
if (priv->appsink[i] && (priv->srcpad || i == 1))
gst_element_set_state (priv->appsink[i], state);
if (priv->appqueue[i])
if (priv->appqueue[i] && (priv->srcpad || i == 1))
gst_element_set_state (priv->appqueue[i], state);
if (priv->udpqueue[i])
if (priv->udpqueue[i] && (priv->srcpad || i == 1))
gst_element_set_state (priv->udpqueue[i], state);
if (priv->tee[i])
if (priv->tee[i] && (priv->srcpad || i == 1))
gst_element_set_state (priv->tee[i], state);
if (priv->funnel[i])
if (priv->funnel[i] && (priv->sinkpad || i == 1))
gst_element_set_state (priv->funnel[i], state);
if (priv->appsrc[i])
if (priv->appsrc[i] && (priv->sinkpad || i == 1))
gst_element_set_state (priv->appsrc[i], state);
}
}
/* be notified of caps changes */
priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps",
(GCallback) caps_notify, stream);
if (priv->srcpad) {
/* be notified of caps changes */
priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps",
(GCallback) caps_notify, stream);
}
priv->is_joined = TRUE;
g_mutex_unlock (&priv->lock);
......@@ -2373,15 +2387,16 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
if (priv->srcpad) {
gst_pad_unlink (priv->srcpad, priv->send_rtp_sink);
g_signal_handler_disconnect (priv->send_src[0], priv->caps_sig);
gst_element_release_request_pad (rtpbin, priv->send_rtp_sink);
gst_object_unref (priv->send_rtp_sink);
priv->send_rtp_sink = NULL;
} else if (priv->recv_rtp_src) {
gst_pad_unlink (priv->recv_rtp_src, priv->sinkpad);
gst_object_unref (priv->recv_rtp_src);
priv->recv_rtp_src = NULL;
}
g_signal_handler_disconnect (priv->send_src[0], priv->caps_sig);
gst_element_release_request_pad (rtpbin, priv->send_rtp_sink);
gst_object_unref (priv->send_rtp_sink);
priv->send_rtp_sink = NULL;
for (i = 0; i < 2; i++) {
if (priv->udpsink[i])
......@@ -2398,18 +2413,31 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
gst_element_set_state (priv->funnel[i], GST_STATE_NULL);
if (priv->appsrc[i])
gst_element_set_state (priv->appsrc[i], GST_STATE_NULL);
if (priv->udpsrc_v4[i]) {
/* and set udpsrc to NULL now before removing */
gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE);
gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL);
/* removing them should also nicely release the request
* pads when they finalize */
gst_bin_remove (bin, priv->udpsrc_v4[i]);
if (priv->sinkpad || i == 1) {
/* and set udpsrc to NULL now before removing */
gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE);
gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL);
/* removing them should also nicely release the request
* pads when they finalize */
gst_bin_remove (bin, priv->udpsrc_v4[i]);
} else {
/* we need to set the state to NULL before unref */
gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL);
gst_object_unref (priv->udpsrc_v4[i]);
}
}
if (priv->udpsrc_v6[i]) {
gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE);
gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL);
gst_bin_remove (bin, priv->udpsrc_v6[i]);
if (priv->sinkpad || i == 1) {
gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE);
gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL);
gst_bin_remove (bin, priv->udpsrc_v6[i]);
} else {
gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL);
gst_object_unref (priv->udpsrc_v6[i]);
}
}
for (l = priv->transport_sources; l; l = l->next) {
......@@ -2423,24 +2451,26 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
gst_bin_remove (bin, s->udpsrc[i]);
}
if (priv->udpsink[i])
if (priv->udpsink[i] && (priv->srcpad || i == 1))
gst_bin_remove (bin, priv->udpsink[i]);
if (priv->appsrc[i])
if (priv->appsrc[i] && (priv->sinkpad || i == 1))
gst_bin_remove (bin, priv->appsrc[i]);
if (priv->appsink[i])
if (priv->appsink[i] && (priv->srcpad || i == 1))
gst_bin_remove (bin, priv->appsink[i]);
if (priv->appqueue[i])
if (priv->appqueue[i] && (priv->srcpad || i == 1))
gst_bin_remove (bin, priv->appqueue[i]);
if (priv->udpqueue[i])
if (priv->udpqueue[i] && (priv->srcpad || i == 1))
gst_bin_remove (bin, priv->udpqueue[i]);
if (priv->tee[i])
if (priv->tee[i] && (priv->srcpad || i == 1))
gst_bin_remove (bin, priv->tee[i]);
if (priv->funnel[i])
if (priv->funnel[i] && (priv->sinkpad || i == 1))
gst_bin_remove (bin, priv->funnel[i]);
gst_element_release_request_pad (rtpbin, priv->recv_sink[i]);
gst_object_unref (priv->recv_sink[i]);
priv->recv_sink[i] = NULL;
if (priv->sinkpad || i == 1) {
gst_element_release_request_pad (rtpbin, priv->recv_sink[i]);
gst_object_unref (priv->recv_sink[i]);
priv->recv_sink[i] = NULL;
}
priv->udpsrc_v4[i] = NULL;
priv->udpsrc_v6[i] = NULL;
......@@ -2460,8 +2490,10 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
g_list_free (priv->transport_sources);
priv->transport_sources = NULL;
gst_object_unref (priv->send_src[0]);
priv->send_src[0] = NULL;
if (priv->srcpad) {
gst_object_unref (priv->send_src[0]);
priv->send_src[0] = NULL;
}
gst_element_release_request_pad (rtpbin, priv->send_src[1]);
gst_object_unref (priv->send_src[1]);
......@@ -2808,7 +2840,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
GstRTSPMulticastTransportSource *source;
GstBin *bin;
bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[0])));
bin = GST_BIN (gst_object_get_parent (GST_OBJECT (priv->funnel[1])));
if (add) {
gchar *host;
......@@ -2825,6 +2857,7 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
source->udpsrc[i] =
gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
g_free (host);
g_object_set (source->udpsrc[i], "loop", FALSE, NULL);
if (priv->srcpad) {
/* we set and keep these to playing so that they don't cause NO_PREROLL return
......@@ -2836,14 +2869,15 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
gst_bin_add (bin, source->udpsrc[i]);
/* and link to the funnel v4 */
source->selpad[i] = selpad =
gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (source->udpsrc[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
if (priv->sinkpad || i == 1) {
source->selpad[i] = selpad =
gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (source->udpsrc[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
}
}
gst_object_unref (bin);
priv->transport_sources =
g_list_prepend (priv->transport_sources, source);
......@@ -2871,14 +2905,18 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
gst_element_set_state (source->udpsrc[i], GST_STATE_NULL);
gst_object_unref (source->udpsrc[i]);
gst_element_release_request_pad (priv->funnel[i],
source->selpad[i]);
if (priv->sinkpad || i == 1) {
gst_element_release_request_pad (priv->funnel[i],
source->selpad[i]);
}
}
g_slice_free (GstRTSPMulticastTransportSource, source);
}
}
gst_object_unref (bin);
/* fall through for the generic case */
}
case GST_RTSP_LOWER_TRANS_UDP:
......
......@@ -21,7 +21,7 @@
#include <rtsp-client.h>
static gchar * session_id;
static gchar *session_id;
static gint cseq;
static guint expected_session_timeout = 60;
static const gchar *expected_unsupported_header;
......@@ -128,7 +128,7 @@ test_response_551 (GstRTSPClient * client, GstRTSPMessage * response,
fail_unless (code == GST_RTSP_STS_OPTION_NOT_SUPPORTED);
fail_unless (g_str_equal (reason, "Option not supported"));
fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_UNSUPPORTED,
&options, 0) == GST_RTSP_OK);
&options, 0) == GST_RTSP_OK);
fail_unless (!g_strcmp0 (expected_unsupported_header, options));
fail_unless (version == GST_RTSP_VERSION_1_0);
......@@ -177,7 +177,7 @@ teardown_client (GstRTSPClient * client)
g_object_unref (client);
}
static gchar*
static gchar *
check_requirements_cb (GstRTSPClient * client, GstRTSPContext * ctx,
gchar ** req, gpointer user_data)
{
......@@ -193,7 +193,7 @@ check_requirements_cb (GstRTSPClient * client, GstRTSPContext * ctx,
index++;
}
return g_string_free (result, FALSE);
return g_string_free (result, FALSE);
}
GST_START_TEST (test_require)
......@@ -393,9 +393,11 @@ test_option_response_200 (GstRTSPClient * client, GstRTSPMessage * response,
methods = gst_rtsp_options_from_text (str);
fail_if (methods == 0);
fail_unless (methods == (GST_RTSP_DESCRIBE |
GST_RTSP_ANNOUNCE |
GST_RTSP_OPTIONS |
GST_RTSP_PAUSE |
GST_RTSP_PLAY |
GST_RTSP_RECORD |
GST_RTSP_SETUP |
GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN));
......@@ -572,8 +574,7 @@ send_teardown (GstRTSPClient * client)
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("%d", cseq);
gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str);
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION,
session_id);
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id);
gst_rtsp_client_set_send_func (client, test_teardown_response_200,
NULL, NULL);
fail_unless (gst_rtsp_client_handle_message (client,
......