[libcamera-devel] [PATCH 13/13] libcamera: pipeline: rkisp1: Attach to an IPA

Niklas Söderlund niklas.soderlund at ragnatech.se
Wed Aug 28 03:17:10 CEST 2019


Add the plumbing to the pipeline handler to interact with an IPA module.
To support this parameter and statistic buffers needs to be associated
with every request queued. The parameters buffer needs to be passed to
the IPA before any buffer in the request is queued to hardware and the
statistics buffer needs to be passed to the IPA for inspection as soon
as it's ready.

This change makes the usage of an IPA module mandatory for the rkisp1
pipeline.

Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
---
 src/libcamera/pipeline/rkisp1/rkisp1.cpp | 263 ++++++++++++++++++++++-
 1 file changed, 252 insertions(+), 11 deletions(-)

diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index de4ab523d0e4fe36..80d4832c49ebe78c 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -9,7 +9,7 @@
 #include <array>
 #include <iomanip>
 #include <memory>
-#include <vector>
+#include <queue>
 
 #include <linux/media-bus-format.h>
 
@@ -34,7 +34,7 @@ class RkISP1CameraData : public CameraData
 {
 public:
 	RkISP1CameraData(PipelineHandler *pipe)
-		: CameraData(pipe), sensor_(nullptr)
+		: CameraData(pipe, 1, 1), sensor_(nullptr)
 	{
 	}
 
@@ -43,8 +43,21 @@ public:
 		delete sensor_;
 	}
 
+	int initCameraData() override;
+
 	Stream stream_;
 	CameraSensor *sensor_;
+
+private:
+	void updateSensor(V4L2ControlList controls);
+	void queueRequestHardware(const void *cookie);
+};
+
+class RkISP1RequestData : public RequestData
+{
+public:
+	Buffer *stat;
+	Buffer *param;
 };
 
 class RkISP1CameraConfiguration : public CameraConfiguration
@@ -99,18 +112,69 @@ private:
 			PipelineHandler::cameraData(camera));
 	}
 
+	friend RkISP1CameraData;
+
 	int initLinks();
 	int createCamera(MediaEntity *sensor);
+	void tryCompleteRequest(Request *request);
 	void bufferReady(Buffer *buffer);
+	void statReady(Buffer *buffer);
+	void paramReady(Buffer *buffer);
 
 	MediaDevice *media_;
 	V4L2Subdevice *dphy_;
 	V4L2Subdevice *isp_;
 	V4L2VideoDevice *video_;
+	V4L2VideoDevice *stat_;
+	V4L2VideoDevice *param_;
+
+	BufferPool statPool_;
+	BufferPool paramPool_;
+
+	std::queue<Buffer *> statBuffers_;
+	std::queue<Buffer *> paramBuffers_;
 
 	Camera *activeCamera_;
 };
 
+int RkISP1CameraData::initCameraData()
+{
+	ipa_->updateSensor.connect(this,
+				   &RkISP1CameraData::updateSensor);
+	ipa_->queueRequest.connect(this,
+				   &RkISP1CameraData::queueRequestHardware);
+	return 0;
+}
+
+void RkISP1CameraData::updateSensor(V4L2ControlList controls)
+{
+	sensor_->setControls(&controls);
+}
+
+void RkISP1CameraData::queueRequestHardware(const void *cookie)
+{
+	/* Translate cookie to request. */
+	Request *request = reinterpret_cast<Request *>(const_cast<void *>(cookie));
+	PipelineHandlerRkISP1 *pipe =
+		static_cast<PipelineHandlerRkISP1 *>(pipe_);
+	RkISP1RequestData *reqData =
+		static_cast<RkISP1RequestData *>(request->data);
+	Buffer *buffer = request->findBuffer(&stream_);
+	int ret;
+
+	ret = pipe->param_->queueBuffer(reqData->param);
+	if (ret < 0)
+		LOG(RkISP1, Error) << "Failed to queue paramaeters";
+
+	ret = pipe->stat_->queueBuffer(reqData->stat);
+	if (ret < 0)
+		LOG(RkISP1, Error) << "Failed to queue statistics";
+
+	ret = pipe->video_->queueBuffer(buffer);
+	if (ret < 0)
+		LOG(RkISP1, Error) << "Failed to queue video";
+}
+
 RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera,
 						     RkISP1CameraData *data)
 	: CameraConfiguration()
@@ -202,12 +266,14 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()
 
 PipelineHandlerRkISP1::PipelineHandlerRkISP1(CameraManager *manager)
 	: PipelineHandler(manager), dphy_(nullptr), isp_(nullptr),
