mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-09 17:05:52 +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;
|
||||
GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client);
|
||||
GstRTSPStatusCode rtsp_status_code;
|
||||
GstClockTime trickmode_interval = 0;
|
||||
gboolean enable_rate_control = TRUE;
|
||||
|
||||
/* parse the range header if we have one */
|
||||
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 */
|
||||
if (klass->adjust_play_mode != NULL) {
|
||||
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)
|
||||
goto adjust_play_mode_failed;
|
||||
}
|
||||
|
||||
gst_rtsp_media_set_rate_control (ctx->media, enable_rate_control);
|
||||
|
||||
/* 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)
|
||||
gst_rtsp_range_free (range);
|
||||
|
||||
|
@ -2031,6 +2037,12 @@ handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
|||
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);
|
||||
|
||||
/* start playing after sending the response */
|
||||
|
@ -2114,6 +2126,12 @@ get_rates_error:
|
|||
send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
|
||||
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
|
||||
|
|
|
@ -109,7 +109,10 @@ struct _GstRTSPClient {
|
|||
* RTSP response(ctx->response) via a call to gst_rtsp_message_init_response()
|
||||
* @make_path_from_uri: called to create path from uri.
|
||||
* @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
|
||||
* be sent for a tunneled connection. The response can be modified. Since: 1.4
|
||||
*
|
||||
|
@ -132,7 +135,12 @@ struct _GstRTSPClientClass {
|
|||
GstRTSPContext * context,
|
||||
GstRTSPTimeRange ** range,
|
||||
GstSeekFlags * flags,
|
||||
gdouble * rate);
|
||||
gdouble * rate,
|
||||
GstClockTime * trickmode_interval,
|
||||
gboolean * enable_rate_control);
|
||||
GstRTSPStatusCode (*adjust_play_response) (GstRTSPClient * client,
|
||||
GstRTSPContext * context);
|
||||
|
||||
/* signals */
|
||||
void (*closed) (GstRTSPClient *client);
|
||||
void (*new_session) (GstRTSPClient *client, GstRTSPSession *session);
|
||||
|
@ -169,7 +177,7 @@ struct _GstRTSPClientClass {
|
|||
GstRTSPStatusCode (*pre_record_request) (GstRTSPClient *client, GstRTSPContext *ctx);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING_LARGE-17];
|
||||
gpointer _gst_reserved[GST_PADDING_LARGE-18];
|
||||
};
|
||||
|
||||
GST_RTSP_SERVER_API
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
*
|
||||
* 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()
|
||||
* 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
|
||||
* 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 */
|
||||
guint latency; /* protected by lock */
|
||||
GstClock *clock; /* protected by lock */
|
||||
gboolean do_rate_control; /* protected by lock */
|
||||
GstRTSPPublishClockMode publish_clock_mode;
|
||||
|
||||
/* Dynamic element handling */
|
||||
|
@ -167,6 +168,7 @@ struct _GstRTSPMediaPrivate
|
|||
#define DEFAULT_STOP_ON_DISCONNECT TRUE
|
||||
#define DEFAULT_MAX_MCAST_TTL 255
|
||||
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
|
||||
#define DEFAULT_DO_RATE_CONTROL TRUE
|
||||
|
||||
#define DEFAULT_DO_RETRANSMISSION FALSE
|
||||
|
||||
|
@ -471,6 +473,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
|
|||
priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
|
||||
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
||||
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
||||
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
|
||||
}
|
||||
|
||||
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_buffer_size (stream, priv->buffer_size);
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
* @range: (transfer none): a #GstRTSPTimeRange
|
||||
* @flags: The minimal set of #GstSeekFlags to use
|
||||
* @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().
|
||||
* In order to perform the seek operation, the pipeline must contain all
|
||||
* needed transport parts (transport sinks).
|
||||
|
@ -2678,8 +2684,9 @@ gst_rtsp_media_get_status (GstRTSPMedia * media)
|
|||
* Since: 1.18
|
||||
*/
|
||||
gboolean
|
||||
gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
|
||||
GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate)
|
||||
gst_rtsp_media_seek_trickmode (GstRTSPMedia * media,
|
||||
GstRTSPTimeRange * range, GstSeekFlags flags, gdouble rate,
|
||||
GstClockTime trickmode_interval)
|
||||
{
|
||||
GstRTSPMediaClass *klass;
|
||||
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");
|
||||
res = TRUE;
|
||||
} else {
|
||||
GstEvent *seek_event;
|
||||
|
||||
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
||||
|
||||
if (rate < 0.0) {
|
||||
|
@ -2801,8 +2810,12 @@ gst_rtsp_media_seek_full_with_rate (GstRTSPMedia * media,
|
|||
stop_type = temp_type;
|
||||
}
|
||||
|
||||
res = gst_element_seek (priv->pipeline, rate, GST_FORMAT_TIME,
|
||||
flags, start_type, start, stop_type, stop);
|
||||
seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type,
|
||||
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 */
|
||||
GST_INFO ("done seeking %d", res);
|
||||
|
@ -2880,7 +2893,7 @@ gboolean
|
|||
gst_rtsp_media_seek_full (GstRTSPMedia * media, GstRTSPTimeRange * range,
|
||||
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
|
||||
gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
|
||||
{
|
||||
return gst_rtsp_media_seek_full_with_rate (media, range, GST_SEEK_FLAG_NONE,
|
||||
1.0);
|
||||
return gst_rtsp_media_seek_trickmode (media, range, GST_SEEK_FLAG_NONE,
|
||||
1.0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -4728,3 +4741,59 @@ gst_rtsp_media_is_receive_only (GstRTSPMedia * media)
|
|||
|
||||
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);
|
||||
|
||||
GST_RTSP_SERVER_API
|
||||
gboolean gst_rtsp_media_seek_full_with_rate (GstRTSPMedia *media,
|
||||
GstRTSPTimeRange *range,
|
||||
GstSeekFlags flags,
|
||||
gdouble rate);
|
||||
gboolean gst_rtsp_media_seek_trickmode (GstRTSPMedia *media,
|
||||
GstRTSPTimeRange *range,
|
||||
GstSeekFlags flags,
|
||||
gdouble rate,
|
||||
GstClockTime trickmode_interval);
|
||||
|
||||
GST_RTSP_SERVER_API
|
||||
GstClockTimeDiff gst_rtsp_media_seekable (GstRTSPMedia *media);
|
||||
|
@ -420,6 +421,12 @@ gboolean gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GP
|
|||
GST_RTSP_SERVER_API
|
||||
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
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTSPMedia, gst_object_unref)
|
||||
#endif
|
||||
|
|
|
@ -37,11 +37,14 @@ gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client,
|
|||
GstRTSPMediaFactory *factory = NULL;
|
||||
gchar *path = NULL;
|
||||
gboolean has_backchannel = FALSE;
|
||||
gboolean has_replay = FALSE;
|
||||
GString *unsupported = g_string_new ("");
|
||||
|
||||
while (*requirements) {
|
||||
if (strcmp (*requirements, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) {
|
||||
has_backchannel = TRUE;
|
||||
} else if (strcmp (*requirements, GST_RTSP_ONVIF_REPLAY_REQUIREMENT) == 0) {
|
||||
has_replay = TRUE;
|
||||
} else {
|
||||
if (unsupported->len)
|
||||
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:
|
||||
if (path)
|
||||
g_free (path);
|
||||
|
@ -86,15 +105,115 @@ out:
|
|||
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
|
||||
gst_rtsp_onvif_client_class_init (GstRTSPOnvifClientClass * klass)
|
||||
{
|
||||
GstRTSPClientClass *client_klass = (GstRTSPClientClass *) klass;
|
||||
|
||||
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
|
||||
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
|
||||
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__ */
|
||||
|
|
|
@ -50,6 +50,7 @@ struct GstRTSPOnvifMediaFactoryPrivate
|
|||
GMutex lock;
|
||||
gchar *backchannel_launch;
|
||||
guint backchannel_bandwidth;
|
||||
gboolean has_replay_support;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory,
|
||||
|
@ -447,6 +448,42 @@ gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory *
|
|||
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:
|
||||
* @factory: a #GstRTSPMediaFactory
|
||||
|
|
|
@ -74,6 +74,12 @@ gchar * gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFa
|
|||
GST_RTSP_SERVER_API
|
||||
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
|
||||
void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth);
|
||||
GST_RTSP_SERVER_API
|
||||
|
|
|
@ -131,6 +131,16 @@ gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
|
|||
if (res) {
|
||||
GstSDPMedia *smedia =
|
||||
&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) {
|
||||
GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media);
|
||||
|
|
|
@ -62,6 +62,7 @@ GST_RTSP_SERVER_API
|
|||
GstRTSPServer *gst_rtsp_onvif_server_new (void);
|
||||
|
||||
#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-media-factory.h"
|
||||
|
|
|
@ -130,6 +130,9 @@ struct _GstRTSPStreamPrivate
|
|||
guint rtx_pt;
|
||||
GstClockTime rtx_time;
|
||||
|
||||
/* rate control */
|
||||
gboolean do_rate_control;
|
||||
|
||||
/* Forward Error Correction with RFC 5109 */
|
||||
GstElement *ulpfec_decoder;
|
||||
GstElement *ulpfec_encoder;
|
||||
|
@ -190,6 +193,7 @@ struct _GstRTSPStreamPrivate
|
|||
GST_RTSP_LOWER_TRANS_TCP
|
||||
#define DEFAULT_MAX_MCAST_TTL 255
|
||||
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
|
||||
#define DEFAULT_DO_RATE_CONTROL TRUE
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -291,6 +295,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
|
|||
priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
|
||||
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
||||
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
||||
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
|
||||
|
||||
g_mutex_init (&priv->lock);
|
||||
|
||||
|
@ -3378,6 +3383,11 @@ create_sender_part (GstRTSPStream * stream, const GstRTSPTransport * transport)
|
|||
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++) {
|
||||
gboolean link_tee = FALSE;
|
||||
/* 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",
|
||||
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
|
||||
* deadlock. This is only needed for sink sending RTCP data. */
|
||||
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",
|
||||
(GCallback) on_sender_ssrc_active, stream);
|
||||
|
||||
g_object_set (priv->session, "disable-sr-timestamp", !priv->do_rate_control,
|
||||
NULL);
|
||||
|
||||
if (priv->srcpad) {
|
||||
/* be notified of caps changes */
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
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:
|
||||
* @stream: a #GstRTSPStream object
|
||||
|
|
|
@ -109,16 +109,16 @@ GST_START_TEST (test_media_seek)
|
|||
fail_unless (applied_rate == 1.0);
|
||||
|
||||
/* seeking with rate set to 1.5 should result in rate == 1.5 */
|
||||
fail_unless (gst_rtsp_media_seek_full_with_rate (media, range,
|
||||
GST_SEEK_FLAG_NONE, 1.5));
|
||||
fail_unless (gst_rtsp_media_seek_trickmode (media, range,
|
||||
GST_SEEK_FLAG_NONE, 1.5, 0));
|
||||
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||
fail_unless (rate == 1.5);
|
||||
fail_unless (applied_rate == 1.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_media_seek_full_with_rate (media, range,
|
||||
GST_SEEK_FLAG_NONE, -2.0));
|
||||
fail_unless (gst_rtsp_media_seek_trickmode (media, range,
|
||||
GST_SEEK_FLAG_NONE, -2.0, 0));
|
||||
fail_unless (gst_rtsp_media_get_rates (media, &rate, &applied_rate));
|
||||
fail_unless (rate == -2.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/threadpool',
|
||||
'gst/token',
|
||||
'gst/onvif',
|
||||
]
|
||||
|
||||
if not get_option('rtspclientsink').disabled()
|
||||
|
|
Loading…
Reference in a new issue