@@ -83,12 +83,14 @@ public:
Signal<FrameBuffer *> inputBufferReady;
Signal<FrameBuffer *> outputBufferReady;
Signal<uint32_t, uint32_t> ispStatsReady;
+ Signal<uint32_t, const ControlList &> metadataReady;
Signal<const ControlList &> setSensorControls;
private:
void saveIspParams();
void setSensorCtrls(const ControlList &sensorControls);
void statsReady(uint32_t frame, uint32_t bufferId);
+ void saveMetadata(uint32_t frame, const ControlList &metadata);
void inputReady(FrameBuffer *input);
void outputReady(FrameBuffer *output);
@@ -33,4 +33,5 @@ interface IPASoftInterface {
interface IPASoftEventInterface {
setSensorControls(libcamera.ControlList sensorControls);
setIspParams();
+ metadataReady(uint32 frame, libcamera.ControlList metadata);
};
@@ -295,15 +295,10 @@ void IPASoftSimple::processStats(const uint32_t frame,
int32_t again = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
frameContext.sensor.gain = camHelper_ ? camHelper_->gain(again) : again;
- /*
- * Software ISP currently does not produce any metadata. Use an empty
- * ControlList for now.
- *
- * \todo Implement proper metadata handling
- */
ControlList metadata(controls::controls);
for (auto const &algo : algorithms())
algo->process(context_, frame, frameContext, stats_, metadata);
+ metadataReady.emit(frame, metadata);
/* Sanity check */
if (!sensorControls.contains(V4L2_CID_EXPOSURE) ||
@@ -184,6 +184,7 @@ class SimplePipelineHandler;
struct SimpleFrameInfo {
uint32_t frame;
Request *request;
+ bool metadataProcessed;
};
class SimpleFrames
@@ -206,6 +207,7 @@ void SimpleFrames::create(Request *request)
SimpleFrameInfo *info = new SimpleFrameInfo;
info->frame = frame;
info->request = request;
+ info->metadataProcessed = false;
frameInfo_[frame] = info;
}
@@ -363,11 +365,12 @@ private:
void tryPipeline(unsigned int code, const Size &size);
static std::vector<const MediaPad *> routedSourcePads(MediaPad *sink);
- void completeRequest(Request *request);
+ void completeRequest(Request *request, bool checkCompleted);
void conversionInputDone(FrameBuffer *buffer);
void conversionOutputDone(FrameBuffer *buffer);
void ispStatsReady(uint32_t frame, uint32_t bufferId);
+ void metadataReady(uint32_t frame, const ControlList &metadata);
void setSensorControls(const ControlList &sensorControls);
};
@@ -620,6 +623,7 @@ int SimpleCameraData::init()
});
swIsp_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone);
swIsp_->ispStatsReady.connect(this, &SimpleCameraData::ispStatsReady);
+ swIsp_->metadataReady.connect(this, &SimpleCameraData::metadataReady);
swIsp_->setSensorControls.connect(this, &SimpleCameraData::setSensorControls);
}
}
@@ -865,7 +869,7 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
/* No conversion, just complete the request. */
Request *request = buffer->request();
pipe->completeBuffer(request, buffer);
- completeRequest(request);
+ completeRequest(request, false);
return;
}
@@ -883,7 +887,7 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
const RequestOutputs &outputs = conversionQueue_.front();
for (auto &[stream, buf] : outputs.outputs)
pipe->completeBuffer(outputs.request, buf);
- completeRequest(outputs.request);
+ completeRequest(outputs.request, false);
conversionQueue_.pop();
return;
@@ -941,7 +945,7 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
/* Otherwise simply complete the request. */
pipe->completeBuffer(request, buffer);
- completeRequest(request);
+ completeRequest(request, false);
}
void SimpleCameraData::clearIncompleteRequests()
@@ -952,11 +956,17 @@ void SimpleCameraData::clearIncompleteRequests()
}
}
-void SimpleCameraData::completeRequest(Request *request)
+void SimpleCameraData::completeRequest(Request *request, bool checkCompleted)
{
+ if (checkCompleted && request->hasPendingBuffers())
+ return;
+
SimpleFrameInfo *info = frameInfo_.find(request);
- if (info)
+ if (info) {
+ if (checkCompleted && !info->metadataProcessed)
+ return;
frameInfo_.destroy(info->frame);
+ }
pipe()->completeRequest(request);
}
@@ -973,7 +983,7 @@ void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)
/* Complete the buffer and the request. */
Request *request = buffer->request();
if (pipe->completeBuffer(request, buffer))
- completeRequest(request);
+ completeRequest(request, true);
}
void SimpleCameraData::ispStatsReady(uint32_t frame, uint32_t bufferId)
@@ -982,6 +992,17 @@ void SimpleCameraData::ispStatsReady(uint32_t frame, uint32_t bufferId)
delayedCtrls_->get(frame));
}
+void SimpleCameraData::metadataReady(uint32_t frame, const ControlList &metadata)
+{
+ SimpleFrameInfo *info = frameInfo_.find(frame);
+ if (!info)
+ return;
+
+ info->request->metadata().merge(metadata);
+ info->metadataProcessed = true;
+ completeRequest(info->request, true);
+}
+
void SimpleCameraData::setSensorControls(const ControlList &sensorControls)
{
delayedCtrls_->push(sensorControls);
@@ -51,6 +51,11 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)
* \brief A signal emitted when the statistics for IPA are ready
*/
+/**
+ * \var SoftwareIsp::metadataReady
+ * \brief A signal emitted when the metadata for IPA are ready
+ */
+
/**
* \var SoftwareIsp::setSensorControls
* \brief A signal emitted when the values to write to the sensor controls are
@@ -136,6 +141,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,
}
ipa_->setIspParams.connect(this, &SoftwareIsp::saveIspParams);
+ ipa_->metadataReady.connect(this, &SoftwareIsp::saveMetadata);
ipa_->setSensorControls.connect(this, &SoftwareIsp::setSensorCtrls);
debayer_->moveToThread(&ispWorkerThread_);
@@ -357,6 +363,11 @@ void SoftwareIsp::statsReady(uint32_t frame, uint32_t bufferId)
ispStatsReady.emit(frame, bufferId);
}
+void SoftwareIsp::saveMetadata(uint32_t frame, const ControlList &metadata)
+{
+ metadataReady.emit(frame, metadata);
+}
+
void SoftwareIsp::inputReady(FrameBuffer *input)
{
inputBufferReady.emit(input);