I am trying to use v4l2_buffer's timestamp value (type timeval) to synchronize images captured from a UVC webcam to external events.
However the timestamp is not the same as the system time, or the up time, etc:
printf("image captured at %ld, %ld\n",
buffer->timestamp.tv_sec,
buffer->timestamp.tv_usec);
struct timeval tv;
gettimeofday(&tv, 0);
printf("current time %ld, %ld\n", tv.tv_sec, tv.tv_usec);
Results in
image captured at 367746, 476270
current time 1335083395, 11225
My uptime is 10 days.
The buffer timestamp has been taken when the exposure of the frame has begun. This is only valid for the V4L2_BUF_TYPE_VIDEO_CAPTURE buffer type. 3.6.7. Timecodes The struct v4l2_timecode structure is designed to hold a SMPTE 12M or similar timecode. (struct struct timeval timestamps are stored in struct v4l2_buffer field timestamp .)
The V4L2_BUF_FLAG_TIMESTAMP_COPY timestamp type which is used by e.g. on mem-to-mem devices is an exception to the rule: the timestamp source flags are copied from the OUTPUT video buffer to the CAPTURE video buffer. Number of the buffer, set by the application except when calling VIDIOC_DQBUF, then it is set by the driver.
Interactions between formats, controls and buffers V4L2 exposes parameters that influence the buffer size, or the way data is laid out in the buffer. Those parameters are exposed through both formats and controls.
To test the timestamp type, mask out bits not belonging to timestamp type by performing a logical and operation with buffer flags and timestamp mask. Unknown timestamp type. This type is used by drivers before Linux 3.9 and may be either monotonic (see below) or realtime (wall clock).
According to http://comments.gmane.org/gmane.linux.drivers.video-input-infrastructure/39892 some v4l2 drivers (including the UVC one) do not use the realtime clock (wall time) but rather a monotonic clock that counts from a not specified point in time. On Linux, this is the boot time (i.e. uptime), however (and I suspect this is the cause of your mismatch) only the time that the computer was actually running (i.e. this clock does not run when the computer is suspended).
If you have the OP's problem, and you're trying to get to epoch timestamps for each frame, you can use the code snippet below to do so.
#include <time.h>
#include <math.h>
//////////////////////
//setup:
long getEpochTimeShift(){
struct timeval epochtime;
struct timespec vsTime;
gettimeofday(&epochtime, NULL);
clock_gettime(CLOCK_MONOTONIC, &vsTime);
long uptime_ms = vsTime.tv_sec* 1000 + (long) round( vsTime.tv_nsec/ 1000000.0);
long epoch_ms = epochtime.tv_sec * 1000 + (long) round( epochtime.tv_usec/1000.0);
return epoch_ms - uptime_ms;
}
//stick this somewhere so that it runs once, on the startup of your capture process
// noting, if you hibernate a laptop, you might need to recalc this if you don't restart
// the process after dehibernation
long toEpochOffset_ms = getEpochTimeShift();
//////////////////////
//...somewhere in your capture loop:
struct v4l2_buffer buf;
//make the v4l call to xioctl(fd, VIDIOC_DQBUF, &buf)
//then:
long temp_ms = 1000 * buf.timestamp.tv_sec + (long) round( buf.timestamp.tv_usec / 1000.0);
long epochTimeStamp_ms = temp_ms + toEpochOffset_ms ;
printf( "the frame's timestamp in epoch ms is: %ld", epochTimeStamp_ms);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With