@@ -17,6 +17,7 @@ libipa_headers = files([
'lux.h',
'module.h',
'pwl.h',
+ 'sync_helper.h',
])
libipa_sources = files([
@@ -36,6 +37,7 @@ libipa_sources = files([
'lux.cpp',
'module.cpp',
'pwl.cpp',
+ 'sync_helper.cpp',
])
libipa_includes = include_directories('..')
new file mode 100644
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025 Ideas on Board Oy
+ *
+ * Helper class that handles sync
+ */
+#include "sync_helper.h"
+
+#include <algorithm>
+#include <chrono>
+#include <libcamera/controls.h>
+
+/**
+ * \file sync_helper.h
+ * \brief Helper class that encapsulates handling sync
+ */
+
+namespace libcamera {
+
+using namespace std::literals::chrono_literals;
+
+namespace ipa {
+
+/**
+ * \class SyncHelper
+ * \brief Class for handling sync
+ *
+ * In order for a Camera to support the sync algorithm (via the sync layer), it
+ * needs to implement the FrameDurationLimits control, the SyncAdjustment
+ * control, and the SensorTimestamp metadata. The first is handled by AGC, the
+ * last is handled by the IPA cores, and the second one is handled by this
+ * helper. It must be plumbed into IPAs, however.
+ */
+
+/**
+ * \fn SyncHelper::SyncHelper()
+ * \brief Construct an SyncHelper instance
+ */
+
+/**
+ * \brief Return an entry for the ControlInfoMap of the IPA for SyncAdjustment
+ * \param[in] maxFrameDuration The maximum value for FrameDurationLimits
+ *
+ * This function creates an entry for SyncAdjustment that can be insterted
+ * directly into the ControlInfoMap of the IPA.
+ *
+ * The SyncAdjustment limits are computed based on the \a maxFrameDuration.
+ * Technically the limits of SyncAdjustment depend on the currently set
+ * FrameDurationLimits, but since they can be set in the same request this
+ * doesn't really work. Instead report half of the maximum FrameDurationLimits
+ * as the SyncAdjustment limits.
+ *
+ * \return Entry for ControlInfoMap for SyncAdjustment
+ */
+ControlInfo SyncHelper::controlInfo(int64_t maxFrameDuration) const
+{
+ return ControlInfo(static_cast<int32_t>(-maxFrameDuration / 2),
+ static_cast<int32_t>(maxFrameDuration / 2), 0);
+}
+
+/**
+ * \brief Set the sync adjustment value
+ * \param[in] sync The SyncAdjustment value as passed in by the application, in microseconds
+ * \param[in] minFrameDuration The minimum frame duration as set by FrameDurationLimits
+ *
+ * This function takes the value of SyncAdjustment as passed in by the
+ * application, and saves it to be later read by getSync(). The \a sync value
+ * will be clamped by \a minFrameDuration. This
+ * function is meant to be called by the IPA at queueRequest time.
+ */
+void SyncHelper::setSync(int32_t sync, utils::Duration minFrameDuration)
+{
+ utils::Duration value = std::chrono::microseconds(sync);
+ frameDurationOffset_ = std::clamp(value,
+ -minFrameDuration, minFrameDuration);
+}
+
+/**
+ * \fn SyncHelper::getSync()
+ * \brief Retrieve the set sync adjustment value
+ *
+ * This function returns the SyncAdjustment value stored in setSync(). It is
+ * meant to be read out by the IPA when the computing the frame duration to
+ * set, usually by AGC.
+ *
+ * \return The amount of time to adjust the frame duration by for sync
+ */
+
+/**
+ * \fn SyncHelper::resetSync()
+ * \brief Reset the stored sync adjustment value
+ *
+ * This function resets the state of the sync helper, that is it zeros the
+ * stored frame duration offset.
+ */
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025 Ideas on Board Oy
+ *
+ * Helper class that handles sync
+ */
+
+#pragma once
+
+#include <libcamera/base/utils.h>
+
+#include <libcamera/controls.h>
+
+namespace libcamera {
+
+namespace ipa {
+
+class SyncHelper
+{
+public:
+ SyncHelper() = default;
+ ~SyncHelper() = default;
+
+ ControlInfo controlInfo(int64_t maxFrameDuration) const;
+
+ void setSync(int32_t sync, utils::Duration minFrameDuration);
+ utils::Duration getSync() const { return frameDurationOffset_; }
+ void resetSync() { frameDurationOffset_ = utils::Duration(0); }
+
+private:
+ utils::Duration frameDurationOffset_ = utils::Duration(0);
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
The sync layer allows any Camera to get sync support as long as it implements: - SyncAdjustment control - FrameDurationLimits control - SensorTimestamp metadata While FrameDurationLimits is usually implemented by AGC and SensorTimestamp is already implemented by all pipeline handlers, only SyncAdjustment is left that needs to be implemented for all platforms. It naturally would be a good idea to implement it in libipa so all IPAs can easily be supported. Add SyncHelper that wraps handling of the SyncAdjustment control. Although it still needs to be plumbed into each IPA, it should mitigate a lot of future code duplication. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> --- src/ipa/libipa/meson.build | 2 + src/ipa/libipa/sync_helper.cpp | 99 ++++++++++++++++++++++++++++++++++ src/ipa/libipa/sync_helper.h | 36 +++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 src/ipa/libipa/sync_helper.cpp create mode 100644 src/ipa/libipa/sync_helper.h