rtsp-server: Add new ensure-keyunit-on-start property

While the suspend modes NONE and PAUSED provided a low startup latency
for connecting clients they did not ensure that streams started on
fresh data.

With this property we can maintain the low startup latency of those
suspend modes while also ensuring that a stream starts on a key unit.
Furthermore, by modifying the value of a new property,
ensure-keyunit-on-start-timeout, it is possible to accept a keyunit of
a certain age but discard it if too much time has passed and instead
force a new keyunit.

Fixes #2443

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4334>
This commit is contained in:
Jacob Johnsson 2023-06-26 08:25:36 +02:00 committed by GStreamer Marge Bot
parent acccc91005
commit eb0272e210
11 changed files with 837 additions and 10 deletions

View file

@ -3767,6 +3767,34 @@ g_object_unref() after usage.</doc>
</instance-parameter>
</parameters>
</method>
<method name="get_ensure_keyunit_on_start" c:identifier="gst_rtsp_media_get_ensure_keyunit_on_start" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Get ensure-keyunit-on-start flag.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">The ensure-keyunit-on-start flag.</doc>
<type name="gboolean" c:type="gboolean"/>
</return-value>
<parameters>
<instance-parameter name="media" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">a #GstRTSPMedia</doc>
<type name="RTSPMedia" c:type="GstRTSPMedia*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_ensure_keyunit_on_start_timeout" c:identifier="gst_rtsp_media_get_ensure_keyunit_on_start_timeout" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Get ensure-keyunit-on-start-timeout time.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">The ensure-keyunit-on-start-timeout time.</doc>
<type name="guint" c:type="guint"/>
</return-value>
<parameters>
<instance-parameter name="media" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">a #GstRTSPMedia</doc>
<type name="RTSPMedia" c:type="GstRTSPMedia*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_latency" c:identifier="gst_rtsp_media_get_latency">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Get the latency that is used for receiving media.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.h"/>
@ -4415,6 +4443,48 @@ INADDR_ANY.</doc>
</parameter>
</parameters>
</method>
<method name="set_ensure_keyunit_on_start" c:identifier="gst_rtsp_media_set_ensure_keyunit_on_start" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Set whether or not a keyunit should be ensured when a client connects. It
will also configure the streams to drop delta units to ensure that they start
on a keyunit.
Note that this will only affect non-shared medias for now.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="media" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">a #GstRTSPMedia</doc>
<type name="RTSPMedia" c:type="GstRTSPMedia*"/>
</instance-parameter>
<parameter name="ensure_keyunit_on_start" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">the new value</doc>
<type name="gboolean" c:type="gboolean"/>
</parameter>
</parameters>
</method>
<method name="set_ensure_keyunit_on_start_timeout" c:identifier="gst_rtsp_media_set_ensure_keyunit_on_start_timeout" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Sets the maximum allowed time before the first keyunit is considered
expired.
Note that this will only have an effect when ensure-keyunit-on-start is
enabled.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="media" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">a #GstRTSPMedia</doc>
<type name="RTSPMedia" c:type="GstRTSPMedia*"/>
</instance-parameter>
<parameter name="timeout" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">the new value</doc>
<type name="guint" c:type="guint"/>
</parameter>
</parameters>
</method>
<method name="set_eos_shutdown" c:identifier="gst_rtsp_media_set_eos_shutdown">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Set or unset if an EOS event will be sent to the pipeline for @media before
it is unprepared.</doc>
@ -4857,6 +4927,22 @@ when the media was not in the suspended state.</doc>
<property name="element" writable="1" construct-only="1" transfer-ownership="none">
<type name="Gst.Element"/>
</property>
<property name="ensure-keyunit-on-start" version="1.24" writable="1" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">Whether or not a keyunit should be ensured when a client connects. It
will also configure the streams to drop delta units to ensure that they start
on a keyunit.
Note that this will only affect non-shared medias for now.</doc>
<type name="gboolean" c:type="gboolean"/>
</property>
<property name="ensure-keyunit-on-start-timeout" version="1.24" writable="1" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c">The maximum allowed time before the first keyunit is considered
expired.
Note that this will only have an effect when ensure-keyunit-on-start is
enabled.</doc>
<type name="guint" c:type="guint"/>
</property>
<property name="eos-shutdown" writable="1" transfer-ownership="none">
<type name="gboolean" c:type="gboolean"/>
</property>
@ -5568,6 +5654,34 @@ of all medias created from this factory.</doc>
</instance-parameter>
</parameters>
</method>
<method name="get_ensure_keyunit_on_start" c:identifier="gst_rtsp_media_factory_get_ensure_keyunit_on_start" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Get ensure-keyunit-on-start flag.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">The ensure-keyunit-on-start flag.</doc>
<type name="gboolean" c:type="gboolean"/>
</return-value>
<parameters>
<instance-parameter name="factory" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">a #GstRTSPMediaFactory</doc>
<type name="RTSPMediaFactory" c:type="GstRTSPMediaFactory*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_ensure_keyunit_on_start_timeout" c:identifier="gst_rtsp_media_factory_get_ensure_keyunit_on_start_timeout" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Get ensure-keyunit-on-start-timeout time.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">The ensure-keyunit-on-start-timeout time.</doc>
<type name="guint" c:type="guint"/>
</return-value>
<parameters>
<instance-parameter name="factory" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">a #GstRTSPMediaFactory</doc>
<type name="RTSPMediaFactory" c:type="GstRTSPMediaFactory*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_latency" c:identifier="gst_rtsp_media_factory_get_latency">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Get the latency that is used for receiving media</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.h"/>
@ -5928,6 +6042,41 @@ receiving media</doc>
</parameter>
</parameters>
</method>
<method name="set_ensure_keyunit_on_start" c:identifier="gst_rtsp_media_factory_set_ensure_keyunit_on_start" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">If media from this factory should ensure a key unit when a client connects.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="factory" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">a #GstRTSPMediaFactory</doc>
<type name="RTSPMediaFactory" c:type="GstRTSPMediaFactory*"/>
</instance-parameter>
<parameter name="ensure_keyunit_on_start" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">the new value</doc>
<type name="gboolean" c:type="gboolean"/>
</parameter>
</parameters>
</method>
<method name="set_ensure_keyunit_on_start_timeout" c:identifier="gst_rtsp_media_factory_set_ensure_keyunit_on_start_timeout" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Configures medias from this factory to consider keyunits older than timeout
to be expired. Expired keyunits will be discarded.</doc>
<source-position filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="factory" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">a #GstRTSPMediaFactory</doc>
<type name="RTSPMediaFactory" c:type="GstRTSPMediaFactory*"/>
</instance-parameter>
<parameter name="timeout" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">the new value</doc>
<type name="guint" c:type="guint"/>
</parameter>
</parameters>
</method>
<method name="set_eos_shutdown" c:identifier="gst_rtsp_media_factory_set_eos_shutdown">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Configure if media created from this factory will have an EOS sent to the
pipeline before shutdown.</doc>
@ -6212,6 +6361,25 @@ when a client disconnects without sending TEARDOWN.</doc>
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Whether the created media should send and receive RTCP</doc>
<type name="gboolean" c:type="gboolean"/>
</property>
<property name="ensure-keyunit-on-start" version="1.24" writable="1" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">If media from this factory should ensure a key unit when a client connects.
This property will ensure that the stream always starts on a key unit
instead of a delta unit which the client would not be able to decode.
Note that this will only affect non-shared medias for now.</doc>
<type name="gboolean" c:type="gboolean"/>
</property>
<property name="ensure-keyunit-on-start-timeout" version="1.24" writable="1" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory.c">Timeout in milliseconds used to determine if a keyunit should be discarded
when a client connects.
If the timeout has been reached a new keyframe will be forced, otherwise
the currently blocking keyframe will be used.
This options is only relevant when ensure-keyunit-on-start is enabled.</doc>
<type name="guint" c:type="guint"/>
</property>
<property name="eos-shutdown" writable="1" transfer-ownership="none">
<type name="gboolean" c:type="gboolean"/>
</property>

