Skip to content

Commit

Permalink
V4L/DVB (13827): uvcvideo: Switch to a monotonic clock for V4L2 buffe…
Browse files Browse the repository at this point in the history
…rs timestamps

The realtime clock provided by do_gettimeofday() is affected by time
jumps caused by NTP or DST. Furthermore, preliminary investigation
showed that SMP systems the realtime clock is based on the CPU TSC,
and those could get slightly out of sync, resulting in jitter in the
timestamps depending on which processor handles the USB interrupts.

Instead of the realtime clock, use a monotonic high resolution clock to
timestamp the buffer. As this could in theory introduce a regression
with some userspace applications expecting a realtime clock timestamp,
add a module parameter to switch back to the realtime clock.

Thanks to Paulo Assis for pointing out and investigating the issue.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Laurent Pinchart authored and Mauro Carvalho Chehab committed Feb 26, 2010
1 parent 0f7ff39 commit 310fe52
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 10 deletions.
49 changes: 40 additions & 9 deletions drivers/media/video/uvc/uvc_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define DRIVER_VERSION "v0.1.0"
#endif

unsigned int uvc_clock_param = CLOCK_MONOTONIC;
unsigned int uvc_no_drop_param;
static unsigned int uvc_quirks_param;
unsigned int uvc_trace_param;
Expand Down Expand Up @@ -1891,6 +1892,45 @@ static int uvc_reset_resume(struct usb_interface *intf)
return __uvc_resume(intf, 1);
}

/* ------------------------------------------------------------------------
* Module parameters
*/

static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
{
if (uvc_clock_param == CLOCK_MONOTONIC)
return sprintf(buffer, "CLOCK_MONOTONIC");
else
return sprintf(buffer, "CLOCK_REALTIME");
}

static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
{
if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
val += strlen("clock_");

if (strcasecmp(val, "monotonic") == 0)
uvc_clock_param = CLOCK_MONOTONIC;
else if (strcasecmp(val, "realtime") == 0)
uvc_clock_param = CLOCK_REALTIME;
else
return -EINVAL;

return 0;
}

module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
&uvc_clock_param, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(quirks, "Forced device quirks");
module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(trace, "Trace level bitmask");
module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(timeout, "Streaming control requests timeout");

/* ------------------------------------------------------------------------
* Driver initialization and cleanup
*/
Expand Down Expand Up @@ -2197,15 +2237,6 @@ static void __exit uvc_cleanup(void)
module_init(uvc_init);
module_exit(uvc_cleanup);

module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(quirks, "Forced device quirks");
module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(trace, "Trace level bitmask");
module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(timeout, "Streaming control requests timeout");

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
Expand Down
1 change: 0 additions & 1 deletion drivers/media/video/uvc/uvc_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_unlock_irqrestore(&queue->irqlock, flags);

buf->buf.sequence = queue->sequence++;
do_gettimeofday(&buf->buf.timestamp);

wake_up(&buf->wait);
return nextbuf;
Expand Down
10 changes: 10 additions & 0 deletions drivers/media/video/uvc/uvc_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
* when the EOF bit is set to force synchronisation on the next packet.
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
struct timespec ts;

if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n");
Expand All @@ -419,6 +421,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}

if (uvc_clock_param == CLOCK_MONOTONIC)
ktime_get_ts(&ts);
else
ktime_get_real_ts(&ts);

buf->buf.timestamp.tv_sec = ts.tv_sec;
buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;

/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/media/video/uvc/uvcvideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ struct uvc_driver {
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1

extern unsigned int uvc_clock_param;
extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
extern unsigned int uvc_timeout_param;
Expand Down

0 comments on commit 310fe52

Please sign in to comment.