[libcamera-devel] [RFC 2/3] libcamera: v4l2_device: Add methods to get/set format
Niklas Söderlund
niklas.soderlund at ragnatech.se
Sun Jan 27 01:39:56 CET 2019
Hi Jacopo,
Thanks for your work.
On 2019-01-26 16:13:17 +0100, Jacopo Mondi wrote:
> Add methods to set and get the image format programmed on a V4L2Device
> for both the single and multi planar use case.
>
> Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
> ---
> src/libcamera/include/v4l2_device.h | 13 +++
> src/libcamera/v4l2_device.cpp | 131 ++++++++++++++++++++++++++++
> 2 files changed, 144 insertions(+)
>
> diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h
> index ee0c4eb..01dbf45 100644
> --- a/src/libcamera/include/v4l2_device.h
> +++ b/src/libcamera/include/v4l2_device.h
> @@ -14,6 +14,7 @@
>
> #include <libcamera/buffer.h>
> #include <libcamera/event_notifier.h>
> +#include <libcamera/stream.h>
>
> namespace libcamera {
>
> @@ -81,6 +82,9 @@ public:
> int requestBuffers(unsigned int qty = 8);
> int requestBuffers(unsigned int qty, std::vector<FrameBuffer *> &buffers);
>
> + int format(StreamConfiguration *config);
> + int setFormat(StreamConfiguration *config);
> +
I'm not sure these should take StreamConfiguration as an argument. Maybe
the PipelineHandler should translate the StreamConfigurations it
receives into a structure which is V4L2 specific?
> int queueBuffer(FrameBuffer *frame);
> FrameBuffer *dequeueBuffer();
>
> @@ -93,6 +97,7 @@ private:
> std::string deviceNode_;
> int fd_;
> V4L2Capability caps_;
> + unsigned int buftype_;
>
> enum v4l2_memory memoryType_;
> enum v4l2_buf_type bufferType_;
> @@ -101,6 +106,14 @@ private:
> void bufferAvailable(EventNotifier *notifier);
>
> EventNotifier *fdEvent_;
> +
> + unsigned int getPlanesFromFormat(unsigned int pixfmt);
> + unsigned int getBppFromFormat(unsigned int pixfmt);
Should these methods be part of the V4L2Device or some other v4l2 util
collection? I wonder if this even could be useful for applications as we
currently expose the pixel format as a V4L2 FOURCC there. I'm not sure
what the end design will look like so this is just an open question.
> + int getFormatSingleplane(StreamConfiguration *config);
> + int setFormatSingleplane(StreamConfiguration *config);
> +
> + int getFormatMultiplane(StreamConfiguration *config);
> + int setFormatMultiplane(StreamConfiguration *config);
Here I like the deviation from our usual style of not using get*().
> };
>
> } /* namespace libcamera */
> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
> index 4d39c85..d16691d 100644
> --- a/src/libcamera/v4l2_device.cpp
> +++ b/src/libcamera/v4l2_device.cpp
> @@ -203,6 +203,15 @@ int V4L2Device::open()
> return -EINVAL;
> }
>
> + if (caps_.isCapture())
> + buftype_ = caps_.isMultiplanar() ?
> + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
> + V4L2_BUF_TYPE_VIDEO_CAPTURE;
> + else
> + buftype_ = caps_.isMultiplanar() ?
> + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
> + V4L2_BUF_TYPE_VIDEO_OUTPUT;
> +
> return 0;
> }
>
> @@ -314,6 +323,26 @@ int V4L2Device::requestBuffers(unsigned int qty, std::vector<FrameBuffer *> &buf
> return 0;
> }
>
> +/**
> + * \brief Retrieve the image format set on the V4L2 device
> + * \return 0 for success, a negative error code otherwise
> + */
> +int V4L2Device::format(StreamConfiguration *config)
> +{
> + return caps_.isMultiplanar() ? getFormatMultiplane(config) :
> + getFormatSingleplane(config);
> +}
> +
> +/**
> + * \brief Program an image format on the V4L2 device
> + * \return 0 for success, a negative error code otherwise
> + */
> +int V4L2Device::setFormat(StreamConfiguration *config)
> +{
> + return caps_.isMultiplanar() ? setFormatMultiplane(config) :
> + setFormatSingleplane(config);
> +}
Looking at the implementation of the get*() and set*() bellow I'm
wondering if it's possible to handle the difference between the two
inside just one {get,set}Format() function. Or do you expect these
functions to grow over time?
If you really want to keep them separate maybe it's possible to split
out the creation of the v4l2_format strucutre and keep the actual ioctl
and config->set*() common somehow? Or maybe I'm just obsessing about two
things that looks similar but really are not.
> +
> int V4L2Device::queueBuffer(FrameBuffer *frame)
> {
> struct v4l2_buffer buf = {};
> @@ -422,6 +451,108 @@ int V4L2Device::streamOff()
> }
>
> delete fdEvent_;
> +}
> +
> +/* TODO: this is a simple stub at the moment. */
> +unsigned int V4L2Device::getPlanesFromFormat(unsigned int pixfmt)
> +{
> + return 1;
> +}
> +
> +/* TODO: this is a simple stub at the moment. */
> +unsigned int V4L2Device::getBppFromFormat(unsigned int pixfmt)
> +{
> + return 16;
> +}
> +
> +int V4L2Device::getFormatSingleplane(StreamConfiguration *config)
> +{
> + struct v4l2_format v4l2Fmt;
> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix;
> + int ret;
> +
> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt);
> + if (ret) {
> + ret = -errno;
> + LOG(Error) << "Unable to get format: " << strerror(-ret);
> + return ret;
> + }
> +
> + config->setWidth(pix->width);
> + config->setHeight(pix->height);
> + config->setPixelFormat(pix->pixelformat);
> +
> + return 0;
> +}
> +
> +int V4L2Device::setFormatSingleplane(StreamConfiguration *config)
> +{
> + struct v4l2_format v4l2Fmt;
> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix;
> + int ret;
> +
> + v4l2Fmt.type = buftype_;
> + pix->width = config->width();
> + pix->height = config->height();
> +
> + pix->width = config->width();
> + pix->height = config->height();
> + pix->pixelformat = config->pixelformat();
> +
> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt);
> + if (ret) {
> + ret = -errno;
> + LOG(Error) << "Unable to set format: " << strerror(-ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +int V4L2Device::getFormatMultiplane(StreamConfiguration *config)
> +{
> + struct v4l2_format v4l2Fmt;
> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp;
> + int ret;
> +
> + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt);
> + if (ret) {
> + ret = -errno;
> + LOG(Error) << "Unable to get format: " << strerror(-ret);
> + return ret;
> + }
> +
> + config->setWidth(pix->width);
> + config->setHeight(pix->height);
> + config->setPixelFormat(pix->pixelformat);
> +
> + return 0;
> +}
> +
> +int V4L2Device::setFormatMultiplane(StreamConfiguration *config)
> +{
> + struct v4l2_format v4l2Fmt;
> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp;
> + int ret;
> +
> + v4l2Fmt.type = buftype_;
> + pix->width = config->width();
> + pix->height = config->height();
> + pix->pixelformat = config->pixelformat();
> +
> + unsigned int numPlanes = getPlanesFromFormat(pix->pixelformat);
> + unsigned int bpp = getBppFromFormat(pix->pixelformat);
> + for (unsigned int i = 0; i < numPlanes; ++i) {
> + pix->plane_fmt[i].bytesperline = bpp * pix->width;
> + pix->plane_fmt[i].sizeimage = bpp * pix->width * pix->height;
> + }
> +
> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt);
> + if (ret) {
> + ret = -errno;
> + LOG(Error) << "Unable to set format: " << strerror(-ret);
> + return ret;
> + }
>
> return 0;
> }
> --
> 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