-	  video_(nullptr)
+	  video_(nullptr), stat_(nullptr), param_(nullptr)
 {
 }
 
 PipelineHandlerRkISP1::~PipelineHandlerRkISP1()
 {
+	delete param_;
+	delete stat_;
 	delete video_;
 	delete isp_;
 	delete dphy_;
@@ -317,6 +383,20 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)
 	if (ret)
 		return ret;
 
+	V4L2DeviceFormat statFormat = {};
+	statFormat.fourcc = V4L2_META_FMT_RK_ISP1_STAT_3A;
+
+	ret = stat_->setFormat(&statFormat);
+	if (ret)
+		return ret;
+
+	V4L2DeviceFormat paramFormat = {};
+	paramFormat.fourcc = V4L2_META_FMT_RK_ISP1_PARAMS;
+
+	ret = param_->setFormat(&paramFormat);
+	if (ret)
+		return ret;
+
 	if (outputFormat.size != cfg.size ||
 	    outputFormat.fourcc != cfg.pixelFormat) {
 		LOG(RkISP1, Error)
@@ -333,30 +413,92 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera,
 					   const std::set<Stream *> &streams)
 {
 	Stream *stream = *streams.begin();
+	int ret;
 
 	if (stream->memoryType() == InternalMemory)
-		return video_->exportBuffers(&stream->bufferPool());
+		ret = video_->exportBuffers(&stream->bufferPool());
 	else
-		return video_->importBuffers(&stream->bufferPool());
+		ret = video_->importBuffers(&stream->bufferPool());
+
+	if (ret)
+		return ret;
+
+	statPool_.createBuffers(stream->configuration().bufferCount);
+	ret = stat_->exportBuffers(&statPool_);
+	if (ret) {
+		video_->releaseBuffers();
+		return ret;
+	}
+
+	paramPool_.createBuffers(stream->configuration().bufferCount);
+	ret = param_->exportBuffers(&paramPool_);
+	if (ret) {
+		stat_->releaseBuffers();
+		video_->releaseBuffers();
+		return ret;
+	}
+
+	for (unsigned int i = 0; i < stream->configuration().bufferCount; i++) {
+		statBuffers_.push(new Buffer(i));
+		paramBuffers_.push(new Buffer(i));
+	}
+
+	return ret;
 }
 
 int PipelineHandlerRkISP1::freeBuffers(Camera *camera,
 				       const std::set<Stream *> &streams)
 {
+	while (!paramBuffers_.empty())
+		paramBuffers_.pop();
+
+	while (!statBuffers_.empty())
+		statBuffers_.pop();
+
+	if (param_->releaseBuffers())
+		LOG(RkISP1, Error) << "Failed to release parameters buffers";
+
+	if (stat_->releaseBuffers())
+		LOG(RkISP1, Error) << "Failed to release stat buffers";
+
 	if (video_->releaseBuffers())
-		LOG(RkISP1, Error) << "Failed to release buffers";
+		LOG(RkISP1, Error) << "Failed to release video buffers";
 
 	return 0;
 }
 
 int PipelineHandlerRkISP1::start(Camera *camera)
 {
+	RkISP1CameraData *data = cameraData(camera);
 	int ret;
 
+	ret = data->ipa_->initSensor(data->sensor_->controls());
+	if (ret)
+		return ret;
+
+	ret = param_->streamOn();
+	if (ret) {
+		LOG(RkISP1, Error)
+			<< "Failed to start parameters " << camera->name();
+		return ret;
+	}
+
+	ret = stat_->streamOn();
+	if (ret) {
+		param_->streamOff();
+		LOG(RkISP1, Error)
+			<< "Failed to start statisticis " << camera->name();
+		return ret;
+	}
+
 	ret = video_->streamOn();
-	if (ret)
+	if (ret) {
+		param_->streamOff();
+		stat_->streamOff();
+
 		LOG(RkISP1, Error)
 			<< "Failed to start camera " << camera->name();
+	}
 
 	activeCamera_ = camera;
 
@@ -372,6 +514,16 @@ void PipelineHandlerRkISP1::stop(Camera *camera)
 		LOG(RkISP1, Warning)
 			<< "Failed to stop camera " << camera->name();
 
+	ret = stat_->streamOff();
+	if (ret)
+		LOG(RkISP1, Warning)
+			<< "Failed to stop statisticis " << camera->name();
+
+	ret = param_->streamOff();
+	if (ret)
+		LOG(RkISP1, Warning)
+			<< "Failed to stop parameters " << camera->name();
+
 	activeCamera_ = nullptr;
 }
 