View file

@ -55,7 +55,7 @@ rtsp_server_headers = files(
install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server')
gst_rtsp_server_deps = [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep, gst_dep]
gst_rtsp_server_deps = [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep, gst_dep, gstvideo_dep]
gst_rtsp_server = library('gstrtspserver-@0@'.format(api_version),
rtsp_server_sources,
include_directories : rtspserver_incs,
@ -104,6 +104,6 @@ gst_libraries += [[pkg_name, library_def]]
gst_rtsp_server_dep = declare_dependency(link_with : gst_rtsp_server,
include_directories : rtspserver_incs,
sources : rtsp_server_gen_sources,
dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep])
dependencies : [gstrtsp_dep, gstrtp_dep, gstsdp_dep, gstnet_dep, gstapp_dep, gstvideo_dep])
meson.override_dependency(pkg_name, gst_rtsp_server_dep)

View file

@ -59,6 +59,8 @@ struct _GstRTSPMediaFactoryPrivate
GstRTSPProfile profiles;
GstRTSPLowerTrans protocols;
guint buffer_size;
gboolean ensure_keyunit_on_start;
guint ensure_keyunit_on_start_timeout;
gint dscp_qos;
GstRTSPAddressPool *pool;
GstRTSPTransportMode transport_mode;
@ -90,6 +92,8 @@ struct _GstRTSPMediaFactoryPrivate
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
GST_RTSP_LOWER_TRANS_TCP
#define DEFAULT_BUFFER_SIZE 0x80000
#define DEFAULT_ENSURE_KEYUNIT_ON_START FALSE
#define DEFAULT_ENSURE_KEYUNIT_ON_START_TIMEOUT 100
#define DEFAULT_LATENCY 200
#define DEFAULT_MAX_MCAST_TTL 255
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
@ -109,6 +113,8 @@ enum
PROP_PROFILES,
PROP_PROTOCOLS,
PROP_BUFFER_SIZE,
PROP_ENSURE_KEYUNIT_ON_START,
PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT,
PROP_LATENCY,
PROP_TRANSPORT_MODE,
PROP_STOP_ON_DISCONNECT,
@ -214,6 +220,48 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
"The kernel UDP buffer size to use", 0, G_MAXUINT,
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPMediaFactory:ensure-keyunit-on-start:
*
* If media from this factory should ensure a key unit when a client connects.
*
* This property will ensure that the stream always starts on a key unit
* instead of a delta unit which the client would not be able to decode.
*
* Note that this will only affect non-shared medias for now.
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class, PROP_ENSURE_KEYUNIT_ON_START,
g_param_spec_boolean ("ensure-keyunit-on-start",
"Ensure keyunit on start",
"If media from this factory should ensure a key unit when a client "
"connects.",
DEFAULT_ENSURE_KEYUNIT_ON_START,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPMediaFactory:ensure-keyunit-on-start-timeout:
*
* Timeout in milliseconds used to determine if a keyunit should be discarded
* when a client connects.
*
* If the timeout has been reached a new keyframe will be forced, otherwise
* the currently blocking keyframe will be used.
*
* This options is only relevant when ensure-keyunit-on-start is enabled.
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class,
PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT,
g_param_spec_uint ("ensure-keyunit-on-start-timeout",
"Timeout for discarding old keyunit on start",
"Timeout in milliseconds used to determine if a keyunit should be "
"discarded when a client connects.", 0, G_MAXUINT,
DEFAULT_ENSURE_KEYUNIT_ON_START_TIMEOUT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LATENCY,
g_param_spec_uint ("latency", "Latency",
"Latency used for receiving media in milliseconds", 0, G_MAXUINT,
@ -304,6 +352,9 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
priv->profiles = DEFAULT_PROFILES;
priv->protocols = DEFAULT_PROTOCOLS;
priv->buffer_size = DEFAULT_BUFFER_SIZE;
priv->ensure_keyunit_on_start = DEFAULT_ENSURE_KEYUNIT_ON_START;
priv->ensure_keyunit_on_start_timeout =
DEFAULT_ENSURE_KEYUNIT_ON_START_TIMEOUT;
priv->latency = DEFAULT_LATENCY;
priv->transport_mode = DEFAULT_TRANSPORT_MODE;
priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
@ -373,6 +424,14 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid,
g_value_set_uint (value,
gst_rtsp_media_factory_get_buffer_size (factory));
break;
case PROP_ENSURE_KEYUNIT_ON_START:
g_value_set_boolean (value,
gst_rtsp_media_factory_get_ensure_keyunit_on_start (factory));
break;
case PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT:
g_value_set_uint (value,
gst_rtsp_media_factory_get_ensure_keyunit_on_start_timeout (factory));
break;
case PROP_LATENCY:
g_value_set_uint (value, gst_rtsp_media_factory_get_latency (factory));
break;
@ -438,6 +497,14 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid,
gst_rtsp_media_factory_set_buffer_size (factory,
g_value_get_uint (value));
break;
case PROP_ENSURE_KEYUNIT_ON_START:
gst_rtsp_media_factory_set_ensure_keyunit_on_start (factory,
g_value_get_boolean (value));
break;
case PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT:
gst_rtsp_media_factory_set_ensure_keyunit_on_start_timeout (factory,
g_value_get_uint (value));
break;
case PROP_LATENCY:
gst_rtsp_media_factory_set_latency (factory, g_value_get_uint (value));
break;
@ -853,6 +920,111 @@ gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
return result;
}
/**
* gst_rtsp_media_factory_set_ensure_keyunit_on_start:
* @factory: a #GstRTSPMediaFactory
* @ensure_keyunit_on_start: the new value
*
* If media from this factory should ensure a key unit when a client connects.
*
* Since: 1.24
*/
void
gst_rtsp_media_factory_set_ensure_keyunit_on_start (GstRTSPMediaFactory *
factory, gboolean ensure_keyunit_on_start)
{
GstRTSPMediaFactoryPrivate *priv;
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
priv = factory->priv;
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
priv->ensure_keyunit_on_start = ensure_keyunit_on_start;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
/**
* gst_rtsp_media_factory_get_ensure_keyunit_on_start:
* @factory: a #GstRTSPMediaFactory
*
* Get ensure-keyunit-on-start flag.
*
* Returns: The ensure-keyunit-on-start flag.
*
* Since: 1.24
*/
gboolean
gst_rtsp_media_factory_get_ensure_keyunit_on_start (GstRTSPMediaFactory *
factory)
{
GstRTSPMediaFactoryPrivate *priv;
gboolean result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
priv = factory->priv;
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
result = priv->ensure_keyunit_on_start;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
}
/**
* gst_rtsp_media_factory_set_ensure_keyunit_on_start_timeout:
* @factory: a #GstRTSPMediaFactory
* @timeout: the new value
*
* Configures medias from this factory to consider keyunits older than timeout
* to be expired. Expired keyunits will be discarded.
*
* Since: 1.24
*/
void
gst_rtsp_media_factory_set_ensure_keyunit_on_start_timeout (GstRTSPMediaFactory
* factory, guint timeout)
{
GstRTSPMediaFactoryPrivate *priv;
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
priv = factory->priv;
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
priv->ensure_keyunit_on_start_timeout = timeout;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
/**
* gst_rtsp_media_factory_get_ensure_keyunit_on_start_timeout:
* @factory: a #GstRTSPMediaFactory
*
* Get ensure-keyunit-on-start-timeout time.
*
* Returns: The ensure-keyunit-on-start-timeout time.
*
* Since: 1.24
*/
guint
gst_rtsp_media_factory_get_ensure_keyunit_on_start_timeout (GstRTSPMediaFactory
* factory)
{
GstRTSPMediaFactoryPrivate *priv;
guint result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
priv = factory->priv;
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
result = priv->ensure_keyunit_on_start_timeout;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
}
/**
* gst_rtsp_media_factory_set_dscp_qos:
* @factory: a #GstRTSPMediaFactory
@ -1878,6 +2050,8 @@ default_construct (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
/* We need to call this prior to collecting streams */
gst_rtsp_media_set_enable_rtcp (media, enable_rtcp);
gst_rtsp_media_set_ensure_keyunit_on_start (media,
gst_rtsp_media_factory_get_ensure_keyunit_on_start (factory));
gst_rtsp_media_collect_streams (media);
@ -1928,6 +2102,8 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
GstRTSPMediaFactoryPrivate *priv = factory->priv;
gboolean shared, eos_shutdown, stop_on_disconnect;
guint size;
gboolean ensure_keyunit_on_start;
guint ensure_keyunit_on_start_timeout;
gint dscp_qos;
GstRTSPSuspendMode suspend_mode;
GstRTSPProfile profiles;
@ -1949,6 +2125,8 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
shared = priv->shared;
eos_shutdown = priv->eos_shutdown;
size = priv->buffer_size;
ensure_keyunit_on_start = priv->ensure_keyunit_on_start;
ensure_keyunit_on_start_timeout = priv->ensure_keyunit_on_start_timeout;
dscp_qos = priv->dscp_qos;
profiles = priv->profiles;
protocols = priv->protocols;
@ -1966,6 +2144,9 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
gst_rtsp_media_set_shared (media, shared);
gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
gst_rtsp_media_set_buffer_size (media, size);
gst_rtsp_media_set_ensure_keyunit_on_start (media, ensure_keyunit_on_start);
gst_rtsp_media_set_ensure_keyunit_on_start_timeout (media,
ensure_keyunit_on_start_timeout);
gst_rtsp_media_set_dscp_qos (media, dscp_qos);
gst_rtsp_media_set_profiles (media, profiles);
gst_rtsp_media_set_protocols (media, protocols);

View file

@ -191,6 +191,21 @@ void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFacto
GST_RTSP_SERVER_API
guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory);
GST_RTSP_SERVER_API
void gst_rtsp_media_factory_set_ensure_keyunit_on_start (GstRTSPMediaFactory * factory,
gboolean ensure_keyunit_on_start);
GST_RTSP_SERVER_API
gboolean gst_rtsp_media_factory_get_ensure_keyunit_on_start (GstRTSPMediaFactory * factory);
GST_RTSP_SERVER_API
void gst_rtsp_media_factory_set_ensure_keyunit_on_start_timeout (GstRTSPMediaFactory * factory,
guint timeout);
GST_RTSP_SERVER_API
guint gst_rtsp_media_factory_get_ensure_keyunit_on_start_timeout (GstRTSPMediaFactory * factory);
GST_RTSP_SERVER_API
void gst_rtsp_media_factory_set_retransmission_time (GstRTSPMediaFactory * factory,
GstClockTime time);

View file

@ -77,6 +77,8 @@
#include <gst/sdp/gstmikey.h>
#include <gst/rtp/gstrtppayloads.h>
#include <gst/video/video-event.h>
#define AES_128_KEY_LEN 16
#define AES_256_KEY_LEN 32
@ -107,6 +109,10 @@ struct _GstRTSPMediaPrivate
gboolean reused;
gboolean eos_shutdown;
guint buffer_size;
gboolean ensure_keyunit_on_start;
guint ensure_keyunit_on_start_timeout;
gboolean keyunit_is_expired; /* if the blocking keyunit has expired */
GSource *keyunit_expiration_source;
gint dscp_qos;
GstRTSPAddressPool *pool;
gchar *multicast_iface;
@ -172,6 +178,8 @@ struct _GstRTSPMediaPrivate
GST_RTSP_LOWER_TRANS_TCP
#define DEFAULT_EOS_SHUTDOWN FALSE
#define DEFAULT_BUFFER_SIZE 0x80000
#define DEFAULT_ENSURE_KEYUNIT_ON_START FALSE
#define DEFAULT_ENSURE_KEYUNIT_ON_START_TIMEOUT 100
#define DEFAULT_DSCP_QOS (-1)
#define DEFAULT_TIME_PROVIDER FALSE
#define DEFAULT_LATENCY 200
@ -197,6 +205,8 @@ enum
PROP_PROTOCOLS,
PROP_EOS_SHUTDOWN,
PROP_BUFFER_SIZE,
PROP_ENSURE_KEYUNIT_ON_START,
PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT,
PROP_ELEMENT,
PROP_TIME_PROVIDER,
PROP_LATENCY,
@ -371,6 +381,44 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
"The kernel UDP buffer size to use", 0, G_MAXUINT,
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPMedia:ensure-keyunit-on-start:
*
* Whether or not a keyunit should be ensured when a client connects. It
* will also configure the streams to drop delta units to ensure that they start
* on a keyunit.
*
* Note that this will only affect non-shared medias for now.
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class, PROP_ENSURE_KEYUNIT_ON_START,
g_param_spec_boolean ("ensure-keyunit-on-start",
"Ensure keyunit on start",
"Whether the stream will ensure a keyunit when a client connects.",
DEFAULT_ENSURE_KEYUNIT_ON_START,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPMedia:ensure-keyunit-on-start-timeout:
*
* The maximum allowed time before the first keyunit is considered
* expired.
*
* Note that this will only have an effect when ensure-keyunit-on-start is
* enabled.
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class,
PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT,
g_param_spec_uint ("ensure-keyunit-on-start-timeout",
"Timeout for discarding old keyunit on start",
"Timeout in milliseconds used to determine if a keyunit should be "
"discarded when a client connects.", 0, G_MAXUINT,
DEFAULT_ENSURE_KEYUNIT_ON_START_TIMEOUT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ELEMENT,
g_param_spec_object ("element", "The Element",
"The GstBin to use for streaming the media", GST_TYPE_ELEMENT,
@ -504,6 +552,11 @@ gst_rtsp_media_init (GstRTSPMedia * media)
priv->protocols = DEFAULT_PROTOCOLS;
priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
priv->buffer_size = DEFAULT_BUFFER_SIZE;
priv->ensure_keyunit_on_start = DEFAULT_ENSURE_KEYUNIT_ON_START;
priv->ensure_keyunit_on_start_timeout =
DEFAULT_ENSURE_KEYUNIT_ON_START_TIMEOUT;
priv->keyunit_is_expired = FALSE;
priv->keyunit_expiration_source = NULL;
priv->time_provider = DEFAULT_TIME_PROVIDER;
priv->transport_mode = DEFAULT_TRANSPORT_MODE;
priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
@ -554,6 +607,12 @@ gst_rtsp_media_finalize (GObject * obj)
g_cond_clear (&priv->cond);
g_rec_mutex_clear (&priv->state_lock);
if (priv->keyunit_expiration_source != NULL) {
g_source_destroy (priv->keyunit_expiration_source);
g_source_unref (priv->keyunit_expiration_source);
priv->keyunit_expiration_source = NULL;
}
G_OBJECT_CLASS (gst_rtsp_media_parent_class)->finalize (obj);
}
@ -588,6 +647,14 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
case PROP_BUFFER_SIZE:
g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
break;
case PROP_ENSURE_KEYUNIT_ON_START:
g_value_set_boolean (value,
gst_rtsp_media_get_ensure_keyunit_on_start (media));
break;
case PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT:
g_value_set_uint (value,
gst_rtsp_media_get_ensure_keyunit_on_start_timeout (media));
break;
case PROP_TIME_PROVIDER:
g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media));
break;
@ -649,6 +716,14 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
case PROP_BUFFER_SIZE:
gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
break;
case PROP_ENSURE_KEYUNIT_ON_START:
gst_rtsp_media_set_ensure_keyunit_on_start (media,
g_value_get_boolean (value));
break;
case PROP_ENSURE_KEYUNIT_ON_START_TIMEOUT:
gst_rtsp_media_set_ensure_keyunit_on_start_timeout (media,
g_value_get_uint (value));
break;
case PROP_TIME_PROVIDER:
gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value));
break;
@ -1487,6 +1562,116 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
return res;
}
/**
* gst_rtsp_media_set_ensure_keyunit_on_start:
* @media: a #GstRTSPMedia
* @ensure_keyunit_on_start: the new value
*
* Set whether or not a keyunit should be ensured when a client connects. It
* will also configure the streams to drop delta units to ensure that they start
* on a keyunit.
*
* Note that this will only affect non-shared medias for now.
*
* Since: 1.24
*/
void
gst_rtsp_media_set_ensure_keyunit_on_start (GstRTSPMedia * media,
gboolean ensure_keyunit_on_start)
{
GstRTSPMediaPrivate *priv;
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
priv = media->priv;
g_mutex_lock (&priv->lock);
priv->ensure_keyunit_on_start = ensure_keyunit_on_start;
g_mutex_unlock (&priv->lock);
}
/**
* gst_rtsp_media_get_ensure_keyunit_on_start:
* @media: a #GstRTSPMedia
*
* Get ensure-keyunit-on-start flag.
*
* Returns: The ensure-keyunit-on-start flag.
*
* Since: 1.24
*/
gboolean
gst_rtsp_media_get_ensure_keyunit_on_start (GstRTSPMedia * media)
{
GstRTSPMediaPrivate *priv;
gboolean result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
priv = media->priv;
g_mutex_lock (&priv->lock);
result = priv->ensure_keyunit_on_start;
g_mutex_unlock (&priv->lock);
return result;
}
/**
* gst_rtsp_media_set_ensure_keyunit_on_start_timeout:
* @media: a #GstRTSPMedia
* @timeout: the new value
*
* Sets the maximum allowed time before the first keyunit is considered
* expired.
*
* Note that this will only have an effect when ensure-keyunit-on-start is
* enabled.
*
* Since: 1.24
*/
void
gst_rtsp_media_set_ensure_keyunit_on_start_timeout (GstRTSPMedia * media,
guint timeout)
{
GstRTSPMediaPrivate *priv;
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
priv = media->priv;
g_mutex_lock (&priv->lock);
priv->ensure_keyunit_on_start_timeout = timeout;
g_mutex_unlock (&priv->lock);
}
/**
* gst_rtsp_media_get_ensure_keyunit_on_start_timeout
* @media: a #GstRTSPMedia
*
* Get ensure-keyunit-on-start-timeout time.
*
* Returns: The ensure-keyunit-on-start-timeout time.
*
* Since: 1.24
*/
guint
gst_rtsp_media_get_ensure_keyunit_on_start_timeout (GstRTSPMedia * media)
{
GstRTSPMediaPrivate *priv;
guint result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
priv = media->priv;
g_mutex_lock (&priv->lock);
result = priv->ensure_keyunit_on_start_timeout;
g_mutex_unlock (&priv->lock);
return result;
}
static void
do_set_dscp_qos (GstRTSPStream * stream, gint * dscp_qos)
{
@ -2502,6 +2687,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
gst_rtsp_stream_set_protocols (stream, priv->protocols);
gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size);
gst_rtsp_stream_set_drop_delta_units (stream, priv->ensure_keyunit_on_start);
gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode);
gst_rtsp_stream_set_rate_control (stream, priv->do_rate_control);
@ -2837,6 +3023,23 @@ media_streams_set_blocked (GstRTSPMedia * media, gboolean blocked)
priv->blocking_msg_received = 0;
}
static void
stream_install_drop_probe (GstRTSPStream * stream, gpointer user_data)
{
if (!gst_rtsp_stream_is_complete (stream))
return;
gst_rtsp_stream_install_drop_probe (stream);
}
static void
media_streams_install_drop_probe (GstRTSPMedia * media)
{
GstRTSPMediaPrivate *priv = media->priv;
g_ptr_array_foreach (priv->streams, (GFunc) stream_install_drop_probe, NULL);
}
static void
gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
{
@ -4590,6 +4793,15 @@ do_set_seqnum (GstRTSPStream * stream)
}
}
static gboolean
enable_keyunit_expired (GstRTSPMedia * media)
{
GST_DEBUG_OBJECT (media, "keyunit has expired");
media->priv->keyunit_is_expired = TRUE;
return G_SOURCE_REMOVE;
}
/* call with state_lock */
static gboolean
default_suspend (GstRTSPMedia * media)
@ -4629,6 +4841,20 @@ default_suspend (GstRTSPMedia * media)
if (ret != GST_STATE_CHANGE_FAILURE && ret != GST_STATE_CHANGE_ASYNC)
priv->expected_async_done = FALSE;
/* set expiration date on buffer in case of delayed PLAY request */
if (priv->ensure_keyunit_on_start) {
/* no need to install the timer if configured to trigger immediately */
if (priv->ensure_keyunit_on_start_timeout == 0) {
enable_keyunit_expired (media);
} else {
priv->keyunit_expiration_source =
g_timeout_source_new (priv->ensure_keyunit_on_start_timeout);
g_source_set_callback (priv->keyunit_expiration_source,
G_SOURCE_FUNC (enable_keyunit_expired), (gpointer) media, NULL);
g_source_attach (priv->keyunit_expiration_source, priv->thread->context);
}
}
return TRUE;
/* ERRORS */
@ -4684,6 +4910,7 @@ gst_rtsp_media_suspend (GstRTSPMedia * media)
}
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_SUSPENDED);
done:
g_rec_mutex_unlock (&priv->state_lock);
@ -4710,6 +4937,79 @@ suspend_failed:
}
}
/* Call with state_lock */
static gboolean
ensure_new_keyunit (GstRTSPMedia * media)
{
GstRTSPMediaPrivate *priv = media->priv;
gboolean preroll_ok;
gboolean is_blocking = FALSE;
/* nothing to be done without complete senders */
if (get_num_complete_sender_streams (media) == 0) {
GST_DEBUG_OBJECT (media, "no complete senders, skipping force keyunit");
return TRUE;
}
is_blocking = media_streams_blocking (media);
/* if we unsuspend before the keyunit is expired remove the timer so that
* no future buffer is marked as expired */
if (is_blocking && !priv->keyunit_is_expired) {
GST_DEBUG_OBJECT (media, "using currently blocking keyunit");
g_source_destroy (priv->keyunit_expiration_source);
g_source_unref (priv->keyunit_expiration_source);
priv->keyunit_expiration_source = NULL;
return TRUE;
}
/* set the media to preparing, thus requiring a successful preroll before
* completing unsuspend. */
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
GST_DEBUG_OBJECT (media, "ensuring new keyunit, doing preroll");
if (!start_preroll (media))
goto start_failed;
if (is_blocking) {
/* if we end up here then the keyunit has expired and the timer callback
* has been removed so reset the flag */
priv->keyunit_is_expired = FALSE;
/* install a probe that will drop the currently blocking keyunit on all
* complete streams. */
GST_DEBUG_OBJECT (media, "media is blocking. Installing drop probe");
media_streams_install_drop_probe (media);
}
/* force the keyunit from src */
GST_DEBUG_OBJECT (media, "sending force keyunit event");
gst_element_send_event (priv->element,
gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
TRUE, 0));
/* wait preroll */
g_rec_mutex_unlock (&priv->state_lock);
preroll_ok = wait_preroll (media);
g_rec_mutex_lock (&priv->state_lock);
if (!preroll_ok)
goto preroll_failed;
return TRUE;
start_failed:
{
GST_WARNING ("failed to preroll pipeline");
return FALSE;
}
preroll_failed:
{
GST_WARNING ("failed while waiting to preroll pipeline");
return FALSE;
}
}
/* call with state_lock */
static gboolean
default_unsuspend (GstRTSPMedia * media)
@ -4749,11 +5049,16 @@ default_unsuspend (GstRTSPMedia * media)
if (!preroll_ok)
goto preroll_failed;
break;
}
default:
break;
}
if (gst_rtsp_media_get_ensure_keyunit_on_start (media)) {
return ensure_new_keyunit (media);
}
return TRUE;
/* ERRORS */
@ -4764,7 +5069,7 @@ start_failed:
}
preroll_failed:
{
GST_WARNING ("failed to preroll pipeline");
GST_WARNING ("failed while waiting to preroll pipeline");
return FALSE;
}
}

