gboolean is_joined;
gchar *control;
+ GstRTSPProfile profiles;
GstRTSPLowerTrans protocols;
/* pads on the rtpbin */
GList *transports;
gint dscp_qos;
+
+ /* stream blocking */
+ gulong blocked_id;
+ gboolean blocking;
};
#define DEFAULT_CONTROL NULL
+#define DEFAULT_PROFILES GST_RTSP_PROFILE_AVP
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
GST_RTSP_LOWER_TRANS_TCP
{
PROP_0,
PROP_CONTROL,
+ PROP_PROFILES,
PROP_PROTOCOLS,
PROP_LAST
};
"The control string for this stream", DEFAULT_CONTROL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#ifdef GST_TYPE_RTSP_PROFILE
+ g_object_class_install_property (gobject_class, PROP_PROFILES,
+ g_param_spec_flags ("profiles", "Profiles",
+ "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE,
+ DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
g_param_spec_flags ("protocols", "Protocols",
"Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
priv->dscp_qos = -1;
priv->control = g_strdup (DEFAULT_CONTROL);
+ priv->profiles = DEFAULT_PROFILES;
priv->protocols = DEFAULT_PROTOCOLS;
g_mutex_init (&priv->lock);
case PROP_CONTROL:
g_value_take_string (value, gst_rtsp_stream_get_control (stream));
break;
+ case PROP_PROFILES:
+ g_value_set_flags (value, gst_rtsp_stream_get_profiles (stream));
+ break;
case PROP_PROTOCOLS:
g_value_set_flags (value, gst_rtsp_stream_get_protocols (stream));
break;
case PROP_CONTROL:
gst_rtsp_stream_set_control (stream, g_value_get_string (value));
break;
+ case PROP_PROFILES:
+ gst_rtsp_stream_set_profiles (stream, g_value_get_flags (value));
+ break;
case PROP_PROTOCOLS:
gst_rtsp_stream_set_protocols (stream, g_value_get_flags (value));
break;
}
/**
+ * gst_rtsp_stream_get_pt:
+ * @stream: a #GstRTSPStream
+ *
+ * Get the stream payload type.
+ *
+ * Return: the stream payload type.
+ */
+guint
+gst_rtsp_stream_get_pt (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ guint pt;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), -1);
+
+ priv = stream->priv;
+
+ g_object_get (G_OBJECT (priv->payloader), "pt", &pt, NULL);
+
+ return pt;
+}
+
+/**
* gst_rtsp_stream_get_srcpad:
* @stream: a #GstRTSPStream
*
res = (g_strcmp0 (priv->control, control) == 0);
else {
guint streamid;
- sscanf (control, "stream=%u", &streamid);
- res = (streamid == priv->idx);
+
+ if (sscanf (control, "stream=%u", &streamid) > 0)
+ res = (streamid == priv->idx);
+ else
+ res = FALSE;
}
g_mutex_unlock (&priv->lock);
}
/**
+ * gst_rtsp_stream_is_transport_supported:
+ * @stream: a #GstRTSPStream
+ * @transport: a #GstRTSPTransport
+ *
+ * Check if @transport can be handled by stream
+ *
+ * Returns: %TRUE if @transport can be handled by @stream.
+ */
+gboolean
+gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream,
+ GstRTSPTransport * transport)
+{
+ GstRTSPStreamPrivate *priv;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (transport->trans != GST_RTSP_TRANS_RTP)
+ goto unsupported_transmode;
+
+ if (!(transport->profile & priv->profiles))
+ goto unsupported_profile;
+
+ if (!(transport->lower_transport & priv->protocols))
+ goto unsupported_ltrans;
+
+ g_mutex_unlock (&priv->lock);
+
+ return TRUE;
+
+ /* ERRORS */
+unsupported_transmode:
+ {
+ GST_DEBUG ("unsupported transport mode %d", transport->trans);
+ return FALSE;
+ }
+unsupported_profile:
+ {
+ GST_DEBUG ("unsupported profile %d", transport->profile);
+ return FALSE;
+ }
+unsupported_ltrans:
+ {
+ GST_DEBUG ("unsupported lower transport %d", transport->lower_transport);
+ return FALSE;
+ }
+}
+
+/**
+ * gst_rtsp_stream_set_profiles:
+ * @stream: a #GstRTSPStream
+ * @profiles: the new profiles
+ *
+ * Configure the allowed profiles for @stream.
+ */
+void
+gst_rtsp_stream_set_profiles (GstRTSPStream * stream, GstRTSPProfile profiles)
+{
+ GstRTSPStreamPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->profiles = profiles;
+ g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_stream_get_profiles:
+ * @stream: a #GstRTSPStream
+ *
+ * Get the allowed profiles of @stream.
+ *
+ * Returns: a #GstRTSPProfile
+ */
+GstRTSPProfile
+gst_rtsp_stream_get_profiles (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ GstRTSPProfile res;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_RTSP_PROFILE_UNKNOWN);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ res = priv->profiles;
+ g_mutex_unlock (&priv->lock);
+
+ return res;
+}
+
+/**
* gst_rtsp_stream_set_protocols:
* @stream: a #GstRTSPStream
* @protocols: the new flags
gst_element_set_state (udpsink0, GST_STATE_NULL);
gst_object_unref (udpsink0);
}
- if (udpsink1) {
- gst_element_set_state (udpsink1, GST_STATE_NULL);
- gst_object_unref (udpsink1);
- }
if (inetaddr)
g_object_unref (inetaddr);
g_list_free_full (rejected_addresses,
* @rtpbin: a rtpbin element in @bin
* @state: the target state of the new elements
*
- * Join the #Gstbin @bin that contains the element @rtpbin.
+ * Join the #GstBin @bin that contains the element @rtpbin.
*
* @stream will link to @rtpbin, which must be inside @bin. The elements
* added to @bin will be set to the state given in @state.
/**
* gst_rtsp_stream_get_rtpinfo:
* @stream: a #GstRTSPStream
- * @rtptime: result RTP timestamp
- * @seq: result RTP seqnum
+ * @rtptime: (allow-none): result RTP timestamp
+ * @seq: (allow-none): result RTP seqnum
+ * @clock_rate: the clock rate
+ * @running_time: (allow-none): result running-time
*
- * Retrieve the current rtptime and seq. This is used to
+ * Retrieve the current rtptime, seq and running-time. This is used to
* construct a RTPInfo reply header.
*
- * Returns: %TRUE when rtptime and seq could be determined.
+ * Returns: %TRUE when rtptime, seq and running-time could be determined.
*/
gboolean
gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
- guint * rtptime, guint * seq)
+ guint * rtptime, guint * seq, guint * clock_rate,
+ GstClockTime * running_time)
{
GstRTSPStreamPrivate *priv;
+ GstStructure *stats;
GObjectClass *payobjclass;
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
- g_return_val_if_fail (rtptime != NULL, FALSE);
- g_return_val_if_fail (seq != NULL, FALSE);
priv = stream->priv;
payobjclass = G_OBJECT_GET_CLASS (priv->payloader);
- if (!g_object_class_find_property (payobjclass, "seqnum") ||
- !g_object_class_find_property (payobjclass, "timestamp"))
- return FALSE;
+ g_mutex_lock (&priv->lock);
+
+ if (g_object_class_find_property (payobjclass, "stats")) {
+ g_object_get (priv->payloader, "stats", &stats, NULL);
+ if (stats == NULL)
+ goto no_stats;
- g_object_get (priv->payloader, "seqnum", seq, "timestamp", rtptime, NULL);
+ if (seq)
+ gst_structure_get_uint (stats, "seqnum", seq);
+
+ if (rtptime)
+ gst_structure_get_uint (stats, "timestamp", rtptime);
+
+ if (running_time)
+ gst_structure_get_clock_time (stats, "running-time", running_time);
+
+ if (clock_rate) {
+ gst_structure_get_uint (stats, "clock-rate", clock_rate);
+ if (*clock_rate == 0 && running_time)
+ *running_time = GST_CLOCK_TIME_NONE;
+ }
+ gst_structure_free (stats);
+ } else {
+ if (!g_object_class_find_property (payobjclass, "seqnum") ||
+ !g_object_class_find_property (payobjclass, "timestamp"))
+ goto no_stats;
+
+ if (seq)
+ g_object_get (priv->payloader, "seqnum", seq, NULL);
+
+ if (rtptime)
+ g_object_get (priv->payloader, "timestamp", rtptime, NULL);
+
+ if (running_time)
+ *running_time = GST_CLOCK_TIME_NONE;
+ }
+ g_mutex_unlock (&priv->lock);
return TRUE;
+
+ /* ERRORS */
+no_stats:
+ {
+ GST_WARNING ("Could not get payloader stats");
+ g_mutex_unlock (&priv->lock);
+ return FALSE;
+ }
}
/**
/**
* gst_rtsp_stream_transport_filter:
* @stream: a #GstRTSPStream
- * @func: (scope call): a callback
+ * @func: (scope call) (allow-none): a callback
* @user_data: user data passed to @func
*
* Call @func for each transport managed by @stream. The result value of @func
return result;
}
+
+static GstPadProbeReturn
+pad_blocking (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+ GstRTSPStreamPrivate *priv;
+ GstRTSPStream *stream;
+
+ stream = user_data;
+ priv = stream->priv;
+
+ GST_DEBUG_OBJECT (pad, "now blocking");
+
+ g_mutex_lock (&priv->lock);
+ priv->blocking = TRUE;
+ g_mutex_unlock (&priv->lock);
+
+ gst_element_post_message (priv->payloader,
+ gst_message_new_element (GST_OBJECT_CAST (priv->payloader),
+ gst_structure_new_empty ("GstRTSPStreamBlocking")));
+
+ return GST_PAD_PROBE_OK;
+}
+
+/**
+ * gst_rtsp_stream_set_blocked:
+ * @stream: a #GstRTSPStream
+ * @blocked: boolean indicating we should block or unblock
+ *
+ * Blocks or unblocks the dataflow on @stream.
+ *
+ * Returns: %TRUE on success
+ */
+gboolean
+gst_rtsp_stream_set_blocked (GstRTSPStream * stream, gboolean blocked)
+{
+ GstRTSPStreamPrivate *priv;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ if (blocked) {
+ priv->blocking = FALSE;
+ if (priv->blocked_id == 0) {
+ priv->blocked_id = gst_pad_add_probe (priv->srcpad,
+ GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER |
+ GST_PAD_PROBE_TYPE_BUFFER_LIST, pad_blocking,
+ g_object_ref (stream), g_object_unref);
+ }
+ } else {
+ if (priv->blocked_id != 0) {
+ gst_pad_remove_probe (priv->srcpad, priv->blocked_id);
+ priv->blocked_id = 0;
+ priv->blocking = FALSE;
+ }
+ }
+ g_mutex_unlock (&priv->lock);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtsp_stream_is_blocking:
+ * @stream: a #GstRTSPStream
+ *
+ * Check if @stream is blocking on a #GstBuffer.
+ *
+ * Returns: %TRUE if @stream is blocking
+ */
+gboolean
+gst_rtsp_stream_is_blocking (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ gboolean result;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ result = priv->blocking;
+ g_mutex_unlock (&priv->lock);
+
+ return result;
+}