mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +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
7 changed files with 370 additions and 32 deletions
|
@ -630,6 +630,13 @@ gst_rtsp_stream_seekable
|
|||
GstRTSPStreamTransportFilterFunc
|
||||
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>
|
||||
GST_RTSP_STREAM_CAST
|
||||
GST_RTSP_STREAM_CLASS_CAST
|
||||
|
|
|
@ -1517,6 +1517,7 @@ void
|
|||
gst_rtsp_media_set_latency (GstRTSPMedia * media, guint latency)
|
||||
{
|
||||
GstRTSPMediaPrivate *priv;
|
||||
guint i;
|
||||
|
||||
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);
|
||||
priv->latency = latency;
|
||||
if (priv->rtpbin)
|
||||
if (priv->rtpbin) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -3108,6 +3120,38 @@ request_aux_receiver (GstElement * rtpbin, guint sessid, GstRTSPMedia * media)
|
|||
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
|
||||
start_prepare (GstRTSPMedia * media)
|
||||
{
|
||||
|
@ -3119,6 +3163,9 @@ start_prepare (GstRTSPMedia * media)
|
|||
if (priv->status != GST_RTSP_MEDIA_STATUS_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
|
||||
* dynamic elements */
|
||||
for (i = 0; i < priv->streams->len; i++) {
|
||||
|
@ -3145,7 +3192,7 @@ start_prepare (GstRTSPMedia * media)
|
|||
|
||||
if (priv->rtpbin)
|
||||
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)) {
|
||||
GstElement *elem = walk->data;
|
||||
|
@ -3806,6 +3853,9 @@ default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp)
|
|||
s = gst_caps_get_structure (caps, 0);
|
||||
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_caps_unref (caps);
|
||||
}
|
||||
|
|
|
@ -373,40 +373,75 @@ gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info,
|
|||
|
||||
update_sdp_from_tags (stream, smedia);
|
||||
|
||||
if ((profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF)
|
||||
&& (rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) {
|
||||
/* ssrc multiplexed retransmit functionality */
|
||||
guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream);
|
||||
if (profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF) {
|
||||
if ((rtx_time = gst_rtsp_stream_get_retransmission_time (stream))) {
|
||||
/* ssrc multiplexed retransmit functionality */
|
||||
guint rtx_pt = gst_rtsp_stream_get_retransmission_pt (stream);
|
||||
|
||||
if (rtx_pt == 0) {
|
||||
g_warning ("failed to find an available dynamic payload type. "
|
||||
"Not adding retransmission");
|
||||
} else {
|
||||
gchar *tmp;
|
||||
GstStructure *s;
|
||||
gint caps_pt, caps_rate;
|
||||
if (rtx_pt == 0) {
|
||||
g_warning ("failed to find an available dynamic payload type. "
|
||||
"Not adding retransmission");
|
||||
} else {
|
||||
gchar *tmp;
|
||||
GstStructure *s;
|
||||
gint caps_pt, caps_rate;
|
||||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
if (s == NULL)
|
||||
goto no_caps_info;
|
||||
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);
|
||||
/* 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", rtx_pt);
|
||||
gst_sdp_media_add_format (smedia, tmp);
|
||||
g_free (tmp);
|
||||
tmp = g_strdup_printf ("%d", rtx_pt);
|
||||
gst_sdp_media_add_format (smedia, tmp);
|
||||
g_free (tmp);
|
||||
|
||||
tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate);
|
||||
gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
|
||||
g_free (tmp);
|
||||
tmp = g_strdup_printf ("%d rtx/%d", rtx_pt, caps_rate);
|
||||
gst_sdp_media_add_attribute (smedia, "rtpmap", tmp);
|
||||
g_free (tmp);
|
||||
|
||||
tmp =
|
||||
g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt,
|
||||
caps_pt, GST_TIME_AS_MSECONDS (rtx_time));
|
||||
gst_sdp_media_add_attribute (smedia, "fmtp", tmp);
|
||||
g_free (tmp);
|
||||
tmp =
|
||||
g_strdup_printf ("%d apt=%d;rtx-time=%" G_GINT64_FORMAT, rtx_pt,
|
||||
caps_pt, GST_TIME_AS_MSECONDS (rtx_time));
|
||||
gst_sdp_media_add_attribute (smedia, "fmtp", 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;
|
||||
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 */
|
||||
GstRTSPAddressPool *pool;
|
||||
|
||||
|
@ -301,6 +308,10 @@ gst_rtsp_stream_finalize (GObject * obj)
|
|||
g_object_unref (priv->rtxsend);
|
||||
if (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++) {
|
||||
if (priv->socket_v4[i])
|
||||
|
@ -2362,6 +2373,28 @@ done:
|
|||
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:
|
||||
* @stream: a #GstRTSPStream
|
||||
|
@ -2385,6 +2418,7 @@ gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid)
|
|||
bin = gst_bin_new (NULL);
|
||||
stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL);
|
||||
update_rtx_receive_pt_map (stream);
|
||||
update_ulpfec_decoder_pt (stream);
|
||||
gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxreceive));
|
||||
|
||||
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);
|
||||
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
|
||||
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:
|
||||
* @stream: a #GstRTSPStream object
|
||||
|
|
|
@ -109,14 +109,18 @@ struct _GstRtspClientSinkPad
|
|||
{
|
||||
GstGhostPad parent;
|
||||
GstElement *custom_payloader;
|
||||
guint ulpfec_percentage;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
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);
|
||||
G_DEFINE_TYPE (GstRtspClientSinkPad, gst_rtsp_client_sink_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_UNLOCK (pad);
|
||||
break;
|
||||
case PROP_PAD_ULPFEC_PERCENTAGE:
|
||||
GST_OBJECT_LOCK (pad);
|
||||
pad->ulpfec_percentage = g_value_get_uint (value);
|
||||
GST_OBJECT_UNLOCK (pad);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
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);
|
||||
GST_OBJECT_UNLOCK (pad);
|
||||
break;
|
||||
case PROP_PAD_ULPFEC_PERCENTAGE:
|
||||
GST_OBJECT_LOCK (pad);
|
||||
g_value_set_uint (value, pad->ulpfec_percentage);
|
||||
GST_OBJECT_UNLOCK (pad);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -192,6 +206,11 @@ gst_rtsp_client_sink_pad_class_init (GstRtspClientSinkPadClass * klass)
|
|||
g_param_spec_object ("payloader", "Payloader",
|
||||
"The payloader element to use (NULL = default automatically selected)",
|
||||
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
|
||||
|
@ -1099,7 +1118,7 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink,
|
|||
GstRTSPStreamContext * context, GstElement * payloader, GstPad * pad)
|
||||
{
|
||||
GstRTSPStream *stream = NULL;
|
||||
guint pt, aux_pt;
|
||||
guint pt, aux_pt, ulpfec_pt;
|
||||
|
||||
GST_OBJECT_LOCK (sink);
|
||||
|
||||
|
@ -1125,6 +1144,11 @@ gst_rtsp_client_sink_create_stream (GstRTSPClientSink * sink,
|
|||
goto no_free_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);
|
||||
|
||||
|
||||
|
@ -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_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 (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_RTSP_STATE_UNLOCK (sink);
|
||||
|
||||
context->ulpfec_percentage = cspad->ulpfec_percentage;
|
||||
|
||||
gst_element_sync_state_with_parent (payloader);
|
||||
|
||||
gst_object_unref (payloader);
|
||||
|
@ -3502,6 +3531,32 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPClientSink * sink)
|
|||
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
|
||||
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);
|
||||
}
|
||||
|
||||
g_signal_connect (sink->rtpbin, "request-fec-encoder",
|
||||
(GCallback) request_fec_encoder, sink);
|
||||
|
||||
if (!gst_rtsp_stream_join_bin (context->stream,
|
||||
GST_BIN (sink->internal_bin), sink->rtpbin, GST_STATE_PAUSED)) {
|
||||
goto join_bin_failed;
|
||||
|
|
|
@ -118,6 +118,8 @@ struct _GstRTSPStreamContext {
|
|||
guint8 channel[2];
|
||||
|
||||
GstRTSPStreamTransport *stream_transport;
|
||||
|
||||
guint ulpfec_percentage;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue