linuxv4l2uvc

Systematic offset on V4L2 frames


I'm grabbing frames from an UVC device using the V4L2 API. I want to measure the exposure time by calculating the offset between the timestamp of the frame and the current clock time. This is the code I'm using:

/* Control code snipped */
struct v4l2_buffer buf = {0}
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_DQBUF, &buf);

switch( buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MASK )
{
    case V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC:
    {
        struct timespec uptime = {0};
        clock_gettime(CLOCK_MONOTONIC,&uptime);

        float const secs =
            (buf.timestamp.tv_sec - uptime.tv_sec) +
            (buf.timestamp.tv_usec - uptime.tv_nsec/1000.0f)/1000.0f;

        if( V4L2_BUF_FLAG_TSTAMP_SRC_SOE == (buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) )
            printf("%s: frame exposure started %.03f seconds ago\n",__FUNCTION__,-secs);
        else if( V4L2_BUF_FLAG_TSTAMP_SRC_EOF == (buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) )
            printf("%s: frame finished capturing %.03f seconds ago\n",__FUNCTION__,-secs);
        else printf("%s: unsupported timestamp in frame\n",__FUNCTION__);

        break;
    }

    case V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN:
    case V4L2_BUF_FLAG_TIMESTAMP_COPY:
    default:
        printf("%s: no usable timestamp found in frame\n",__FUNCTION__);
}

Examples of what this returns for an exposure time of 1 second set with VIDIOC_S_CTRL:

read_frame: frame exposure started 28.892 seconds ago
read_frame: frame exposure started 28.944 seconds ago
read_frame: frame exposure started 28.895 seconds ago
read_frame: frame exposure started 29.037 seconds ago

I'm getting that weird 30-second offset between the SRC_SOE timestamp and the monotonic clock, with the 1-second exposure weld in. The V4L2/UVC timestamp is supposed to be computed from the result of ktime_get_ts(). Any idea what I am doing wrong?

This runs on a Linux 4.4 Gentoo system. The webcam is a DMK21AU04.AS, recognized as a standard UVC device.


Solution

  • the thing is...

    1 s = 1000ms,
    1 ms = 1000us,
    1 us = 1000ns.

    so...

    it should be like...

    float const secs =
            (buf.timestamp.tv_sec - uptime.tv_sec) +
            (buf.timestamp.tv_usec - uptime.tv_nsec/1000.0f)/1000000.0f;