[libcamera-devel,v5,08/19] libcamera: ipu3: Cache the camera sizes

Message ID 20190326083902.26121-9-jacopo@jmondi.org
State Superseded
Headers show
Series
  • libcamera: ipu3: Add ImgU support
Related show

Commit Message

Jacopo Mondi March 26, 2019, 8:38 a.m. UTC
When creating a camera, make sure a the image sensor provides images in
a format compatible with IPU3 CIO2 unit requirements and cache the
minimum and maximum camera sizes.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 2 deletions(-)

Comments

Laurent Pinchart April 2, 2019, 7:27 a.m. UTC | #1
Hi Jacopo,

Thank you for the patch.

On Tue, Mar 26, 2019 at 09:38:51AM +0100, Jacopo Mondi wrote:
> When creating a camera, make sure a the image sensor provides images in
> a format compatible with IPU3 CIO2 unit requirements and cache the
> minimum and maximum camera sizes.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
>  1 file changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index 55489c31df2d..d42c81273cc6 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -8,11 +8,14 @@
>  #include <memory>
>  #include <vector>
>  
> +#include <linux/media-bus-format.h>
> +
>  #include <libcamera/camera.h>
>  #include <libcamera/request.h>
>  #include <libcamera/stream.h>
>  
>  #include "device_enumerator.h"
> +#include "geometry.h"
>  #include "log.h"
>  #include "media_device.h"
>  #include "pipeline_handler.h"
> @@ -24,6 +27,22 @@ namespace libcamera {
>  
>  LOG_DEFINE_CATEGORY(IPU3)
>  
> +static int mediaBusToCIO2Format(unsigned int code)
> +{
> +	switch (code) {
> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SBGGR10;
> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SGBRG10;
> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SGRBG10;
> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SRGGB10;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  class PipelineHandlerIPU3 : public PipelineHandler
>  {
>  public:
> @@ -70,6 +89,9 @@ private:
>  		V4L2Subdevice *sensor_;
>  
>  		Stream stream_;
> +
> +		/* Maximum sizes and the mbus code used to produce them. */
> +		std::pair<unsigned int, SizeRange> maxSizes_;

The use of std::pair here makes the code below use .first and .second,
which are not very readable. I think it would be better to store the
pixel format and max size in two separate fields, of unsigned int and
SizeRange types respectively. Or, now that I think about it, as you only
care about the maximum size, maybe adding a Size structure to geometry.h
would be a good idea.

>  	};
>  
>  	IPU3CameraData *cameraData(const Camera *camera)
> @@ -404,18 +426,48 @@ void PipelineHandlerIPU3::registerCameras()
>  		if (ret)
>  			continue;
>  
> -		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> -
> +		/*
> +		 * Make sure the sensor produces at least one image format
> +		 * compatible with IPU3 CIO2 requirements and cache the camera
> +		 * maximum sizes.
> +		 */
>  		data->sensor_ = new V4L2Subdevice(sensor);
>  		ret = data->sensor_->open();
>  		if (ret)
>  			continue;
>  
> +		for (auto it : data->sensor_->formats(0)) {
> +			int mbusCode = mediaBusToCIO2Format(it.first);
> +			if (mbusCode < 0)
> +				continue;
> +
> +			for (const SizeRange &size : it.second) {
> +				SizeRange &maxSize = data->maxSizes_.second;
> +
> +				if (maxSize.maxWidth < size.maxWidth &&
> +				    maxSize.maxHeight < size.maxHeight) {
> +					maxSize.maxWidth = size.maxWidth;
> +					maxSize.maxHeight = size.maxHeight;
> +					data->maxSizes_.first = mbusCode;
> +				}
> +			}
> +		}

One blank line ?

> +		if (data->maxSizes_.second.maxWidth == 0) {
> +			LOG(IPU3, Info)
> +				<< "Sensor '" << data->sensor_->entityName()
> +				<< "' detected, but no supported image format "
> +				<< " found: skip camera creation";
> +			continue;
> +		}
> +
>  		data->csi2_ = new V4L2Subdevice(csi2);
>  		ret = data->csi2_->open();
>  		if (ret)
>  			continue;
>  
> +		data->cio2_->bufferReady.connect(data.get(),
> +						 &IPU3CameraData::bufferReady);
> +

This seems unrelated to this patch, is it needed ?

>  		registerCamera(std::move(camera), std::move(data));
>  
>  		LOG(IPU3, Info)
Jacopo Mondi April 2, 2019, 8:26 a.m. UTC | #2
Hi Laurent,

On Tue, Apr 02, 2019 at 10:27:17AM +0300, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Tue, Mar 26, 2019 at 09:38:51AM +0100, Jacopo Mondi wrote:
> > When creating a camera, make sure a the image sensor provides images in
> > a format compatible with IPU3 CIO2 unit requirements and cache the
> > minimum and maximum camera sizes.
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >  src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
> >  1 file changed, 54 insertions(+), 2 deletions(-)
> >
> > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > index 55489c31df2d..d42c81273cc6 100644
> > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > @@ -8,11 +8,14 @@
> >  #include <memory>
> >  #include <vector>
> >
> > +#include <linux/media-bus-format.h>
> > +
> >  #include <libcamera/camera.h>
> >  #include <libcamera/request.h>
> >  #include <libcamera/stream.h>
> >
> >  #include "device_enumerator.h"
> > +#include "geometry.h"
> >  #include "log.h"
> >  #include "media_device.h"
> >  #include "pipeline_handler.h"
> > @@ -24,6 +27,22 @@ namespace libcamera {
> >
> >  LOG_DEFINE_CATEGORY(IPU3)
> >
> > +static int mediaBusToCIO2Format(unsigned int code)
> > +{
> > +	switch (code) {
> > +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> > +		return V4L2_PIX_FMT_IPU3_SBGGR10;
> > +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> > +		return V4L2_PIX_FMT_IPU3_SGBRG10;
> > +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> > +		return V4L2_PIX_FMT_IPU3_SGRBG10;
> > +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> > +		return V4L2_PIX_FMT_IPU3_SRGGB10;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> >  class PipelineHandlerIPU3 : public PipelineHandler
> >  {
> >  public:
> > @@ -70,6 +89,9 @@ private:
> >  		V4L2Subdevice *sensor_;
> >
> >  		Stream stream_;
> > +
> > +		/* Maximum sizes and the mbus code used to produce them. */
> > +		std::pair<unsigned int, SizeRange> maxSizes_;
>
> The use of std::pair here makes the code below use .first and .second,
> which are not very readable. I think it would be better to store the
> pixel format and max size in two separate fields, of unsigned int and
> SizeRange types respectively. Or, now that I think about it, as you only
> care about the maximum size, maybe adding a Size structure to geometry.h
> would be a good idea.
>

I see... I'll ponder about it. Adding new stuff it's always a burden
because of documentation and such, but I get your point...

> >  	};
> >
> >  	IPU3CameraData *cameraData(const Camera *camera)
> > @@ -404,18 +426,48 @@ void PipelineHandlerIPU3::registerCameras()
> >  		if (ret)
> >  			continue;
> >
> > -		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> > -
> > +		/*
> > +		 * Make sure the sensor produces at least one image format
> > +		 * compatible with IPU3 CIO2 requirements and cache the camera
> > +		 * maximum sizes.
> > +		 */
> >  		data->sensor_ = new V4L2Subdevice(sensor);
> >  		ret = data->sensor_->open();
> >  		if (ret)
> >  			continue;
> >
> > +		for (auto it : data->sensor_->formats(0)) {
> > +			int mbusCode = mediaBusToCIO2Format(it.first);
> > +			if (mbusCode < 0)
> > +				continue;
> > +
> > +			for (const SizeRange &size : it.second) {
> > +				SizeRange &maxSize = data->maxSizes_.second;
> > +
> > +				if (maxSize.maxWidth < size.maxWidth &&
> > +				    maxSize.maxHeight < size.maxHeight) {
> > +					maxSize.maxWidth = size.maxWidth;
> > +					maxSize.maxHeight = size.maxHeight;
> > +					data->maxSizes_.first = mbusCode;
> > +				}
> > +			}
> > +		}
>
> One blank line ?

Not sure, as this is an error condition, I like it better without an
empty line.

>
> > +		if (data->maxSizes_.second.maxWidth == 0) {
> > +			LOG(IPU3, Info)
> > +				<< "Sensor '" << data->sensor_->entityName()
> > +				<< "' detected, but no supported image format "
> > +				<< " found: skip camera creation";
> > +			continue;
> > +		}
> > +
> >  		data->csi2_ = new V4L2Subdevice(csi2);
> >  		ret = data->csi2_->open();
> >  		if (ret)
> >  			continue;
> >
> > +		data->cio2_->bufferReady.connect(data.get(),
> > +						 &IPU3CameraData::bufferReady);
> > +
>
> This seems unrelated to this patch, is it needed ?

please see:
 > > -           data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);

A few lines above here.

Thanks
  j

>
> >  		registerCamera(std::move(camera), std::move(data));
> >
> >  		LOG(IPU3, Info)
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart April 2, 2019, 9:11 a.m. UTC | #3
Hi Jacopo,

On Tue, Apr 02, 2019 at 10:26:07AM +0200, Jacopo Mondi wrote:
> On Tue, Apr 02, 2019 at 10:27:17AM +0300, Laurent Pinchart wrote:
> > On Tue, Mar 26, 2019 at 09:38:51AM +0100, Jacopo Mondi wrote:
> >> When creating a camera, make sure a the image sensor provides images in
> >> a format compatible with IPU3 CIO2 unit requirements and cache the
> >> minimum and maximum camera sizes.
> >>
> >> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >> ---
> >>  src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
> >>  1 file changed, 54 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> >> index 55489c31df2d..d42c81273cc6 100644
> >> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> >> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> >> @@ -8,11 +8,14 @@
> >>  #include <memory>
> >>  #include <vector>
> >>
> >> +#include <linux/media-bus-format.h>
> >> +
> >>  #include <libcamera/camera.h>
> >>  #include <libcamera/request.h>
> >>  #include <libcamera/stream.h>
> >>
> >>  #include "device_enumerator.h"
> >> +#include "geometry.h"
> >>  #include "log.h"
> >>  #include "media_device.h"
> >>  #include "pipeline_handler.h"
> >> @@ -24,6 +27,22 @@ namespace libcamera {
> >>
> >>  LOG_DEFINE_CATEGORY(IPU3)
> >>
> >> +static int mediaBusToCIO2Format(unsigned int code)
> >> +{
> >> +	switch (code) {
> >> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> >> +		return V4L2_PIX_FMT_IPU3_SBGGR10;
> >> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> >> +		return V4L2_PIX_FMT_IPU3_SGBRG10;
> >> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> >> +		return V4L2_PIX_FMT_IPU3_SGRBG10;
> >> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> >> +		return V4L2_PIX_FMT_IPU3_SRGGB10;
> >> +	default:
> >> +		return -EINVAL;
> >> +	}
> >> +}
> >> +
> >>  class PipelineHandlerIPU3 : public PipelineHandler
> >>  {
> >>  public:
> >> @@ -70,6 +89,9 @@ private:
> >>  		V4L2Subdevice *sensor_;
> >>
> >>  		Stream stream_;
> >> +
> >> +		/* Maximum sizes and the mbus code used to produce them. */
> >> +		std::pair<unsigned int, SizeRange> maxSizes_;
> >
> > The use of std::pair here makes the code below use .first and .second,
> > which are not very readable. I think it would be better to store the
> > pixel format and max size in two separate fields, of unsigned int and
> > SizeRange types respectively. Or, now that I think about it, as you only
> > care about the maximum size, maybe adding a Size structure to geometry.h
> > would be a good idea.
> >
> 
> I see... I'll ponder about it. Adding new stuff it's always a burden
> because of documentation and such, but I get your point...

I know it can be a bit painful :-( A Size structure should hopefully be
simple though.

> >>  	};
> >>
> >>  	IPU3CameraData *cameraData(const Camera *camera)
> >> @@ -404,18 +426,48 @@ void PipelineHandlerIPU3::registerCameras()
> >>  		if (ret)
> >>  			continue;
> >>
> >> -		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> >> -
> >> +		/*
> >> +		 * Make sure the sensor produces at least one image format
> >> +		 * compatible with IPU3 CIO2 requirements and cache the camera
> >> +		 * maximum sizes.
> >> +		 */
> >>  		data->sensor_ = new V4L2Subdevice(sensor);
> >>  		ret = data->sensor_->open();
> >>  		if (ret)
> >>  			continue;
> >>
> >> +		for (auto it : data->sensor_->formats(0)) {
> >> +			int mbusCode = mediaBusToCIO2Format(it.first);
> >> +			if (mbusCode < 0)
> >> +				continue;
> >> +
> >> +			for (const SizeRange &size : it.second) {
> >> +				SizeRange &maxSize = data->maxSizes_.second;
> >> +
> >> +				if (maxSize.maxWidth < size.maxWidth &&
> >> +				    maxSize.maxHeight < size.maxHeight) {
> >> +					maxSize.maxWidth = size.maxWidth;
> >> +					maxSize.maxHeight = size.maxHeight;
> >> +					data->maxSizes_.first = mbusCode;
> >> +				}
> >> +			}
> >> +		}
> >
> > One blank line ?
> 
> Not sure, as this is an error condition, I like it better without an
> empty line.

There are generally empty lines after a for loop of if block, but it's
your code :-)

> >> +		if (data->maxSizes_.second.maxWidth == 0) {
> >> +			LOG(IPU3, Info)
> >> +				<< "Sensor '" << data->sensor_->entityName()
> >> +				<< "' detected, but no supported image format "
> >> +				<< " found: skip camera creation";
> >> +			continue;
> >> +		}
> >> +
> >>  		data->csi2_ = new V4L2Subdevice(csi2);
> >>  		ret = data->csi2_->open();
> >>  		if (ret)
> >>  			continue;
> >>
> >> +		data->cio2_->bufferReady.connect(data.get(),
> >> +						 &IPU3CameraData::bufferReady);
> >> +
> >
> > This seems unrelated to this patch, is it needed ?
> 
> please see:
> >> -           data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> 
> A few lines above here.

I know, what I meant is that moving the code seems unrelated, as you
don't touch it (apart from wrapping the line).

> >>  		registerCamera(std::move(camera), std::move(data));
> >>
> >>  		LOG(IPU3, Info)
Jacopo Mondi April 2, 2019, 9:23 a.m. UTC | #4
Hi Laurent,

On Tue, Apr 02, 2019 at 12:11:59PM +0300, Laurent Pinchart wrote:
> Hi Jacopo,
>
> On Tue, Apr 02, 2019 at 10:26:07AM +0200, Jacopo Mondi wrote:
> > On Tue, Apr 02, 2019 at 10:27:17AM +0300, Laurent Pinchart wrote:
> > > On Tue, Mar 26, 2019 at 09:38:51AM +0100, Jacopo Mondi wrote:
> > >> When creating a camera, make sure a the image sensor provides images in
> > >> a format compatible with IPU3 CIO2 unit requirements and cache the
> > >> minimum and maximum camera sizes.
> > >>
> > >> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > >> ---
> > >>  src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
> > >>  1 file changed, 54 insertions(+), 2 deletions(-)
> > >>
> > >> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > >> index 55489c31df2d..d42c81273cc6 100644
> > >> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> > >> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > >> @@ -8,11 +8,14 @@
> > >>  #include <memory>
> > >>  #include <vector>
> > >>
> > >> +#include <linux/media-bus-format.h>
> > >> +
> > >>  #include <libcamera/camera.h>
> > >>  #include <libcamera/request.h>
> > >>  #include <libcamera/stream.h>
> > >>
> > >>  #include "device_enumerator.h"
> > >> +#include "geometry.h"
> > >>  #include "log.h"
> > >>  #include "media_device.h"
> > >>  #include "pipeline_handler.h"
> > >> @@ -24,6 +27,22 @@ namespace libcamera {
> > >>
> > >>  LOG_DEFINE_CATEGORY(IPU3)
> > >>
> > >> +static int mediaBusToCIO2Format(unsigned int code)
> > >> +{
> > >> +	switch (code) {
> > >> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> > >> +		return V4L2_PIX_FMT_IPU3_SBGGR10;
> > >> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> > >> +		return V4L2_PIX_FMT_IPU3_SGBRG10;
> > >> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> > >> +		return V4L2_PIX_FMT_IPU3_SGRBG10;
> > >> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> > >> +		return V4L2_PIX_FMT_IPU3_SRGGB10;
> > >> +	default:
> > >> +		return -EINVAL;
> > >> +	}
> > >> +}
> > >> +
> > >>  class PipelineHandlerIPU3 : public PipelineHandler
> > >>  {
> > >>  public:
> > >> @@ -70,6 +89,9 @@ private:
> > >>  		V4L2Subdevice *sensor_;
> > >>
> > >>  		Stream stream_;
> > >> +
> > >> +		/* Maximum sizes and the mbus code used to produce them. */
> > >> +		std::pair<unsigned int, SizeRange> maxSizes_;
> > >
> > > The use of std::pair here makes the code below use .first and .second,
> > > which are not very readable. I think it would be better to store the
> > > pixel format and max size in two separate fields, of unsigned int and
> > > SizeRange types respectively. Or, now that I think about it, as you only
> > > care about the maximum size, maybe adding a Size structure to geometry.h
> > > would be a good idea.
> > >
> >
> > I see... I'll ponder about it. Adding new stuff it's always a burden
> > because of documentation and such, but I get your point...
>
> I know it can be a bit painful :-( A Size structure should hopefully be
> simple though.
>
> > >>  	};
> > >>
> > >>  	IPU3CameraData *cameraData(const Camera *camera)
> > >> @@ -404,18 +426,48 @@ void PipelineHandlerIPU3::registerCameras()
> > >>  		if (ret)
> > >>  			continue;
> > >>
> > >> -		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> > >> -
> > >> +		/*
> > >> +		 * Make sure the sensor produces at least one image format
> > >> +		 * compatible with IPU3 CIO2 requirements and cache the camera
> > >> +		 * maximum sizes.
> > >> +		 */
> > >>  		data->sensor_ = new V4L2Subdevice(sensor);
> > >>  		ret = data->sensor_->open();
> > >>  		if (ret)
> > >>  			continue;
> > >>
> > >> +		for (auto it : data->sensor_->formats(0)) {
> > >> +			int mbusCode = mediaBusToCIO2Format(it.first);
> > >> +			if (mbusCode < 0)
> > >> +				continue;
> > >> +
> > >> +			for (const SizeRange &size : it.second) {
> > >> +				SizeRange &maxSize = data->maxSizes_.second;
> > >> +
> > >> +				if (maxSize.maxWidth < size.maxWidth &&
> > >> +				    maxSize.maxHeight < size.maxHeight) {
> > >> +					maxSize.maxWidth = size.maxWidth;
> > >> +					maxSize.maxHeight = size.maxHeight;
> > >> +					data->maxSizes_.first = mbusCode;
> > >> +				}
> > >> +			}
> > >> +		}
> > >
> > > One blank line ?
> >
> > Not sure, as this is an error condition, I like it better without an
> > empty line.
>
> There are generally empty lines after a for loop of if block, but it's
> your code :-)
>
> > >> +		if (data->maxSizes_.second.maxWidth == 0) {
> > >> +			LOG(IPU3, Info)
> > >> +				<< "Sensor '" << data->sensor_->entityName()
> > >> +				<< "' detected, but no supported image format "
> > >> +				<< " found: skip camera creation";
> > >> +			continue;
> > >> +		}
> > >> +
> > >>  		data->csi2_ = new V4L2Subdevice(csi2);
> > >>  		ret = data->csi2_->open();
> > >>  		if (ret)
> > >>  			continue;
> > >>
> > >> +		data->cio2_->bufferReady.connect(data.get(),
> > >> +						 &IPU3CameraData::bufferReady);
> > >> +
> > >
> > > This seems unrelated to this patch, is it needed ?
> >
> > please see:
> > >> -           data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> >
> > A few lines above here.
>
> I know, what I meant is that moving the code seems unrelated, as you
> don't touch it (apart from wrapping the line).
>

Ah, got it. I moved it here because I want to connect the signal only
after we have successfully validated the sensor provided formats
(introduced in this patch), so I don't think it's unrelated, isn't it?

Thanks
  j

> > >>  		registerCamera(std::move(camera), std::move(data));
> > >>
> > >>  		LOG(IPU3, Info)
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart April 2, 2019, 9:27 a.m. UTC | #5
Hi Jacopo,

On Tue, Apr 02, 2019 at 11:23:30AM +0200, Jacopo Mondi wrote:
> On Tue, Apr 02, 2019 at 12:11:59PM +0300, Laurent Pinchart wrote:
> > On Tue, Apr 02, 2019 at 10:26:07AM +0200, Jacopo Mondi wrote:
> >> On Tue, Apr 02, 2019 at 10:27:17AM +0300, Laurent Pinchart wrote:
> >>> On Tue, Mar 26, 2019 at 09:38:51AM +0100, Jacopo Mondi wrote:
> >>>> When creating a camera, make sure a the image sensor provides images in
> >>>> a format compatible with IPU3 CIO2 unit requirements and cache the
> >>>> minimum and maximum camera sizes.
> >>>>
> >>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >>>> ---
> >>>>  src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
> >>>>  1 file changed, 54 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> >>>> index 55489c31df2d..d42c81273cc6 100644
> >>>> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> >>>> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> >>>> @@ -8,11 +8,14 @@
> >>>>  #include <memory>
> >>>>  #include <vector>
> >>>>
> >>>> +#include <linux/media-bus-format.h>
> >>>> +
> >>>>  #include <libcamera/camera.h>
> >>>>  #include <libcamera/request.h>
> >>>>  #include <libcamera/stream.h>
> >>>>
> >>>>  #include "device_enumerator.h"
> >>>> +#include "geometry.h"
> >>>>  #include "log.h"
> >>>>  #include "media_device.h"
> >>>>  #include "pipeline_handler.h"
> >>>> @@ -24,6 +27,22 @@ namespace libcamera {
> >>>>
> >>>>  LOG_DEFINE_CATEGORY(IPU3)
> >>>>
> >>>> +static int mediaBusToCIO2Format(unsigned int code)
> >>>> +{
> >>>> +	switch (code) {
> >>>> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> >>>> +		return V4L2_PIX_FMT_IPU3_SBGGR10;
> >>>> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> >>>> +		return V4L2_PIX_FMT_IPU3_SGBRG10;
> >>>> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> >>>> +		return V4L2_PIX_FMT_IPU3_SGRBG10;
> >>>> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> >>>> +		return V4L2_PIX_FMT_IPU3_SRGGB10;
> >>>> +	default:
> >>>> +		return -EINVAL;
> >>>> +	}
> >>>> +}
> >>>> +
> >>>>  class PipelineHandlerIPU3 : public PipelineHandler
> >>>>  {
> >>>>  public:
> >>>> @@ -70,6 +89,9 @@ private:
> >>>>  		V4L2Subdevice *sensor_;
> >>>>
> >>>>  		Stream stream_;
> >>>> +
> >>>> +		/* Maximum sizes and the mbus code used to produce them. */
> >>>> +		std::pair<unsigned int, SizeRange> maxSizes_;
> >>>
> >>> The use of std::pair here makes the code below use .first and .second,
> >>> which are not very readable. I think it would be better to store the
> >>> pixel format and max size in two separate fields, of unsigned int and
> >>> SizeRange types respectively. Or, now that I think about it, as you only
> >>> care about the maximum size, maybe adding a Size structure to geometry.h
> >>> would be a good idea.
> >>>
> >>
> >> I see... I'll ponder about it. Adding new stuff it's always a burden
> >> because of documentation and such, but I get your point...
> >
> > I know it can be a bit painful :-( A Size structure should hopefully be
> > simple though.
> >
> >>>>  	};
> >>>>
> >>>>  	IPU3CameraData *cameraData(const Camera *camera)
> >>>> @@ -404,18 +426,48 @@ void PipelineHandlerIPU3::registerCameras()
> >>>>  		if (ret)
> >>>>  			continue;
> >>>>
> >>>> -		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> >>>> -
> >>>> +		/*
> >>>> +		 * Make sure the sensor produces at least one image format
> >>>> +		 * compatible with IPU3 CIO2 requirements and cache the camera
> >>>> +		 * maximum sizes.
> >>>> +		 */
> >>>>  		data->sensor_ = new V4L2Subdevice(sensor);
> >>>>  		ret = data->sensor_->open();
> >>>>  		if (ret)
> >>>>  			continue;
> >>>>
> >>>> +		for (auto it : data->sensor_->formats(0)) {
> >>>> +			int mbusCode = mediaBusToCIO2Format(it.first);
> >>>> +			if (mbusCode < 0)
> >>>> +				continue;
> >>>> +
> >>>> +			for (const SizeRange &size : it.second) {
> >>>> +				SizeRange &maxSize = data->maxSizes_.second;
> >>>> +
> >>>> +				if (maxSize.maxWidth < size.maxWidth &&
> >>>> +				    maxSize.maxHeight < size.maxHeight) {
> >>>> +					maxSize.maxWidth = size.maxWidth;
> >>>> +					maxSize.maxHeight = size.maxHeight;
> >>>> +					data->maxSizes_.first = mbusCode;
> >>>> +				}
> >>>> +			}
> >>>> +		}
> >>>
> >>> One blank line ?
> >>
> >> Not sure, as this is an error condition, I like it better without an
> >> empty line.
> >
> > There are generally empty lines after a for loop of if block, but it's
> > your code :-)
> >
> >>>> +		if (data->maxSizes_.second.maxWidth == 0) {
> >>>> +			LOG(IPU3, Info)
> >>>> +				<< "Sensor '" << data->sensor_->entityName()
> >>>> +				<< "' detected, but no supported image format "
> >>>> +				<< " found: skip camera creation";
> >>>> +			continue;
> >>>> +		}
> >>>> +
> >>>>  		data->csi2_ = new V4L2Subdevice(csi2);
> >>>>  		ret = data->csi2_->open();
> >>>>  		if (ret)
> >>>>  			continue;
> >>>>
> >>>> +		data->cio2_->bufferReady.connect(data.get(),
> >>>> +						 &IPU3CameraData::bufferReady);
> >>>> +
> >>>
> >>> This seems unrelated to this patch, is it needed ?
> >>
> >> please see:
> >> 
> >>>> -           data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> >>
> >> A few lines above here.
> >
> > I know, what I meant is that moving the code seems unrelated, as you
> > don't touch it (apart from wrapping the line).
> >
> 
> Ah, got it. I moved it here because I want to connect the signal only
> after we have successfully validated the sensor provided formats
> (introduced in this patch), so I don't think it's unrelated, isn't it?

My point is that there's no strict need to connect the signal only after
validating the sensor formats. It's no big deal though.

> >>>>  		registerCamera(std::move(camera), std::move(data));
> >>>>
> >>>>  		LOG(IPU3, Info)
Niklas Söderlund April 2, 2019, 11:08 a.m. UTC | #6
Hi Jacopo,

Thanks for your work.

On 2019-03-26 09:38:51 +0100, Jacopo Mondi wrote:
> When creating a camera, make sure a the image sensor provides images in
> a format compatible with IPU3 CIO2 unit requirements and cache the
> minimum and maximum camera sizes.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/pipeline/ipu3/ipu3.cpp | 56 +++++++++++++++++++++++++++-
>  1 file changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> index 55489c31df2d..d42c81273cc6 100644
> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> @@ -8,11 +8,14 @@
>  #include <memory>
>  #include <vector>
>  
> +#include <linux/media-bus-format.h>
> +
>  #include <libcamera/camera.h>
>  #include <libcamera/request.h>
>  #include <libcamera/stream.h>
>  
>  #include "device_enumerator.h"
> +#include "geometry.h"
>  #include "log.h"
>  #include "media_device.h"
>  #include "pipeline_handler.h"
> @@ -24,6 +27,22 @@ namespace libcamera {
>  
>  LOG_DEFINE_CATEGORY(IPU3)
>  
> +static int mediaBusToCIO2Format(unsigned int code)
> +{
> +	switch (code) {
> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SBGGR10;
> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SGBRG10;
> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SGRBG10;
> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> +		return V4L2_PIX_FMT_IPU3_SRGGB10;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  class PipelineHandlerIPU3 : public PipelineHandler
>  {
>  public:
> @@ -70,6 +89,9 @@ private:
>  		V4L2Subdevice *sensor_;
>  
>  		Stream stream_;
> +
> +		/* Maximum sizes and the mbus code used to produce them. */
> +		std::pair<unsigned int, SizeRange> maxSizes_;
>  	};
>  
>  	IPU3CameraData *cameraData(const Camera *camera)
> @@ -404,18 +426,48 @@ void PipelineHandlerIPU3::registerCameras()
>  		if (ret)
>  			continue;
>  
> -		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
> -
> +		/*
> +		 * Make sure the sensor produces at least one image format
> +		 * compatible with IPU3 CIO2 requirements and cache the camera
> +		 * maximum sizes.
> +		 */
>  		data->sensor_ = new V4L2Subdevice(sensor);
>  		ret = data->sensor_->open();
>  		if (ret)
>  			continue;
>  
> +		for (auto it : data->sensor_->formats(0)) {
> +			int mbusCode = mediaBusToCIO2Format(it.first);
> +			if (mbusCode < 0)
> +				continue;
> +
> +			for (const SizeRange &size : it.second) {
> +				SizeRange &maxSize = data->maxSizes_.second;
> +
> +				if (maxSize.maxWidth < size.maxWidth &&
> +				    maxSize.maxHeight < size.maxHeight) {
> +					maxSize.maxWidth = size.maxWidth;
> +					maxSize.maxHeight = size.maxHeight;
> +					data->maxSizes_.first = mbusCode;
> +				}
> +			}
> +		}
> +		if (data->maxSizes_.second.maxWidth == 0) {
> +			LOG(IPU3, Info)
> +				<< "Sensor '" << data->sensor_->entityName()
> +				<< "' detected, but no supported image format "
> +				<< " found: skip camera creation";
> +			continue;
> +		}
> +

Nit-pick: I would break this out into a cacheSizes() function as 
registerCameras() is becoming rather large. Nothing I will press tho.

>  		data->csi2_ = new V4L2Subdevice(csi2);
>  		ret = data->csi2_->open();
>  		if (ret)
>  			continue;
>  
> +		data->cio2_->bufferReady.connect(data.get(),
> +						 &IPU3CameraData::bufferReady);
> +
>  		registerCamera(std::move(camera), std::move(data));
>  
>  		LOG(IPU3, Info)
> -- 
> 2.21.0
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 55489c31df2d..d42c81273cc6 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -8,11 +8,14 @@ 
 #include <memory>
 #include <vector>
 
+#include <linux/media-bus-format.h>
+
 #include <libcamera/camera.h>
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
 
 #include "device_enumerator.h"
+#include "geometry.h"
 #include "log.h"
 #include "media_device.h"
 #include "pipeline_handler.h"
@@ -24,6 +27,22 @@  namespace libcamera {
 
 LOG_DEFINE_CATEGORY(IPU3)
 
+static int mediaBusToCIO2Format(unsigned int code)
+{
+	switch (code) {
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+		return V4L2_PIX_FMT_IPU3_SBGGR10;
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+		return V4L2_PIX_FMT_IPU3_SGBRG10;
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+		return V4L2_PIX_FMT_IPU3_SGRBG10;
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		return V4L2_PIX_FMT_IPU3_SRGGB10;
+	default:
+		return -EINVAL;
+	}
+}
+
 class PipelineHandlerIPU3 : public PipelineHandler
 {
 public:
@@ -70,6 +89,9 @@  private:
 		V4L2Subdevice *sensor_;
 
 		Stream stream_;
+
+		/* Maximum sizes and the mbus code used to produce them. */
+		std::pair<unsigned int, SizeRange> maxSizes_;
 	};
 
 	IPU3CameraData *cameraData(const Camera *camera)
@@ -404,18 +426,48 @@  void PipelineHandlerIPU3::registerCameras()
 		if (ret)
 			continue;
 
-		data->cio2_->bufferReady.connect(data.get(), &IPU3CameraData::bufferReady);
-
+		/*
+		 * Make sure the sensor produces at least one image format
+		 * compatible with IPU3 CIO2 requirements and cache the camera
+		 * maximum sizes.
+		 */
 		data->sensor_ = new V4L2Subdevice(sensor);
 		ret = data->sensor_->open();
 		if (ret)
 			continue;
 
+		for (auto it : data->sensor_->formats(0)) {
+			int mbusCode = mediaBusToCIO2Format(it.first);
+			if (mbusCode < 0)
+				continue;
+
+			for (const SizeRange &size : it.second) {
+				SizeRange &maxSize = data->maxSizes_.second;
+
+				if (maxSize.maxWidth < size.maxWidth &&
+				    maxSize.maxHeight < size.maxHeight) {
+					maxSize.maxWidth = size.maxWidth;
+					maxSize.maxHeight = size.maxHeight;
+					data->maxSizes_.first = mbusCode;
+				}
+			}
+		}
+		if (data->maxSizes_.second.maxWidth == 0) {
+			LOG(IPU3, Info)
+				<< "Sensor '" << data->sensor_->entityName()
+				<< "' detected, but no supported image format "
+				<< " found: skip camera creation";
+			continue;
+		}
+
 		data->csi2_ = new V4L2Subdevice(csi2);
 		ret = data->csi2_->open();
 		if (ret)
 			continue;
 
+		data->cio2_->bufferReady.connect(data.get(),
+						 &IPU3CameraData::bufferReady);
+
 		registerCamera(std::move(camera), std::move(data));
 
 		LOG(IPU3, Info)