#define GST_RTP_BIN_SHUTDOWN_UNLOCK(bin) \
GST_RTP_BIN_DYN_UNLOCK (bin); \
+/* Minimum time offset to apply. This compensates for rounding errors in NTP to
+ * RTP timestamp conversions */
+#define MIN_TS_OFFSET (4 * GST_MSECOND)
+
struct _GstRtpBinPrivate
{
GMutex bin_lock;
#define DEFAULT_RFC7273_SYNC FALSE
#define DEFAULT_MAX_STREAMS G_MAXUINT
#define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT 0
+#define DEFAULT_MAX_TS_OFFSET 3000000000
enum
{
PROP_MAX_MISORDER_TIME,
PROP_RFC7273_SYNC,
PROP_MAX_STREAMS,
- PROP_MAX_TS_OFFSET_ADJUSTMENT
+ PROP_MAX_TS_OFFSET_ADJUSTMENT,
+ PROP_MAX_TS_OFFSET
};
#define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type())
static void
stream_set_ts_offset (GstRtpBin * bin, GstRtpBinStream * stream,
- gint64 ts_offset, gboolean check)
+ gint64 ts_offset, gint64 max_ts_offset, gint64 min_ts_offset,
+ gboolean allow_positive_ts_offset)
{
gint64 prev_ts_offset;
"ts-offset %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT
", diff: %" G_GINT64_FORMAT, ts_offset, prev_ts_offset, diff);
- if (check) {
- /* only change diff when it changed more than 4 milliseconds. This
- * compensates for rounding errors in NTP to RTP timestamp
- * conversions */
- if (ABS (diff) < 4 * GST_MSECOND) {
- GST_DEBUG_OBJECT (bin, "offset too small, ignoring");
+ /* ignore minor offsets */
+ if (ABS (diff) < min_ts_offset) {
+ GST_DEBUG_OBJECT (bin, "offset too small, ignoring");
+ return;
+ }
+
+ /* sanity check offset */
+ if (max_ts_offset > 0) {
+ if (ts_offset > 0 && !allow_positive_ts_offset) {
+ GST_DEBUG_OBJECT (bin,
+ "offset is positive (clocks are out of sync), ignoring");
return;
}
- if (ABS (diff) > (3 * GST_SECOND)) {
- GST_WARNING_OBJECT (bin, "offset unusually large, ignoring");
+ if (ABS (ts_offset) > max_ts_offset) {
+ GST_DEBUG_OBJECT (bin, "offset too large, ignoring");
return;
}
}
+
g_object_set (stream->buffer, "ts-offset", ts_offset, NULL);
}
GST_DEBUG_OBJECT (bin, "stream SSRC %08x, delta %" G_GINT64_FORMAT,
/* combine to get the final diff to apply to the running_time */
stream->rt_delta = rtdiff - ntpdiff;
- stream_set_ts_offset (bin, stream, stream->rt_delta, FALSE);
+ stream_set_ts_offset (bin, stream, stream->rt_delta, bin->max_ts_offset,
+ 0, FALSE);
} else {
gint64 min, rtp_min, clock_base = stream->clock_base;
gboolean all_sync, use_rtp;
else
ts_offset = ostream->rt_delta - min;
- stream_set_ts_offset (bin, ostream, ts_offset, TRUE);
+ stream_set_ts_offset (bin, ostream, ts_offset, bin->max_ts_offset,
+ MIN_TS_OFFSET, TRUE);
}
}
gst_rtp_bin_send_sync_event (stream);
DEFAULT_MAX_TS_OFFSET_ADJUSTMENT, G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRtpBin:max-ts-offset:
+ *
+ * Used to set an upper limit of how large a time offset may be. This
+ * is used to protect against unrealistic values as a result of either
+ * client,server or clock issues.
+ */
+ g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET,
+ g_param_spec_int64 ("max-ts-offset", "Max TS Offset",
+ "The maximum absolute value of the time offset in (nanoseconds). "
+ "Note, if the ntp-sync parameter is set the default value is "
+ "changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
rtpbin->rfc7273_sync = DEFAULT_RFC7273_SYNC;
rtpbin->max_streams = DEFAULT_MAX_STREAMS;
rtpbin->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT;
+ rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+ rtpbin->max_ts_offset_is_set = FALSE;
/* some default SDES entries */
cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ());
break;
case PROP_NTP_SYNC:
rtpbin->ntp_sync = g_value_get_boolean (value);
+ /* The default value of max_ts_offset depends on ntp_sync. If user
+ * hasn't set it then change default value */
+ if (!rtpbin->max_ts_offset_is_set) {
+ if (rtpbin->ntp_sync) {
+ rtpbin->max_ts_offset = 0;
+ } else {
+ rtpbin->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+ }
+ }
break;
case PROP_RTCP_SYNC:
g_atomic_int_set (&rtpbin->rtcp_sync, g_value_get_enum (value));
gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
"max-ts-offset-adjustment", value);
break;
+ case PROP_MAX_TS_OFFSET:
+ rtpbin->max_ts_offset = g_value_get_int64 (value);
+ rtpbin->max_ts_offset_is_set = TRUE;
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_MAX_TS_OFFSET_ADJUSTMENT:
g_value_set_uint64 (value, rtpbin->max_ts_offset_adjustment);
break;
+ case PROP_MAX_TS_OFFSET:
+ g_value_set_int64 (value, rtpbin->max_ts_offset);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
#define DEFAULT_RFC7273_SYNC FALSE
#define DEFAULT_MAX_TS_OFFSET_ADJUSTMENT 0
+#define DEFAULT_MAX_TS_OFFSET 3000000000
enum
{
PROP_USER_AGENT,
PROP_MAX_RTCP_RTP_TIME_DIFF,
PROP_RFC7273_SYNC,
- PROP_MAX_TS_OFFSET_ADJUSTMENT
+ PROP_MAX_TS_OFFSET_ADJUSTMENT,
+ PROP_MAX_TS_OFFSET
};
#define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type())
G_PARAM_STATIC_STRINGS));
/**
+ * GstRtpBin:max-ts-offset:
+ *
+ * Used to set an upper limit of how large a time offset may be. This
+ * is used to protect against unrealistic values as a result of either
+ * client,server or clock issues.
+ */
+ g_object_class_install_property (gobject_class, PROP_MAX_TS_OFFSET,
+ g_param_spec_int64 ("max-ts-offset", "Max TS Offset",
+ "The maximum absolute value of the time offset in (nanoseconds). "
+ "Note, if the ntp-sync parameter is set the default value is "
+ "changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
* GstRTSPSrc::handle-request:
* @rtspsrc: a #GstRTSPSrc
* @request: a #GstRTSPMessage
src->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
src->rfc7273_sync = DEFAULT_RFC7273_SYNC;
src->max_ts_offset_adjustment = DEFAULT_MAX_TS_OFFSET_ADJUSTMENT;
+ src->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+ src->max_ts_offset_is_set = FALSE;
/* get a list of all extensions */
src->extensions = gst_rtsp_ext_list_get ();
break;
case PROP_NTP_SYNC:
rtspsrc->ntp_sync = g_value_get_boolean (value);
+ /* The default value of max_ts_offset depends on ntp_sync. If user
+ * hasn't set it then change default value */
+ if (!rtspsrc->max_ts_offset_is_set) {
+ if (rtspsrc->ntp_sync) {
+ rtspsrc->max_ts_offset = 0;
+ } else {
+ rtspsrc->max_ts_offset = DEFAULT_MAX_TS_OFFSET;
+ }
+ }
break;
case PROP_USE_PIPELINE_CLOCK:
rtspsrc->use_pipeline_clock = g_value_get_boolean (value);
case PROP_MAX_TS_OFFSET_ADJUSTMENT:
rtspsrc->max_ts_offset_adjustment = g_value_get_uint64 (value);
break;
+ case PROP_MAX_TS_OFFSET:
+ rtspsrc->max_ts_offset = g_value_get_int64 (value);
+ rtspsrc->max_ts_offset_is_set = TRUE;
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_MAX_TS_OFFSET_ADJUSTMENT:
g_value_set_uint64 (value, rtspsrc->max_ts_offset_adjustment);
break;
+ case PROP_MAX_TS_OFFSET:
+ g_value_set_int64 (value, rtspsrc->max_ts_offset);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
src->max_ts_offset_adjustment, NULL);
}
+ if (g_object_class_find_property (klass, "max-ts-offset")) {
+ gint64 max_ts_offset;
+
+ /* setting max-ts-offset in the manager has side effects so only do it
+ * if the value differs */
+ g_object_get (src->manager, "max-ts-offset", &max_ts_offset, NULL);
+ if (max_ts_offset != src->max_ts_offset) {
+ g_object_set (src->manager, "max-ts-offset", src->max_ts_offset,
+ NULL);
+ }
+ }
+
/* buffer mode pauses are handled by adding offsets to buffer times,
* but some depayloaders may have a hard time syncing output times
* with such input times, e.g. container ones, most notably ASF */