[libcamera-devel,1/3] libcamera: v4l2_subdevice: Implement ENUM_FRAME_SIZES

Message ID 20190219165620.2385-2-jacopo@jmondi.org
State Accepted
Headers show
Series
  • libcamera: v4l2_subdev and v4l2_device mixed
Related show

Commit Message

Jacopo Mondi Feb. 19, 2019, 4:56 p.m. UTC
Implement enumFormat() methods to enumerate the available image
resolutions on the subdevice.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 src/libcamera/include/v4l2_subdevice.h | 11 ++++
 src/libcamera/v4l2_subdevice.cpp       | 90 ++++++++++++++++++++++++++
 2 files changed, 101 insertions(+)

Comments

Niklas Söderlund Feb. 21, 2019, 3:31 p.m. UTC | #1
Hi Jacopo,

Thanks for your patch.

On 2019-02-19 17:56:18 +0100, Jacopo Mondi wrote:
> Implement enumFormat() methods to enumerate the available image
> resolutions on the subdevice.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/include/v4l2_subdevice.h | 11 ++++
>  src/libcamera/v4l2_subdevice.cpp       | 90 ++++++++++++++++++++++++++
>  2 files changed, 101 insertions(+)
> 
> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
> index 82fa6685ab52..c7045776555c 100644
> --- a/src/libcamera/include/v4l2_subdevice.h
> +++ b/src/libcamera/include/v4l2_subdevice.h
> @@ -14,6 +14,16 @@ namespace libcamera {
>  class MediaEntity;
>  struct Rectangle;
>  
> +struct V4L2SubdeviceFormatEnum {
> +	unsigned int index;
> +	uint32_t mbus_code;
> +
> +	uint32_t minWidth;
> +	uint32_t maxWidth;
> +	uint32_t minHeight;
> +	uint32_t maxHeight;
> +};
> +
>  struct V4L2SubdeviceFormat {
>  	uint32_t mbus_code;
>  	uint32_t width;
> @@ -36,6 +46,7 @@ public:
>  	int setCrop(unsigned int pad, Rectangle *rect);
>  	int setCompose(unsigned int pad, Rectangle *rect);
>  
> +	int enumFormat(unsigned int pad, V4L2SubdeviceFormatEnum *formatEnum);
>  	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
>  	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
>  
> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> index b436f73cc75f..5665154a2762 100644
> --- a/src/libcamera/v4l2_subdevice.cpp
> +++ b/src/libcamera/v4l2_subdevice.cpp
> @@ -26,6 +26,52 @@ namespace libcamera {
>  
>  LOG_DEFINE_CATEGORY(V4L2Subdev)
>  
> +/**
> + * \struct V4L2SubdeviceFormatEnum
> + * \brief The V4L2 sub-device image size enumeration
> + *
> + * This structure describes an image resolution as enumerated by the V4L2
> + * sub-device. The structure is used as format exchange between the caller and
> + * the enumFormat() method. The caller is responsible to fill the media bus
> + * code to use and the index of the format to be enumerated.
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::index
> + * \brief The index of the format to be enumerated
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::mbus_code
> + * \brief The pixel format identification code for the formats to enumerate
> + *
> + * \sa V4L2SubdeviceFormat for media bus format pixel code description.
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::minWidth
> + * \brief The minimum width of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::maxWidth
> + * \brief The maximum width of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::minHeight
> + * \brief The minimum height of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::maxHeight
> + * \brief The maximum height of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
>  /**
>   * \struct V4L2SubdeviceFormat
>   * \brief The V4L2 sub-device image format and sizes
> @@ -171,6 +217,50 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
>  	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
>  }
>  
> +/**
> + * \brief Enumerate the sub-device image resolutions
> + * \param[in] pad The 0-indexed pad number to enumerate formats on
> + * \param[inout] formatEnum The format enumeration description
> + *
> + * The method retrieve the image resolution of the image format with index
> + * formatEnum.index for the pixel format specified by formatEnum.mbus_code.
> + *
> + * To enumerate image resolutions, the caller shall start enumerating all
> + * formats by setting the formatEnum.index field to 0, and increasing it by
> + * one for any successive call, until the -EINVAL return code is returned.

Should we not help pipeline handlers by hiding this? And instead return 
a vector of V4L2SubdeviceFormatEnum with all formats?

> + *
> + * \return 0 on success, or a negative error code otherwise
> + */
> +int V4L2Subdevice::enumFormat(unsigned int pad,
> +			      V4L2SubdeviceFormatEnum *formatEnum)
> +{
> +	struct v4l2_subdev_frame_size_enum sizeEnum = {};
> +
> +	sizeEnum.index = formatEnum->index;
> +	sizeEnum.code = formatEnum->mbus_code;
> +	sizeEnum.pad = pad;

This is confusing, index and code comes from formatEnum while pad is a 
separate argument.

> +	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;

I think this should be configurable by the caller or other way 
customisable. In the not so distant future we will need to add support 
for V4L2_SUBDEV_FORMAT_TRY in a lot of places better to prepare for it 
:-)

> +
> +	int ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);
> +	if (ret) {
> +		ret = -errno;
> +		if (ret == -EINVAL)
> +			return ret;
> +
> +		LOG(V4L2Subdev, Error)
> +			<< "Unable to enumerate format on pad " << pad
> +			<< " of " << deviceNode_ << ": " << strerror(-ret);
> +		return ret;
> +	}
> +
> +	formatEnum->maxWidth = sizeEnum.max_width;
> +	formatEnum->minWidth = sizeEnum.min_width;
> +	formatEnum->maxHeight = sizeEnum.max_height;
> +	formatEnum->minHeight = sizeEnum.min_height;
> +
> +	return 0;
> +}
> +
>  /**
>   * \brief Retrieve the image format set on one of the V4L2 subdevice pads
>   * \param[in] pad The 0-indexed pad number the format is to be retrieved from
> -- 
> 2.20.1
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Laurent Pinchart Feb. 21, 2019, 11:25 p.m. UTC | #2
Hi Jacopo,

Thank you for the patch.

On Tue, Feb 19, 2019 at 05:56:18PM +0100, Jacopo Mondi wrote:
> Implement enumFormat() methods to enumerate the available image
> resolutions on the subdevice.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/include/v4l2_subdevice.h | 11 ++++
>  src/libcamera/v4l2_subdevice.cpp       | 90 ++++++++++++++++++++++++++
>  2 files changed, 101 insertions(+)
> 
> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
> index 82fa6685ab52..c7045776555c 100644
> --- a/src/libcamera/include/v4l2_subdevice.h
> +++ b/src/libcamera/include/v4l2_subdevice.h
> @@ -14,6 +14,16 @@ namespace libcamera {
>  class MediaEntity;
>  struct Rectangle;
>  
> +struct V4L2SubdeviceFormatEnum {
> +	unsigned int index;
> +	uint32_t mbus_code;
> +
> +	uint32_t minWidth;
> +	uint32_t maxWidth;
> +	uint32_t minHeight;
> +	uint32_t maxHeight;
> +};
> +
>  struct V4L2SubdeviceFormat {
>  	uint32_t mbus_code;
>  	uint32_t width;
> @@ -36,6 +46,7 @@ public:
>  	int setCrop(unsigned int pad, Rectangle *rect);
>  	int setCompose(unsigned int pad, Rectangle *rect);
>  
> +	int enumFormat(unsigned int pad, V4L2SubdeviceFormatEnum *formatEnum);
>  	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
>  	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
>  
> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> index b436f73cc75f..5665154a2762 100644
> --- a/src/libcamera/v4l2_subdevice.cpp
> +++ b/src/libcamera/v4l2_subdevice.cpp
> @@ -26,6 +26,52 @@ namespace libcamera {
>  
>  LOG_DEFINE_CATEGORY(V4L2Subdev)
>  
> +/**
> + * \struct V4L2SubdeviceFormatEnum
> + * \brief The V4L2 sub-device image size enumeration
> + *
> + * This structure describes an image resolution as enumerated by the V4L2
> + * sub-device. The structure is used as format exchange between the caller and
> + * the enumFormat() method. The caller is responsible to fill the media bus
> + * code to use and the index of the format to be enumerated.
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::index
> + * \brief The index of the format to be enumerated
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::mbus_code
> + * \brief The pixel format identification code for the formats to enumerate
> + *
> + * \sa V4L2SubdeviceFormat for media bus format pixel code description.
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::minWidth
> + * \brief The minimum width of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::maxWidth
> + * \brief The maximum width of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::minHeight
> + * \brief The minimum height of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
> +/**
> + * \var V4L2SubdeviceFormatEnum::maxHeight
> + * \brief The maximum height of the enumerated format as reported by the V4L2
> + * sub-device
> + */
> +
>  /**
>   * \struct V4L2SubdeviceFormat
>   * \brief The V4L2 sub-device image format and sizes
> @@ -171,6 +217,50 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
>  	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
>  }
>  
> +/**
> + * \brief Enumerate the sub-device image resolutions
> + * \param[in] pad The 0-indexed pad number to enumerate formats on
> + * \param[inout] formatEnum The format enumeration description
> + *
> + * The method retrieve the image resolution of the image format with index
> + * formatEnum.index for the pixel format specified by formatEnum.mbus_code.
> + *
> + * To enumerate image resolutions, the caller shall start enumerating all
> + * formats by setting the formatEnum.index field to 0, and increasing it by
> + * one for any successive call, until the -EINVAL return code is returned.
> + *
> + * \return 0 on success, or a negative error code otherwise
> + */
> +int V4L2Subdevice::enumFormat(unsigned int pad,
> +			      V4L2SubdeviceFormatEnum *formatEnum)
> +{
> +	struct v4l2_subdev_frame_size_enum sizeEnum = {};
> +
> +	sizeEnum.index = formatEnum->index;
> +	sizeEnum.code = formatEnum->mbus_code;
> +	sizeEnum.pad = pad;
> +	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +
> +	int ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);
> +	if (ret) {
> +		ret = -errno;
> +		if (ret == -EINVAL)
> +			return ret;
> +
> +		LOG(V4L2Subdev, Error)
> +			<< "Unable to enumerate format on pad " << pad
> +			<< " of " << deviceNode_ << ": " << strerror(-ret);
> +		return ret;
> +	}

Let's not repeat the mistake of the V4L2 API that requires calling the
same ioctl in a loop. Instead of just wrapping the ioctl, let's make
this function more useful by enumerating all supported formats and
returning a list. You may even want to have two nested loops, one over
formats, and the other over sizes.

> +
> +	formatEnum->maxWidth = sizeEnum.max_width;
> +	formatEnum->minWidth = sizeEnum.min_width;
> +	formatEnum->maxHeight = sizeEnum.max_height;
> +	formatEnum->minHeight = sizeEnum.min_height;
> +
> +	return 0;
> +}
> +
>  /**
>   * \brief Retrieve the image format set on one of the V4L2 subdevice pads
>   * \param[in] pad The 0-indexed pad number the format is to be retrieved from
Jacopo Mondi Feb. 25, 2019, 9:28 a.m. UTC | #3
Hi Niklas,

On Thu, Feb 21, 2019 at 04:31:56PM +0100, Niklas Söderlund wrote:
> Hi Jacopo,
>
> Thanks for your patch.
>
> On 2019-02-19 17:56:18 +0100, Jacopo Mondi wrote:
> > Implement enumFormat() methods to enumerate the available image
> > resolutions on the subdevice.
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >  src/libcamera/include/v4l2_subdevice.h | 11 ++++
> >  src/libcamera/v4l2_subdevice.cpp       | 90 ++++++++++++++++++++++++++
> >  2 files changed, 101 insertions(+)
> >
> > diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
> > index 82fa6685ab52..c7045776555c 100644
> > --- a/src/libcamera/include/v4l2_subdevice.h
> > +++ b/src/libcamera/include/v4l2_subdevice.h
> > @@ -14,6 +14,16 @@ namespace libcamera {
> >  class MediaEntity;
> >  struct Rectangle;
> >
> > +struct V4L2SubdeviceFormatEnum {
> > +	unsigned int index;
> > +	uint32_t mbus_code;
> > +
> > +	uint32_t minWidth;
> > +	uint32_t maxWidth;
> > +	uint32_t minHeight;
> > +	uint32_t maxHeight;
> > +};
> > +
> >  struct V4L2SubdeviceFormat {
> >  	uint32_t mbus_code;
> >  	uint32_t width;
> > @@ -36,6 +46,7 @@ public:
> >  	int setCrop(unsigned int pad, Rectangle *rect);
> >  	int setCompose(unsigned int pad, Rectangle *rect);
> >
> > +	int enumFormat(unsigned int pad, V4L2SubdeviceFormatEnum *formatEnum);
> >  	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
> >  	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
> >
> > diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> > index b436f73cc75f..5665154a2762 100644
> > --- a/src/libcamera/v4l2_subdevice.cpp
> > +++ b/src/libcamera/v4l2_subdevice.cpp
> > @@ -26,6 +26,52 @@ namespace libcamera {
> >
> >  LOG_DEFINE_CATEGORY(V4L2Subdev)
> >
> > +/**
> > + * \struct V4L2SubdeviceFormatEnum
> > + * \brief The V4L2 sub-device image size enumeration
> > + *
> > + * This structure describes an image resolution as enumerated by the V4L2
> > + * sub-device. The structure is used as format exchange between the caller and
> > + * the enumFormat() method. The caller is responsible to fill the media bus
> > + * code to use and the index of the format to be enumerated.
> > + */
> > +
> > +/**
> > + * \var V4L2SubdeviceFormatEnum::index
> > + * \brief The index of the format to be enumerated
> > + */
> > +
> > +/**
> > + * \var V4L2SubdeviceFormatEnum::mbus_code
> > + * \brief The pixel format identification code for the formats to enumerate
> > + *
> > + * \sa V4L2SubdeviceFormat for media bus format pixel code description.
> > + */
> > +
> > +/**
> > + * \var V4L2SubdeviceFormatEnum::minWidth
> > + * \brief The minimum width of the enumerated format as reported by the V4L2
> > + * sub-device
> > + */
> > +
> > +/**
> > + * \var V4L2SubdeviceFormatEnum::maxWidth
> > + * \brief The maximum width of the enumerated format as reported by the V4L2
> > + * sub-device
> > + */
> > +
> > +/**
> > + * \var V4L2SubdeviceFormatEnum::minHeight
> > + * \brief The minimum height of the enumerated format as reported by the V4L2
> > + * sub-device
> > + */
> > +
> > +/**
> > + * \var V4L2SubdeviceFormatEnum::maxHeight
> > + * \brief The maximum height of the enumerated format as reported by the V4L2
> > + * sub-device
> > + */
> > +
> >  /**
> >   * \struct V4L2SubdeviceFormat
> >   * \brief The V4L2 sub-device image format and sizes
> > @@ -171,6 +217,50 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
> >  	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
> >  }
> >
> > +/**
> > + * \brief Enumerate the sub-device image resolutions
> > + * \param[in] pad The 0-indexed pad number to enumerate formats on
> > + * \param[inout] formatEnum The format enumeration description
> > + *
> > + * The method retrieve the image resolution of the image format with index
> > + * formatEnum.index for the pixel format specified by formatEnum.mbus_code.
> > + *
> > + * To enumerate image resolutions, the caller shall start enumerating all
> > + * formats by setting the formatEnum.index field to 0, and increasing it by
> > + * one for any successive call, until the -EINVAL return code is returned.
>
> Should we not help pipeline handlers by hiding this? And instead return
> a vector of V4L2SubdeviceFormatEnum with all formats?
>

Yes, you and Laurent had the same suggestion and is surely better.
I'll re-implement this.

> > + *
> > + * \return 0 on success, or a negative error code otherwise
> > + */
> > +int V4L2Subdevice::enumFormat(unsigned int pad,
> > +			      V4L2SubdeviceFormatEnum *formatEnum)
> > +{
> > +	struct v4l2_subdev_frame_size_enum sizeEnum = {};
> > +
> > +	sizeEnum.index = formatEnum->index;
> > +	sizeEnum.code = formatEnum->mbus_code;
> > +	sizeEnum.pad = pad;
>
> This is confusing, index and code comes from formatEnum while pad is a
> separate argument.
>

All V4L2Subdevice methods accepts a pad as first argument. I would
keep this consistent.

> > +	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>
> I think this should be configurable by the caller or other way
> customisable. In the not so distant future we will need to add support
> for V4L2_SUBDEV_FORMAT_TRY in a lot of places better to prepare for it
> :-)

