summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libcamera/pipeline/raspberrypi/raspberrypi.cpp176
1 files changed, 88 insertions, 88 deletions
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index a80413f9..66b483f7 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -212,9 +212,7 @@ public:
private:
void checkRequestCompleted();
void tryRunPipeline();
- void tryFlushQueues();
- FrameBuffer *updateQueue(std::queue<FrameBuffer *> &q, uint64_t timestamp,
- RPi::Stream *stream);
+ bool findMatchingBuffers(FrameBuffer *&bayerBuffer, FrameBuffer *&embeddedBuffer);
unsigned int ispOutputCount_;
};
@@ -1554,7 +1552,6 @@ void RPiCameraData::handleState()
case State::Idle:
tryRunPipeline();
- tryFlushQueues();
break;
}
}
@@ -1605,41 +1602,8 @@ void RPiCameraData::tryRunPipeline()
bayerQueue_.empty() || embeddedQueue_.empty())
return;
- /* Start with the front of the bayer buffer queue. */
- bayerBuffer = bayerQueue_.front();
-
- /*
- * Find the embedded data buffer with a matching timestamp to pass to
- * the IPA. Any embedded buffers with a timestamp lower than the
- * current bayer buffer will be removed and re-queued to the driver.
- */
- embeddedBuffer = updateQueue(embeddedQueue_, bayerBuffer->metadata().timestamp,
- &unicam_[Unicam::Embedded]);
-
- if (!embeddedBuffer) {
- LOG(RPI, Debug) << "Could not find matching embedded buffer";
-
- /*
- * Look the other way, try to match a bayer buffer with the
- * first embedded buffer in the queue. This will also do some
- * housekeeping on the bayer image queue - clear out any
- * buffers that are older than the first buffer in the embedded
- * queue.
- *
- * But first check if the embedded queue has emptied out.
- */
- if (embeddedQueue_.empty())
- return;
-
- embeddedBuffer = embeddedQueue_.front();
- bayerBuffer = updateQueue(bayerQueue_, embeddedBuffer->metadata().timestamp,
- &unicam_[Unicam::Image]);
-
- if (!bayerBuffer) {
- LOG(RPI, Debug) << "Could not find matching bayer buffer - ending.";
- return;
- }
- }
+ if (!findMatchingBuffers(bayerBuffer, embeddedBuffer))
+ return;
/* Take the first request from the queue and action the IPA. */
Request *request = requestQueue_.front();
@@ -1682,10 +1646,6 @@ void RPiCameraData::tryRunPipeline()
op.controls = { request->controls() };
ipa_->processEvent(op);
- /* Ready to use the buffers, pop them off the queue. */
- bayerQueue_.pop();
- embeddedQueue_.pop();
-
/* Set our state to say the pipeline is active. */
state_ = State::Busy;
@@ -1702,62 +1662,102 @@ void RPiCameraData::tryRunPipeline()
ipa_->processEvent(op);
}
-void RPiCameraData::tryFlushQueues()
+bool RPiCameraData::findMatchingBuffers(FrameBuffer *&bayerBuffer, FrameBuffer *&embeddedBuffer)
{
- /*
- * It is possible for us to end up in a situation where all available
- * Unicam buffers have been dequeued but do not match. This can happen
- * when the system is heavily loaded and we get out of lock-step with
- * the two channels.
- *
- * In such cases, the best thing to do is the re-queue all the buffers
- * and give a chance for the hardware to return to lock-step. We do have
- * to drop all interim frames.
- */
- if (unicam_[Unicam::Image].getBuffers().size() == bayerQueue_.size() &&
- unicam_[Unicam::Embedded].getBuffers().size() == embeddedQueue_.size()) {
- /* This cannot happen when Unicam streams are external. */
- assert(!unicam_[Unicam::Image].isExternal());
+ unsigned int embeddedRequeueCount = 0, bayerRequeueCount = 0;
- LOG(RPI, Warning) << "Flushing all buffer queues!";
-
- while (!bayerQueue_.empty()) {
- unicam_[Unicam::Image].queueBuffer(bayerQueue_.front());
- bayerQueue_.pop();
- }
+ /* Loop until we find a matching bayer and embedded data buffer. */
+ while (!bayerQueue_.empty()) {
+ /* Start with the front of the bayer queue. */
+ bayerBuffer = bayerQueue_.front();
+ /*
+ * Find the embedded data buffer with a matching timestamp to pass to
+ * the IPA. Any embedded buffers with a timestamp lower than the
+ * current bayer buffer will be removed and re-queued to the driver.
+ */
+ uint64_t ts = bayerBuffer->metadata().timestamp;
+ embeddedBuffer = nullptr;
while (!embeddedQueue_.empty()) {
- unicam_[Unicam::Embedded].queueBuffer(embeddedQueue_.front());
- embeddedQueue_.pop();
+ FrameBuffer *b = embeddedQueue_.front();
+ if (!unicam_[Unicam::Embedded].isExternal() && b->metadata().timestamp < ts) {
+ embeddedQueue_.pop();
+ unicam_[Unicam::Embedded].queueBuffer(b);
+ embeddedRequeueCount++;
+ LOG(RPI, Warning) << "Dropping unmatched input frame in stream "
+ << unicam_[Unicam::Embedded].name();
+ } else if (unicam_[Unicam::Embedded].isExternal() || b->metadata().timestamp == ts) {
+ /* We pop the item from the queue lower down. */
+ embeddedBuffer = b;
+ break;
+ } else {
+ break; /* Only higher timestamps from here. */
+ }
}
- }
-}
-FrameBuffer *RPiCameraData::updateQueue(std::queue<FrameBuffer *> &q, uint64_t timestamp,
- RPi::Stream *stream)
-{
- /*
- * If the unicam streams are external (both have be to the same), then we
- * can only return out the top buffer in the queue, and assume they have
- * been synced by queuing at the same time. We cannot drop these frames,
- * as they may have been provided externally.
- */
- while (!q.empty()) {
- FrameBuffer *b = q.front();
- if (!stream->isExternal() && b->metadata().timestamp < timestamp) {
- q.pop();
- stream->queueBuffer(b);
+ if (!embeddedBuffer) {
+ LOG(RPI, Debug) << "Could not find matching embedded buffer";
+
+ /*
+ * If we have requeued all available embedded data buffers in this loop,
+ * then we are fully out of sync, so might as well requeue all the pending
+ * bayer buffers.
+ */
+ if (embeddedRequeueCount == unicam_[Unicam::Embedded].getBuffers().size()) {
+ /* The embedded queue must be empty at this point! */
+ ASSERT(embeddedQueue_.empty());
+
+ LOG(RPI, Warning) << "Flushing bayer stream!";
+ while (!bayerQueue_.empty()) {
+ unicam_[Unicam::Image].queueBuffer(bayerQueue_.front());
+ bayerQueue_.pop();
+ }
+ return false;
+ }
+
+ /*
+ * Not found a matching embedded buffer for the bayer buffer in
+ * the front of the queue. This buffer is now orphaned, so requeue
+ * it back to the device.
+ */
+ unicam_[Unicam::Image].queueBuffer(bayerQueue_.front());
+ bayerQueue_.pop();
+ bayerRequeueCount++;
LOG(RPI, Warning) << "Dropping unmatched input frame in stream "
- << stream->name();
- } else if (stream->isExternal() || b->metadata().timestamp == timestamp) {
- /* The calling function will pop the item from the queue. */
- return b;
+ << unicam_[Unicam::Image].name();
+
+ /*
+ * Similar to the above, if we have requeued all available bayer buffers in
+ * the loop, then we are fully out of sync, so might as well requeue all the
+ * pending embedded data buffers.
+ */
+ if (bayerRequeueCount == unicam_[Unicam::Image].getBuffers().size()) {
+ /* The embedded queue must be empty at this point! */
+ ASSERT(bayerQueue_.empty());
+
+ LOG(RPI, Warning) << "Flushing embedded data stream!";
+ while (!embeddedQueue_.empty()) {
+ unicam_[Unicam::Embedded].queueBuffer(embeddedQueue_.front());
+ embeddedQueue_.pop();
+ }
+ return false;
+ }
+
+ /* If the embedded queue has become empty, we cannot do any more. */
+ if (embeddedQueue_.empty())
+ return false;
} else {
- break; /* Only higher timestamps from here. */
+ /*
+ * We have found a matching bayer and embedded data buffer, so
+ * nothing more to do apart from popping the buffers from the queue.
+ */
+ bayerQueue_.pop();
+ embeddedQueue_.pop();
+ return true;
}
}
- return nullptr;
+ return false;
}
REGISTER_PIPELINE_HANDLER(PipelineHandlerRPi)