#define DEFAULT_IS_LIVE TRUE
#define DEFAULT_IGNORE_X_SERVER_REPLY FALSE
#define DEFAULT_FORCE_NON_COMPLIANT_URL FALSE
+#define DEFAULT_TCP_TIMESTAMP FALSE
enum
{
PROP_IGNORE_X_SERVER_REPLY,
PROP_EXTRA_HTTP_REQUEST_HEADERS,
PROP_FORCE_NON_COMPLIANT_URL,
+ PROP_TCP_TIMESTAMP,
};
#define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type())
"Extra headers to append to HTTP requests when in tunneled mode",
GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRTSPSrc:tcp-timestamp
+ *
+ * Timestamp all buffers with their receive time when receiving RTP packets
+ * over TCP or HTTP.
+ *
+ * When dealing with TCP based connections, setting timestamps for every
+ * packet is not done by default because a server typically bursts data, for
+ * which we don't want to compensate by speeding up the media. The other
+ * timestamps will be interpollated from this one using the RTP timestamps.
+ *
+ * This has the side effect that no drift compensation between the server
+ * and client is done, and over time the RTP timestamps will drift against
+ * the client's clock. This can lead to buffers (and observed end-to-end
+ * latency) to grow over time, or all packets arriving too late once a
+ * threshold is reached.
+ *
+ * Enabling this property will timestamp all RTP packets with their receive
+ * times, which gets around the drift problem but can cause other problems
+ * if the server is sending data not smoothly in real-time.
+ *
+ * Only applicable for RTSP over TCP or HTTP.
+ *
+ * Since: 1.24.10
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_TCP_TIMESTAMP,
+ g_param_spec_boolean ("tcp-timestamp", "TCP Timestamp",
+ "Timestamp RTP packets with receive times in TCP/HTTP mode",
+ DEFAULT_TCP_TIMESTAMP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
/**
* GstRTSPSrc:force-non-compliant-url
*
src->prop_extra_http_request_headers =
gst_structure_new_empty ("extra-http-request-headers");
src->force_non_compliant_url = DEFAULT_FORCE_NON_COMPLIANT_URL;
+ src->tcp_timestamp = DEFAULT_TCP_TIMESTAMP;
/* get a list of all extensions */
src->extensions = gst_rtsp_ext_list_get ();
case PROP_FORCE_NON_COMPLIANT_URL:
rtspsrc->force_non_compliant_url = g_value_get_boolean (value);
break;
+ case PROP_TCP_TIMESTAMP:
+ rtspsrc->tcp_timestamp = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_FORCE_NON_COMPLIANT_URL:
g_value_set_boolean (value, rtspsrc->force_non_compliant_url);
break;
+ case PROP_TCP_TIMESTAMP:
+ g_value_set_boolean (value, rtspsrc->tcp_timestamp);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
src->need_segment = TRUE;
}
- if (src->base_time == -1) {
- /* Take current running_time. This timestamp will be put on
- * the first buffer of each stream because we are a live source and so we
- * timestamp with the running_time. When we are dealing with TCP, we also
- * only timestamp the first buffer (using the DISCONT flag) because a server
- * typically bursts data, for which we don't want to compensate by speeding
- * up the media. The other timestamps will be interpollated from this one
- * using the RTP timestamps. */
- GST_OBJECT_LOCK (src);
- if (GST_ELEMENT_CLOCK (src)) {
- GstClockTime now;
- GstClockTime base_time;
-
- now = gst_clock_get_time (GST_ELEMENT_CLOCK (src));
- base_time = GST_ELEMENT_CAST (src)->base_time;
-
- src->base_time = now - base_time;
-
- GST_DEBUG_OBJECT (src, "first buffer at time %" GST_TIME_FORMAT ", base %"
- GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time));
- }
- GST_OBJECT_UNLOCK (src);
- }
-
/* If needed send a new segment, don't forget we are live and buffer are
* timestamped with running time */
if (src->need_segment) {
stream->need_caps = FALSE;
}
+ if (!is_rtcp && (stream->discont || src->tcp_timestamp)) {
+ GstClockTime timestamp = GST_CLOCK_TIME_NONE;
+
+ GST_OBJECT_LOCK (src);
+ if (GST_ELEMENT_CLOCK (src)) {
+ GstClockTime now;
+
+ now = gst_clock_get_time (GST_ELEMENT_CLOCK (src));
+ timestamp = now - GST_ELEMENT_CAST (src)->base_time;
+ }
+ GST_OBJECT_UNLOCK (src);
+
+ GST_TRACE_OBJECT (src, "setting timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+
+ GST_BUFFER_DTS (buf) = timestamp;
+ }
+
if (stream->discont && !is_rtcp) {
/* mark first RTP buffer as discont */
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
stream->discont = FALSE;
- /* first buffer gets the timestamp, other buffers are not timestamped and
- * their presentation time will be interpollated from the rtp timestamps. */
- GST_DEBUG_OBJECT (src, "setting timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (src->base_time));
-
- GST_BUFFER_TIMESTAMP (buf) = src->base_time;
}
/* chain to the peer pad */
src->need_range = FALSE;
src->running = TRUE;
- src->base_time = -1;
src->state = GST_RTSP_STATE_PLAYING;
/* mark discont */