@@ -765,4 +765,17 @@ int ImgUDevice::enableLinks(bool enable)
return linkSetup(name_, PAD_STAT, statName, 0, enable);
}
+/**
+ * \brief Disconnect bufferReady signals from |input_|, |param_|, |output_|,
+ * |viewfinder_|, and |stat_|.
+ */
+void ImgUDevice::disconnectSignals()
+{
+ input_->bufferReady.disconnect();
+ param_->bufferReady.disconnect();
+ output_->bufferReady.disconnect();
+ viewfinder_->bufferReady.disconnect();
+ stat_->bufferReady.disconnect();
+}
+
} /* namespace libcamera */
@@ -92,6 +92,8 @@ public:
int enableLinks(bool enable);
+ void disconnectSignals();
+
std::unique_ptr<V4L2Subdevice> imgu_;
std::unique_ptr<V4L2VideoDevice> input_;
std::unique_ptr<V4L2VideoDevice> param_;
@@ -64,7 +64,8 @@ public:
void frameStart(uint32_t sequence);
CIO2Device cio2_;
- ImgUDevice *imgu_;
+ ImgUDevice *imgu0_;
+ ImgUDevice *imgu1_;
Stream outStream_;
Stream vfStream_;
@@ -406,7 +407,7 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()
/* Only compute the ImgU configuration if a YUV stream has been requested. */
if (yuvCount) {
- pipeConfig_ = data_->imgu_->calculatePipeConfig(&pipe);
+ pipeConfig_ = data_->imgu0_->calculatePipeConfig(&pipe);
if (pipeConfig_.isNull()) {
LOG(IPU3, Error) << "Failed to calculate pipe configuration: "
<< "unsupported resolutions.";
@@ -518,16 +519,12 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
Stream *outStream = &data->outStream_;
Stream *vfStream = &data->vfStream_;
CIO2Device *cio2 = &data->cio2_;
- ImgUDevice *imgu = data->imgu_;
V4L2DeviceFormat outputFormat;
int ret;
/*
- * FIXME: enabled links in one ImgU pipe interfere with capture
- * operations on the other one. This can be easily triggered by
- * capturing from one camera and then trying to capture from the other
- * one right after, without disabling media links on the first used
- * pipe.
+ * Enabled links in one ImgU pipe interfere with capture
+ * operations on the other one.
*
* The tricky part here is where to disable links on the ImgU instance
* which is currently not in use:
@@ -543,11 +540,11 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
* configuring the device, to allow alternate the usage of the two
* ImgU pipes.
*
- * As a consequence, a Camera using an ImgU shall be configured before
- * any start()/stop() sequence. An application that wants to
- * pre-configure all the camera and then start/stop them alternatively
- * without going through any re-configuration (a sequence that is
- * allowed by the Camera state machine) would now fail on the IPU3.
+ * Now that only one camera is allowed to be used at the same time, we
+ * don't need to handle the complicated interference between the two
+ * ImgU links. Therefore, an application still cannot pre-configure all
+ * the cameras and then start/stop them alternatively without going
+ * throught any re-configuration.
*/
ret = imguMediaDev_->disableLinks();
if (ret)
@@ -560,7 +557,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
* stream which is for raw capture, in which case no buffers will
* ever be queued to the ImgU.
*/
- ret = data->imgu_->enableLinks(true);
+ ret = imgu0_.enableLinks(true);
if (ret)
return ret;
@@ -610,7 +607,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
if (imguConfig.isNull())
return 0;
- ret = imgu->configure(imguConfig, &cio2Format);
+ ret = imgu0_.configure(imguConfig, &cio2Format);
if (ret)
return ret;
@@ -624,12 +621,12 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
if (stream == outStream) {
mainCfg = &cfg;
- ret = imgu->configureOutput(cfg, &outputFormat);
+ ret = imgu0_.configureOutput(cfg, &outputFormat);
if (ret)
return ret;
} else if (stream == vfStream) {
vfCfg = &cfg;
- ret = imgu->configureViewfinder(cfg, &outputFormat);
+ ret = imgu0_.configureViewfinder(cfg, &outputFormat);
if (ret)
return ret;
}
@@ -641,13 +638,13 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
* be at least one active stream in the configuration request).
*/
if (!vfCfg) {
- ret = imgu->configureViewfinder(*mainCfg, &outputFormat);
+ ret = imgu0_.configureViewfinder(*mainCfg, &outputFormat);
if (ret)
return ret;
}
/* Apply the "pipe_mode" control to the ImgU subdevice. */
- ControlList ctrls(imgu->imgu_->controls());
+ ControlList ctrls(imgu0_.imgu_->controls());
/*
* Set the ImgU pipe mode to 'Video' unconditionally to have statistics
* generated.
@@ -657,7 +654,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
*/
ctrls.set(V4L2_CID_IPU3_PIPE_MODE,
static_cast<int32_t>(IPU3PipeModeVideo));
- ret = imgu->imgu_->setControls(&ctrls);
+ ret = imgu0_.imgu_->setControls(&ctrls);
if (ret) {
LOG(IPU3, Error) << "Unable to set pipe_mode control";
return ret;
@@ -691,9 +688,9 @@ int PipelineHandlerIPU3::exportFrameBuffers(Camera *camera, Stream *stream,
unsigned int count = stream->configuration().bufferCount;
if (stream == &data->outStream_)
- return data->imgu_->output_->exportBuffers(count, buffers);
+ return imgu0_.output_->exportBuffers(count, buffers);
else if (stream == &data->vfStream_)
- return data->imgu_->viewfinder_->exportBuffers(count, buffers);
+ return imgu0_.viewfinder_->exportBuffers(count, buffers);
else if (stream == &data->rawStream_)
return data->cio2_.exportBuffers(count, buffers);
@@ -711,7 +708,6 @@ int PipelineHandlerIPU3::exportFrameBuffers(Camera *camera, Stream *stream,
int PipelineHandlerIPU3::allocateBuffers(Camera *camera)
{
IPU3CameraData *data = cameraData(camera);
- ImgUDevice *imgu = data->imgu_;
unsigned int bufferCount;
int ret;
@@ -721,26 +717,26 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera)
data->rawStream_.configuration().bufferCount,
});
- ret = imgu->allocateBuffers(bufferCount);
+ ret = imgu0_.allocateBuffers(bufferCount);
if (ret < 0)
return ret;
/* Map buffers to the IPA. */
unsigned int ipaBufferId = 1;
- for (const std::unique_ptr<FrameBuffer> &buffer : imgu->paramBuffers_) {
+ for (const std::unique_ptr<FrameBuffer> &buffer : imgu0_.paramBuffers_) {
buffer->setCookie(ipaBufferId++);
ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes());
}
- for (const std::unique_ptr<FrameBuffer> &buffer : imgu->statBuffers_) {
+ for (const std::unique_ptr<FrameBuffer> &buffer : imgu0_.statBuffers_) {
buffer->setCookie(ipaBufferId++);
ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes());
}
data->ipa_->mapBuffers(ipaBuffers_);
- data->frameInfos_.init(imgu->paramBuffers_, imgu->statBuffers_);
+ data->frameInfos_.init(imgu0_.paramBuffers_, imgu0_.statBuffers_);
data->frameInfos_.bufferAvailable.connect(
data, &IPU3CameraData::queuePendingRequests);
@@ -760,7 +756,7 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera)
data->ipa_->unmapBuffers(ids);
ipaBuffers_.clear();
- data->imgu_->freeBuffers();
+ imgu0_.freeBuffers();
return 0;
}
@@ -785,9 +781,18 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] const ControlLis
IPU3CameraData *data = cameraData(camera);
CIO2Device *cio2 = &data->cio2_;
- ImgUDevice *imgu = data->imgu_;
int ret;
+ imgu0_.input_->bufferReady.connect(&data->cio2_,
+ &CIO2Device::tryReturnBuffer);
+ imgu0_.output_->bufferReady.connect(data,
+ &IPU3CameraData::imguOutputBufferReady);
+ imgu0_.viewfinder_->bufferReady.connect(data,
+ &IPU3CameraData::imguOutputBufferReady);
+ imgu0_.param_->bufferReady.connect(data,
+ &IPU3CameraData::paramBufferReady);
+ imgu0_.stat_->bufferReady.connect(data,
+ &IPU3CameraData::statBufferReady);
/* Disable test pattern mode on the sensor, if any. */
ret = cio2->sensor()->setTestPatternMode(
controls::draft::TestPatternModeEnum::TestPatternModeOff);
@@ -813,19 +818,21 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] const ControlLis
if (ret)
goto error;
- ret = imgu->start();
+ ret = imgu0_.start();
if (ret)
goto error;
return 0;
error:
- imgu->stop();
+ imgu0_.stop();
cio2->stop();
data->ipa_->stop();
freeBuffers(camera);
LOG(IPU3, Error) << "Failed to start camera " << camera->id();
+ imgu0_.disconnectSignals();
+
return ret;
}
@@ -838,12 +845,14 @@ void PipelineHandlerIPU3::stopDevice(Camera *camera)
data->ipa_->stop();
- ret |= data->imgu_->stop();
+ ret |= imgu0_.stop();
ret |= data->cio2_.stop();
if (ret)
LOG(IPU3, Warning) << "Failed to stop camera " << camera->id();
freeBuffers(camera);
+
+ imgu0_.disconnectSignals();
}
void IPU3CameraData::cancelPendingRequests()
@@ -1186,7 +1195,8 @@ int PipelineHandlerIPU3::registerCameras()
* only, and assign imgu0 to the first one and imgu1 to the
* second.
*/
- data->imgu_ = numCameras ? &imgu1_ : &imgu0_;
+ data->imgu0_ = &imgu0_;
+ data->imgu1_ = &imgu1_;
/*
* Connect video devices' 'bufferReady' signals to their
@@ -1200,16 +1210,6 @@ int PipelineHandlerIPU3::registerCameras()
&IPU3CameraData::cio2BufferReady);
data->cio2_.bufferAvailable.connect(
data.get(), &IPU3CameraData::queuePendingRequests);
- data->imgu_->input_->bufferReady.connect(&data->cio2_,
- &CIO2Device::tryReturnBuffer);
- data->imgu_->output_->bufferReady.connect(data.get(),
- &IPU3CameraData::imguOutputBufferReady);
- data->imgu_->viewfinder_->bufferReady.connect(data.get(),
- &IPU3CameraData::imguOutputBufferReady);
- data->imgu_->param_->bufferReady.connect(data.get(),
- &IPU3CameraData::paramBufferReady);
- data->imgu_->stat_->bufferReady.connect(data.get(),
- &IPU3CameraData::statBufferReady);
/* Create and register the Camera instance. */
const std::string &cameraId = cio2->sensor()->id();
@@ -1302,14 +1302,14 @@ void IPU3CameraData::paramsBufferReady(unsigned int id)
FrameBuffer *outbuffer = it.second;
if (stream == &outStream_)
- imgu_->output_->queueBuffer(outbuffer);
+ imgu0_->output_->queueBuffer(outbuffer);
else if (stream == &vfStream_)
- imgu_->viewfinder_->queueBuffer(outbuffer);
+ imgu0_->viewfinder_->queueBuffer(outbuffer);
}
- imgu_->param_->queueBuffer(info->paramBuffer);
- imgu_->stat_->queueBuffer(info->statBuffer);
- imgu_->input_->queueBuffer(info->rawBuffer);
+ imgu0_->param_->queueBuffer(info->paramBuffer);
+ imgu0_->stat_->queueBuffer(info->statBuffer);
+ imgu0_->input_->queueBuffer(info->rawBuffer);
}
void IPU3CameraData::metadataReady(unsigned int id, const ControlList &metadata)