[v2,1/2] libcamera: Add SensorSequence metadata control
diff mbox series

Message ID 20260703224817.15650-2-ballen4705@googlemail.com
State New
Headers show
Series
  • libcamera: Add SensorSequence request metadata control
Related show

Commit Message

Bruce Allen July 3, 2026, 10:48 p.m. UTC
Add controls::SensorSequence (int64_t, out) to report the monotonic
sequence number from the sensor-facing capture device in request
metadata. Populate the control in all pipeline handlers that already
report SensorTimestamp.

Signed-off-by: Bruce Allen <ballen4705@googlemail.com>
---
 src/libcamera/control_ids_core.yaml                | 18 ++++++++++++++++++
 src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  3 +++
 src/libcamera/pipeline/ipu3/ipu3.cpp               |  2 ++
 src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 ++
 src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 ++
 src/libcamera/pipeline/rpi/common/pipeline_base.cpp |  2 ++
 src/libcamera/pipeline/rpi/pisp/pisp.cpp          |  2 ++
 src/libcamera/pipeline/rpi/vc4/vc4.cpp             |  2 ++
 src/libcamera/pipeline/simple/simple.cpp           |  5 ++++-
 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp        |  2 ++
 src/libcamera/pipeline/vimc/vimc.cpp               |  2 ++
 11 files changed, 41 insertions(+), 1 deletion(-)

Patch
diff mbox series

diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
index 89991d0..d6bc114 100644
--- a/src/libcamera/control_ids_core.yaml
+++ b/src/libcamera/control_ids_core.yaml
@@ -792,6 +792,24 @@  controls:
         \todo Define how the sensor timestamp has to be used in the reprocessing
         use case.
 
+  - SensorSequence:
+      type: int64_t
+      direction: out
+      description: |
+        The monotonic sequence number from the sensor capture device.
+
+        Pipeline handlers populate this metadata control with the sequence
+        number reported by the sensor-facing capture device (for example the
+        CSI-2 receiver or V4L2 video node). Any break in this sequence number
+        indicates that frames were dropped or not captured before the previous
+        request completed.
+
+        While per-buffer FrameMetadata::sequence identifies frames in each
+        completed stream, SensorSequence reflects the sensor-side capture path
+        and is intended for diagnosing frame continuity.
+
+        The SensorSequence control can only be returned in metadata.
+
   - AfMode:
       type: int32_t
       direction: inout
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
index c3d2695..d2175b9 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -1130,6 +1130,9 @@  void PipelineHandlerISI::bufferReady(FrameBuffer *buffer)
 	if (!metadata.contains(controls::SensorTimestamp.id()))
 		metadata.set(controls::SensorTimestamp,
 			     buffer->metadata().timestamp);
+	if (!metadata.contains(controls::SensorSequence.id()))
+		metadata.set(controls::SensorSequence,
+			     static_cast<int64_t>(buffer->metadata().sequence));
 
 	if (completeBuffer(request, buffer))
 		completeRequest(request);
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 0f3e169..6494259 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -1317,6 +1317,8 @@  void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer)
 	 */
 	request->_d()->metadata().set(controls::SensorTimestamp,
 				      buffer->metadata().timestamp);
+	request->_d()->metadata().set(controls::SensorSequence,
+				      static_cast<int64_t>(buffer->metadata().sequence));
 
 	info->effectiveSensorControls = delayedCtrls_->get(buffer->metadata().sequence);
 
diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
index 599ff88..119b249 100644
--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
@@ -1704,6 +1704,8 @@  void PipelineHandlerMaliC55::cruBufferReady(FrameBuffer *buffer)
 	Request *request = info->request;
 	request->_d()->metadata().set(controls::SensorTimestamp,
 				      buffer->metadata().timestamp);
