@@ -727,15 +727,19 @@ int PipelineHandlerBase::start(Camera *camera, const ControlList *controls)
/* A good moment to add an initial clock sample. */
data->wallClockRecovery_.addSample();
- /*
- * Reset the delayed controls with the gain and exposure values set by
- * the IPA.
- */
- data->delayedCtrls_->reset(0);
- data->state_ = CameraData::State::Idle;
+ /* A memory camera wouldn't have a front end device, so you would skip this. */
+ if (data->frontendDevice()) {
+ /*
+ * Reset the delayed controls with the gain and exposure values set by
+ * the IPA.
+ */
+ data->delayedCtrls_->reset(0);
+
+ /* Enable SOF event generation. */
+ data->frontendDevice()->setFrameStartEnabled(true);
+ }
- /* Enable SOF event generation. */
- data->frontendDevice()->setFrameStartEnabled(true);
+ data->state_ = CameraData::State::Idle;
data->platformStart();
@@ -762,7 +766,8 @@ void PipelineHandlerBase::stopDevice(Camera *camera)
stream->dev()->streamOff();
/* Disable SOF event generation. */
- data->frontendDevice()->setFrameStartEnabled(false);
+ if (data->frontendDevice())
+ data->frontendDevice()->setFrameStartEnabled(false);
data->clearIncompleteRequests();
@@ -780,6 +780,7 @@ private:
void prepareCfe();
void prepareBe(uint32_t bufferId, bool stitchSwapBuffers);
+ void runMemoryCamera();
void tryRunPipeline() override;
struct CfeJob {
@@ -1243,7 +1244,7 @@ PipelineHandlerPiSP::platformCreateCamera(std::unique_ptr<RPi::CameraData> &came
/* Wire up all the IPA connections. */
data->ipa_->prepareIspComplete.connect(data, &PiSPCameraData::prepareIspComplete);
- data->ipa_->processStatsComplete.connect(data, &PiSPCameraData::processStatsComplete);
+ /* We don't want the processStatsComplete callback, though, for memory cams. */
/* Create and register the camera. */
const std::string &id = cfe ? data->sensor_->id() : "memory";
@@ -1785,8 +1786,11 @@ void PiSPCameraData::platformStart()
cfeJobQueue_ = {};
- for (unsigned int i = 0; i < config_.numCfeConfigQueue; i++)
- prepareCfe();
+ /* A memory camera wouldn't be using the CFE. */
+ if (cfe_[Cfe::Output0].dev()) {
+ for (unsigned int i = 0; i < config_.numCfeConfigQueue; i++)
+ prepareCfe();
+ }
/* Clear the debug dump file history. */
last_dump_file_.clear();
@@ -1890,8 +1894,12 @@ void PiSPCameraData::beInputDequeue(FrameBuffer *buffer)
<< ", buffer id " << cfe_[Cfe::Output0].getBufferId(buffer)
<< ", timestamp: " << buffer->metadata().timestamp;
- /* The ISP input buffer gets re-queued into CFE. */
- handleStreamBuffer(buffer, &cfe_[Cfe::Output0]);
+ /*
+ * The ISP input buffer gets re-queued into CFE (but not for memory cameras
+ * that aren't using the CFE).
+ */
+ if (cfe_[Cfe::Output0].dev())
+ handleStreamBuffer(buffer, &cfe_[Cfe::Output0]);
handleState();
}
@@ -2361,7 +2369,15 @@ void PiSPCameraData::prepareCfe()
void PiSPCameraData::prepareBe(uint32_t bufferId, bool stitchSwapBuffers)
{
- FrameBuffer *buffer = cfe_[Cfe::Output0].getBuffers().at(bufferId).buffer;
+ FrameBuffer *buffer;
+ if (!sensor_->isMemory())
+ buffer = cfe_[Cfe::Output0].getBuffers().at(bufferId).buffer;
+ else {
+ /* Memory camera. Back end input buffer is in the request. */
+ Request *request = requestQueue_.front();
+ const libcamera::Stream *rawStream = &isp_[Isp::Input];
+ buffer = request->findBuffer(rawStream);
+ }
LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << bufferId
<< ", timestamp: " << buffer->metadata().timestamp;
@@ -2412,8 +2428,33 @@ void PiSPCameraData::prepareBe(uint32_t bufferId, bool stitchSwapBuffers)
isp_[Isp::Config].queueBuffer(config.buffer);
}
+void PiSPCameraData::runMemoryCamera()
+{
+ Request *request = requestQueue_.front();
+
+ applyScalerCrop(request->controls());
+
+ request->metadata().clear();
+
+ state_ = State::Busy;
+
+ ipa::RPi::PrepareParams params;
+ params.buffers.embedded = 0;
+ params.ipaContext = requestQueue_.front()->sequence();
+ params.requestControls = request->controls();
+
+ LOG(RPI, Debug) << "runMemoryCamera: call prepareIsp";
+ ipa_->prepareIsp(params);
+}
+
void PiSPCameraData::tryRunPipeline()
{
+ if (state_ == State::Idle && !requestQueue_.empty() && sensor_->isMemory()) {
+ runMemoryCamera();
+
+ return;
+ }
+
/* If any of our request or buffer queues are empty, we cannot proceed. */
if (state_ != State::Idle || requestQueue_.empty() || !cfeJobComplete())
return;
This is the final commit in the set to support memory cameras (Bayer reprocessing). There are some small fix-ups to allow the camera system to start without the CFE being involved, and we add runMemoryCamera() which pushs a buffer from the request into the Back End ISP. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> --- .../pipeline/rpi/common/pipeline_base.cpp | 23 ++++---- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 53 ++++++++++++++++--- 2 files changed, 61 insertions(+), 15 deletions(-)