[libcamera-devel] [PATCH v4 2/9] ipu3: Allow only one camera being started
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Wed Aug 3 07:58:21 CEST 2022
On Wed, Aug 03, 2022 at 08:52:01AM +0300, Laurent Pinchart via libcamera-devel wrote:
> Hi Harvey,
>
> Thank you for the patch.
>
> On Tue, Aug 02, 2022 at 10:29:36AM +0000, Harvey Yang via libcamera-devel wrote:
> > From: Harvey Yang <chenghaoyang at chromium.org>
> >
> > As we hardly have use cases/applications that need both cameras at the
> > same time, this patch adds a rule that only one camera can be started
> > one time. This also allows the following patches that use both imgus to
> > process frames from one single camera.
>
> While I think this is right for the IPU3, this is the wrong reason. The
> fact that Chrome OS has little use for capturing from the two cameras at
> the same time doesn't meant there are no use cases on other platforms.
>
> The reason why I think this makes sense is that the two ImgU instances
> are actually not independent, both need to be configured before any gets
> started. That conflicts with how the libcamera API operates. I would
> like to not suffer from this limitation though, but that would require
> broader changes in the public API, I think it's fine to limit operation
> to one camera at a time for now.
>
> On a side note, when I select a camera in a video call in the Chrome
> browser, I get a small preview of each available camera. Isn't this a
> use case that is of interest to Chrome OS ?
>
> Kieran told me that this works under Windows on a Surface Go 2.
> Technically speaking, I don't know how we could implement it though, as
> far as I understand, only one instance of the ImgU can operate in video
> mode and guarantee real time operation, while the other instance needs
> to operate in still image capture mode and will work in "batch" mode,
> using the free processing time of the hardware that isn't reserved for
> video mode.
>
> > Signed-off-by: Harvey Yang <chenghaoyang at chromium.org>
> > ---
> > include/libcamera/internal/pipeline_handler.h | 5 ++++
> > src/libcamera/camera.cpp | 11 ++++++++
> > src/libcamera/pipeline/ipu3/ipu3.cpp | 18 +++++++++++++
> > src/libcamera/pipeline_handler.cpp | 26 +++++++++++++++++++
> > 4 files changed, 60 insertions(+)
>
> This patch should be split in two, with one patch that extends the
> Camera and PipelineHandler API, and a second patch to implement it in
> the IPU3 pipeline handler.
>
> > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > index c3e4c258..8277ceda 100644
> > --- a/include/libcamera/internal/pipeline_handler.h
> > +++ b/include/libcamera/internal/pipeline_handler.h
> > @@ -55,6 +55,9 @@ public:
> > virtual int exportFrameBuffers(Camera *camera, Stream *stream,
> > std::vector<std::unique_ptr<FrameBuffer>> *buffers) = 0;
> >
> > + virtual bool acquire(Camera *camera);
> > + virtual void release(Camera *camera);
> > +
> > virtual int start(Camera *camera, const ControlList *controls) = 0;
> > void stop(Camera *camera);
> > bool hasPendingRequests(const Camera *camera) const;
> > @@ -76,6 +79,8 @@ protected:
> >
> > CameraManager *manager_;
> >
> > + std::set<Camera*> acquiredCameras_;
>
> Space between Camera and *.
>
> > +
> > private:
> > void mediaDeviceDisconnected(MediaDevice *media);
> > virtual void disconnect();
> > diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
> > index 713543fd..a31f8769 100644
> > --- a/src/libcamera/camera.cpp
> > +++ b/src/libcamera/camera.cpp
> > @@ -826,6 +826,8 @@ int Camera::exportFrameBuffers(Stream *stream,
> > * \return 0 on success or a negative error code otherwise
> > * \retval -ENODEV The camera has been disconnected from the system
> > * \retval -EBUSY The camera is not free and can't be acquired by the caller
> > + * \retval -EUSERS The maximum number of cameras that can be opened concurrently
> > + * were opened already
>
> That's not how acquire() should work. The purpose of acquire() is to
> reserve a camera for usage by the application, preventing other
> applications that use libcamera from doing the same. It's a simple
> locking mechanism really. With this change, it won't be possible for an
> application to acquire the front and back cameras. This will cause
> issues, for instance, when switching between the front and back cameras
> in an application, if the application wants to acquire the other camera
> before releasing the current one, to make sure that, if the acquire
> fails, the current camera can still be used. It also breaks the use case
> of acquiring multiple cameras to switch between them while preventing
> other applications from using any.
>
> I'd like to see a design proposal for how the public API should evolve
> to make mutual exclusion possible, while keeping use cases such as the
> above supported (unless, of course, you show that those use cases
> actually don't make sense, in which case we could reconsider them).
Another point I forgot to mention, don't we need an API to let
applications query mutual exclusion constraints between cameras ?
> > */
> > int Camera::acquire()
> > {
> > @@ -845,6 +847,14 @@ int Camera::acquire()
> > return -EBUSY;
> > }
> >
> > + if (!d->pipe_->acquire(this)) {
> > + LOG(Camera, Info)
> > + << "The maximum number of cameras that can be opened"
> > + "concurrently were opened already";
> > + d->pipe_->unlock();
> > + return -EUSERS;
> > + }
> > +
> > d->setState(Private::CameraAcquired);
> >
> > return 0;
> > @@ -873,6 +883,7 @@ int Camera::release()
> > if (ret < 0)
> > return ret == -EACCES ? -EBUSY : ret;
> >
> > + d->pipe_->release(this);
> > d->pipe_->unlock();
> >
> > d->setState(Private::CameraAvailable);
> > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > index fd989e61..091a40e1 100644
> > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > @@ -141,6 +141,8 @@ public:
> > int exportFrameBuffers(Camera *camera, Stream *stream,
> > std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
> >
> > + bool acquire(Camera *camera) override;
> > +
> > int start(Camera *camera, const ControlList *controls) override;
> > void stopDevice(Camera *camera) override;
> >
> > @@ -763,8 +765,24 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera)
> > return 0;
> > }
> >
> > +bool PipelineHandlerIPU3::acquire(Camera *camera) {
>
> The curly brace should be on the next line.
>
> > + /*
> > + * Enforce that only a single camera can be used at a time to use both
> > + * ImgUs on the camera, so that StillCapture stream can adopt another
> > + * set of configuration.
> > + */
> > + if (!acquiredCameras_.empty())
>
> Given that the set can only contain a single camera, you could replace
> it with just a pointer.
>
> > + return false;
> > +
> > + return PipelineHandler::acquire(camera);
> > +
> > +}
> > +
> > int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] const ControlList *controls)
> > {
> > + if (acquiredCameras_.empty() || *acquiredCameras_.begin() != camera)
> > + return -EUSERS;
> > +
> > IPU3CameraData *data = cameraData(camera);
> > CIO2Device *cio2 = &data->cio2_;
> > ImgUDevice *imgu = data->imgu_;
> > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > index 7ebd76ad..fff9ee59 100644
> > --- a/src/libcamera/pipeline_handler.cpp
> > +++ b/src/libcamera/pipeline_handler.cpp
> > @@ -270,6 +270,32 @@ void PipelineHandler::unlock()
> > * otherwise
> > */
> >
> > +/**
> > + * \fn PipelineHandler::acquire()
> > + * \brief Check if \a camera can be acquired and supported with the current
> > + * pipeline handler usage. If \a camera has already been acquired (by the same
> > + * or another process), return false.
> > + * \param[in] camera The camera
> > + */
> > +bool PipelineHandler::acquire(Camera *camera)
> > +{
> > + if (acquiredCameras_.find(camera) != acquiredCameras_.end())
> > + return false;
> > +
> > + acquiredCameras_.emplace(camera);
> > + return true;
> > +}
> > +
> > +/**
> > + * \fn PipelineHandler::release()
> > + * \brief Release exclusive access to \a camera
> > + * \param[in] camera The camera
> > + */
> > +void PipelineHandler::release(Camera *camera)
> > +{
> > + acquiredCameras_.erase(camera);
> > +}
> > +
> > /**
> > * \fn PipelineHandler::start()
> > * \brief Start capturing from a group of streams
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list