mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-07-05 14:16:06 +00:00
Implement support for ULP Forward Error Correction
In this initial commit, interface is only exposed for RECORD, further work will be needed in rtspsrc to support this for PLAY. https://bugzilla.gnome.org/show_bug.cgi?id=794911
This commit is contained in:
parent
9f5d3ee7a8
commit
bfc35ae1ae
|
@ -630,6 +630,13 @@ gst_rtsp_stream_seekable
|
||||||
GstRTSPStreamTransportFilterFunc
|
GstRTSPStreamTransportFilterFunc
|
||||||
gst_rtsp_stream_transport_filter
|
gst_rtsp_stream_transport_filter
|
||||||
|
|
||||||
|
gst_rtsp_stream_set_ulpfec_pt
|
||||||
|
gst_rtsp_stream_get_ulpfec_pt
|
||||||
|
gst_rtsp_stream_set_ulpfec_percentage
|
||||||
|
gst_rtsp_stream_get_ulpfec_percentage
|
||||||
|
gst_rtsp_stream_request_ulpfec_decoder
|
||||||
|
gst_rtsp_stream_request_ulpfec_encoder
|
||||||
|
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GST_RTSP_STREAM_CAST
|
GST_RTSP_STREAM_CAST
|
||||||
GST_RTSP_STREAM_CLASS_CAST
|
GST_RTSP_STREAM_CLASS_CAST
|
||||||
|
|
|
@ -1517,6 +1517,7 @@ void
|
||||||
gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency)
|
gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency)
|
||||||
{
|
{
|
||||||
GstRTSPMediaPrivate *priv;
|
GstRTSPMediaPrivate *priv;
|
||||||
|
guint i;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
||||||
|
|
||||||
|
@ -1526,8 +1527,19 @@ gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency)
|
||||||
|
|
||||||
g_mutex_lock (&priv->lock);
|
g_mutex_lock (&priv->lock);
|
||||||
priv->latency = latency;
|
priv->latency = latency;
|
||||||
if (priv->rtpbin)
|
if (priv->rtpbin) {
|
||||||
g_object_set (priv->rtpbin, "latency", latency, NULL);
|
g_object_set (priv->rtpbin, "latency", latency, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < media->priv->streams->len; i++) {
|
||||||
|
GObject *storage = NULL;
|
||||||
|
|
||||||
|
g_signal_emit_by_name (G_OBJECT (media->priv->rtpbin), "get-storage",
|
||||||
|
i, &storage);
|
||||||
|
if (storage)
|
||||||
|
g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_unlock (&priv->lock);
|
g_mutex_unlock (&priv->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3108,6 +3120,38 @@ request_aux_receiver (GstElement * rtpbin, guint sessid, GstRTSPMedia * media)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstElement *
|
||||||
|
request_fec_decoder (GstElement * rtpbin, guint sessid, GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv = media->priv;
|
||||||
|
GstRTSPStream *stream = NULL;
|
||||||
|
guint i;
|
||||||
|
GstElement *res = NULL;
|
||||||
|
|
||||||
|
g_mutex_lock (&priv->lock);
|
||||||
|
for (i = 0; i < priv->streams->len; i++) {
|
||||||
|
stream = g_ptr_array_index (priv->streams, i);
|
||||||
|
|
||||||
|
if (sessid == gst_rtsp_stream_get_index (stream))
|
||||||
|
break;
|
||||||
|
|
||||||
|
stream = NULL;
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
|
if (stream) {
|
||||||
|
res = gst_rtsp_stream_request_ulpfec_decoder (stream, rtpbin, sessid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
new_storage_cb (GstElement * rtpbin, GObject * storage, guint sessid, GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
g_object_set (storage, "size-time", (media->priv->latency + 50) * GST_MSECOND, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
start_prepare (GstRTSPMedia * media)
|
start_prepare (GstRTSPMedia * media)
|
||||||
{
|
{
|
||||||
|
@ -3119,6 +3163,9 @@ start_prepare (GstRTSPMedia * media)
|
||||||
if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
|
if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARING)
|
||||||
goto no_longer_preparing;
|
goto no_longer_preparing;
|
||||||
|
|
||||||
|
g_signal_connect (priv->rtpbin, "new-storage", G_CALLBACK (new_storage_cb), media);
|
||||||
|
g_signal_connect (priv->rtpbin, "request-fec-decoder", G_CALLBACK (request_fec_decoder), media);
|
||||||
|
|
||||||
/* link streams we already have, other streams might appear when we have
|
/* link streams we already have, other streams might appear when we have
|
||||||
* dynamic elements */
|
* dynamic elements */
|
||||||
for (i = 0; i < priv->streams->len; i++) {
|
for (i = 0; i < priv->streams->len; i++) {
|
||||||
|
@ -3145,7 +3192,7 @@ start_prepare (GstRTSPMedia * media)
|
||||||
|
|
||||||
if (priv->rtpbin)
|
if (priv->rtpbin)
|
||||||
g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission,
|
g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission,
|
||||||
NULL);
|
"do-lost", TRUE, NULL);
|
||||||
|
|
||||||
for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
|
for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
|
||||||
GstElement *elem = walk->data;
|
GstElement *elem = walk->data;
|
||||||
|
@ -3806,6 +3853,9 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp)
|
||||||
s = gst_caps_get_structure (caps, 0);
|
s = gst_caps_get_structure (caps, 0);
|
||||||
gst_structure_set_name (s, "application/x-rtp");
|
gst_structure_set_name (s, "application/x-rtp");
|
||||||
|
|
||||||
|
if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "ULPFEC"))
|
||||||
|
gst_structure_set (s, "is-fec", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||||
|
|
||||||
gst_rtsp_stream_set_pt_map (stream, pt, caps);
|
gst_rtsp_stream_set_pt_map (stream, pt, caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,40 +373,75 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info,
|
||||||
|
|
||||||
update_sdp_from_tags (stream, smedia);
|
update_sdp_from_tags (stream, smedia);
|
||||||
|
|
||||||
if ((profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF)
|
if (profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF) {
|
||||||
&& (rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) {
|
if ((rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) {
|
||||||
/* ssrc multiplexed retransmit functionality */
|
/* ssrc multiplexed retransmit functionality */
|
||||||
guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream);
|
guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream);
|
||||||
|
|
||||||
if (rtx_pt == 0) {
|
if (rtx_pt == 0) {
|
||||||
g_warning ("failed to find an available dynamic payload type. "
|
g_warning ("failed to find an available dynamic payload type. "
|
||||||
"Not adding retransmission");
|
"Not adding retransmission");
|
||||||
} else {
|
} else {
|
||||||
gchar *tmp;
|
gchar *tmp;
|
||||||
GstStructure *s;
|
GstStructure *s;
|
||||||
gint caps_pt, caps_rate;
|
gint caps_pt, caps_rate;
|
||||||
|
|
||||||
s = gst_caps_get_structure (caps, 0);
|
s = gst_caps_get_structure (caps, 0);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
goto no_caps_info;
|
goto no_caps_info;
|
||||||
|
|
||||||
/* get payload type and clock rate */
|
/* get payload type and clock rate */
|
||||||
gst_structure_get_int (s, "payload", &caps_pt);
|
gst_structure_get_int (s, "payload", &caps_pt);
|
||||||
gst_structure_get_int (s, "clock-rate", &caps_rate);
|
gst_structure_get_int (s, "clock-rate", &caps_rate);
|
||||||
|
|
||||||
tmp = g_strdup_printf ("%d", rtx_pt);
|
tmp = g_strdup_printf ("%d", rtx_pt);
|
||||||
gst_sdp_media_add_format (smedia, tmp);
|
gst_sdp_media_add_format (smedia, tmp);
|
||||||
g_free (tmp);
|
g_free (tmp);
|
||||||
|
|
||||||
tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate);
|
tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate);
|
||||||
gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
|
gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
|
||||||
g_free (tmp);
|
g_free (tmp);
|
||||||
|
|
||||||
tmp =
|
tmp =
|
||||||
g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt,
|
g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt,
|
||||||
caps_pt, GST_TIME_AS_MSECONDS (rtx_time));
|
caps_pt, GST_TIME_AS_MSECONDS (rtx_time));
|
||||||
gst_sdp_media_add_attribute (smedia, "fmtp", tmp);
|
gst_sdp_media_add_attribute (smedia, "fmtp", tmp);
|
||||||
g_free (tmp);
|
g_free (tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_rtsp_stream_get_ulpfec_percentage (stream)) {
|
||||||
|
guint ulpfec_pt = gst_rtsp_stream_get_ulpfec_pt (stream);
|
||||||
|
|
||||||
|
if (ulpfec_pt == 0) {
|
||||||
|
g_warning ("failed to find an available dynamic payload type. "
|
||||||
|
"Not adding ulpfec");
|
||||||
|
} else {
|
||||||
|
gchar *tmp;
|
||||||
|
GstStructure *s;
|
||||||
|
gint caps_pt, caps_rate;
|
||||||
|
|
||||||
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
if (s == NULL)
|
||||||
|
goto no_caps_info;
|
||||||
|
|
||||||
|
/* get payload type and clock rate */
|
||||||
|
gst_structure_get_int (s, "payload", &caps_pt);
|
||||||
|
gst_structure_get_int (s, "clock-rate", &caps_rate);
|
||||||
|
|
||||||
|
tmp = g_strdup_printf ("%d", ulpfec_pt);
|
||||||
|
gst_sdp_media_add_format (smedia, tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
tmp = g_strdup_printf ("%d ulpfec/%d", ulpfec_pt, caps_rate);
|
||||||
|
gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
tmp =
|
||||||
|
g_strdup_printf ("%d apt=%d", ulpfec_pt, caps_pt);
|
||||||
|
gst_sdp_media_add_attribute (smedia, "fmtp", tmp);
|
||||||
|
g_free (tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,13 @@ struct _GstRTSPStreamPrivate
|
||||||
guint rtx_pt;
|
guint rtx_pt;
|
||||||
GstClockTime rtx_time;
|
GstClockTime rtx_time;
|
||||||
|
|
||||||
|
/* Forward Error Correction with RFC 5109 */
|
||||||
|
GstElement *ulpfec_decoder;
|
||||||
|
GstElement *ulpfec_encoder;
|
||||||
|
guint ulpfec_pt;
|
||||||
|
gboolean ulpfec_enabled;
|
||||||
|
guint ulpfec_percentage;
|
||||||
|
|
||||||
/* pool used to manage unicast and multicast addresses */
|
/* pool used to manage unicast and multicast addresses */
|
||||||
GstRTSPAddressPool *pool;
|
GstRTSPAddressPool *pool;
|
||||||
|
|
||||||
|
@ -301,6 +308,10 @@ gst_rtsp_stream_finalize (GObject * obj)
|
||||||
g_object_unref (priv->rtxsend);
|
g_object_unref (priv->rtxsend);
|
||||||
if (priv->rtxreceive)
|
if (priv->rtxreceive)
|
||||||
g_object_unref (priv->rtxreceive);
|
g_object_unref (priv->rtxreceive);
|
||||||
|
if (priv->ulpfec_encoder)
|
||||||
|
gst_object_unref (priv->ulpfec_encoder);
|
||||||
|
if (priv->ulpfec_decoder)
|
||||||
|
gst_object_unref (priv->ulpfec_decoder);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
if (priv->socket_v4[i])
|
if (priv->socket_v4[i])
|
||||||
|
@ -2362,6 +2373,28 @@ done:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
retrieve_ulpfec_pt (gpointer key, GstCaps *caps, GstElement *ulpfec_decoder)
|
||||||
|
{
|
||||||
|
guint pt = GPOINTER_TO_INT (key);
|
||||||
|
const GstStructure *s = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "ULPFEC"))
|
||||||
|
g_object_set (ulpfec_decoder, "pt", pt, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_ulpfec_decoder_pt (GstRTSPStream * stream)
|
||||||
|
{
|
||||||
|
if (!stream->priv->ulpfec_decoder)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
g_hash_table_foreach (stream->priv->ptmap, (GHFunc) retrieve_ulpfec_pt, stream->priv->ulpfec_decoder);
|
||||||
|
|
||||||
|
done:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_stream_request_aux_receiver:
|
* gst_rtsp_stream_request_aux_receiver:
|
||||||
* @stream: a #GstRTSPStream
|
* @stream: a #GstRTSPStream
|
||||||
|
@ -2385,6 +2418,7 @@ gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid)
|
||||||
bin = gst_bin_new (NULL);
|
bin = gst_bin_new (NULL);
|
||||||
stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL);
|
stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL);
|
||||||
update_rtx_receive_pt_map (stream);
|
update_rtx_receive_pt_map (stream);
|
||||||
|
update_ulpfec_decoder_pt (stream);
|
||||||
gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxreceive));
|
gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxreceive));
|
||||||
|
|
||||||
pad = gst_element_get_static_pad (stream->priv->rtxreceive, "src");
|
pad = gst_element_get_static_pad (stream->priv->rtxreceive, "src");
|
||||||
|
@ -4982,3 +5016,133 @@ gst_rtsp_stream_handle_keymgmt (GstRTSPStream * stream, const gchar * keymgmt)
|
||||||
g_strfreev (specs);
|
g_strfreev (specs);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_get_ulpfec_pt:
|
||||||
|
*
|
||||||
|
* Returns: the payload type used for ULPFEC protection packets
|
||||||
|
*
|
||||||
|
* Since: 1.16
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_rtsp_stream_get_ulpfec_pt (GstRTSPStream *stream)
|
||||||
|
{
|
||||||
|
guint res;
|
||||||
|
|
||||||
|
g_mutex_lock (&stream->priv->lock);
|
||||||
|
res = stream->priv->ulpfec_pt;
|
||||||
|
g_mutex_unlock (&stream->priv->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_set_ulpfec_pt:
|
||||||
|
*
|
||||||
|
* Set the payload type to be used for ULPFEC protection packets
|
||||||
|
*
|
||||||
|
* Since: 1.16
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_stream_set_ulpfec_pt (GstRTSPStream * stream, guint pt)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_RTSP_STREAM (stream));
|
||||||
|
|
||||||
|
g_mutex_lock (&stream->priv->lock);
|
||||||
|
stream->priv->ulpfec_pt = pt;
|
||||||
|
if (stream->priv->ulpfec_encoder) {
|
||||||
|
g_object_set (stream->priv->ulpfec_encoder, "pt", pt, NULL);
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&stream->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_request_ulpfec_decoder:
|
||||||
|
*
|
||||||
|
* Creating a rtpulpfecdec element
|
||||||
|
*
|
||||||
|
* Returns: (transfer full) (nullable): a #GstElement.
|
||||||
|
*
|
||||||
|
* Since: 1.16
|
||||||
|
*/
|
||||||
|
GstElement *
|
||||||
|
gst_rtsp_stream_request_ulpfec_decoder (GstRTSPStream * stream, GstElement *rtpbin, guint sessid)
|
||||||
|
{
|
||||||
|
GObject *internal_storage = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
|
||||||
|
stream->priv->ulpfec_decoder = gst_object_ref (gst_element_factory_make ("rtpulpfecdec", NULL));
|
||||||
|
|
||||||
|
g_signal_emit_by_name (G_OBJECT (rtpbin), "get-internal-storage", sessid, &internal_storage);
|
||||||
|
g_object_set (stream->priv->ulpfec_decoder, "storage", internal_storage, NULL);
|
||||||
|
g_object_unref (internal_storage);
|
||||||
|
update_ulpfec_decoder_pt (stream);
|
||||||
|
|
||||||
|
return stream->priv->ulpfec_decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_request_ulpfec_encoder:
|
||||||
|
*
|
||||||
|
* Creating a rtpulpfecenc element
|
||||||
|
*
|
||||||
|
* Returns: (transfer full) (nullable): a #GstElement.
|
||||||
|
*
|
||||||
|
* Since: 1.16
|
||||||
|
*/
|
||||||
|
GstElement *
|
||||||
|
gst_rtsp_stream_request_ulpfec_encoder (GstRTSPStream * stream, guint sessid)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
|
||||||
|
|
||||||
|
if (!stream->priv->ulpfec_percentage)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
stream->priv->ulpfec_encoder = gst_object_ref (gst_element_factory_make ("rtpulpfecenc", NULL));
|
||||||
|
|
||||||
|
g_object_set (stream->priv->ulpfec_encoder, "pt", stream->priv->ulpfec_pt, "percentage", stream->priv->ulpfec_percentage, NULL);
|
||||||
|
|
||||||
|
return stream->priv->ulpfec_encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_set_ulpfec_percentage:
|
||||||
|
*
|
||||||
|
* Sets the amount of redundancy to apply when creating ULPFEC
|
||||||
|
* protection packets.
|
||||||
|
*
|
||||||
|
* Since: 1.16
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, guint percentage)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_RTSP_STREAM (stream));
|
||||||
|
|
||||||
|
g_mutex_lock (&stream->priv->lock);
|
||||||
|
stream->priv->ulpfec_percentage = percentage;
|
||||||
|
if (stream->priv->ulpfec_encoder) {
|
||||||
|
g_object_set (stream->priv->ulpfec_encoder, "percentage", percentage, NULL);
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&stream->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_stream_get_ulpfec_percentage:
|
||||||
|
*
|
||||||
|
* Returns: the amount of redundancy applied when creating ULPFEC
|
||||||
|
* protection packets.
|
||||||
|
*
|
||||||
|
* Since: 1.16
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream)
|
||||||
|
{
|
||||||
|
guint res;
|
||||||
|
|
||||||
|
g_mutex_lock (&stream->priv->lock);
|
||||||
|
res = stream->priv->ulpfec_percentage;
|
||||||
|
g_mutex_unlock (&stream->priv->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -307,6 +307,28 @@ gboolean gst_rtsp_stream_is_receiver (GstRTSPStream * stream);
|
||||||
GST_RTSP_SERVER_API
|
GST_RTSP_SERVER_API
|
||||||
gboolean gst_rtsp_stream_handle_keymgmt (GstRTSPStream *stream, const gchar *keymgmt);
|
gboolean gst_rtsp_stream_handle_keymgmt (GstRTSPStream *stream, const gchar *keymgmt);
|
||||||
|
|
||||||
|
/* ULP Forward Error Correction (RFC 5109) */
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
gboolean gst_rtsp_stream_get_ulpfec_enabled (GstRTSPStream *stream);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
void gst_rtsp_stream_set_ulpfec_pt (GstRTSPStream *stream, guint pt);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
guint gst_rtsp_stream_get_ulpfec_pt (GstRTSPStream *stream);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
GstElement * gst_rtsp_stream_request_ulpfec_decoder (GstRTSPStream *stream, GstElement *rtpbin, guint sessid);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
GstElement * gst_rtsp_stream_request_ulpfec_encoder (GstRTSPStream *stream, guint sessid);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
void gst_rtsp_stream_set_ulpfec_percentage (GstRTSPStream *stream, guint percentage);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_API
|
||||||
|
guint gst_rtsp_stream_get_ulpfec_percentage (GstRTSPStream *stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPStreamTransportFilterFunc:
|
* GstRTSPStreamTransportFilterFunc:
|
||||||
* @stream: a #GstRTSPStream object
|
* @stream: a #GstRTSPStream object
|
||||||
|
|
|
@ -109,14 +109,18 @@ struct _GstRtspClientSinkPad
|
||||||
{
|
{
|
||||||
GstGhostPad parent;
|
GstGhostPad parent;
|
||||||
GstElement *custom_payloader;
|
GstElement *custom_payloader;
|
||||||
|
guint ulpfec_percentage;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_PAD_0,
|
PROP_PAD_0,
|
||||||
PROP_PAD_PAYLOADER
|
PROP_PAD_PAYLOADER,
|
||||||
|
PROP_PAD_ULPFEC_PERCENTAGE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_PAD_ULPFEC_PERCENTAGE 0
|
||||||
|
|
||||||
static GType gst_rtsp_client_sink_pad_get_type (void);
|
static GType gst_rtsp_client_sink_pad_get_type (void);
|
||||||
G_DEFINE_TYPE (GstRtspClientSinkPad, gst_rtsp_client_sink_pad,
|
G_DEFINE_TYPE (GstRtspClientSinkPad, gst_rtsp_client_sink_pad,
|
||||||
GST_TYPE_GHOST_PAD);
|
GST_TYPE_GHOST_PAD);
|
||||||
|
@ -140,6 +144,11 @@ gst_rtsp_client_sink_pad_set_property (GObject * object, guint prop_id,
|
||||||
gst_object_ref_sink (pad->custom_payloader);
|
gst_object_ref_sink (pad->custom_payloader);
|
||||||
GST_OBJECT_UNLOCK (pad);
|
GST_OBJECT_UNLOCK (pad);
|
||||||
break;
|
break;
|
||||||
|
case PROP_PAD_ULPFEC_PERCENTAGE:
|
||||||
|
GST_OBJECT_LOCK (pad);
|
||||||
|
pad->ulpfec_percentage = g_value_get_uint (value);
|
||||||
|
GST_OBJECT_UNLOCK (pad);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -160,6 +169,11 @@ gst_rtsp_client_sink_pad_get_property (GObject * object, guint prop_id,
|
||||||
g_value_set_object (value, pad->custom_payloader);
|
g_value_set_object (value, pad->custom_payloader);
|
||||||
GST_OBJECT_UNLOCK (pad);
|
GST_OBJECT_UNLOCK (pad);
|
||||||
break;
|
break;
|
||||||
|
case PROP_PAD_ULPFEC_PERCENTAGE:
|
||||||
|
GST_OBJECT_LOCK (pad);
|
||||||
|
g_value_set_uint (value, pad->ulpfec_percentage);
|
||||||
|
GST_OBJECT_UNLOCK (pad);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -192,6 +206,11 @@ gst_rtsp_client_sink_pad_class_init (GstRtspClientSinkPadClass * klass)
|
||||||
g_param_spec_object ("payloader", "Payloader",
|
g_param_spec_object ("payloader", "Payloader",
|
||||||
"The payloader element to use (NULL = default automatically selected)",
|
"The payloader element to use (NULL = default automatically selected)",
|
||||||
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_klass, PROP_PAD_ULPFEC_PERCENTAGE,
|
||||||
|
g_param_spec_uint ("ulpfec-percentage", "ULPFEC percentage",
|
||||||
|
"The percentage of ULP redundancy to apply", 0, 100, DEFAULT_PAD_ULPFEC_PERCENTAGE,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1099,7 +1118,7 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink,
|
||||||
GstRTSPStreamContext * context, GstElement * payloader, GstPad * pad)
|
GstRTSPStreamContext * context, GstElement * payloader, GstPad * pad)
|
||||||
{
|
{
|
||||||
GstRTSPStream *stream = NULL;
|
GstRTSPStream *stream = NULL;
|
||||||
guint pt, aux_pt;
|
guint pt, aux_pt, ulpfec_pt;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (sink);
|
GST_OBJECT_LOCK (sink);
|
||||||
|
|
||||||
|
@ -1125,6 +1144,11 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink,
|
||||||
goto no_free_pt;
|
goto no_free_pt;
|
||||||
sink->next_dyn_pt++;
|
sink->next_dyn_pt++;
|
||||||
|
|
||||||
|
ulpfec_pt = sink->next_dyn_pt;
|
||||||
|
if (ulpfec_pt > 127)
|
||||||
|
goto no_free_pt;
|
||||||
|
sink->next_dyn_pt++;
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (sink);
|
GST_OBJECT_UNLOCK (sink);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1143,6 +1167,9 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink,
|
||||||
gst_rtsp_stream_set_mtu (stream, sink->rtp_blocksize);
|
gst_rtsp_stream_set_mtu (stream, sink->rtp_blocksize);
|
||||||
gst_rtsp_stream_set_multicast_iface (stream, sink->multi_iface);
|
gst_rtsp_stream_set_multicast_iface (stream, sink->multi_iface);
|
||||||
|
|
||||||
|
gst_rtsp_stream_set_ulpfec_pt (stream, ulpfec_pt);
|
||||||
|
gst_rtsp_stream_set_ulpfec_percentage (stream, context->ulpfec_percentage);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (priv->pool)
|
if (priv->pool)
|
||||||
gst_rtsp_stream_set_address_pool (stream, priv->pool);
|
gst_rtsp_stream_set_address_pool (stream, priv->pool);
|
||||||
|
@ -1229,6 +1256,8 @@ gst_rtsp_client_sink_setup_payloader (GstRTSPClientSink * sink, GstPad * pad,
|
||||||
gst_object_unref (GST_OBJECT (sinkpad));
|
gst_object_unref (GST_OBJECT (sinkpad));
|
||||||
GST_RTSP_STATE_UNLOCK (sink);
|
GST_RTSP_STATE_UNLOCK (sink);
|
||||||
|
|
||||||
|
context->ulpfec_percentage = cspad->ulpfec_percentage;
|
||||||
|
|
||||||
gst_element_sync_state_with_parent (payloader);
|
gst_element_sync_state_with_parent (payloader);
|
||||||
|
|
||||||
gst_object_unref (payloader);
|
gst_object_unref (payloader);
|
||||||
|
@ -3502,6 +3531,32 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstElement *
|
||||||
|
request_fec_encoder (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink)
|
||||||
|
{
|
||||||
|
GstRTSPStream *stream = NULL;
|
||||||
|
GstElement *ret = NULL;
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
|
GST_RTSP_STATE_LOCK (sink);
|
||||||
|
for (walk = sink->contexts; walk; walk = g_list_next (walk)) {
|
||||||
|
GstRTSPStreamContext *context = (GstRTSPStreamContext *) walk->data;
|
||||||
|
|
||||||
|
if (sessid == gst_rtsp_stream_get_index (context->stream)) {
|
||||||
|
stream = context->stream;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream != NULL) {
|
||||||
|
ret = gst_rtsp_stream_request_ulpfec_encoder (stream, sessid);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_RTSP_STATE_UNLOCK (sink);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink)
|
gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink)
|
||||||
{
|
{
|
||||||
|
@ -3568,6 +3623,9 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink)
|
||||||
(GCallback) request_aux_sender, sink);
|
(GCallback) request_aux_sender, sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_signal_connect (sink->rtpbin, "request-fec-encoder",
|
||||||
|
(GCallback) request_fec_encoder, sink);
|
||||||
|
|
||||||
if (!gst_rtsp_stream_join_bin (context->stream,
|
if (!gst_rtsp_stream_join_bin (context->stream,
|
||||||
GST_BIN (sink->internal_bin), sink->rtpbin, GST_STATE_PAUSED)) {
|
GST_BIN (sink->internal_bin), sink->rtpbin, GST_STATE_PAUSED)) {
|
||||||
goto join_bin_failed;
|
goto join_bin_failed;
|
||||||
|
|
|
@ -118,6 +118,8 @@ struct _GstRTSPStreamContext {
|
||||||
guint8 channel[2];
|
guint8 channel[2];
|
||||||
|
|
||||||
GstRTSPStreamTransport *stream_transport;
|
GstRTSPStreamTransport *stream_transport;
|
||||||
|
|
||||||
|
guint ulpfec_percentage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue