[PATCH 3/5] libcamera: v4l2: Add wallclock metadata to video devices

David Plowman david.plowman at raspberrypi.com
Fri Dec 6 15:27:40 CET 2024


FrameMetadata is extended to include a wallclock timestamp.

When a frame is dequeued, we use the ClockRecovery class to generate a
good estimate of a wallclock timestamp to correspond to the frame's
SensorTimestamp.

Pipeline handlers must enable wallclocks for chosen devices by passing
an appropriate ClockRecovery object.

Signed-off-by: David Plowman <david.plowman at raspberrypi.com>
---
 include/libcamera/framebuffer.h               |  1 +
 include/libcamera/internal/v4l2_videodevice.h |  5 +++
 src/libcamera/v4l2_videodevice.cpp            | 36 ++++++++++++++++++-
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h
index ff839243..4579d0c6 100644
--- a/include/libcamera/framebuffer.h
+++ b/include/libcamera/framebuffer.h
@@ -35,6 +35,7 @@ struct FrameMetadata {
 	Status status;
 	unsigned int sequence;
 	uint64_t timestamp;
+	uint64_t wallClock;
 
 	Span<Plane> planes() { return planes_; }
 	Span<const Plane> planes() const { return planes_; }
diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h
index f021c2a0..5327c112 100644
--- a/include/libcamera/internal/v4l2_videodevice.h
+++ b/include/libcamera/internal/v4l2_videodevice.h
@@ -37,6 +37,7 @@
 
 namespace libcamera {
 
+class ClockRecovery;
 class EventNotifier;
 class MediaDevice;
 class MediaEntity;
@@ -232,6 +233,8 @@ public:
 
 	V4L2PixelFormat toV4L2PixelFormat(const PixelFormat &pixelFormat) const;
 
+	void enableWallClock(ClockRecovery *wallClockRecovery);
+
 protected:
 	std::string logPrefix() const override;
 
@@ -290,6 +293,8 @@ private:
 
 	Timer watchdog_;
 	utils::Duration watchdogDuration_;
+
+	ClockRecovery *wallClockRecovery_;
 };
 
 class V4L2M2MDevice
diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index a5cf6784..2007dffc 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -26,6 +26,7 @@
 #include <libcamera/base/unique_fd.h>
 #include <libcamera/base/utils.h>
 
+#include "libcamera/internal/clock_recovery.h"
 #include "libcamera/internal/formats.h"
 #include "libcamera/internal/framebuffer.h"
 #include "libcamera/internal/media_device.h"
@@ -534,7 +535,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2DeviceFormat &f)
 V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)
 	: V4L2Device(deviceNode), formatInfo_(nullptr), cache_(nullptr),
 	  fdBufferNotifier_(nullptr), state_(State::Stopped),
-	  watchdogDuration_(0.0)
+	  watchdogDuration_(0.0), wallClockRecovery_(nullptr)
 {
 	/*
 	 * We default to an MMAP based CAPTURE video device, however this will
@@ -1865,6 +1866,17 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
 	metadata.timestamp = buf.timestamp.tv_sec * 1000000000ULL
 			   + buf.timestamp.tv_usec * 1000ULL;
 
+	metadata.wallClock = 0;
+	if (wallClockRecovery_) {
+		/*
+		 * Sample the internal (CLOCK_BOOTTIME) and realtime (CLOCK_REALTIME) clocks and
+		 * update the clock recovery model. Then derive the wallclock estimate for the
+		 * frame timestamp.
+		 */
+		wallClockRecovery_->addSample();
+		metadata.wallClock = wallClockRecovery_->getOutput(metadata.timestamp / 1000);
+	}
+
 	if (V4L2_TYPE_IS_OUTPUT(buf.type))
 		return buffer;
 
@@ -1965,6 +1977,11 @@ int V4L2VideoDevice::streamOn()
 		return ret;
 	}
 
+	if (wallClockRecovery_) {
+		/* A good moment to sample the clocks to improve the clock recovery model. */
+		wallClockRecovery_->addSample();
+	}
+
 	state_ = State::Streaming;
 	if (watchdogDuration_ && !queuedBuffers_.empty())
 		watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
@@ -2120,6 +2137,23 @@ V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelForma
 	return {};
 }
 
+/**
+ * \brief Enable wall clock timestamps for this device
+ * \param[in] wallClockRecovery an appropriately configured ClockRecovery, or
+ * nullptr to disable wall clocks
+ *
+ * When buffers are dequeued, wall clock timestamps will be generated that
+ * correspond to the frame's timestamp, as returned by V4l2.
+ */
+void V4L2VideoDevice::enableWallClock(ClockRecovery *wallClockRecovery)
+{
+	wallClockRecovery_ = wallClockRecovery;
+
+	/* Also a reasonable moment to sample the two clocks. */
+	if (wallClockRecovery_)
+		wallClockRecovery_->addSample();
+}
+
 /**
  * \class V4L2M2MDevice
  * \brief Memory-to-Memory video device
-- 
2.39.5



More information about the libcamera-devel mailing list