+	request->_d()->metadata().set(controls::SensorSequence,
+				      static_cast<int64_t>(buffer->metadata().sequence));
 
 	MaliC55CameraData *data = cameraData(request->_d()->camera());
 	data->ipa_->fillParams(request->sequence(), info->paramBuffer->cookie());
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 4f9c0aa..0c73f5a 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -1647,6 +1647,8 @@  void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer)
 		 */
 		request->_d()->metadata().set(controls::SensorTimestamp,
 					      metadata.timestamp);
+		request->_d()->metadata().set(controls::SensorSequence,
+					      static_cast<int64_t>(metadata.sequence));
 
 		if (isRaw_) {
 			const ControlList &ctrls =
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
index 5a5acf6..dcf8e6a 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -1514,6 +1514,8 @@  void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request
 {
 	if (auto x = bufferControls.get(controls::SensorTimestamp))
 		request->_d()->metadata().set(controls::SensorTimestamp, *x);
+	if (auto x = bufferControls.get(controls::SensorSequence))
+		request->_d()->metadata().set(controls::SensorSequence, *x);
 	if (auto x = bufferControls.get(controls::FrameWallClock))
 		request->_d()->metadata().set(controls::FrameWallClock, *x);
 
diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
index b744c90..0832432 100644
--- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp
+++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
@@ -1766,6 +1766,8 @@  void PiSPCameraData::cfeBufferDequeue(FrameBuffer *buffer)
 
 		ctrl.set(controls::SensorTimestamp, sensorTimestamp);
 		ctrl.set(controls::FrameWallClock, wallClockTimestamp);
+		ctrl.set(controls::SensorSequence,
+			 static_cast<int64_t>(buffer->metadata().sequence));
 		job.sensorControls = std::move(ctrl);
 		job.delayContext = delayContext;
 	} else if (stream == &cfe_[Cfe::Config]) {
diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
index 3e9a490..1e7b26a 100644
--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
@@ -787,6 +787,8 @@  void Vc4CameraData::unicamBufferDequeue(FrameBuffer *buffer)
 
 		ctrl.set(controls::SensorTimestamp, sensorTimestamp);
 		ctrl.set(controls::FrameWallClock, wallClockTimestamp);
+		ctrl.set(controls::SensorSequence,
+			 static_cast<int64_t>(buffer->metadata().sequence));
 		bayerQueue_.push({ buffer, std::move(ctrl), delayContext });
 	} else {
 		embeddedQueue_.push(buffer);
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index e26f438..ce34bb2 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -939,9 +939,12 @@  void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 		}
 	}
 
-	if (request)
+	if (request) {
 		request->_d()->metadata().set(controls::SensorTimestamp,
 					      buffer->metadata().timestamp);
+		request->_d()->metadata().set(controls::SensorSequence,
+					      static_cast<int64_t>(buffer->metadata().sequence));
+	}
 
 	/*
 	 * Queue the captured and the request buffer to the converter or Software
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 3435a76..e0b7dad 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -897,6 +897,8 @@  void UVCCameraData::imageBufferReady(FrameBuffer *buffer)
 	/* \todo Use the UVC metadata to calculate a more precise timestamp */
 	request->_d()->metadata().set(controls::SensorTimestamp,
 				      buffer->metadata().timestamp);
+	request->_d()->metadata().set(controls::SensorSequence,
+				      static_cast<int64_t>(buffer->metadata().sequence));
 
 	pipe()->completeBuffer(request, buffer);
 	pipe()->completeRequest(request);
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 01d8fb2..ff809a1 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -617,6 +617,8 @@  void VimcCameraData::imageBufferReady(FrameBuffer *buffer)
 	/* Record the sensor's timestamp in the request metadata. */
 	request->_d()->metadata().set(controls::SensorTimestamp,
 				      buffer->metadata().timestamp);
+	request->_d()->metadata().set(controls::SensorSequence,
+				      static_cast<int64_t>(buffer->metadata().sequence));
 
 	pipe->completeBuffer(request, buffer);
 	pipe->completeRequest(request);