| Message ID | 20260805151819.16382-2-ballen4705@googlemail.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
CC Naushir Patuck Please see below 2026. 08. 05. 17:18 keltezéssel, Bruce Allen írta: > Add controls::SensorSequence (int64_t, out) to report the monotonic > sequence number from the sensor-facing capture device in request > metadata, and populate it in pipeline handlers that already report > SensorTimestamp. > > Signed-off-by: Bruce Allen <ballen4705@googlemail.com> > --- > src/libcamera/control_ids_core.yaml | 29 +++++++++++++++++++ > 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 ++ > .../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, 52 insertions(+), 1 deletion(-) > > diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml > index 89991d0..bebfb49 100644 > --- a/src/libcamera/control_ids_core.yaml > +++ b/src/libcamera/control_ids_core.yaml > @@ -792,6 +792,35 @@ 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) for the frame associated with the > + request. > + > + While per-buffer FrameMetadata::sequence identifies frames in each > + completed stream, SensorSequence reflects the sensor-side capture path. > + If the value increases by more than one between consecutive completed > + requests, frames were not captured before the earlier request finished. > + This complements sequence numbers derived from request delivery and is > + intended for diagnosing frame continuity. > + > + After Camera::stop() followed by Camera::start(), SensorSequence restarts > + from 0 for the new streaming session. The first returned frame has > + SensorSequence == 0 when the first capture buffer of the session is > + completed to that request. Applications must not assume continuity of > + SensorSequence values across camera session stop/start boundaries. In https://patchwork.libcamera.org/patch/15057/#21643 it was stated Should we add that there are no guarantees about this sequence number being reset on start/stop? I'm guessing this still applies to the raspberry pi pipeline handlers? Regards, Barnabás Pőcze > + > + On successful frames where SensorTimestamp is populated, > + SensorSequence will also be populated. > + > + 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 406d683..5cf428c 100644 > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp > @@ -1783,6 +1783,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);
Hi Barnabás,
(CC Naushir)
thanks, that was incredibly fast! Regarding Naushir's earlier comment:
https://patchwork.libcamera.org/patch/15057/#21643
"Should we add that there are no guarantees about this sequence number
being reset on start/stop?"
That caution was about the kernel/driver sequence, which may not restart
at zero on STREAMON. It still applies in that sense (Raspberry Pi and
other drivers sometimes start at a non-zero V4L2 sequence).
However, for the application-visible SensorSequence value, libcamera
already initializes this. V4L2VideoDevice resets its rebase state on
every streamOn() and subtracts the first dequeued sequence so
FrameMetadata::sequence starts at 0 for each new streaming session:
https://git.libcamera.org/libcamera/libcamera.git/tree/src/libcamera/v4l2_videodevice.cpp
(See V4L2VideoDevice::streamOn() resetting firstFrame_, and
dequeueBuffer() subtracting firstFrame_ from buf.sequence. Background on
that behaviour:
https://lists.libcamera.org/pipermail/libcamera-devel/2022-June/031163.html)
The Raspberry Pi pipeline handlers (and the others in this series)
populate SensorSequence from that same buffer->metadata().sequence, so
after Camera::stop() followed by Camera::start() the capture-device
sequence DOES restart from 0 for the new session.
The remaining caveat, which is already in the v3 control docs, is only
about which request the application sees first: SensorSequence == 0 on
the first returned frame when the first capture buffer of the session is
completed to that request. Internal / freewheel buffers could mean the
first request returned to the application has SensorSequence > 0, even
though the counter has been reset for the new session.
So I believe the v3 wording is accurate for RPi as well: we do not claim
continuity across stop/start, and we do claim a session restart from 0
at the V4L2VideoDevice layer, with the first-returned-request hedge above.
Cheers,
Bruce
On 05.08.26 17:25, Barnabás Pőcze wrote:
> CC Naushir Patuck
>
> Please see below
>
> 2026. 08. 05. 17:18 keltezéssel, Bruce Allen írta:
>> Add controls::SensorSequence (int64_t, out) to report the monotonic
>> sequence number from the sensor-facing capture device in request
>> metadata, and populate it in pipeline handlers that already report
>> SensorTimestamp.
>>
>> Signed-off-by: Bruce Allen <ballen4705@googlemail.com>
>> ---
>> src/libcamera/control_ids_core.yaml | 29 +++++++++++++++++++
>> 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 ++
>> .../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, 52 insertions(+), 1 deletion(-)
>>
>> diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/
>> control_ids_core.yaml
>> index 89991d0..bebfb49 100644
>> --- a/src/libcamera/control_ids_core.yaml
>> +++ b/src/libcamera/control_ids_core.yaml
>> @@ -792,6 +792,35 @@ 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) for the frame associated
>> with the
>> + request.
>> +
>> + While per-buffer FrameMetadata::sequence identifies frames in
>> each
>> + completed stream, SensorSequence reflects the sensor-side
>> capture path.
>> + If the value increases by more than one between consecutive
>> completed
>> + requests, frames were not captured before the earlier request
>> finished.
>> + This complements sequence numbers derived from request
>> delivery and is
>> + intended for diagnosing frame continuity.
>> +
>> + After Camera::stop() followed by Camera::start(),
>> SensorSequence restarts
>> + from 0 for the new streaming session. The first returned
>> frame has
>> + SensorSequence == 0 when the first capture buffer of the
>> session is
>> + completed to that request. Applications must not assume
>> continuity of
>> + SensorSequence values across camera session stop/start
>> boundaries.
>
> In https://patchwork.libcamera.org/patch/15057/#21643 it was stated
>
> Should we add that there are no guarantees about this sequence number
> being reset on start/stop?
>
> I'm guessing this still applies to the raspberry pi pipeline handlers?
>
>
> Regards,
> Barnabás Pőcze
>
>
>> +
>> + On successful frames where SensorTimestamp is populated,
>> + SensorSequence will also be populated.
>> +
>> + 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 406d683..5cf428c 100644
>> --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp
>> +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
>> @@ -1783,6 +1783,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);
>
Hi 2026. 08. 05. 17:39 keltezéssel, Bruce Allen írta: > Hi Barnabás, > (CC Naushir) > > thanks, that was incredibly fast! Regarding Naushir's earlier comment: > > https://patchwork.libcamera.org/patch/15057/#21643 > > "Should we add that there are no guarantees about this sequence number > being reset on start/stop?" > > That caution was about the kernel/driver sequence, which may not restart at zero on STREAMON. It still applies in that sense (Raspberry Pi and other drivers sometimes start at a non-zero V4L2 sequence). > > However, for the application-visible SensorSequence value, libcamera already initializes this. V4L2VideoDevice resets its rebase state on every streamOn() and subtracts the first dequeued sequence so FrameMetadata::sequence starts at 0 for each new streaming session: > > > https://git.libcamera.org/libcamera/libcamera.git/tree/src/libcamera/v4l2_videodevice.cpp > > (See V4L2VideoDevice::streamOn() resetting firstFrame_, and dequeueBuffer() subtracting firstFrame_ from buf.sequence. Background on that behaviour: > > https://lists.libcamera.org/pipermail/libcamera-devel/2022-June/031163.html) Ahh, I see, this was added later and I completely forgot about it. > > The Raspberry Pi pipeline handlers (and the others in this series) populate SensorSequence from that same buffer->metadata().sequence, so after Camera::stop() followed by Camera::start() the capture-device sequence DOES restart from 0 for the new session. > > The remaining caveat, which is already in the v3 control docs, is only about which request the application sees first: SensorSequence == 0 on the first returned frame when the first capture buffer of the session is completed to that request. Internal / freewheel buffers could mean the first request returned to the application has SensorSequence > 0, even though the counter has been reset for the new session. > > So I believe the v3 wording is accurate for RPi as well: we do not claim > continuity across stop/start, and we do claim a session restart from 0 at the V4L2VideoDevice layer, with the first-returned-request hedge above. I feel like the wording is not too useful then. In essence it's saying that the sequence number starts at 0 except if it doesn't due to some unknowable internal implementation details. So maybe it would be better to just mention that the first sequence number after `start()` is implementation defined, and applications must be prepare to handle that. Not sure... > > Cheers, > Bruce > > > > On 05.08.26 17:25, Barnabás Pőcze wrote: >> CC Naushir Patuck >> >> Please see below >> >> 2026. 08. 05. 17:18 keltezéssel, Bruce Allen írta: >>> Add controls::SensorSequence (int64_t, out) to report the monotonic >>> sequence number from the sensor-facing capture device in request >>> metadata, and populate it in pipeline handlers that already report >>> SensorTimestamp. >>> >>> Signed-off-by: Bruce Allen <ballen4705@googlemail.com> >>> --- >>> src/libcamera/control_ids_core.yaml | 29 +++++++++++++++++++ >>> 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 ++ >>> .../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, 52 insertions(+), 1 deletion(-) >>> >>> diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/ control_ids_core.yaml >>> index 89991d0..bebfb49 100644 >>> --- a/src/libcamera/control_ids_core.yaml >>> +++ b/src/libcamera/control_ids_core.yaml >>> @@ -792,6 +792,35 @@ 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) for the frame associated with the >>> + request. >>> + >>> + While per-buffer FrameMetadata::sequence identifies frames in each >>> + completed stream, SensorSequence reflects the sensor-side capture path. >>> + If the value increases by more than one between consecutive completed >>> + requests, frames were not captured before the earlier request finished. >>> + This complements sequence numbers derived from request delivery and is >>> + intended for diagnosing frame continuity. >>> + >>> + After Camera::stop() followed by Camera::start(), SensorSequence restarts >>> + from 0 for the new streaming session. The first returned frame has >>> + SensorSequence == 0 when the first capture buffer of the session is >>> + completed to that request. Applications must not assume continuity of >>> + SensorSequence values across camera session stop/start boundaries. >> >> In https://patchwork.libcamera.org/patch/15057/#21643 it was stated >> >> Should we add that there are no guarantees about this sequence number being reset on start/stop? >> >> I'm guessing this still applies to the raspberry pi pipeline handlers? >> >> >> Regards, >> Barnabás Pőcze >> >> >>> + >>> + On successful frames where SensorTimestamp is populated, >>> + SensorSequence will also be populated. >>> + >>> + 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 406d683..5cf428c 100644 >>> --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp >>> +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp >>> @@ -1783,6 +1783,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); >> >
Hi Barnabás, >> However, for the application-visible SensorSequence value, libcamera >> already initializes this. V4L2VideoDevice resets its rebase state on >> every streamOn() and subtracts the first dequeued sequence so >> FrameMetadata::sequence starts at 0 for each new streaming session: >> >> >> https://git.libcamera.org/libcamera/libcamera.git/tree/src/libcamera/ >> v4l2_videodevice.cpp >> >> (See V4L2VideoDevice::streamOn() resetting firstFrame_, and >> dequeueBuffer() subtracting firstFrame_ from buf.sequence. Background >> on that behaviour: >> >> https://lists.libcamera.org/pipermail/libcamera-devel/2022- >> June/031163.html) > > Ahh, I see, this was added later and I completely forgot about it. (:-) >> So I believe the v3 wording is accurate for RPi as well: we do not claim >> continuity across stop/start, and we do claim a session restart from 0 >> at the V4L2VideoDevice layer, with the first-returned-request hedge >> above. > I feel like the wording is not too useful then. In essence it's saying that > the sequence number starts at 0 except if it doesn't due to some unknowable > internal implementation details. So maybe it would be better to just > mention > that the first sequence number after `start()` is implementation defined, > and applications must be prepare to handle that. Not sure... Let me argue that this wording is useful. In almost all cases, SensorSequence will start at zero. In the rare cases where it does not, it will likely start at one. So I think it is worth describing the usual case. If SensorSequence starts at a *large* value, that is an important clue that s*omething* is going on which needs investigation. We need to describe the expected/usual behavior in the docs, so that the user can look out for unusual behavior. (Having said this, I don't care much. I just don't want to have to keep patching libcamera to get SensorSequence. So if you ask me to trim the docs as you describe above, or just do it yourself, fine with me.) Cheers, Bruce
diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml index 89991d0..bebfb49 100644 --- a/src/libcamera/control_ids_core.yaml +++ b/src/libcamera/control_ids_core.yaml @@ -792,6 +792,35 @@ 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) for the frame associated with the + request. + + While per-buffer FrameMetadata::sequence identifies frames in each + completed stream, SensorSequence reflects the sensor-side capture path. + If the value increases by more than one between consecutive completed + requests, frames were not captured before the earlier request finished. + This complements sequence numbers derived from request delivery and is + intended for diagnosing frame continuity. + + After Camera::stop() followed by Camera::start(), SensorSequence restarts + from 0 for the new streaming session. The first returned frame has + SensorSequence == 0 when the first capture buffer of the session is + completed to that request. Applications must not assume continuity of + SensorSequence values across camera session stop/start boundaries. + + On successful frames where SensorTimestamp is populated, + SensorSequence will also be populated. + + 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 406d683..5cf428c 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -1783,6 +1783,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);
Add controls::SensorSequence (int64_t, out) to report the monotonic sequence number from the sensor-facing capture device in request metadata, and populate it in pipeline handlers that already report SensorTimestamp. Signed-off-by: Bruce Allen <ballen4705@googlemail.com> --- src/libcamera/control_ids_core.yaml | 29 +++++++++++++++++++ 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 ++ .../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, 52 insertions(+), 1 deletion(-)