diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 6e039bf3..004a8d53 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -181,6 +181,54 @@ LOG_DEFINE_CATEGORY(SimplePipeline)
 
 class SimplePipelineHandler;
 
+struct SimpleFrameInfo {
+	SimpleFrameInfo(uint32_t f, Request *r)
+		: frame(f), request(r)
+	{
+	}
+
+	uint32_t frame;
+	Request *request;
+};
+
+class SimpleFrames
+{
+public:
+	void create(Request *request);
+	void destroy(uint32_t frame);
+	void clear();
+
+	SimpleFrameInfo *find(uint32_t frame);
+
+private:
+	std::map<uint32_t, SimpleFrameInfo> frameInfo_;
+};
+
+void SimpleFrames::create(Request *request)
+{
+	const uint32_t frame = request->sequence();
+	auto [it, inserted] = frameInfo_.try_emplace(frame, frame, request);
+	ASSERT(inserted);
+}
+
+void SimpleFrames::destroy(uint32_t frame)
+{
+	frameInfo_.erase(frame);
+}
+
+void SimpleFrames::clear()
+{
+	frameInfo_.clear();
+}
+
+SimpleFrameInfo *SimpleFrames::find(uint32_t frame)
+{
+	auto info = frameInfo_.find(frame);
+	if (info == frameInfo_.end())
+		return nullptr;
+	return &info->second;
+}
+
 struct SimplePipelineInfo {
 	const char *driver;
 	/*
@@ -293,11 +341,13 @@ public:
 
 	std::unique_ptr<Converter> converter_;
 	std::unique_ptr<SoftwareIsp> swIsp_;
+	SimpleFrames frameInfo_;
 
 private:
 	void tryPipeline(unsigned int code, const Size &size);
 	static std::vector<const MediaPad *> routedSourcePads(MediaPad *sink);
 
+	void completeRequest(Request *request);
 	void conversionInputDone(FrameBuffer *buffer);
 	void conversionOutputDone(FrameBuffer *buffer);
 
@@ -785,7 +835,7 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 			/* No conversion, just complete the request. */
 			Request *request = buffer->request();
 			pipe->completeBuffer(request, buffer);
-			pipe->completeRequest(request);
+			completeRequest(request);
 			return;
 		}
 
@@ -803,7 +853,7 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 		const RequestOutputs &outputs = conversionQueue_.front();
 		for (auto &[stream, buf] : outputs.outputs)
 			pipe->completeBuffer(outputs.request, buf);
-		pipe->completeRequest(outputs.request);
+		completeRequest(outputs.request);
 		conversionQueue_.pop();
 
 		return;
@@ -861,7 +911,7 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 
 	/* Otherwise simply complete the request. */
 	pipe->completeBuffer(request, buffer);
-	pipe->completeRequest(request);
+	completeRequest(request);
 }
 
 void SimpleCameraData::clearIncompleteRequests()
@@ -872,6 +922,18 @@ void SimpleCameraData::clearIncompleteRequests()
 	}
 }
 
+void SimpleCameraData::completeRequest(Request *request)
+{
+	SimpleFrameInfo *info = frameInfo_.find(request->sequence());
+	if (!info) {
+		/* Something is really wrong, let's return. */
+		return;
+	}
+
+	frameInfo_.destroy(info->frame);
+	pipe()->completeRequest(request);
+}
+
 void SimpleCameraData::conversionInputDone(FrameBuffer *buffer)
 {
 	/* Queue the input buffer back for capture. */
@@ -885,7 +947,7 @@ void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)
 	/* Complete the buffer and the request. */
 	Request *request = buffer->request();
 	if (pipe->completeBuffer(request, buffer))
-		pipe->completeRequest(request);
+		completeRequest(request);
 }
 
 void SimpleCameraData::ispStatsReady(uint32_t frame, uint32_t bufferId)
@@ -1398,6 +1460,7 @@ void SimplePipelineHandler::stopDevice(Camera *camera)
 
 	video->bufferReady.disconnect(data, &SimpleCameraData::imageBufferReady);
 
+	data->frameInfo_.clear();
 	data->clearIncompleteRequests();
 	data->conversionBuffers_.clear();
 
@@ -1426,6 +1489,7 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)
 		}
 	}
 
+	data->frameInfo_.create(request);
 	if (data->useConversion_) {
 		data->conversionQueue_.push({ request, std::move(buffers) });
 		if (data->swIsp_)