View file

@ -278,6 +278,20 @@ void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guin
GST_RTSP_SERVER_API
guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media);
GST_RTSP_SERVER_API
void gst_rtsp_media_set_ensure_keyunit_on_start (GstRTSPMedia* media,
gboolean ensure_keyunit_on_start);
GST_RTSP_SERVER_API
gboolean gst_rtsp_media_get_ensure_keyunit_on_start (GstRTSPMedia* media);
GST_RTSP_SERVER_API
void gst_rtsp_media_set_ensure_keyunit_on_start_timeout (GstRTSPMedia* media,
guint timeout);
GST_RTSP_SERVER_API
guint gst_rtsp_media_get_ensure_keyunit_on_start_timeout (GstRTSPMedia* media);
GST_RTSP_SERVER_API
void gst_rtsp_media_set_retransmission_time (GstRTSPMedia *media, GstClockTime time);

View file

@ -146,6 +146,10 @@ gst_rtsp_onvif_media_factory_construct (GstRTSPMediaFactory * factory,
g_object_new (media_gtype, "element", element,
"transport-mode", GST_RTSP_TRANSPORT_MODE_PLAY, NULL);
/* we need to call this prior to collecting streams */
gst_rtsp_media_set_ensure_keyunit_on_start (media,
gst_rtsp_media_factory_get_ensure_keyunit_on_start (factory));
/* this adds the non-backchannel streams */
gst_rtsp_media_collect_streams (media);

View file

@ -63,6 +63,10 @@ gboolean gst_rtsp_stream_is_tcp_receiver (GstRTSPStream * stream
void gst_rtsp_media_set_enable_rtcp (GstRTSPMedia *media, gboolean enable);
void gst_rtsp_stream_set_enable_rtcp (GstRTSPStream *stream, gboolean enable);
void gst_rtsp_stream_set_drop_delta_units (GstRTSPStream * stream, gboolean drop);
gboolean gst_rtsp_stream_install_drop_probe (GstRTSPStream * stream);
G_END_DECLS
#endif /* __GST_RTSP_SERVER_INTERNAL_H__ */

View file

@ -230,6 +230,14 @@ struct _GstRTSPStreamPrivate
gulong block_early_rtcp_probe;
GstPad *block_early_rtcp_pad_ipv6;
gulong block_early_rtcp_probe_ipv6;
/* set to drop delta units in blocking pad */
gboolean drop_delta_units;
/* used to indicate that the drop probe has dropped a buffer and should be
* removed */
gboolean remove_drop_probe;
};
#define DEFAULT_CONTROL NULL
@ -357,6 +365,8 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
priv->block_early_rtcp_probe = 0;
priv->block_early_rtcp_pad_ipv6 = NULL;
priv->block_early_rtcp_probe_ipv6 = 0;
priv->drop_delta_units = FALSE;
priv->remove_drop_probe = FALSE;
}
typedef struct _UdpClientAddrInfo UdpClientAddrInfo;
@ -4317,7 +4327,7 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
else
g_object_get (priv->appsink[0], "last-sample", &last_sample, NULL);
if (last_sample) {
if (last_sample && !priv->blocking) {
GstCaps *caps;
GstBuffer *buffer;
GstSegment *segment;
@ -4373,6 +4383,8 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
gst_sample_unref (last_sample);
}
} else if (priv->blocking) {
if (last_sample != NULL)
gst_sample_unref (last_sample);
if (seq) {
if (!priv->blocked_buffer)
goto stats;
@ -5326,6 +5338,14 @@ rtp_pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
gst_rtp_buffer_unmap (&rtp);
}
priv->position = GST_BUFFER_TIMESTAMP (buffer);
if (priv->drop_delta_units) {
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
g_assert (!priv->blocking);
GST_DEBUG_OBJECT (pad, "dropping delta-unit buffer");
ret = GST_PAD_PROBE_DROP;
goto done;
}
}
} else if ((info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST)) {
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
@ -5338,12 +5358,20 @@ rtp_pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
gst_rtp_buffer_unmap (&rtp);
}
priv->position = GST_BUFFER_TIMESTAMP (buffer);
if (priv->drop_delta_units) {
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
g_assert (!priv->blocking);
GST_DEBUG_OBJECT (pad, "dropping delta-unit buffer");
ret = GST_PAD_PROBE_DROP;
goto done;
}
}
} else if ((info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)) {
if (GST_EVENT_TYPE (info->data) == GST_EVENT_GAP) {
gst_event_parse_gap (info->data, &priv->position, NULL);
} else {
ret = GST_PAD_PROBE_PASS;
g_mutex_unlock (&priv->lock);
GST_WARNING ("Passing event.");
goto done;
}
} else {
@ -5371,6 +5399,11 @@ rtp_pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
gst_event_unref (event);
}
/* make sure to block on the correct frame type */
if (priv->drop_delta_units) {
g_assert (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
}
priv->blocking = TRUE;
GST_DEBUG_OBJECT (pad, "Now blocking");
@ -5378,14 +5411,44 @@ rtp_pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
GST_DEBUG_OBJECT (stream, "position: %" GST_TIME_FORMAT,
GST_TIME_ARGS (priv->position));
g_mutex_unlock (&priv->lock);
gst_element_post_message (priv->payloader,
gst_message_new_element (GST_OBJECT_CAST (priv->payloader),
gst_structure_new ("GstRTSPStreamBlocking", "is_complete",
G_TYPE_BOOLEAN, priv->is_complete, NULL)));
done:
g_mutex_unlock (&priv->lock);
return ret;
}
/* this probe will drop a single buffer. It is used when an old buffer is
* blocking the pipeline, such as between a DESCRIBE and a PLAY request. */
static GstPadProbeReturn
drop_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstRTSPStreamPrivate *priv;
GstRTSPStream *stream;
/* drop an old buffer stuck in a blocked pipeline */
GstPadProbeReturn ret = GST_PAD_PROBE_DROP;
stream = user_data;
priv = stream->priv;
g_mutex_lock (&priv->lock);
if ((info->type & GST_PAD_PROBE_TYPE_BUFFER ||
info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST)) {
/* if a buffer has been dropped then remove this probe */
if (priv->remove_drop_probe) {
priv->remove_drop_probe = FALSE;
ret = GST_PAD_PROBE_REMOVE;
} else {
priv->blocking = FALSE;
priv->remove_drop_probe = TRUE;
}
} else {
ret = GST_PAD_PROBE_PASS;
}
g_mutex_unlock (&priv->lock);
return ret;
}
@ -5423,6 +5486,26 @@ done:
return ret;
}
static void
install_drop_probe (GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv;
priv = stream->priv;
/* if receiver */
if (priv->sinkpad)
return;
/* install for data channel only */
if (priv->send_src[0]) {
gst_pad_add_probe (priv->send_src[0],
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER |
GST_PAD_PROBE_TYPE_BUFFER_LIST |
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, drop_probe,
g_object_ref (stream), g_object_unref);
}
}
static void
set_blocked (GstRTSPStream * stream, gboolean blocked)
@ -5499,6 +5582,34 @@ gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked)
return TRUE;
}
/**
* gst_rtsp_stream_install_drop_probe:
* @stream: a #GstRTSPStream
*
* This probe can be installed when the currently blocking buffer should be
* dropped. When it has successfully dropped the buffer, it will remove itself.
* The goal is to avoid sending old data, typically when there has been a delay
* between a DESCRIBE and a PLAY request.
*
* Returns: %TRUE on success
*
* Since: 1.24
*/
gboolean
gst_rtsp_stream_install_drop_probe (GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
priv = stream->priv;
g_mutex_lock (&priv->lock);
install_drop_probe (stream);
g_mutex_unlock (&priv->lock);
return TRUE;
}
/**
* gst_rtsp_stream_ublock_linked:
* @stream: a #GstRTSPStream
@ -6415,3 +6526,25 @@ gst_rtsp_stream_unblock_rtcp (GstRTSPStream * stream)
}
g_mutex_unlock (&priv->lock);
}
/**
* gst_rtsp_stream_set_drop_delta_units:
* @stream: a #GstRTSPStream
* @drop: TRUE if delta unit frames are supposed to be dropped.
*
* Decide whether the blocking probe is supposed to drop delta units at the
* beginning of a stream.
*
* Since: 1.24
*/
void
gst_rtsp_stream_set_drop_delta_units (GstRTSPStream * stream, gboolean drop)
{
GstRTSPStreamPrivate *priv;
g_return_if_fail (GST_IS_RTSP_STREAM (stream));
priv = stream->priv;
g_mutex_lock (&priv->lock);
priv->drop_delta_units = drop;
g_mutex_unlock (&priv->lock);
}

View file

@ -146,6 +146,8 @@ gstsdp_dep = dependency('gstreamer-sdp-1.0', version : gst_req,
fallback : ['gst-plugins-base', 'sdp_dep'])
gstapp_dep = dependency('gstreamer-app-1.0', version : gst_req,
fallback : ['gst-plugins-base', 'app_dep'])
gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req,
fallback : ['gst-plugins-base', 'video_dep'])
gstnet_dep = dependency('gstreamer-net-1.0', version : gst_req,
fallback : ['gstreamer', 'gst_net_dep'])
if host_machine.system() != 'windows'

View file

@ -57,7 +57,8 @@ foreach test_name : rtsp_server_tests
exe = executable(test_name, fname,
include_directories : rtspserver_incs,
c_args : rtspserver_args + test_c_args,
dependencies : [gstcheck_dep, gstrtsp_dep, gstrtp_dep, gst_rtsp_server_dep]
dependencies : [gstcheck_dep, gstrtsp_dep, gstrtp_dep, gst_rtsp_server_dep,
gstvideo_dep]
)
test(test_name, exe,
env : env,