summaryrefslogtreecommitdiff
path: root/sys/v4l2/gstv4l2src.c
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2014-09-05 08:29:20 -0400
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2014-09-09 18:50:59 -0400
commitb706103fab54d38136ca234cb6013d782651d59f (patch)
tree61f1c14ef170ed965a4afb1bf7e02e41217393a9 /sys/v4l2/gstv4l2src.c
parent5c933fa781ef61ac5b7e45fa855d0f916fd5957b (diff)
v4l2: Detect bad drivers timestamps
Even though the UVC driver do a great deal of effort to prevent bad timestamp to be sent to userspace, there still exist UVC hardware that are so buggy that the timestamp endup nearly random. This code detect and ignore timestamp from these drivers, making these camera usable. This has been tested on both invalid and valid cameras, making sure it does not trigger for valid cameras. https://bugzilla.gnome.org/show_bug.cgi?id=732910
Diffstat (limited to 'sys/v4l2/gstv4l2src.c')
-rw-r--r--sys/v4l2/gstv4l2src.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c
index e1c0df035..8a4155c94 100644
--- a/sys/v4l2/gstv4l2src.c
+++ b/sys/v4l2/gstv4l2src.c
@@ -561,6 +561,9 @@ gst_v4l2src_start (GstBaseSrc * src)
v4l2src->ctrl_time = 0;
gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time);
+ v4l2src->has_bad_timestamp = FALSE;
+ v4l2src->last_timestamp = 0;
+
return TRUE;
}
@@ -575,6 +578,9 @@ static gboolean
gst_v4l2src_unlock_stop (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+
+ v4l2src->last_timestamp = 0;
+
return gst_v4l2_object_unlock_stop (v4l2src->v4l2object);
}
@@ -670,7 +676,8 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
abs_time = GST_CLOCK_TIME_NONE;
}
- if (timestamp != GST_CLOCK_TIME_NONE) {
+retry:
+ if (!v4l2src->has_bad_timestamp && timestamp != GST_CLOCK_TIME_NONE) {
struct timespec now;
GstClockTime gstnow;
@@ -680,7 +687,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
clock_gettime (CLOCK_MONOTONIC, &now);
gstnow = GST_TIMESPEC_TO_TIME (now);
- if (gstnow < timestamp && (timestamp - gstnow) > (10 * GST_SECOND)) {
+ if (timestamp > gstnow || (gstnow - timestamp) > (10 * GST_SECOND)) {
GTimeVal now;
/* very large diff, fall back to system time */
@@ -688,12 +695,39 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
gstnow = GST_TIMEVAL_TO_TIME (now);
}
- if (gstnow > timestamp) {
- delay = gstnow - timestamp;
- } else {
- delay = 0;
+ /* Detect buggy drivers here, and stop using their timestamp. Failing any
+ * of these condition would imply a very buggy driver:
+ * - Timestamp in the future
+ * - Timestamp is going backward compare to last seen timestamp
+ * - Timestamp is jumping forward for less then a frame duration
+ * - Delay is bigger then the actual timestamp
+ * */
+ if (timestamp > gstnow) {
+ GST_WARNING_OBJECT (v4l2src,
+ "Timestamp in the future detected, ignoring driver timestamps");
+ v4l2src->has_bad_timestamp = TRUE;
+ goto retry;
+ }
+
+ if (v4l2src->last_timestamp > timestamp) {
+ GST_WARNING_OBJECT (v4l2src,
+ "Timestamp going backward, ignoring driver timestamps");
+ v4l2src->has_bad_timestamp = TRUE;
+ goto retry;
}
+ delay = gstnow - timestamp;
+
+ if (delay > timestamp) {
+ GST_WARNING_OBJECT (v4l2src,
+ "Timestamp does not correlate with any clock, ignoring driver timestamps");
+ v4l2src->has_bad_timestamp = TRUE;
+ goto retry;
+ }
+
+ /* Save last timestamp for sanity checks */
+ v4l2src->last_timestamp = timestamp;
+
GST_DEBUG_OBJECT (v4l2src, "ts: %" GST_TIME_FORMAT " now %" GST_TIME_FORMAT
" delay %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
GST_TIME_ARGS (gstnow), GST_TIME_ARGS (delay));