<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hi,<br>
    </p>
    <div class="moz-cite-prefix">On 6/29/22 16:00, Harvey Yang via
      libcamera-devel wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:20220629103018.4025635-4-chenghaoyang@google.com">
      <pre class="moz-quote-pre" wrap="">From: Harvey Yang <a class="moz-txt-link-rfc2396E" href="mailto:chenghaoyang@chromium.org"><chenghaoyang@chromium.org></a>

With only one camera being started, we can always use imgu0 to process
frames (for video/preview). In the following patches, we'll use imgu1
for still capture if needed.

Signed-off-by: Harvey Yang <a class="moz-txt-link-rfc2396E" href="mailto:chenghaoyang@chromium.org"><chenghaoyang@chromium.org></a>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp | 86 ++++++++++++++++------------
 1 file changed, 48 insertions(+), 38 deletions(-)

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index c943ee6a..e219f704 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -64,7 +64,8 @@ public:
        void frameStart(uint32_t sequence);
 
        CIO2Device cio2_;
-       ImgUDevice *imgu_;
+       ImgUDevice *imgu0_;
+       ImgUDevice *imgu1_;</pre>
    </blockquote>
    <p>You might also be interested to at
      <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::registerCameras()">PipelineHandlerIPU3::registerCameras()</a> which allows registering
      two cameras for IPU3, assigning the 2 exposed IMGUs to each
      camera.</p>
    <pre><code>             <span class="hl com">/**</span>
<span class="hl com">            * \todo Dynamically assign ImgU and output devices to each</span>
<span class="hl com">            * stream and camera; as of now, limit support to two cameras</span>
<span class="hl com">            * only, and assign imgu0 to the first one and imgu1 to the</span>
<span class="hl com">            * second.</span>
<span class="hl com">            */</span>
                data<span class="hl opt">-></span>imgu_ <span class="hl opt">=</span> numCameras <span class="hl opt">? &</span>imgu1_ <span class="hl opt">: &</span>imgu0_<span class="hl opt">;

</span></code><code></code></pre>
    <p>This should be addressed as well, I think.</p>
    <p>Rest bits of the patch, looks on the right track to me.<br>
    </p>
    <blockquote type="cite"
      cite="mid:20220629103018.4025635-4-chenghaoyang@google.com">
      <pre class="moz-quote-pre" wrap="">
 
        Stream outStream_;
        Stream vfStream_;
@@ -406,7 +407,7 @@ <a class="moz-txt-link-freetext" href="CameraConfiguration::Status">CameraConfiguration::Status</a> <a class="moz-txt-link-freetext" href="IPU3CameraConfiguration::validate()">IPU3CameraConfiguration::validate()</a>
 
        /* 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,7 +519,6 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::configure(Camera">PipelineHandlerIPU3::configure(Camera</a> *camera, CameraConfiguration *c)
        Stream *outStream = &data->outStream_;
        Stream *vfStream = &data->vfStream_;
        CIO2Device *cio2 = &data->cio2_;
-       ImgUDevice *imgu = data->imgu_;
        V4L2DeviceFormat outputFormat;
        int ret;
 
@@ -560,7 +560,7 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::configure(Camera">PipelineHandlerIPU3::configure(Camera</a> *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 +610,7 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::configure(Camera">PipelineHandlerIPU3::configure(Camera</a> *camera, CameraConfiguration *c)
        if (imguConfig.isNull())
                return 0;
 
-       ret = imgu->configure(imguConfig, &cio2Format);
+       ret = imgu0_.configure(imguConfig, &cio2Format);
        if (ret)
                return ret;
 
@@ -624,12 +624,12 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::configure(Camera">PipelineHandlerIPU3::configure(Camera</a> *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 +641,13 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::configure(Camera">PipelineHandlerIPU3::configure(Camera</a> *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 +657,7 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::configure(Camera">PipelineHandlerIPU3::configure(Camera</a> *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 +691,9 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::exportFrameBuffers(Camera">PipelineHandlerIPU3::exportFrameBuffers(Camera</a> *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 +711,6 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::exportFrameBuffers(Camera">PipelineHandlerIPU3::exportFrameBuffers(Camera</a> *camera, Stream *stream,
 int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::allocateBuffers(Camera">PipelineHandlerIPU3::allocateBuffers(Camera</a> *camera)
 {
        IPU3CameraData *data = cameraData(camera);
-       ImgUDevice *imgu = data->imgu_;
        unsigned int bufferCount;
        int ret;
 
@@ -721,26 +720,26 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::allocateBuffers(Camera">PipelineHandlerIPU3::allocateBuffers(Camera</a> *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 <a class="moz-txt-link-freetext" href="std::unique_ptr">std::unique_ptr</a><FrameBuffer> &buffer : imgu->paramBuffers_) {
+       for (const <a class="moz-txt-link-freetext" href="std::unique_ptr">std::unique_ptr</a><FrameBuffer> &buffer : imgu0_.paramBuffers_) {
                buffer->setCookie(ipaBufferId++);
                ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes());
        }
 
-       for (const <a class="moz-txt-link-freetext" href="std::unique_ptr">std::unique_ptr</a><FrameBuffer> &buffer : imgu->statBuffers_) {
+       for (const <a class="moz-txt-link-freetext" href="std::unique_ptr">std::unique_ptr</a><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, &<a class="moz-txt-link-freetext" href="IPU3CameraData::queuePendingRequests">IPU3CameraData::queuePendingRequests</a>);
 
@@ -760,7 +759,7 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::freeBuffers(Camera">PipelineHandlerIPU3::freeBuffers(Camera</a> *camera)
        data->ipa_->unmapBuffers(ids);
        ipaBuffers_.clear();
 
-       data->imgu_->freeBuffers();
+       imgu0_.freeBuffers();
 
        return 0;
 }
@@ -777,9 +776,18 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::start(Camera">PipelineHandlerIPU3::start(Camera</a> *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_,
+                                          &<a class="moz-txt-link-freetext" href="CIO2Device::tryReturnBuffer">CIO2Device::tryReturnBuffer</a>);
+       imgu0_.output_->bufferReady.connect(data,
+                                           &<a class="moz-txt-link-freetext" href="IPU3CameraData::imguOutputBufferReady">IPU3CameraData::imguOutputBufferReady</a>);
+       imgu0_.viewfinder_->bufferReady.connect(data,
+                                               &<a class="moz-txt-link-freetext" href="IPU3CameraData::imguOutputBufferReady">IPU3CameraData::imguOutputBufferReady</a>);
+       imgu0_.param_->bufferReady.connect(data,
+                                          &<a class="moz-txt-link-freetext" href="IPU3CameraData::paramBufferReady">IPU3CameraData::paramBufferReady</a>);
+       imgu0_.stat_->bufferReady.connect(data,
+                                         &<a class="moz-txt-link-freetext" href="IPU3CameraData::statBufferReady">IPU3CameraData::statBufferReady</a>);
        /* Disable test pattern mode on the sensor, if any. */
        ret = cio2->sensor()->setTestPatternMode(
                <a class="moz-txt-link-freetext" href="controls::draft::TestPatternModeEnum::TestPatternModeOff">controls::draft::TestPatternModeEnum::TestPatternModeOff</a>);