@@ -380,6 +532,16 @@ int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request)
 	RkISP1CameraData *data = cameraData(camera);
 	Stream *stream = &data->stream_;
 
+	if (paramBuffers_.empty()) {
+		LOG(RkISP1, Error) << "Parameters buffer underrun";
+		return -ENOENT;
+	}
+
+	if (statBuffers_.empty()) {
+		LOG(RkISP1, Error) << "Statisitc buffer underrun";
+		return -ENOENT;
+	}
+
 	Buffer *buffer = request->findBuffer(stream);
 	if (!buffer) {
 		LOG(RkISP1, Error)
@@ -387,12 +549,24 @@ int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request)
 		return -ENOENT;
 	}
 
-	int ret = video_->queueBuffer(buffer);
-	if (ret < 0)
-		return ret;
+	RkISP1RequestData *reqData = new RkISP1RequestData();
+	request->data = reqData;
+	reqData->param = paramBuffers_.front();
+	reqData->stat = statBuffers_.front();
+
+	prepareInternalBuffer(reqData->param, request,
+			      &paramPool_.buffers()[reqData->param->index()]);
+	prepareInternalBuffer(reqData->stat, request,
+			      &statPool_.buffers()[reqData->stat->index()]);
+
+	paramBuffers_.pop();
+	statBuffers_.pop();
 
 	PipelineHandler::queueRequest(camera, request);
 
+	data->ipa_->processRequest(request, request->controls(),
+				   *reqData->param);
+
 	return 0;
 }
 
@@ -435,6 +609,10 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)
 	std::unique_ptr<RkISP1CameraData> data =
 		utils::make_unique<RkISP1CameraData>(this);
 
+	data->controlInfo_.emplace(std::piecewise_construct,
+				   std::forward_as_tuple(AeEnable),
+				   std::forward_as_tuple(AeEnable, false, true));
+
 	data->sensor_ = new CameraSensor(sensor);
 	ret = data->sensor_->init();
 	if (ret)
@@ -478,7 +656,17 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)
 	if (video_->open() < 0)
 		return false;
 
+	stat_ = V4L2VideoDevice::fromEntityName(media_, "rkisp1-statistics");
+	if (stat_->open() < 0)
+		return false;
+
+	param_ = V4L2VideoDevice::fromEntityName(media_, "rkisp1-input-params");
+	if (param_->open() < 0)
+		return false;
+
 	video_->bufferReady.connect(this, &PipelineHandlerRkISP1::bufferReady);
+	stat_->bufferReady.connect(this, &PipelineHandlerRkISP1::statReady);
+	param_->bufferReady.connect(this, &PipelineHandlerRkISP1::paramReady);
 
 	/* Configure default links. */
 	if (initLinks() < 0) {
@@ -504,13 +692,66 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)
  * Buffer Handling
  */
 
+void PipelineHandlerRkISP1::tryCompleteRequest(Request *request)
+{
+	RkISP1RequestData *reqData =
+		static_cast<RkISP1RequestData *>(request->data);
+
+	if (reqData->param)
+		return;
+
+	if (reqData->stat)
+		return;
+
+	if (request->hasPendingBuffers())
+		return;
+
+	delete reqData;
+	request->data = nullptr;
+
+	completeRequest(activeCamera_, request);
+}
+
 void PipelineHandlerRkISP1::bufferReady(Buffer *buffer)
 {
 	ASSERT(activeCamera_);
 	Request *request = buffer->request();
 
 	completeBuffer(activeCamera_, request, buffer);
-	completeRequest(activeCamera_, request);
+	tryCompleteRequest(request);
+}
+
+void PipelineHandlerRkISP1::statReady(Buffer *buffer)
+{
+	ASSERT(activeCamera_);
+	RkISP1CameraData *data = cameraData(activeCamera_);
+	Request *request = buffer->request();
+	RkISP1RequestData *reqData =
+		static_cast<RkISP1RequestData *>(request->data);
+
+	data->ipa_->updateStatistics(request, *buffer);
+
+	/* TODO: Fetch libcamera status controls from IPA */
+
+	reqData->stat = nullptr;
+
+	statBuffers_.push(buffer);
+
+	tryCompleteRequest(request);
+}
+
+void PipelineHandlerRkISP1::paramReady(Buffer *buffer)
+{
+	ASSERT(activeCamera_);
+	Request *request = buffer->request();
+	RkISP1RequestData *reqData =
+		static_cast<RkISP1RequestData *>(request->data);
+
+	reqData->param = nullptr;
+
+	paramBuffers_.push(buffer);
+
+	tryCompleteRequest(request);
 }
 
 REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1);
-- 
2.22.1



More information about the libcamera-devel mailing list