mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-24 16:18:16 +00:00
onvif: Implement and test the Streaming Specification
https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf
This commit is contained in:
parent
7640cb8f21
commit
0f498eabf4
15 changed files with 1727 additions and 23 deletions
|
@ -1833,6 +1833,8 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx,
|
||||||
GstSeekFlags flags = GST_SEEK_FLAG_NONE;
|
GstSeekFlags flags = GST_SEEK_FLAG_NONE;
|
||||||
GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client);
|
GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client);
|
||||||
GstRTSPStatusCode rtsp_status_code;
|
GstRTSPStatusCode rtsp_status_code;
|
||||||
|
GstClockTime trickmode_interval = 0;
|
||||||
|
gboolean enable_rate_control = TRUE;
|
||||||
|
|
||||||
/* parse the range header if we have one */
|
/* parse the range header if we have one */
|
||||||
res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0);
|
res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0);
|
||||||
|
@ -1876,13 +1878,17 @@ setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx,
|
||||||
/* give the application a chance to tweak range, flags, or rate */
|
/* give the application a chance to tweak range, flags, or rate */
|
||||||
if (klass->adjust_play_mode != NULL) {
|
if (klass->adjust_play_mode != NULL) {
|
||||||
rtsp_status_code =
|
rtsp_status_code =
|
||||||
klass->adjust_play_mode (client, ctx, &range, &flags, &rate);
|
klass->adjust_play_mode (client, ctx, &range, &flags, &rate,
|
||||||
|
&trickmode_interval, &enable_rate_control);
|
||||||
if (rtsp_status_code != GST_RTSP_STS_OK)
|
if (rtsp_status_code != GST_RTSP_STS_OK)
|
||||||
goto adjust_play_mode_failed;
|
goto adjust_play_mode_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_rtsp_media_set_rate_control (ctx->media, enable_rate_control);
|
||||||
|
|
||||||
/* now do the seek with the seek options */
|
/* now do the seek with the seek options */
|
||||||
(void) gst_rtsp_media_seek_full_with_rate (ctx->media, range, flags, rate);
|
gst_rtsp_media_seek_trickmode (ctx->media, range, flags, rate,
|
||||||
|
trickmode_interval);
|
||||||
if (range != NULL)
|
if (range != NULL)
|
||||||
gst_rtsp_range_free (range);
|
gst_rtsp_range_free (range);
|
||||||
|
|
||||||
|
@ -2031,6 +2037,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
g_strdup_printf ("%1.3f", rate));
|
g_strdup_printf ("%1.3f", rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (klass->adjust_play_response) {
|
||||||
|
code = klass->adjust_play_response (client, ctx);
|
||||||
|
if (code != GST_RTSP_STS_OK)
|
||||||
|
goto adjust_play_response_failed;
|
||||||
|
}
|
||||||
|
|
||||||
send_message (client, ctx, ctx->response, FALSE);
|
send_message (client, ctx, ctx->response, FALSE);
|
||||||
|
|
||||||
/* start playing after sending the response */
|
/* start playing after sending the response */
|
||||||
|
@ -2114,6 +2126,12 @@ get_rates_error:
|
||||||
send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
|
send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
adjust_play_response_failed:
|
||||||
|
{
|
||||||
|
GST_ERROR ("client %p: failed to adjust play response", client);
|
||||||
|
send_generic_response (client, code, ctx);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -109,7 +109,10 @@ struct _GstRTSPClient {
|
||||||
* RTSP response(ctx->response) via a call to gst_rtsp_message_init_response()
|
* RTSP response(ctx->response) via a call to gst_rtsp_message_init_response()
|
||||||
* @make_path_from_uri: called to create path from uri.
|
* @make_path_from_uri: called to create path from uri.
|
||||||
* @adjust_play_mode: called to give the application the possibility to adjust
|
* @adjust_play_mode: called to give the application the possibility to adjust
|
||||||
* the range, seek flags, and/or rate. Since 1.18
|
* the range, seek flags, rate and rate-control. Since 1.18
|
||||||
|
* @adjust_play_response: called to give the implementation the possibility to
|
||||||
|
* adjust the response to a play request, for example if extra headers were
|
||||||
|
* parsed when #GstRTSPClientClass.adjust_play_mode was called. Since 1.18
|
||||||
* @tunnel_http_response: called when a response to the GET request is about to
|
* @tunnel_http_response: called when a response to the GET request is about to
|
||||||
* be sent for a tunneled connection. The response can be modified. Since: 1.4
|
* be sent for a tunneled connection. The response can be modified. Since: 1.4
|
||||||
*
|
*
|
||||||
|
@ -132,7 +135,12 @@ struct _GstRTSPClientClass {
|
||||||
GstRTSPContext * context,
|
GstRTSPContext * context,
|
||||||
GstRTSPTimeRange ** range,
|
GstRTSPTimeRange ** range,
|
||||||
GstSeekFlags * flags,
|
GstSeekFlags * flags,
|
||||||
gdouble * rate);
|
gdouble * rate,
|
||||||
|
GstClockTime * trickmode_interval,
|
||||||
|
gboolean * enable_rate_control);
|
||||||
|
GstRTSPStatusCode (*adjust_play_response) (GstRTSPClient * client,
|
||||||
|
GstRTSPContext * context);
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
void (*closed) (GstRTSPClient *client);
|
void (*closed) (GstRTSPClient *client);
|
||||||
void (*new_session) (GstRTSPClient *client, GstRTSPSession *session);
|
void (*new_session) (GstRTSPClient *client, GstRTSPSession *session);
|
||||||
|
@ -169,7 +177,7 @@ struct _GstRTSPClientClass {
|
||||||
GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx);
|
GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx);
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
gpointer _gst_reserved[GST_PADDING_LARGE-17];
|
gpointer _gst_reserved[GST_PADDING_LARGE-18];
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
*
|
*
|
||||||
* The state of the media can be controlled with gst_rtsp_media_set_state ().
|
* The state of the media can be controlled with gst_rtsp_media_set_state ().
|
||||||
* Seeking can be done with gst_rtsp_media_seek(), or gst_rtsp_media_seek_full()
|
* Seeking can be done with gst_rtsp_media_seek(), or gst_rtsp_media_seek_full()
|
||||||
* or gst_rtsp_media_seek_full_with_rate() for finer control of the seek.
|
* or gst_rtsp_media_seek_trickmode() for finer control of the seek.
|
||||||
*
|
*
|
||||||
* With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
|
* With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
|
||||||
* gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
|
* gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
|
||||||
|
@ -146,6 +146,7 @@ struct _GstRTSPMediaPrivate
|
||||||
gboolean do_retransmission; /* protected by lock */
|
gboolean do_retransmission; /* protected by lock */
|
||||||
guint latency; /* protected by lock */
|
guint latency; /* protected by lock */
|
||||||
GstClock *clock; /* protected by lock */
|
GstClock *clock; /* protected by lock */
|
||||||
|
gboolean do_rate_control; /* protected by lock */
|
||||||
GstRTSPPublishClockMode publish_clock_mode;
|
GstRTSPPublishClockMode publish_clock_mode;
|
||||||
|
|
||||||
/* Dynamic element handling */
|
/* Dynamic element handling */
|
||||||
|
@ -167,6 +168,7 @@ struct _GstRTSPMediaPrivate
|
||||||
#define DEFAULT_STOP_ON_DISCONNECT TRUE
|
#define DEFAULT_STOP_ON_DISCONNECT TRUE
|
||||||
#define DEFAULT_MAX_MCAST_TTL 255
|
#define DEFAULT_MAX_MCAST_TTL 255
|
||||||
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
|
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
|
||||||
|
#define DEFAULT_DO_RATE_CONTROL TRUE
|
||||||
|
|
||||||
#define DEFAULT_DO_RETRANSMISSION FALSE
|
#define DEFAULT_DO_RETRANSMISSION FALSE
|
||||||
|
|
||||||
|
@ -471,6 +473,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
|
||||||
priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
|
priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
|
||||||
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
||||||
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
||||||
|
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2293,6 +2296,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
|
||||||
gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
|
gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
|
||||||
gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size);
|
gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size);
|
||||||
gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode);
|
gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode);
|
||||||
|
gst_rtsp_stream_set_rate_control (stream, priv->do_rate_control);
|
||||||
|
|
||||||
g_ptr_array_add (priv->streams, stream);
|
g_ptr_array_add (priv->streams, stream);
|
||||||
|
|
||||||
|
@ -2662,13 +2666,15 @@ gst_rtsp_media_get_status (GstRTSPMedia * media)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_seek_full_with_rate:
|
* gst_rtsp_media_seek_trickmode:
|
||||||
* @media: a #GstRTSPMedia
|
* @media: a #GstRTSPMedia
|
||||||
* @range: (transfer none): a #GstRTSPTimeRange
|
* @range: (transfer none): a #GstRTSPTimeRange
|
||||||
* @flags: The minimal set of #GstSeekFlags to use
|
* @flags: The minimal set of #GstSeekFlags to use
|
||||||
* @rate: the rate to use in the seek
|
* @rate: the rate to use in the seek
|
||||||
|
* @trickmode_interval: The trickmode interval to use for KEY_UNITS trick mode
|
||||||
*
|
*
|
||||||
* Seek the pipeline of @media to @range with the given @flags and @rate.
|
* Seek the pipeline of @media to @range with the given @flags and @rate,
|
||||||
|
* and @trickmode_interval.
|
||||||
* @media must be prepared with gst_rtsp_media_prepare().
|
* @media must be prepared with gst_rtsp_media_prepare().
|
||||||
* In order to perform the seek operation, the pipeline must contain all
|
* In order to perform the seek operation, the pipeline must contain all
|
||||||
* needed transport parts (transport sinks).
|
* needed transport parts (transport sinks).
|
||||||
|
@ -2678,8 +2684,9 @@ gst_rtsp_media_get_status (GstRTSPMedia * media)
|
||||||
* Since: 1.18
|
* Since: 1.18
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
|
gst_rtsp_media_seek_trickmode (GstRTSPMedia * media,
|
||||||
GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate)
|
GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate,
|
||||||
|
GstClockTime trickmode_interval)
|
||||||
{
|
{
|
||||||
GstRTSPMediaClass *klass;
|
GstRTSPMediaClass *klass;
|
||||||
GstRTSPMediaPrivate *priv;
|
GstRTSPMediaPrivate *priv;
|
||||||
|
@ -2789,6 +2796,8 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
|
||||||
GST_DEBUG ("no position change, no flags set by caller, so not seeking");
|
GST_DEBUG ("no position change, no flags set by caller, so not seeking");
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
} else {
|
} else {
|
||||||
|
GstEvent *seek_event;
|
||||||
|
|
||||||
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
||||||
|
|
||||||
if (rate < 0.0) {
|
if (rate < 0.0) {
|
||||||
|
@ -2801,8 +2810,12 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
|
||||||
stop_type = temp_type;
|
stop_type = temp_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME,
|
seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type,
|
||||||
flags, start_type, start, stop_type, stop);
|
start, stop_type, stop);
|
||||||
|
|
||||||
|
gst_event_set_seek_trickmode_interval (seek_event, trickmode_interval);
|
||||||
|
|
||||||
|
res = gst_element_send_event (priv->pipeline, seek_event);
|
||||||
|
|
||||||
/* and block for the seek to complete */
|
/* and block for the seek to complete */
|
||||||
GST_INFO ("done seeking %d", res);
|
GST_INFO ("done seeking %d", res);
|
||||||
|
@ -2880,7 +2893,7 @@ gboolean
|
||||||
gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
GstSeekFlags flags)
|
GstSeekFlags flags)
|
||||||
{
|
{
|
||||||
return gst_rtsp_media_seek_full_with_rate (media, range, flags, 1.0);
|
return gst_rtsp_media_seek_trickmode (media, range, flags, 1.0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2896,8 +2909,8 @@ gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
||||||
{
|
{
|
||||||
return gst_rtsp_media_seek_full_with_rate (media, range, GST_SEEK_FLAG_NONE,
|
return gst_rtsp_media_seek_trickmode (media, range, GST_SEEK_FLAG_NONE,
|
||||||
1.0);
|
1.0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -4728,3 +4741,59 @@ gst_rtsp_media_is_receive_only (GstRTSPMedia * media)
|
||||||
|
|
||||||
return receive_only;
|
return receive_only;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_set_rate_control:
|
||||||
|
*
|
||||||
|
* Define whether @media will follow the Rate-Control=no behaviour as specified
|
||||||
|
* in the ONVIF replay spec.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_media_set_rate_control (GstRTSPMedia * media, gboolean enabled)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (media, "%s rate control", enabled ? "Enabling" : "Disabling");
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
g_mutex_lock (&priv->lock);
|
||||||
|
priv->do_rate_control = enabled;
|
||||||
|
for (i = 0; i < priv->streams->len; i++) {
|
||||||
|
GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
|
||||||
|
|
||||||
|
gst_rtsp_stream_set_rate_control (stream, enabled);
|
||||||
|
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_rate_control:
|
||||||
|
*
|
||||||
|
* Returns: whether @media will follow the Rate-Control=no behaviour as specified
|
||||||
|
* in the ONVIF replay spec.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_media_get_rate_control (GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
g_mutex_lock (&priv->lock);
|
||||||
|
res = priv->do_rate_control;
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -388,10 +388,11 @@ gboolean gst_rtsp_media_seek_full (GstRTSPMedia *media,
|
||||||
GstSeekFlags flags);
|
GstSeekFlags flags);
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
gboolean gst_rtsp_media_seek_full_with_rate (GstRTSPMedia *media,
|
gboolean gst_rtsp_media_seek_trickmode (GstRTSPMedia *media,
|
||||||
GstRTSPTimeRange *range,
|
GstRTSPTimeRange *range,
|
||||||
GstSeekFlags flags,
|
GstSeekFlags flags,
|
||||||
gdouble rate);
|
gdouble rate,
|
||||||
|
GstClockTime trickmode_interval);
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media);
|
GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media);
|
||||||
|
@ -420,6 +421,12 @@ gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GP
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
gboolean gst_rtsp_media_is_receive_only (GstRTSPMedia * media);
|
gboolean gst_rtsp_media_is_receive_only (GstRTSPMedia * media);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
void gst_rtsp_media_set_rate_control (GstRTSPMedia * media, gboolean enabled);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_media_get_rate_control (GstRTSPMedia * media);
|
||||||
|
|
||||||
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
|
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,11 +37,14 @@ gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client,
|
||||||
GstRTSPMediaFactory *factory = NULL;
|
GstRTSPMediaFactory *factory = NULL;
|
||||||
gchar *path = NULL;
|
gchar *path = NULL;
|
||||||
gboolean has_backchannel = FALSE;
|
gboolean has_backchannel = FALSE;
|
||||||
|
gboolean has_replay = FALSE;
|
||||||
GString *unsupported = g_string_new ("");
|
GString *unsupported = g_string_new ("");
|
||||||
|
|
||||||
while (*requirements) {
|
while (*requirements) {
|
||||||
if (strcmp (*requirements, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) {
|
if (strcmp (*requirements, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) {
|
||||||
has_backchannel = TRUE;
|
has_backchannel = TRUE;
|
||||||
|
} else if (strcmp (*requirements, GST_RTSP_ONVIF_REPLAY_REQUIREMENT) == 0) {
|
||||||
|
has_replay = TRUE;
|
||||||
} else {
|
} else {
|
||||||
if (unsupported->len)
|
if (unsupported->len)
|
||||||
g_string_append (unsupported, ", ");
|
g_string_append (unsupported, ", ");
|
||||||
|
@ -75,6 +78,22 @@ gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_replay && !GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory)) {
|
||||||
|
if (unsupported->len)
|
||||||
|
g_string_append (unsupported, ", ");
|
||||||
|
g_string_append (unsupported, GST_RTSP_ONVIF_REPLAY_REQUIREMENT);
|
||||||
|
} else if (has_replay) {
|
||||||
|
GstRTSPOnvifMediaFactory *onvif_factory =
|
||||||
|
GST_RTSP_ONVIF_MEDIA_FACTORY (factory);
|
||||||
|
|
||||||
|
if (!gst_rtsp_onvif_media_factory_has_replay_support (onvif_factory)) {
|
||||||
|
if (unsupported->len)
|
||||||
|
g_string_append (unsupported, ", ");
|
||||||
|
g_string_append (unsupported, GST_RTSP_ONVIF_REPLAY_REQUIREMENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (path)
|
if (path)
|
||||||
g_free (path);
|
g_free (path);
|
||||||
|
@ -86,15 +105,115 @@ out:
|
||||||
return g_string_free (unsupported, FALSE);
|
return g_string_free (unsupported, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstRTSPStatusCode
|
||||||
|
gst_rtsp_onvif_client_adjust_play_mode (GstRTSPClient * client,
|
||||||
|
GstRTSPContext * ctx, GstRTSPTimeRange ** range, GstSeekFlags * flags,
|
||||||
|
gdouble * rate, GstClockTime * trickmode_interval,
|
||||||
|
gboolean * enable_rate_control)
|
||||||
|
{
|
||||||
|
GstRTSPStatusCode ret = GST_RTSP_STS_BAD_REQUEST;
|
||||||
|
gchar **split = NULL;
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_FRAMES,
|
||||||
|
&str, 0) == GST_RTSP_OK) {
|
||||||
|
|
||||||
|
split = g_strsplit (str, "/", 2);
|
||||||
|
|
||||||
|
if (!g_strcmp0 (split[0], "intra")) {
|
||||||
|
if (split[1]) {
|
||||||
|
guint64 interval;
|
||||||
|
gchar *end;
|
||||||
|
|
||||||
|
interval = g_ascii_strtoull (split[1], &end, 10);
|
||||||
|
|
||||||
|
if (!end || *end != '\0') {
|
||||||
|
GST_ERROR ("Unexpected interval value %s", split[1]);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*trickmode_interval = interval * GST_MSECOND;
|
||||||
|
}
|
||||||
|
*flags |= GST_SEEK_FLAG_TRICKMODE_KEY_UNITS;
|
||||||
|
} else if (!g_strcmp0 (split[0], "predicted")) {
|
||||||
|
if (split[1]) {
|
||||||
|
GST_ERROR ("Predicted frames mode does not allow an interval (%s)",
|
||||||
|
str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
*flags |= GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED;
|
||||||
|
} else {
|
||||||
|
GST_ERROR ("Invalid frames mode (%s)", str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RATE_CONTROL,
|
||||||
|
&str, 0) == GST_RTSP_OK) {
|
||||||
|
if (!g_strcmp0 (str, "no")) {
|
||||||
|
*enable_rate_control = FALSE;
|
||||||
|
} else if (!g_strcmp0 (str, "yes")) {
|
||||||
|
*enable_rate_control = TRUE;
|
||||||
|
} else {
|
||||||
|
GST_ERROR ("Invalid rate control header: %s", str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = GST_RTSP_STS_OK;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (split)
|
||||||
|
g_strfreev (split);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstRTSPStatusCode
|
||||||
|
gst_rtsp_onvif_client_adjust_play_response (GstRTSPClient * client,
|
||||||
|
GstRTSPContext * ctx)
|
||||||
|
{
|
||||||
|
GstRTSPStatusCode ret = GST_RTSP_STS_OK;
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RATE_CONTROL,
|
||||||
|
&str, 0) == GST_RTSP_OK) {
|
||||||
|
gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_RATE_CONTROL,
|
||||||
|
gst_rtsp_media_get_rate_control (ctx->media) ? "yes" : "no");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtsp_onvif_client_class_init (GstRTSPOnvifClientClass * klass)
|
gst_rtsp_onvif_client_class_init (GstRTSPOnvifClientClass * klass)
|
||||||
{
|
{
|
||||||
GstRTSPClientClass *client_klass = (GstRTSPClientClass *) klass;
|
GstRTSPClientClass *client_klass = (GstRTSPClientClass *) klass;
|
||||||
|
|
||||||
client_klass->check_requirements = gst_rtsp_onvif_client_check_requirements;
|
client_klass->check_requirements = gst_rtsp_onvif_client_check_requirements;
|
||||||
|
client_klass->adjust_play_mode = gst_rtsp_onvif_client_adjust_play_mode;
|
||||||
|
client_klass->adjust_play_response =
|
||||||
|
gst_rtsp_onvif_client_adjust_play_response;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtsp_onvif_client_init (GstRTSPOnvifClient * client)
|
gst_rtsp_onvif_client_init (GstRTSPOnvifClient * client)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_onvif_client_new:
|
||||||
|
*
|
||||||
|
* Create a new #GstRTSPOnvifClient instance.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a new #GstRTSPOnvifClient
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
GstRTSPClient *
|
||||||
|
gst_rtsp_onvif_client_new (void)
|
||||||
|
{
|
||||||
|
GstRTSPClient *result;
|
||||||
|
|
||||||
|
result = g_object_new (GST_TYPE_RTSP_ONVIF_CLIENT, NULL);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -59,4 +59,7 @@ struct GstRTSPOnvifClient
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
GType gst_rtsp_onvif_client_get_type (void);
|
GType gst_rtsp_onvif_client_get_type (void);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
GstRTSPClient * gst_rtsp_onvif_client_new (void);
|
||||||
|
|
||||||
#endif /* __GST_RTSP_ONVIF_CLIENT_H__ */
|
#endif /* __GST_RTSP_ONVIF_CLIENT_H__ */
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct GstRTSPOnvifMediaFactoryPrivate
|
||||||
GMutex lock;
|
GMutex lock;
|
||||||
gchar *backchannel_launch;
|
gchar *backchannel_launch;
|
||||||
guint backchannel_bandwidth;
|
guint backchannel_bandwidth;
|
||||||
|
gboolean has_replay_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory,
|
G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory,
|
||||||
|
@ -447,6 +448,42 @@ gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory *
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_onvif_media_factory_has_replay_support:
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if ONVIF replay is supported by the media factory.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_onvif_media_factory_has_replay_support (GstRTSPOnvifMediaFactory *
|
||||||
|
factory)
|
||||||
|
{
|
||||||
|
gboolean has_replay_support;
|
||||||
|
|
||||||
|
g_mutex_lock (&factory->priv->lock);
|
||||||
|
has_replay_support = factory->priv->has_replay_support;
|
||||||
|
g_mutex_unlock (&factory->priv->lock);
|
||||||
|
|
||||||
|
return has_replay_support;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_onvif_media_factory_set_replay_support:
|
||||||
|
*
|
||||||
|
* Set to %TRUE if ONVIF replay is supported by the media factory.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_onvif_media_factory_set_replay_support (GstRTSPOnvifMediaFactory *
|
||||||
|
factory, gboolean has_replay_support)
|
||||||
|
{
|
||||||
|
g_mutex_lock (&factory->priv->lock);
|
||||||
|
factory->priv->has_replay_support = has_replay_support;
|
||||||
|
g_mutex_unlock (&factory->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_onvif_media_factory_set_backchannel_bandwidth:
|
* gst_rtsp_onvif_media_factory_set_backchannel_bandwidth:
|
||||||
* @factory: a #GstRTSPMediaFactory
|
* @factory: a #GstRTSPMediaFactory
|
||||||
|
|
|
@ -74,6 +74,12 @@ gchar * gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFa
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
gboolean gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * factory);
|
gboolean gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * factory);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_onvif_media_factory_has_replay_support (GstRTSPOnvifMediaFactory * factory);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
void gst_rtsp_onvif_media_factory_set_replay_support (GstRTSPOnvifMediaFactory * factory, gboolean has_replay_support);
|
||||||
|
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth);
|
void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth);
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
|
|
|
@ -131,6 +131,16 @@ gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
|
||||||
if (res) {
|
if (res) {
|
||||||
GstSDPMedia *smedia =
|
GstSDPMedia *smedia =
|
||||||
&g_array_index (sdp->medias, GstSDPMedia, sdp->medias->len - 1);
|
&g_array_index (sdp->medias, GstSDPMedia, sdp->medias->len - 1);
|
||||||
|
gchar *x_onvif_track, *media_str;
|
||||||
|
|
||||||
|
media_str =
|
||||||
|
g_ascii_strup (gst_structure_get_string (s, "media"), -1);
|
||||||
|
x_onvif_track =
|
||||||
|
g_strdup_printf ("%s%03d", media_str, sdp->medias->len - 1);
|
||||||
|
gst_sdp_media_add_attribute (smedia, "x-onvif-track",
|
||||||
|
x_onvif_track);
|
||||||
|
g_free (x_onvif_track);
|
||||||
|
g_free (media_str);
|
||||||
|
|
||||||
if (sinkpad) {
|
if (sinkpad) {
|
||||||
GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media);
|
GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media);
|
||||||
|
|
|
@ -62,6 +62,7 @@ GST_RTSP_SERVER_API
|
||||||
GstRTSPServer *gst_rtsp_onvif_server_new (void);
|
GstRTSPServer *gst_rtsp_onvif_server_new (void);
|
||||||
|
|
||||||
#define GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT "www.onvif.org/ver20/backchannel"
|
#define GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT "www.onvif.org/ver20/backchannel"
|
||||||
|
#define GST_RTSP_ONVIF_REPLAY_REQUIREMENT "onvif-replay"
|
||||||
|
|
||||||
#include "rtsp-onvif-client.h"
|
#include "rtsp-onvif-client.h"
|
||||||
#include "rtsp-onvif-media-factory.h"
|
#include "rtsp-onvif-media-factory.h"
|
||||||
|
|
|
@ -130,6 +130,9 @@ struct _GstRTSPStreamPrivate
|
||||||
guint rtx_pt;
|
guint rtx_pt;
|
||||||
GstClockTime rtx_time;
|
GstClockTime rtx_time;
|
||||||
|
|
||||||
|
/* rate control */
|
||||||
|
gboolean do_rate_control;
|
||||||
|
|
||||||
/* Forward Error Correction with RFC 5109 */
|
/* Forward Error Correction with RFC 5109 */
|
||||||
GstElement *ulpfec_decoder;
|
GstElement *ulpfec_decoder;
|
||||||
GstElement *ulpfec_encoder;
|
GstElement *ulpfec_encoder;
|
||||||
|
@ -190,6 +193,7 @@ struct _GstRTSPStreamPrivate
|
||||||
GST_RTSP_LOWER_TRANS_TCP
|
GST_RTSP_LOWER_TRANS_TCP
|
||||||
#define DEFAULT_MAX_MCAST_TTL 255
|
#define DEFAULT_MAX_MCAST_TTL 255
|
||||||
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
|
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
|
||||||
|
#define DEFAULT_DO_RATE_CONTROL TRUE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -291,6 +295,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
|
||||||
priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
|
priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
|
||||||
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
||||||
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
||||||
|
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
|
||||||
|
|
||||||
g_mutex_init (&priv->lock);
|
g_mutex_init (&priv->lock);
|
||||||
|
|
||||||
|
@ -3378,6 +3383,11 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_object_class_find_property (G_OBJECT_GET_CLASS (priv->payloader),
|
||||||
|
"onvif-no-rate-control"))
|
||||||
|
g_object_set (priv->payloader, "onvif-no-rate-control",
|
||||||
|
!priv->do_rate_control, NULL);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
gboolean link_tee = FALSE;
|
gboolean link_tee = FALSE;
|
||||||
/* For the sender we create this bit of pipeline for both
|
/* For the sender we create this bit of pipeline for both
|
||||||
|
@ -3436,6 +3446,9 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport)
|
||||||
g_object_set (priv->appsink[i], "emit-signals", FALSE, "buffer-list",
|
g_object_set (priv->appsink[i], "emit-signals", FALSE, "buffer-list",
|
||||||
TRUE, "max-buffers", 1, NULL);
|
TRUE, "max-buffers", 1, NULL);
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
g_object_set (priv->appsink[i], "sync", priv->do_rate_control, NULL);
|
||||||
|
|
||||||
/* we need to set sync and preroll to FALSE for the sink to avoid
|
/* we need to set sync and preroll to FALSE for the sink to avoid
|
||||||
* deadlock. This is only needed for sink sending RTCP data. */
|
* deadlock. This is only needed for sink sending RTCP data. */
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
|
@ -3765,6 +3778,9 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
|
||||||
g_signal_connect (priv->session, "on-sender-ssrc-active",
|
g_signal_connect (priv->session, "on-sender-ssrc-active",
|
||||||
(GCallback) on_sender_ssrc_active, stream);
|
(GCallback) on_sender_ssrc_active, stream);
|
||||||
|
|
||||||
|
g_object_set (priv->session, "disable-sr-timestamp", !priv->do_rate_control,
|
||||||
|
NULL);
|
||||||
|
|
||||||
if (priv->srcpad) {
|
if (priv->srcpad) {
|
||||||
/* be notified of caps changes */
|
/* be notified of caps changes */
|
||||||
priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps",
|
priv->caps_sig = g_signal_connect (priv->send_src[0], "notify::caps",
|
||||||
|
@ -5919,3 +5935,53 @@ gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream * stream)
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_set_rate_control:
|
||||||
|
*
|
||||||
|
* Define whether @stream will follow the Rate-Control=no behaviour as specified
|
||||||
|
* in the ONVIF replay spec.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled)
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (stream, "%s rate control",
|
||||||
|
enabled ? "Enabling" : "Disabling");
|
||||||
|
|
||||||
|
g_mutex_lock (&stream->priv->lock);
|
||||||
|
stream->priv->do_rate_control = enabled;
|
||||||
|
if (stream->priv->appsink[0])
|
||||||
|
g_object_set (stream->priv->appsink[0], "sync", enabled, NULL);
|
||||||
|
if (stream->priv->payloader
|
||||||
|
&& g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv->
|
||||||
|
payloader), "onvif-no-rate-control"))
|
||||||
|
g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled,
|
||||||
|
NULL);
|
||||||
|
if (stream->priv->session) {
|
||||||
|
g_object_set (stream->priv->session, "disable-sr-timestamp", !enabled,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&stream->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_get_rate_control:
|
||||||
|
*
|
||||||
|
* Returns: whether @stream will follow the Rate-Control=no behaviour as specified
|
||||||
|
* in the ONVIF replay spec.
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_stream_get_rate_control (GstRTSPStream * stream)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
g_mutex_lock (&stream->priv->lock);
|
||||||
|
ret = stream->priv->do_rate_control;
|
||||||
|
g_mutex_unlock (&stream->priv->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -359,6 +359,12 @@ void gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream,
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream);
|
guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
void gst_rtsp_stream_set_rate_control (GstRTSPStream * stream, gboolean enabled);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_stream_get_rate_control (GstRTSPStream * stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPStreamTransportFilterFunc:
|
* GstRTSPStreamTransportFilterFunc:
|
||||||
* @stream: a #GstRTSPStream object
|
* @stream: a #GstRTSPStream object
|
||||||
|
|
|
@ -109,16 +109,16 @@ GST_START_TEST (test_media_seek)
|
||||||
fail_unless (applied_rate == 1.0);
|
fail_unless (applied_rate == 1.0);
|
||||||
|
|
||||||
/* seeking with rate set to 1.5 should result in rate == 1.5 */
|
/* seeking with rate set to 1.5 should result in rate == 1.5 */
|
||||||
fail_unless (gst_rtsp_media_seek_full_with_rate (media, range,
|
fail_unless (gst_rtsp_media_seek_trickmode (media, range,
|
||||||
GST_SEEK_FLAG_NONE, 1.5));
|
GST_SEEK_FLAG_NONE, 1.5, 0));
|
||||||
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||||
fail_unless (rate == 1.5);
|
fail_unless (rate == 1.5);
|
||||||
fail_unless (applied_rate == 1.0);
|
fail_unless (applied_rate == 1.0);
|
||||||
|
|
||||||
/* seeking with rate set to -2.0 should result in rate == -2.0 */
|
/* seeking with rate set to -2.0 should result in rate == -2.0 */
|
||||||
fail_unless (gst_rtsp_range_parse ("npt=10-5", &range) == GST_RTSP_OK);
|
fail_unless (gst_rtsp_range_parse ("npt=10-5", &range) == GST_RTSP_OK);
|
||||||
fail_unless (gst_rtsp_media_seek_full_with_rate (media, range,
|
fail_unless (gst_rtsp_media_seek_trickmode (media, range,
|
||||||
GST_SEEK_FLAG_NONE, -2.0));
|
GST_SEEK_FLAG_NONE, -2.0, 0));
|
||||||
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||||
fail_unless (rate == -2.0);
|
fail_unless (rate == -2.0);
|
||||||
fail_unless (applied_rate == 1.0);
|
fail_unless (applied_rate == 1.0);
|
||||||
|
|
1353
tests/check/gst/onvif.c
Normal file
1353
tests/check/gst/onvif.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,7 @@ rtsp_server_tests = [
|
||||||
'gst/stream',
|
'gst/stream',
|
||||||
'gst/threadpool',
|
'gst/threadpool',
|
||||||
'gst/token',
|
'gst/token',
|
||||||
|
'gst/onvif',
|
||||||
]
|
]
|
||||||
|
|
||||||
if not get_option('rtspclientsink').disabled()
|
if not get_option('rtspclientsink').disabled()
|
||||||
|
|
Loading…
Reference in a new issue