[libcamera-devel] [PATCH v2 2/6] libcamera: v4l2_subdevice: Implement ENUM_FRAME_SIZES

Niklas Söderlund niklas.soderlund at ragnatech.se
Tue Feb 26 03:39:42 CET 2019


Hi Jacopo,

Thanks for your patch.

On 2019-02-25 13:10:33 +0100, Jacopo Mondi wrote:
> Implement enumFormat() methods to enumerate the available image
> resolutions on the subdevice.
> 
> Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
> ---
>  src/libcamera/include/v4l2_subdevice.h |  8 +++
>  src/libcamera/v4l2_subdevice.cpp       | 93 ++++++++++++++++++++++++++
>  2 files changed, 101 insertions(+)
> 
> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h
> index fcfbee5af106..cb033a76933c 100644
> --- a/src/libcamera/include/v4l2_subdevice.h
> +++ b/src/libcamera/include/v4l2_subdevice.h
> @@ -7,7 +7,9 @@
>  #ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__
>  #define __LIBCAMERA_V4L2_SUBDEVICE_H__
>  
> +#include <map>
>  #include <string>
> +#include <vector>
>  
>  #include "media_object.h"
>  
> @@ -38,16 +40,22 @@ public:
>  	int setCrop(unsigned int pad, Rectangle *rect);
>  	int setCompose(unsigned int pad, Rectangle *rect);
>  
> +	std::vector<V4L2SubdeviceFormat> &formats(unsigned int pad);

As you return a referent to the internal data structure should it not 
at lest be const?

>  	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format);
>  	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format);
>  
>  private:
> +	int listPadFormats(unsigned int pad,
> +			   std::vector<V4L2SubdeviceFormat> *formats);
> +	void listFormats();
>  	int setSelection(unsigned int pad, unsigned int target,
>  			 Rectangle *rect);
>  
>  	const MediaEntity *entity_;
>  	std::string deviceNode_;
>  	int fd_;
> +
> +	std::map<unsigned int, std::vector<V4L2SubdeviceFormat>> formats_;
>  };
>  
>  } /* namespace libcamera */
> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> index ebf87f0124cb..0e9c654579dc 100644
> --- a/src/libcamera/v4l2_subdevice.cpp
> +++ b/src/libcamera/v4l2_subdevice.cpp
> @@ -5,6 +5,10 @@
>   * v4l2_subdevice.cpp - V4L2 Subdevice
>   */
>  
> +#include <map>
> +#include <string>
> +#include <vector>
> +
>  #include <fcntl.h>
>  #include <string.h>
>  #include <sys/ioctl.h>
> @@ -116,6 +120,8 @@ int V4L2Subdevice::open()
>  	}
>  	fd_ = ret;
>  
> +	listFormats();
> +

I would inline the function here, but I won't push it as its mostly 
taste.

>  	return 0;
>  }
>  
> @@ -178,6 +184,17 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)
>  	return setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);
>  }
>  
> +/**
> + * \brief List the sub-device image resolutions and formats on \a pad
> + * \param[in] pad The 0-indexed pad number to enumerate formats on
> + *
> + * \return A vector of image formats, or an empty vector on error
> + */
> +std::vector<V4L2SubdeviceFormat> &V4L2Subdevice::formats(unsigned int pad)
> +{
> +	return formats_[pad];

Maybe add a bounds checking on pad here? What would happen if a pad that 
don't exists is requested?

> +}
> +
>  /**
>   * \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
> @@ -242,6 +259,82 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)
>  	return 0;
>  }
>  
> +int V4L2Subdevice::listPadFormats(unsigned int pad,
> +				  std::vector<V4L2SubdeviceFormat> *formats)
> +{
> +	struct v4l2_subdev_frame_size_enum sizeEnum = {};
> +	struct v4l2_subdev_mbus_code_enum mbusEnum = {};
> +	int ret;
> +
> +	mbusEnum.index = 0;
> +	mbusEnum.pad = pad;
> +	mbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +
> +	while (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum))) {
> +		sizeEnum.index = 0;
> +		sizeEnum.code = mbusEnum.code;
> +		sizeEnum.pad = pad;
> +		sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> +
> +		while (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE,
> +				     &sizeEnum))) {
> +
> +			/* Store the minimum and maximum reported sizes. */
> +			V4L2SubdeviceFormat minFormat = {
> +				.mbus_code = mbusEnum.code,
> +				.width = sizeEnum.min_width,
> +				.height = sizeEnum.min_height,
> +			};
> +			formats->push_back(minFormat);
> +
> +			V4L2SubdeviceFormat maxFormat = {
> +				.mbus_code = mbusEnum.code,
> +				.width = sizeEnum.max_width,
> +				.height = sizeEnum.max_height,
> +			};
> +			formats->push_back(maxFormat);
> +
> +			sizeEnum.index++;
> +		}
> +
> +		if (-errno != -EINVAL) {
> +			LOG(V4L2Subdev, Error)
> +				<< "Unable to enumerate format on pad " << pad
> +				<< " of " << deviceNode_ << ": "
> +				<< strerror(-ret);
> +			return ret;
> +		}
> +
> +		mbusEnum.index++;
> +	}
> +
> +	if (-errno != -EINVAL) {
> +		LOG(V4L2Subdev, Error)
> +			<< "Unable to enumerate format on pad " << pad
> +			<< " of " << deviceNode_ << ": " << strerror(-ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +void V4L2Subdevice::listFormats()
> +{
> +	int ret;
> +
> +	for (MediaPad *pad : entity_->pads()) {
> +		std::vector<V4L2SubdeviceFormat> formats = {};
> +		ret = listPadFormats(pad->index(), &formats);

Can't listPadFormats() return the vector instead of taking a pointer as 
an argument? With copy elision there would be no performance impact.

> +		if (ret) {
> +			formats = {};
> +			formats_[pad->index()] = formats;
> +			continue;
> +		}
> +
> +		formats_[pad->index()] = formats;

This can be simplified, how about

    for (MediaPad *pad : entity_->pads()) {
        std::vector<V4L2SubdeviceFormat> formats = {};
        ret = listPadFormats(pad->index(), &formats);
        if (ret)
            formats = {}

        formats_[pad->index()] = formats;
    }


Or with the return type of listPadFormats() changed

    for (MediaPad *pad : entity_->pads())
        formats_[pad->index()] = listPadFormats(pad->index());


> +	}
> +}
> +
>  int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,
>  				Rectangle *rect)
>  {
> -- 
> 2.20.1
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

-- 
Regards,
Niklas Söderlund


More information about the libcamera-devel mailing list