@@ -807,19 +815,24 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::start(Camera">PipelineHandlerIPU3::start(Camera</a> *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_.input_->bufferReady.disconnect();
+       imgu0_.output_->bufferReady.disconnect();
+       imgu0_.viewfinder_->bufferReady.disconnect();
+       imgu0_.param_->bufferReady.disconnect();
+       imgu0_.stat_->bufferReady.disconnect();
        inUseCamera_ = nullptr;
 
        return ret;
@@ -834,13 +847,19 @@ void <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::stopDevice(Camera">PipelineHandlerIPU3::stopDevice(Camera</a> *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);
 
+       data->imgu0_->input_->bufferReady.disconnect();
+       data->imgu0_->output_->bufferReady.disconnect();
+       data->imgu0_->viewfinder_->bufferReady.disconnect();
+       data->imgu0_->param_->bufferReady.disconnect();
+       data->imgu0_->stat_->bufferReady.disconnect();
+
        inUseCamera_ = nullptr;
 }
 
@@ -1184,7 +1203,8 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::registerCameras()">PipelineHandlerIPU3::registerCameras()</a>
                 * 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
@@ -1198,16 +1218,6 @@ int <a class="moz-txt-link-freetext" href="PipelineHandlerIPU3::registerCameras()">PipelineHandlerIPU3::registerCameras()</a>
                                        &<a class="moz-txt-link-freetext" href="IPU3CameraData::cio2BufferReady">IPU3CameraData::cio2BufferReady</a>);
                data->cio2_.bufferAvailable.connect(
                        data.get(), &<a class="moz-txt-link-freetext" href="IPU3CameraData::queuePendingRequests">IPU3CameraData::queuePendingRequests</a>);
-               data->imgu_->input_->bufferReady.connect(&data->cio2_,
-                                       &<a class="moz-txt-link-freetext" href="CIO2Device::tryReturnBuffer">CIO2Device::tryReturnBuffer</a>);
-               data->imgu_->output_->bufferReady.connect(data.get(),
-                                       &<a class="moz-txt-link-freetext" href="IPU3CameraData::imguOutputBufferReady">IPU3CameraData::imguOutputBufferReady</a>);
-               data->imgu_->viewfinder_->bufferReady.connect(data.get(),
-                                       &<a class="moz-txt-link-freetext" href="IPU3CameraData::imguOutputBufferReady">IPU3CameraData::imguOutputBufferReady</a>);
-               data->imgu_->param_->bufferReady.connect(data.get(),
-                                       &<a class="moz-txt-link-freetext" href="IPU3CameraData::paramBufferReady">IPU3CameraData::paramBufferReady</a>);
-               data->imgu_->stat_->bufferReady.connect(data.get(),
-                                       &<a class="moz-txt-link-freetext" href="IPU3CameraData::statBufferReady">IPU3CameraData::statBufferReady</a>);
 
                /* Create and register the Camera instance. */
                const <a class="moz-txt-link-freetext" href="std::string">std::string</a> &cameraId = cio2->sensor()->id();
@@ -1300,14 +1310,14 @@ void <a class="moz-txt-link-freetext" href="IPU3CameraData::paramsBufferReady(unsigned">IPU3CameraData::paramsBufferReady(unsigned</a> 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 <a class="moz-txt-link-freetext" href="IPU3CameraData::metadataReady(unsigned">IPU3CameraData::metadataReady(unsigned</a> int id, const ControlList &metadata)
</pre>
    </blockquote>
  </body>
</html>