I'm really not sure about this one, I could add a field to
V4L2SubdeviceFormatEnum for this...

>
> > +
> > +	int ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);
> > +	if (ret) {
> > +		ret = -errno;
> > +		if (ret == -EINVAL)
> > +			return ret;
> > +
> > +		LOG(V4L2Subdev, Error)
> > +			<< "Unable to enumerate format on pad " << pad
> > +			<< " of " << deviceNode_ << ": " << strerror(-ret);
> > +		return ret;
> > +	}
> > +
> > +	formatEnum->maxWidth = sizeEnum.max_width;
> > +	formatEnum->minWidth = sizeEnum.min_width;
> > +	formatEnum->maxHeight = sizeEnum.max_height;
> > +	formatEnum->minHeight = sizeEnum.min_height;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> >   * \brief Retrieve the image format set on one of the V4L2 subdevice pads
> >   * \param[in] pad The 0-indexed pad number the format is to be retrieved from
> > --
> > 2.20.1
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel
>
> --
> Regards,
> Niklas Söderlund
Jacopo Mondi Feb. 25, 2019, 9:44 a.m. UTC | #4
On Mon, Feb 25, 2019 at 10:28:33AM +0100, Jacopo Mondi wrote:
> Hi Niklas,
>
> On Thu, Feb 21, 2019 at 04:31:56PM +0100, Niklas Söderlund wrote:
> > Hi Jacopo,
> >
> > Thanks for your patch.
> >
> > On 2019-02-19 17:56:18 +0100, Jacopo Mondi wrote:
> > > Implement enumFormat() methods to enumerate the available image
> > > resolutions on the subdevice.
> > >
> > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > >  src/libcamera/include/v4l2_subdevice.h | 11 ++++
> > >  src/libcamera/v4l2_subdevice.cpp       | 90 ++++++++++++++++++++++++++
> > >  2 files changed, 101 insertions(+)
> > >
> > > diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
> > > index 82fa6685ab52..c7045776555c 100644
> > > --- a/src/libcamera/include/v4l2_subdevice.h
> > > +++ b/src/libcamera/include/v4l2_subdevice.h
> > > @@ -14,6 +14,16 @@ namespace libcamera {
> > >  class MediaEntity;
> > >  struct Rectangle;
> > >
> > > +struct V4L2SubdeviceFormatEnum {
> > > +	unsigned int index;
> > > +	uint32_t mbus_code;
> > > +
> > > +	uint32_t minWidth;
> > > +	uint32_t maxWidth;
> > > +	uint32_t minHeight;
> > > +	uint32_t maxHeight;
> > > +};
> > > +
> > >  struct V4L2SubdeviceFormat {
> > >  	uint32_t mbus_code;
> > >  	uint32_t width;
> > > @@ -36,6 +46,7 @@ public:
> > >  	int setCrop(unsigned int pad, Rectangle *rect);
> > >  	int setCompose(unsigned int pad, Rectangle *rect);
> > >
> > > +	int enumFormat(unsigned int pad, V4L2SubdeviceFormatEnum *formatEnum);
> > >  	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
> > >  	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
> > >
> > > diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> > > index b436f73cc75f..5665154a2762 100644
> > > --- a/src/libcamera/v4l2_subdevice.cpp
> > > +++ b/src/libcamera/v4l2_subdevice.cpp
> > > @@ -26,6 +26,52 @@ namespace libcamera {
> > >
> > >  LOG_DEFINE_CATEGORY(V4L2Subdev)
> > >
> > > +/**
> > > + * \struct V4L2SubdeviceFormatEnum
> > > + * \brief The V4L2 sub-device image size enumeration
> > > + *
> > > + * This structure describes an image resolution as enumerated by the V4L2
> > > + * sub-device. The structure is used as format exchange between the caller and
> > > + * the enumFormat() method. The caller is responsible to fill the media bus
> > > + * code to use and the index of the format to be enumerated.
> > > + */
> > > +
> > > +/**
> > > + * \var V4L2SubdeviceFormatEnum::index
> > > + * \brief The index of the format to be enumerated
> > > + */
> > > +
> > > +/**
> > > + * \var V4L2SubdeviceFormatEnum::mbus_code
> > > + * \brief The pixel format identification code for the formats to enumerate
> > > + *
> > > + * \sa V4L2SubdeviceFormat for media bus format pixel code description.
> > > + */
> > > +
> > > +/**
> > > + * \var V4L2SubdeviceFormatEnum::minWidth
> > > + * \brief The minimum width of the enumerated format as reported by the V4L2
> > > + * sub-device
> > > + */
> > > +
> > > +/**
> > > + * \var V4L2SubdeviceFormatEnum::maxWidth
> > > + * \brief The maximum width of the enumerated format as reported by the V4L2
> > > + * sub-device
> > > + */
> > > +
> > > +/**
> > > + * \var V4L2SubdeviceFormatEnum::minHeight
> > > + * \brief The minimum height of the enumerated format as reported by the V4L2
> > > + * sub-device
> > > + */
> > > +
> > > +/**
> > > + * \var V4L2SubdeviceFormatEnum::maxHeight
> > > + * \brief The maximum height of the enumerated format as reported by the V4L2
> > > + * sub-device
> > > + */
> > > +
> > >  /**
> > >   * \struct V4L2SubdeviceFormat
> > >   * \brief The V4L2 sub-device image format and sizes
> > > @@ -171,6 +217,50 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
> > >  	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
> > >  }
> > >
> > > +/**
> > > + * \brief Enumerate the sub-device image resolutions
> > > + * \param[in] pad The 0-indexed pad number to enumerate formats on
> > > + * \param[inout] formatEnum The format enumeration description
> > > + *
> > > + * The method retrieve the image resolution of the image format with index
> > > + * formatEnum.index for the pixel format specified by formatEnum.mbus_code.
> > > + *
> > > + * To enumerate image resolutions, the caller shall start enumerating all
> > > + * formats by setting the formatEnum.index field to 0, and increasing it by
> > > + * one for any successive call, until the -EINVAL return code is returned.
> >
> > Should we not help pipeline handlers by hiding this? And instead return
> > a vector of V4L2SubdeviceFormatEnum with all formats?
> >
>
> Yes, you and Laurent had the same suggestion and is surely better.
> I'll re-implement this.
>
> > > + *
> > > + * \return 0 on success, or a negative error code otherwise
> > > + */
> > > +int V4L2Subdevice::enumFormat(unsigned int pad,
> > > +			      V4L2SubdeviceFormatEnum *formatEnum)
> > > +{
> > > +	struct v4l2_subdev_frame_size_enum sizeEnum = {};
> > > +
> > > +	sizeEnum.index = formatEnum->index;
> > > +	sizeEnum.code = formatEnum->mbus_code;
> > > +	sizeEnum.pad = pad;
> >
> > This is confusing, index and code comes from formatEnum while pad is a
> > separate argument.
> >
>
> All V4L2Subdevice methods accepts a pad as first argument. I would
> keep this consistent.
>
> > > +	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> >
> > I think this should be configurable by the caller or other way
> > customisable. In the not so distant future we will need to add support
> > for V4L2_SUBDEV_FORMAT_TRY in a lot of places better to prepare for it
> > :-)
>
> I'm really not sure about this one, I could add a field to
> V4L2SubdeviceFormatEnum for this...
>

Re-thinking about this, I would leave this out until we don't define a
way to handle FORMAT_TRY globally, as otherwise I would have to expose
that flag outside of V4L2Subdevice which I would prefer not to...

> >
> > > +
> > > +	int ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);
> > > +	if (ret) {
> > > +		ret = -errno;
> > > +		if (ret == -EINVAL)
> > > +			return ret;
> > > +
> > > +		LOG(V4L2Subdev, Error)
> > > +			<< "Unable to enumerate format on pad " << pad
> > > +			<< " of " << deviceNode_ << ": " << strerror(-ret);
> > > +		return ret;
> > > +	}
> > > +
> > > +	formatEnum->maxWidth = sizeEnum.max_width;
> > > +	formatEnum->minWidth = sizeEnum.min_width;
> > > +	formatEnum->maxHeight = sizeEnum.max_height;
> > > +	formatEnum->minHeight = sizeEnum.min_height;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  /**
> > >   * \brief Retrieve the image format set on one of the V4L2 subdevice pads
> > >   * \param[in] pad The 0-indexed pad number the format is to be retrieved from
> > > --
> > > 2.20.1
> > >
> > > _______________________________________________
> > > libcamera-devel mailing list
> > > libcamera-devel@lists.libcamera.org
> > > https://lists.libcamera.org/listinfo/libcamera-devel
> >
> > --
> > Regards,
> > Niklas Söderlund



> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Laurent Pinchart Feb. 25, 2019, 7:50 p.m. UTC | #5
Hi Jacopo,

On Mon, Feb 25, 2019 at 10:44:35AM +0100, Jacopo Mondi wrote:
> On Mon, Feb 25, 2019 at 10:28:33AM +0100, Jacopo Mondi wrote:
> > On Thu, Feb 21, 2019 at 04:31:56PM +0100, Niklas Söderlund wrote:
> >> On 2019-02-19 17:56:18 +0100, Jacopo Mondi wrote:
> >>> Implement enumFormat() methods to enumerate the available image
> >>> resolutions on the subdevice.
> >>>
> >>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> >>> ---
> >>>  src/libcamera/include/v4l2_subdevice.h | 11 ++++
> >>>  src/libcamera/v4l2_subdevice.cpp       | 90 ++++++++++++++++++++++++++
> >>>  2 files changed, 101 insertions(+)
> >>>
> >>> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
> >>> index 82fa6685ab52..c7045776555c 100644
> >>> --- a/src/libcamera/include/v4l2_subdevice.h
> >>> +++ b/src/libcamera/include/v4l2_subdevice.h
> >>> @@ -14,6 +14,16 @@ namespace libcamera {
> >>>  class MediaEntity;
> >>>  struct Rectangle;
> >>>
> >>> +struct V4L2SubdeviceFormatEnum {
> >>> +	unsigned int index;
> >>> +	uint32_t mbus_code;
> >>> +
> >>> +	uint32_t minWidth;
> >>> +	uint32_t maxWidth;
> >>> +	uint32_t minHeight;
> >>> +	uint32_t maxHeight;
> >>> +};
> >>> +
> >>>  struct V4L2SubdeviceFormat {
> >>>  	uint32_t mbus_code;
> >>>  	uint32_t width;
> >>> @@ -36,6 +46,7 @@ public:
> >>>  	int setCrop(unsigned int pad, Rectangle *rect);
> >>>  	int setCompose(unsigned int pad, Rectangle *rect);
> >>>
> >>> +	int enumFormat(unsigned int pad, V4L2SubdeviceFormatEnum *formatEnum);
> >>>  	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
> >>>  	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
> >>>
> >>> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> >>> index b436f73cc75f..5665154a2762 100644
> >>> --- a/src/libcamera/v4l2_subdevice.cpp
> >>> +++ b/src/libcamera/v4l2_subdevice.cpp
> >>> @@ -26,6 +26,52 @@ namespace libcamera {
> >>>
> >>>  LOG_DEFINE_CATEGORY(V4L2Subdev)
> >>>
> >>> +/**
> >>> + * \struct V4L2SubdeviceFormatEnum
> >>> + * \brief The V4L2 sub-device image size enumeration
> >>> + *
> >>> + * This structure describes an image resolution as enumerated by the V4L2
> >>> + * sub-device. The structure is used as format exchange between the caller and
> >>> + * the enumFormat() method. The caller is responsible to fill the media bus
> >>> + * code to use and the index of the format to be enumerated.
> >>> + */
> >>> +
> >>> +/**
> >>> + * \var V4L2SubdeviceFormatEnum::index
> >>> + * \brief The index of the format to be enumerated
> >>> + */
> >>> +
> >>> +/**
> >>> + * \var V4L2SubdeviceFormatEnum::mbus_code
> >>> + * \brief The pixel format identification code for the formats to enumerate
> >>> + *
> >>> + * \sa V4L2SubdeviceFormat for media bus format pixel code description.
> >>> + */
> >>> +
> >>> +/**
> >>> + * \var V4L2SubdeviceFormatEnum::minWidth
> >>> + * \brief The minimum width of the enumerated format as reported by the V4L2
> >>> + * sub-device
> >>> + */
> >>> +
> >>> +/**
> >>> + * \var V4L2SubdeviceFormatEnum::maxWidth
> >>> + * \brief The maximum width of the enumerated format as reported by the V4L2
> >>> + * sub-device
> >>> + */
> >>> +
> >>> +/**
> >>> + * \var V4L2SubdeviceFormatEnum::minHeight
> >>> + * \brief The minimum height of the enumerated format as reported by the V4L2
> >>> + * sub-device
> >>> + */
> >>> +
> >>> +/**
> >>> + * \var V4L2SubdeviceFormatEnum::maxHeight
> >>> + * \brief The maximum height of the enumerated format as reported by the V4L2
> >>> + * sub-device
> >>> + */
> >>> +
> >>>  /**
> >>>   * \struct V4L2SubdeviceFormat
> >>>   * \brief The V4L2 sub-device image format and sizes
> >>> @@ -171,6 +217,50 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
> >>>  	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
> >>>  }
> >>>
> >>> +/**
> >>> + * \brief Enumerate the sub-device image resolutions
> >>> + * \param[in] pad The 0-indexed pad number to enumerate formats on
> >>> + * \param[inout] formatEnum The format enumeration description
> >>> + *
> >>> + * The method retrieve the image resolution of the image format with index
> >>> + * formatEnum.index for the pixel format specified by formatEnum.mbus_code.
> >>> + *
> >>> + * To enumerate image resolutions, the caller shall start enumerating all
> >>> + * formats by setting the formatEnum.index field to 0, and increasing it by
> >>> + * one for any successive call, until the -EINVAL return code is returned.
> >>
> >> Should we not help pipeline handlers by hiding this? And instead return
> >> a vector of V4L2SubdeviceFormatEnum with all formats?
> >>
> >
> > Yes, you and Laurent had the same suggestion and is surely better.
> > I'll re-implement this.
> >
> >>> + *
> >>> + * \return 0 on success, or a negative error code otherwise
> >>> + */
> >>> +int V4L2Subdevice::enumFormat(unsigned int pad,
> >>> +			      V4L2SubdeviceFormatEnum *formatEnum)
> >>> +{
> >>> +	struct v4l2_subdev_frame_size_enum sizeEnum = {};
> >>> +
> >>> +	sizeEnum.index = formatEnum->index;
> >>> +	sizeEnum.code = formatEnum->mbus_code;
> >>> +	sizeEnum.pad = pad;
> >>
> >> This is confusing, index and code comes from formatEnum while pad is a
> >> separate argument.
> >>
> >
> > All V4L2Subdevice methods accepts a pad as first argument. I would
> > keep this consistent.
> >
> >>> +	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> >>
> >> I think this should be configurable by the caller or other way
> >> customisable. In the not so distant future we will need to add support
> >> for V4L2_SUBDEV_FORMAT_TRY in a lot of places better to prepare for it
> >> :-)
> >
> > I'm really not sure about this one, I could add a field to
> > V4L2SubdeviceFormatEnum for this...
> >
> 
> Re-thinking about this, I would leave this out until we don't define a
> way to handle FORMAT_TRY globally, as otherwise I would have to expose
> that flag outside of V4L2Subdevice which I would prefer not to...

I think you made the right decision.

> >>> +
> >>> +	int ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);
> >>> +	if (ret) {
> >>> +		ret = -errno;
> >>> +		if (ret == -EINVAL)
> >>> +			return ret;
> >>> +
> >>> +		LOG(V4L2Subdev, Error)
> >>> +			<< "Unable to enumerate format on pad " << pad
> >>> +			<< " of " << deviceNode_ << ": " << strerror(-ret);
> >>> +		return ret;
> >>> +	}
> >>> +
> >>> +	formatEnum->maxWidth = sizeEnum.max_width;
> >>> +	formatEnum->minWidth = sizeEnum.min_width;
> >>> +	formatEnum->maxHeight = sizeEnum.max_height;
> >>> +	formatEnum->minHeight = sizeEnum.min_height;
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>>  /**
> >>>   * \brief Retrieve the image format set on one of the V4L2 subdevice pads
> >>>   * \param[in] pad The 0-indexed pad number the format is to be retrieved from
Niklas Söderlund Feb. 25, 2019, 10:35 p.m. UTC | #6
Hi Jacopo, Laurent,

> > >
> > > All V4L2Subdevice methods accepts a pad as first argument. I would
> > > keep this consistent.
> > >
> > >>> +	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> > >>
> > >> I think this should be configurable by the caller or other way
> > >> customisable. In the not so distant future we will need to add support
> > >> for V4L2_SUBDEV_FORMAT_TRY in a lot of places better to prepare for it
> > >> :-)
> > >
> > > I'm really not sure about this one, I could add a field to
> > > V4L2SubdeviceFormatEnum for this...
> > >
> > 
> > Re-thinking about this, I would leave this out until we don't define a
> > way to handle FORMAT_TRY globally, as otherwise I would have to expose
> > that flag outside of V4L2Subdevice which I would prefer not to...
> 
> I think you made the right decision.

After mocking around a bit more in the code I now agree with you both.  
Hard coding of V4L2_SUBDEV_FORMAT_ACTIVE is how it's done in other 
places so we can change this when we add V4L2_SUBDEV_FORMAT_TRY in the 
future. Sorry for not noticing this in my first review.

Patch

diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
index 82fa6685ab52..c7045776555c 100644
--- a/src/libcamera/include/v4l2_subdevice.h
+++ b/src/libcamera/include/v4l2_subdevice.h
@@ -14,6 +14,16 @@  namespace libcamera {
 class MediaEntity;
 struct Rectangle;
 
+struct V4L2SubdeviceFormatEnum {
+	unsigned int index;
+	uint32_t mbus_code;
+
+	uint32_t minWidth;
+	uint32_t maxWidth;
+	uint32_t minHeight;
+	uint32_t maxHeight;
+};
+
 struct V4L2SubdeviceFormat {
 	uint32_t mbus_code;
 	uint32_t width;
@@ -36,6 +46,7 @@  public:
 	int setCrop(unsigned int pad, Rectangle *rect);
 	int setCompose(unsigned int pad, Rectangle *rect);
 
+	int enumFormat(unsigned int pad, V4L2SubdeviceFormatEnum *formatEnum);
 	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
 	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
 
diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
index b436f73cc75f..5665154a2762 100644
--- a/src/libcamera/v4l2_subdevice.cpp
+++ b/src/libcamera/v4l2_subdevice.cpp
@@ -26,6 +26,52 @@  namespace libcamera {
 
 LOG_DEFINE_CATEGORY(V4L2Subdev)
 
+/**
+ * \struct V4L2SubdeviceFormatEnum
+ * \brief The V4L2 sub-device image size enumeration
+ *
+ * This structure describes an image resolution as enumerated by the V4L2
+ * sub-device. The structure is used as format exchange between the caller and
+ * the enumFormat() method. The caller is responsible to fill the media bus
+ * code to use and the index of the format to be enumerated.
+ */
+
+/**
+ * \var V4L2SubdeviceFormatEnum::index
+ * \brief The index of the format to be enumerated
+ */
+
+/**
+ * \var V4L2SubdeviceFormatEnum::mbus_code
+ * \brief The pixel format identification code for the formats to enumerate
+ *
+ * \sa V4L2SubdeviceFormat for media bus format pixel code description.
+ */
+
+/**
+ * \var V4L2SubdeviceFormatEnum::minWidth
+ * \brief The minimum width of the enumerated format as reported by the V4L2
+ * sub-device
+ */
+
+/**
+ * \var V4L2SubdeviceFormatEnum::maxWidth
+ * \brief The maximum width of the enumerated format as reported by the V4L2
+ * sub-device
+ */
+
+/**
+ * \var V4L2SubdeviceFormatEnum::minHeight
+ * \brief The minimum height of the enumerated format as reported by the V4L2
+ * sub-device
+ */
+
+/**
+ * \var V4L2SubdeviceFormatEnum::maxHeight
+ * \brief The maximum height of the enumerated format as reported by the V4L2
+ * sub-device
+ */
+
 /**
  * \struct V4L2SubdeviceFormat
  * \brief The V4L2 sub-device image format and sizes
@@ -171,6 +217,50 @@  int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
 	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
 }
 
+/**
+ * \brief Enumerate the sub-device image resolutions
+ * \param[in] pad The 0-indexed pad number to enumerate formats on
+ * \param[inout] formatEnum The format enumeration description
+ *
+ * The method retrieve the image resolution of the image format with index
+ * formatEnum.index for the pixel format specified by formatEnum.mbus_code.
+ *
+ * To enumerate image resolutions, the caller shall start enumerating all
+ * formats by setting the formatEnum.index field to 0, and increasing it by
+ * one for any successive call, until the -EINVAL return code is returned.
+ *
+ * \return 0 on success, or a negative error code otherwise
+ */
+int V4L2Subdevice::enumFormat(unsigned int pad,
+			      V4L2SubdeviceFormatEnum *formatEnum)
+{
+	struct v4l2_subdev_frame_size_enum sizeEnum = {};
+
+	sizeEnum.index = formatEnum->index;
+	sizeEnum.code = formatEnum->mbus_code;
+	sizeEnum.pad = pad;
+	sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+	int ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);
+	if (ret) {
+		ret = -errno;
+		if (ret == -EINVAL)
+			return ret;
+
+		LOG(V4L2Subdev, Error)
+			<< "Unable to enumerate format on pad " << pad
+			<< " of " << deviceNode_ << ": " << strerror(-ret);
+		return ret;
+	}
+
+	formatEnum->maxWidth = sizeEnum.max_width;
+	formatEnum->minWidth = sizeEnum.min_width;
+	formatEnum->maxHeight = sizeEnum.max_height;
+	formatEnum->minHeight = sizeEnum.min_height;
+
+	return 0;
+}
+
 /**
  * \brief Retrieve the image format set on one of the V4L2 subdevice pads
  * \param[in] pad The 0-indexed pad number the format is to be retrieved from