Commit 3a754d51 authored by Mathieu Duponchelle's avatar Mathieu Duponchelle 🐸

FEC elements: document, remove irrelevant properties

The ulpfecenc "mux-seq" and "ssrc" properties were initially added
because the element did more than implement ULPFEC. As it was
decided that FLEXFEC would be implemented in a separate element,
both properties are now unneeded and confusing.

Change the default for the ulpfecenc multi-packet property,
as it is expected that most users of this element will be protecting video
streams.

Change the default property for the rtpredenc allow-no-red-blocks
property, as it should also be its default mode of operation.

https://bugzilla.gnome.org/show_bug.cgi?id=793843
parent efb4ee19
...@@ -25,6 +25,18 @@ ...@@ -25,6 +25,18 @@
* *
* Decode Redundant Audio Data (RED) as per RFC 2198. * Decode Redundant Audio Data (RED) as per RFC 2198.
* *
* This element is mostly provided for chrome webrtc compatibility:
* chrome will wrap ulpfec-protected streams in RED packets, and such
* streams need to be unwrapped by this element before being passed on
* to #GstRtpUlpFecDec.
*
* The #GstRtpRedDec:pt property should be set to the expected payload
* types of the RED packets.
*
* When using #GstRtpBin, this element should be inserted through the
* #GstRtpBin::request-fec-decoder signal.
*
* See also: #GstRtpRedEnc, #GstWebRTCBin, #GstRtpBin
* Since: 1.14 * Since: 1.14
*/ */
......
...@@ -25,6 +25,20 @@ ...@@ -25,6 +25,20 @@
* *
* Encode Redundant Audio Data (RED) as per RFC 2198. * Encode Redundant Audio Data (RED) as per RFC 2198.
* *
* This element is mostly provided for chrome webrtc compatibility:
* chrome expects protection packets generated by #GstRtpUlpFecEnc
* to be wrapped in RED packets for backward compatibility purposes,
* but does not actually make use of the redundant packets that could
* be encoded with this element.
*
* As such, when used for that purpose, only the #GstRtpRedEnc:pt property
* should be set to a payload type different from both the protected and
* protection packets' payload types.
*
* When using #GstRtpBin, this element should be inserted through the
* #GstRtpBin::request-fec-encoder signal.
*
* See also: #GstRtpRedDec, #GstWebRTCBin, #GstRtpBin
* Since: 1.14 * Since: 1.14
*/ */
...@@ -54,7 +68,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", ...@@ -54,7 +68,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
#define DEFAULT_PT (0) #define DEFAULT_PT (0)
#define DEFAULT_DISTANCE (0) #define DEFAULT_DISTANCE (0)
#define DEFAULT_ALLOW_NO_RED_BLOCKS (FALSE) #define DEFAULT_ALLOW_NO_RED_BLOCKS (TRUE)
GST_DEBUG_CATEGORY_STATIC (gst_rtp_red_enc_debug); GST_DEBUG_CATEGORY_STATIC (gst_rtp_red_enc_debug);
#define GST_CAT_DEFAULT (gst_rtp_red_enc_debug) #define GST_CAT_DEFAULT (gst_rtp_red_enc_debug)
......
...@@ -26,9 +26,30 @@ ...@@ -26,9 +26,30 @@
* Helper element for storing packets to aid later packet recovery from packet * Helper element for storing packets to aid later packet recovery from packet
* loss using RED/FEC (Forward Error Correction). * loss using RED/FEC (Forward Error Correction).
* *
* This element is used internally by rtpbin and is usually created * The purpose of this element is to store a moving window of packets which
* automatically. * downstream elements such as #GstRtpUlpFecDec can request in order to perform
* recovery of lost packets upon receiving custom GstRtpPacketLost events,
* usually from #GstRtpJitterBuffer.
* *
* As such, when building a pipeline manually, it should have the form:
*
* ```
* rtpstorage ! rtpjitterbuffer ! rtpulpfecdec
* ```
*
* where rtpulpfecdec get passed a reference to the object pointed to by
* the #GstRtpStorage:internal-storage property.
*
* The #GstRtpStorage:size-time property should be configured with a value
* equal to the #GstRtpJitterBuffer latency, plus some tolerance, in the order
* of milliseconds, for example in the example found at
* <https://github.com/sdroege/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs>,
* `size-time` is configured as 200 + 50 milliseconds (latency + tolerance).
*
* When using #GstRtpBin, a storage element is created automatically, and
* can be configured upon receiving the #GstRtpBin::new-storage signal.
*
* See also: #GstRtpBin, #GstRtpUlpFecDec
* Since: 1.14 * Since: 1.14
*/ */
......
...@@ -26,6 +26,25 @@ ...@@ -26,6 +26,25 @@
* Generic Forward Error Correction (FEC) decoder for Uneven Level * Generic Forward Error Correction (FEC) decoder for Uneven Level
* Protection (ULP) as described in RFC 5109. * Protection (ULP) as described in RFC 5109.
* *
* This element will work in combination with an upstream #GstRtpStorage
* element and attempt to recover packets declared lost through custom
* 'GstRTPPacketLost' events, usually emitted by #GstRtpJitterBuffer.
*
* As such, this element cannot be usefully used from the command line,
* because a reference to the upstream storage object needs to be
* provided to it through its #GstRtpUlpFecDec:storage property, example
* programs are available at
* <https://github.com/sdroege/gstreamer-rs/blob/master/examples/src/bin/rtpfecserver.rs>
* and
* <https://github.com/sdroege/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs>.
*
* Additionally, the payload types of the protection packets *must* be
* provided to this element via its #GstRtpUlpFecDec:pt property.
*
* When using #GstRtpBin, this element should be inserted through the
* #GstRtpBin::request-fec-decoder signal.
*
* See also: #GstRtpUlpFecEnc, #GstRtpBin, #GstRtpStorage
* Since: 1.14 * Since: 1.14
*/ */
......
...@@ -26,6 +26,46 @@ ...@@ -26,6 +26,46 @@
* Generic Forward Error Correction (FEC) encoder using Uneven Level * Generic Forward Error Correction (FEC) encoder using Uneven Level
* Protection (ULP) as described in RFC 5109. * Protection (ULP) as described in RFC 5109.
* *
* This element will insert protection packets in any RTP stream, which
* can then be used on the receiving side to recover lost packets.
*
* This element rewrites packets' seqnums, which means that when combined
* with retransmission elements such as #GstRtpRtxSend, it *must* be
* placed upstream of those, otherwise retransmission requests will request
* incorrect seqnums.
*
* A payload type for the protection packets *must* be specified, different
* from the payload type of the protected packets, with the GstRtpUlpFecEnc:pt
* property.
*
* The marker bit of RTP packets is used to determine sets of packets to
* protect as a unit, in order to modulate the level of protection, this
* behaviour can be disabled with GstRtpUlpFecEnc:multipacket, but should
* be left enabled for video streams.
*
* The level of protection can be configured with two properties,
* #GstRtpUlpFecEnc:percentage and #GstRtpUlpFecEnc:percentage-important,
* the element will determine which percentage to use for a given set of
* packets based on the presence of the #GST_BUFFER_FLAG_NON_DROPPABLE
* flag, upstream payloaders are expected to set this flag on "important"
* packets such as those making up a keyframe.
*
* The percentage is expressed not in terms of bytes, but in terms of
* packets, this for implementation convenience. The drawback with this
* approach is that when using a percentage different from 100 %, and a
* low bitrate, entire frames may be contained in a single packet, leading
* to some packets not being protected, thus lowering the overall recovery
* rate on the receiving side.
*
* When using #GstRtpBin, this element should be inserted through the
* #GstRtpBin::request-fec-encoder signal.
*
* Example programs using this element can be found at
* <https://github.com/sdroege/gstreamer-rs/blob/master/examples/src/bin/rtpfecserver.rs>
* and
* <https://github.com/sdroege/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs>.
*
* See also: #GstRtpUlpFecDec, #GstRtpBin
* Since: 1.14 * Since: 1.14
*/ */
...@@ -47,14 +87,11 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", ...@@ -47,14 +87,11 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS ("application/x-rtp")); GST_STATIC_CAPS ("application/x-rtp"));
#define UNDEF_PT 255 #define UNDEF_PT 255
#define UNDEF_SSRC 0
#define DEFAULT_PT UNDEF_PT #define DEFAULT_PT UNDEF_PT
#define DEFAULT_SSRC UNDEF_SSRC
#define DEFAULT_PCT 0 #define DEFAULT_PCT 0
#define DEFAULT_PCT_IMPORTANT 0 #define DEFAULT_PCT_IMPORTANT 0
#define DEFAULT_MULTIPACKET FALSE #define DEFAULT_MULTIPACKET TRUE
#define DEFAULT_MUX_SEQ FALSE
#define PACKETS_BUF_MAX_LENGTH (RTP_ULPFEC_PROTECTED_PACKETS_MAX(TRUE)) #define PACKETS_BUF_MAX_LENGTH (RTP_ULPFEC_PROTECTED_PACKETS_MAX(TRUE))
...@@ -66,10 +103,8 @@ G_DEFINE_TYPE (GstRtpUlpFecEnc, gst_rtp_ulpfec_enc, GST_TYPE_ELEMENT); ...@@ -66,10 +103,8 @@ G_DEFINE_TYPE (GstRtpUlpFecEnc, gst_rtp_ulpfec_enc, GST_TYPE_ELEMENT);
enum enum
{ {
PROP_0, PROP_0,
PROP_SSRC,
PROP_PT, PROP_PT,
PROP_MULTIPACKET, PROP_MULTIPACKET,
PROP_MUX_SEQ,
PROP_PROTECTED, PROP_PROTECTED,
PROP_PERCENTAGE, PROP_PERCENTAGE,
PROP_PERCENTAGE_IMPORTANT, PROP_PERCENTAGE_IMPORTANT,
...@@ -346,16 +381,13 @@ gst_rtp_ulpfec_enc_stream_ctx_cache_packet (GstRtpUlpFecEncStreamCtx * ctx, ...@@ -346,16 +381,13 @@ gst_rtp_ulpfec_enc_stream_ctx_cache_packet (GstRtpUlpFecEncStreamCtx * ctx,
static void static void
gst_rtp_ulpfec_enc_stream_ctx_configure (GstRtpUlpFecEncStreamCtx * ctx, gst_rtp_ulpfec_enc_stream_ctx_configure (GstRtpUlpFecEncStreamCtx * ctx,
guint pt, guint32 fec_ssrc, guint pt, guint percentage, guint percentage_important,
guint percentage, guint percentage_important, gboolean multipacket, gboolean multipacket)
gboolean mux_seq)
{ {
ctx->pt = pt; ctx->pt = pt;
ctx->fec_ssrc = fec_ssrc;
ctx->percentage = percentage; ctx->percentage = percentage;
ctx->percentage_important = percentage_important; ctx->percentage_important = percentage_important;
ctx->multipacket = multipacket; ctx->multipacket = multipacket;
ctx->mux_seq = mux_seq;
ctx->fec_nth = percentage ? 100 / percentage : 0; ctx->fec_nth = percentage ? 100 / percentage : 0;
if (percentage) { if (percentage) {
...@@ -375,9 +407,8 @@ gst_rtp_ulpfec_enc_stream_ctx_configure (GstRtpUlpFecEncStreamCtx * ctx, ...@@ -375,9 +407,8 @@ gst_rtp_ulpfec_enc_stream_ctx_configure (GstRtpUlpFecEncStreamCtx * ctx,
static GstRtpUlpFecEncStreamCtx * static GstRtpUlpFecEncStreamCtx *
gst_rtp_ulpfec_enc_stream_ctx_new (guint ssrc, gst_rtp_ulpfec_enc_stream_ctx_new (guint ssrc,
GstElement * parent, GstPad * srcpad, GstElement * parent, GstPad * srcpad,
guint pt, guint32 fec_ssrc, guint pt, guint percentage, guint percentage_important,
guint percentage, guint percentage_important, gboolean multipacket, gboolean multipacket)
gboolean mux_seq)
{ {
GstRtpUlpFecEncStreamCtx *ctx = g_new0 (GstRtpUlpFecEncStreamCtx, 1); GstRtpUlpFecEncStreamCtx *ctx = g_new0 (GstRtpUlpFecEncStreamCtx, 1);
...@@ -392,8 +423,8 @@ gst_rtp_ulpfec_enc_stream_ctx_new (guint ssrc, ...@@ -392,8 +423,8 @@ gst_rtp_ulpfec_enc_stream_ctx_new (guint ssrc,
(GDestroyNotify) rtp_ulpfec_map_info_unmap); (GDestroyNotify) rtp_ulpfec_map_info_unmap);
ctx->parent = parent; ctx->parent = parent;
ctx->scratch_buf = g_array_new (FALSE, TRUE, sizeof (guint8)); ctx->scratch_buf = g_array_new (FALSE, TRUE, sizeof (guint8));
gst_rtp_ulpfec_enc_stream_ctx_configure (ctx, pt, fec_ssrc, gst_rtp_ulpfec_enc_stream_ctx_configure (ctx, pt,
percentage, percentage_important, multipacket, mux_seq); percentage, percentage_important, multipacket);
return ctx; return ctx;
} }
...@@ -425,7 +456,7 @@ gst_rtp_ulpfec_enc_stream_ctx_process (GstRtpUlpFecEncStreamCtx * ctx, ...@@ -425,7 +456,7 @@ gst_rtp_ulpfec_enc_stream_ctx_process (GstRtpUlpFecEncStreamCtx * ctx,
ctx->num_packets_received++; ctx->num_packets_received++;
if (ctx->mux_seq && ctx->seqnum_offset > 0) { if (ctx->seqnum_offset > 0) {
buffer = gst_buffer_make_writable (buffer); buffer = gst_buffer_make_writable (buffer);
if (!gst_rtp_buffer_map (buffer, if (!gst_rtp_buffer_map (buffer,
GST_MAP_READWRITE | GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING, &rtp)) GST_MAP_READWRITE | GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING, &rtp))
...@@ -443,11 +474,8 @@ gst_rtp_ulpfec_enc_stream_ctx_process (GstRtpUlpFecEncStreamCtx * ctx, ...@@ -443,11 +474,8 @@ gst_rtp_ulpfec_enc_stream_ctx_process (GstRtpUlpFecEncStreamCtx * ctx,
if (push_fec) { if (push_fec) {
guint32 fec_timestamp = gst_rtp_buffer_get_timestamp (&rtp); guint32 fec_timestamp = gst_rtp_buffer_get_timestamp (&rtp);
guint32 fec_ssrc = guint32 fec_ssrc = gst_rtp_buffer_get_ssrc (&rtp);
ctx->fec_ssrc == guint16 fec_seq = gst_rtp_buffer_get_seq (&rtp) + 1;
UNDEF_SSRC ? gst_rtp_buffer_get_ssrc (&rtp) : ctx->fec_ssrc;
guint16 fec_seq =
ctx->mux_seq ? gst_rtp_buffer_get_seq (&rtp) + 1 : ctx->seqnum;
gst_rtp_buffer_unmap (&rtp); gst_rtp_buffer_unmap (&rtp);
...@@ -477,8 +505,8 @@ gst_rtp_ulpfec_enc_aquire_ctx (GstRtpUlpFecEnc * fec, guint ssrc) ...@@ -477,8 +505,8 @@ gst_rtp_ulpfec_enc_aquire_ctx (GstRtpUlpFecEnc * fec, guint ssrc)
if (ctx == NULL) { if (ctx == NULL) {
ctx = ctx =
gst_rtp_ulpfec_enc_stream_ctx_new (ssrc, GST_ELEMENT_CAST (fec), gst_rtp_ulpfec_enc_stream_ctx_new (ssrc, GST_ELEMENT_CAST (fec),
fec->srcpad, fec->pt, fec->ssrc, fec->percentage, fec->srcpad, fec->pt, fec->percentage,
fec->percentage_important, fec->multipacket, fec->mux_seq); fec->percentage_important, fec->multipacket);
g_hash_table_insert (fec->ssrc_to_ctx, GUINT_TO_POINTER (ssrc), ctx); g_hash_table_insert (fec->ssrc_to_ctx, GUINT_TO_POINTER (ssrc), ctx);
} }
GST_OBJECT_UNLOCK (fec); GST_OBJECT_UNLOCK (fec);
...@@ -524,9 +552,8 @@ gst_rtp_ulpfec_enc_configure_ctx (gpointer key, gpointer value, ...@@ -524,9 +552,8 @@ gst_rtp_ulpfec_enc_configure_ctx (gpointer key, gpointer value,
GstRtpUlpFecEnc *fec = user_data; GstRtpUlpFecEnc *fec = user_data;
GstRtpUlpFecEncStreamCtx *ctx = value; GstRtpUlpFecEncStreamCtx *ctx = value;
gst_rtp_ulpfec_enc_stream_ctx_configure (ctx, fec->pt, fec->ssrc, gst_rtp_ulpfec_enc_stream_ctx_configure (ctx, fec->pt,
fec->percentage, fec->percentage_important, fec->percentage, fec->percentage_important, fec->multipacket);
fec->multipacket, fec->mux_seq);
} }
static void static void
...@@ -539,9 +566,6 @@ gst_rtp_ulpfec_enc_set_property (GObject * object, guint prop_id, ...@@ -539,9 +566,6 @@ gst_rtp_ulpfec_enc_set_property (GObject * object, guint prop_id,
case PROP_PT: case PROP_PT:
fec->pt = g_value_get_uint (value); fec->pt = g_value_get_uint (value);
break; break;
case PROP_SSRC:
fec->ssrc = g_value_get_uint (value);
break;
case PROP_MULTIPACKET: case PROP_MULTIPACKET:
fec->multipacket = g_value_get_boolean (value); fec->multipacket = g_value_get_boolean (value);
break; break;
...@@ -551,9 +575,6 @@ gst_rtp_ulpfec_enc_set_property (GObject * object, guint prop_id, ...@@ -551,9 +575,6 @@ gst_rtp_ulpfec_enc_set_property (GObject * object, guint prop_id,
case PROP_PERCENTAGE_IMPORTANT: case PROP_PERCENTAGE_IMPORTANT:
fec->percentage_important = g_value_get_uint (value); fec->percentage_important = g_value_get_uint (value);
break; break;
case PROP_MUX_SEQ:
fec->mux_seq = g_value_get_boolean (value);
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;
...@@ -574,9 +595,6 @@ gst_rtp_ulpfec_enc_get_property (GObject * object, guint prop_id, ...@@ -574,9 +595,6 @@ gst_rtp_ulpfec_enc_get_property (GObject * object, guint prop_id,
case PROP_PT: case PROP_PT:
g_value_set_uint (value, fec->pt); g_value_set_uint (value, fec->pt);
break; break;
case PROP_SSRC:
g_value_set_uint (value, fec->ssrc);
break;
case PROP_PROTECTED: case PROP_PROTECTED:
g_value_set_uint (value, fec->num_packets_protected); g_value_set_uint (value, fec->num_packets_protected);
break; break;
...@@ -589,9 +607,6 @@ gst_rtp_ulpfec_enc_get_property (GObject * object, guint prop_id, ...@@ -589,9 +607,6 @@ gst_rtp_ulpfec_enc_get_property (GObject * object, guint prop_id,
case PROP_MULTIPACKET: case PROP_MULTIPACKET:
g_value_set_boolean (value, fec->multipacket); g_value_set_boolean (value, fec->multipacket);
break; break;
case PROP_MUX_SEQ:
g_value_set_boolean (value, fec->mux_seq);
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;
...@@ -650,11 +665,6 @@ gst_rtp_ulpfec_enc_class_init (GstRtpUlpFecEncClass * klass) ...@@ -650,11 +665,6 @@ gst_rtp_ulpfec_enc_class_init (GstRtpUlpFecEncClass * klass)
GST_DEBUG_FUNCPTR (gst_rtp_ulpfec_enc_get_property); GST_DEBUG_FUNCPTR (gst_rtp_ulpfec_enc_get_property);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_rtp_ulpfec_enc_dispose); gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_rtp_ulpfec_enc_dispose);
g_object_class_install_property (gobject_class, PROP_SSRC,
g_param_spec_uint ("ssrc", "SSRC",
"The SSRC to use on FEC'd packets", 0, G_MAXUINT32, DEFAULT_SSRC,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PT, g_object_class_install_property (gobject_class, PROP_PT,
g_param_spec_uint ("pt", "payload type", g_param_spec_uint ("pt", "payload type",
"The payload type of FEC packets", 0, 255, DEFAULT_PT, "The payload type of FEC packets", 0, 255, DEFAULT_PT,
...@@ -665,12 +675,6 @@ gst_rtp_ulpfec_enc_class_init (GstRtpUlpFecEncClass * klass) ...@@ -665,12 +675,6 @@ gst_rtp_ulpfec_enc_class_init (GstRtpUlpFecEncClass * klass)
"Apply FEC on multiple packets", DEFAULT_MULTIPACKET, "Apply FEC on multiple packets", DEFAULT_MULTIPACKET,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MUX_SEQ,
g_param_spec_boolean ("mux-seq", "Mux seq",
"Mux seqnum for media and fec packets in same seqnum space",
DEFAULT_MUX_SEQ,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PERCENTAGE, g_object_class_install_property (gobject_class, PROP_PERCENTAGE,
g_param_spec_uint ("percentage", "Percentage", g_param_spec_uint ("percentage", "Percentage",
"FEC overhead percentage for the whole stream", 0, 100, DEFAULT_PCT, "FEC overhead percentage for the whole stream", 0, 100, DEFAULT_PCT,
......
...@@ -56,7 +56,6 @@ struct _GstRtpUlpFecEnc { ...@@ -56,7 +56,6 @@ struct _GstRtpUlpFecEnc {
guint percentage; guint percentage;
guint percentage_important; guint percentage_important;
gboolean multipacket; gboolean multipacket;
gboolean mux_seq;
guint num_packets_protected; guint num_packets_protected;
}; };
...@@ -68,7 +67,6 @@ typedef struct { ...@@ -68,7 +67,6 @@ typedef struct {
/* settings */ /* settings */
guint pt; guint pt;
guint32 fec_ssrc;
guint percentage; guint percentage;
guint percentage_important; guint percentage_important;
gboolean multipacket; gboolean multipacket;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment