[PATCH 3/5] libcamera: v4l2: Add wallclock metadata to video devices
Kieran Bingham
kieran.bingham at ideasonboard.com
Fri Dec 6 16:37:22 CET 2024
Quoting David Plowman (2024-12-06 14:27:40)
> 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;
This breaks in the CI build I'm afraid:
https://gitlab.freedesktop.org/camera/libcamera/-/jobs/67848569
[481/650] Generating Documentation/doxygen-internal with a custom command
FAILED: Documentation/internal-api-html
/usr/bin/doxygen Documentation/Doxyfile-internal
/builds/camera/libcamera/include/libcamera/framebuffer.h:38: error: Member wallClock (variable) of struct libcamera::FrameMetadata is not documented. (warning treated as error, aborting now)
Either we need to add the doc (which is what I'd do) - or potentially
depending on discussions below, remove the addition...
>
> 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_) {
I know Laurent discussed passing in the 'ClockRecovery' class as a way
of giving the responsibility to the Pipeline handler - but I'm not
particularly fond of it. (I won't object if this is preferred all
round).
To me - especially if there is an addition of uint64_t wallClock in the
FrameMetadata, then this should just always be enabled.
But if it's /really/ optional and passed in, - then I don't think we
should store a metadata.wallClock below.
> + /*
> + * 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);
As that could be called in the pipeline handler. And to me - then I
would ask why are we getting the V4L2VideoDevice to manage the
clockRecovery object..
(And I think that it should 'just' be in the V4L2VideoDevice in this
instance if we're going to provide wall clock timestamps of buffers).
> + }
> +
> 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
Is there a reason we can think of for /why/ we would disable the wall
clocks?
It doesn't seem like a 'desired' feature to me - unless the costs of
doing the clock recovery are prohibitively expensive? Which I wouldn't
expect it to be ?
> + *
> + * 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