Message ID | 20190128151137.31075-3-jacopo@jmondi.org |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Jacopo, I only have variable/layout concerns here - which is certainly not a blocker at the moment. Also - if the outcome of the discussion below changes this patches expectations - then we'll need to adapt other patches too - so that would be a global patch fix at that point. Thus I don't think that discussion blocks this patch. On 28/01/2019 15:11, 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@jmondi.org> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > src/libcamera/include/v4l2_device.h | 10 +++ > src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > 2 files changed, 138 insertions(+) > > diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > index c70959e..fe54220 100644 > --- a/src/libcamera/include/v4l2_device.h > +++ b/src/libcamera/include/v4l2_device.h > @@ -86,10 +86,20 @@ public: > const char *deviceName() const { return caps_.card(); } > const char *busName() const { return caps_.bus_info(); } > > + int format(V4L2DeviceFormat *fmt); > + int setFormat(V4L2DeviceFormat *fmt); > + > private: > std::string deviceNode_; > int fd_; > V4L2Capability caps_; > + enum v4l2_buf_type bufferType_; > + > + int getFormatSingleplane(V4L2DeviceFormat *fmt); > + int setFormatSingleplane(V4L2DeviceFormat *fmt); > + > + int getFormatMultiplane(V4L2DeviceFormat *fmt); > + int setFormatMultiplane(V4L2DeviceFormat *fmt); Can I confirm <or prompt discussion> on our class layouts? Have we defined a layout anywhere? Here this creates: class ClassName { public: ClassName(); ~ClassName(); void publicFunctions(); int publicData; bool publicBool; private: int privateData; bool privateBool; int privateFunctions(); int morePrivateFunctions(); } Which is: PublicFunctions PublicData PrivateData PrivateFunctions So the 'data' both public and private is sandwiched in the middle. I don't mind this - but in my mind I thought we were doing: class ClassName { public: ClassName(); ~ClassName(); void publicFunctions(); int publicData; bool publicBool; private: int privateFunctions(); int morePrivateFunctions(); int privateData; bool privateBool; } Which is: PublicFunctions PublicData PrivateFunctions PrivateData so that the public, and private (or protected) sections follow the same sequence? Any comments from the team here? > }; > > } /* namespace libcamera */ > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > index d6143f2..5c415d0 100644 > --- a/src/libcamera/v4l2_device.cpp > +++ b/src/libcamera/v4l2_device.cpp > @@ -227,6 +227,15 @@ int V4L2Device::open() > return -EINVAL; > } > > + if (caps_.isCapture()) > + bufferType_ = caps_.isMultiplanar() > + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE > + : V4L2_BUF_TYPE_VIDEO_CAPTURE; > + else > + bufferType_ = caps_.isMultiplanar() > + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > + : V4L2_BUF_TYPE_VIDEO_OUTPUT; > + > return 0; > } > > @@ -269,4 +278,123 @@ void V4L2Device::close() > * \return The string containing the device location > */ > > +/** > + * \brief Retrieve the image format set on the V4L2 device > + * \return 0 for success, a negative error code otherwise > + */ > +int V4L2Device::format(V4L2DeviceFormat *fmt) > +{> + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : I think the precedence is that the : would be below the ? here ? But I'm doubting myself - so hopefully Laurent will chime in with his preferences here. If so perhaps we should set the following change in .clang-format: -BreakBeforeTernaryOperators: false +BreakBeforeTernaryOperators: true which would produce the following: + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) + : getFormatSingleplane(fmt); It doesn't however align the ? with the = in the bufferType_ above: bufferType_ = caps_.isMultiplanar() ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT; ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT; So again - I think that's a non-blocker currently. > + getFormatSingleplane(fmt); > +} > + > +/** > + * \brief Configure an image format on the V4L2 device > + * \return 0 for success, a negative error code otherwise > + */ > +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) > +{ > + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : > + setFormatSingleplane(fmt); > +} > + > +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to get format: " << strerror(-ret); > + return ret; > + } > + > + fmt->width = pix->width; > + fmt->height = pix->height; > + fmt->fourcc = pix->pixelformat; > + fmt->planes = 1; > + fmt->planesFmt[0].bpl = pix->bytesperline; > + fmt->planesFmt[0].size = pix->sizeimage; > + I think we might need to cache the V4L2DeviceFormat in the V4L2Device somewhere... But perhaps that's not required by this patch - if something needs to access this (like the BufferPool creation) it can handle caching the format object. > + return 0; > +} > + > +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + pix->width = fmt->width; > + pix->height = fmt->height; > + pix->pixelformat = fmt->fourcc; > + > + 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(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to get format: " << strerror(-ret); > + return ret; > + } > + > + fmt->width = pix->width; > + fmt->height = pix->height; > + fmt->fourcc = pix->pixelformat; > + fmt->planes = pix->num_planes; > + > + for (unsigned int i = 0; i < fmt->planes; ++i) { > + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; > + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; > + } > + > + return 0; > +} > + > +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + pix->width = fmt->width; > + pix->height = fmt->height; > + pix->pixelformat = fmt->fourcc; > + pix->num_planes = fmt->planes; > + > + for (unsigned int i = 0; i < pix->num_planes; ++i) { > + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; > + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; > + } > + > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to set format: " << strerror(-ret); > + return ret; > + } > + > + return 0; > +} > + > } /* namespace libcamera */ >
Hi Kieran, On Mon, Jan 28, 2019 at 03:42:27PM +0000, Kieran Bingham wrote: > Hi Jacopo, > > I only have variable/layout concerns here - which is certainly not a > blocker at the moment. > > Also - if the outcome of the discussion below changes this patches > expectations - then we'll need to adapt other patches too - so that > would be a global patch fix at that point. > > Thus I don't think that discussion blocks this patch. > > > On 28/01/2019 15:11, 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@jmondi.org> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > --- > > src/libcamera/include/v4l2_device.h | 10 +++ > > src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > > 2 files changed, 138 insertions(+) > > > > diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > > index c70959e..fe54220 100644 > > --- a/src/libcamera/include/v4l2_device.h > > +++ b/src/libcamera/include/v4l2_device.h > > @@ -86,10 +86,20 @@ public: > > const char *deviceName() const { return caps_.card(); } > > const char *busName() const { return caps_.bus_info(); } > > > > + int format(V4L2DeviceFormat *fmt); > > + int setFormat(V4L2DeviceFormat *fmt); > > + > > private: > > std::string deviceNode_; > > int fd_; > > V4L2Capability caps_; > > + enum v4l2_buf_type bufferType_; > > + > > + int getFormatSingleplane(V4L2DeviceFormat *fmt); > > + int setFormatSingleplane(V4L2DeviceFormat *fmt); > > + > > + int getFormatMultiplane(V4L2DeviceFormat *fmt); > > + int setFormatMultiplane(V4L2DeviceFormat *fmt); > > > Can I confirm <or prompt discussion> on our class layouts? > > Have we defined a layout anywhere? > > Here this creates: > > > class ClassName > { > public: > ClassName(); > ~ClassName(); > void publicFunctions(); > > int publicData; > bool publicBool; > > private: > int privateData; > bool privateBool; > > int privateFunctions(); > int morePrivateFunctions(); > } > > Which is: > PublicFunctions > PublicData > PrivateData > PrivateFunctions > > > So the 'data' both public and private is sandwiched in the middle. > I don't mind this - but in my mind I thought we were doing: > > > class ClassName > { > public: > ClassName(); > ~ClassName(); > void publicFunctions(); > > int publicData; > bool publicBool; > > private: > int privateFunctions(); > int morePrivateFunctions(); > > int privateData; > bool privateBool; > } > > Which is: > PublicFunctions > PublicData > PrivateFunctions > PrivateData > > so that the public, and private (or protected) sections follow the same > sequence? > > Any comments from the team here? Quoting the Google's C++ style guide (which I refer to because we actually started from there when we defined our coding guidelines): https://google.github.io/styleguide/cppguide.html#Declaration_Order ... generally prefer the following order: types (including typedef, using, and nested structs and classes), constants, factory functions, constructors, assignment operators, destructor, all other methods, data members. So your PublicFunctions PublicData PrivateFunctions PrivateData Is accurate. I fear we would need a library-wide cleanup, but I can start by making this right at least. > > > }; > > > > } /* namespace libcamera */ > > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > > index d6143f2..5c415d0 100644 > > --- a/src/libcamera/v4l2_device.cpp > > +++ b/src/libcamera/v4l2_device.cpp > > @@ -227,6 +227,15 @@ int V4L2Device::open() > > return -EINVAL; > > } > > > > + if (caps_.isCapture()) > > + bufferType_ = caps_.isMultiplanar() > > + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE > > + : V4L2_BUF_TYPE_VIDEO_CAPTURE; > > + else > > + bufferType_ = caps_.isMultiplanar() > > + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > > + : V4L2_BUF_TYPE_VIDEO_OUTPUT; > > + > > return 0; > > } > > > > @@ -269,4 +278,123 @@ void V4L2Device::close() > > * \return The string containing the device location > > */ > > > > +/** > > + * \brief Retrieve the image format set on the V4L2 device > > + * \return 0 for success, a negative error code otherwise > > + */ > > +int V4L2Device::format(V4L2DeviceFormat *fmt) > > +{> + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : > > I think the precedence is that the : would be below the ? here ? > > But I'm doubting myself - so hopefully Laurent will chime in with his > preferences here. > > > If so perhaps we should set the following change in .clang-format: > > -BreakBeforeTernaryOperators: false > +BreakBeforeTernaryOperators: true > > which would produce the following: > > > + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) > + : getFormatSingleplane(fmt); > > > > It doesn't however align the ? with the = in the bufferType_ above: > > bufferType_ = caps_.isMultiplanar() > ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > : V4L2_BUF_TYPE_VIDEO_OUTPUT; > ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > : V4L2_BUF_TYPE_VIDEO_OUTPUT; > > So again - I think that's a non-blocker currently. What makes the style checker and most of the team happy, makes me happy, so I'm open to all this solutions. > > > > + getFormatSingleplane(fmt); > > +} > > + > > +/** > > + * \brief Configure an image format on the V4L2 device > > + * \return 0 for success, a negative error code otherwise > > + */ > > +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) > > +{ > > + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : > > + setFormatSingleplane(fmt); > > +} > > + > > +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to get format: " << strerror(-ret); > > + return ret; > > + } > > + > > + fmt->width = pix->width; > > + fmt->height = pix->height; > > + fmt->fourcc = pix->pixelformat; > > + fmt->planes = 1; > > + fmt->planesFmt[0].bpl = pix->bytesperline; > > + fmt->planesFmt[0].size = pix->sizeimage; > > + > > I think we might need to cache the V4L2DeviceFormat in the V4L2Device > somewhere... > Yes, indeed. I would have had a V4L2DataFormat member initialized at device 'open()' time that could be cached, and re-freshed at every s_fmt.. > But perhaps that's not required by this patch - if something needs to > access this (like the BufferPool creation) it can handle caching the > format object. > I left it out from this two patches to ease integration, but I agree this is a possible optimization, and if any class needs that, it shall be done here. Thanks j > > > > + return 0; > > +} > > + > > +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + pix->width = fmt->width; > > + pix->height = fmt->height; > > + pix->pixelformat = fmt->fourcc; > > + > > + 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(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to get format: " << strerror(-ret); > > + return ret; > > + } > > + > > + fmt->width = pix->width; > > + fmt->height = pix->height; > > + fmt->fourcc = pix->pixelformat; > > + fmt->planes = pix->num_planes; > > + > > + for (unsigned int i = 0; i < fmt->planes; ++i) { > > + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; > > + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; > > + } > > + > > + return 0; > > +} > > + > > +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + pix->width = fmt->width; > > + pix->height = fmt->height; > > + pix->pixelformat = fmt->fourcc; > > + pix->num_planes = fmt->planes; > > + > > + for (unsigned int i = 0; i < pix->num_planes; ++i) { > > + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; > > + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; > > + } > > + > > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to set format: " << strerror(-ret); > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > } /* namespace libcamera */ > > > > -- > Regards > -- > Kieran
Hi Jacopo, On 28/01/2019 16:07, Jacopo Mondi wrote: > Hi Kieran, > > On Mon, Jan 28, 2019 at 03:42:27PM +0000, Kieran Bingham wrote: >> Hi Jacopo, >> >> I only have variable/layout concerns here - which is certainly not a >> blocker at the moment. >> >> Also - if the outcome of the discussion below changes this patches >> expectations - then we'll need to adapt other patches too - so that >> would be a global patch fix at that point. >> >> Thus I don't think that discussion blocks this patch. >> >> >> On 28/01/2019 15:11, 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@jmondi.org> >> >> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> >> >> >>> --- >>> src/libcamera/include/v4l2_device.h | 10 +++ >>> src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ >>> 2 files changed, 138 insertions(+) >>> >>> diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h >>> index c70959e..fe54220 100644 >>> --- a/src/libcamera/include/v4l2_device.h >>> +++ b/src/libcamera/include/v4l2_device.h >>> @@ -86,10 +86,20 @@ public: >>> const char *deviceName() const { return caps_.card(); } >>> const char *busName() const { return caps_.bus_info(); } >>> >>> + int format(V4L2DeviceFormat *fmt); >>> + int setFormat(V4L2DeviceFormat *fmt); >>> + >>> private: >>> std::string deviceNode_; >>> int fd_; >>> V4L2Capability caps_; >>> + enum v4l2_buf_type bufferType_; >>> + >>> + int getFormatSingleplane(V4L2DeviceFormat *fmt); >>> + int setFormatSingleplane(V4L2DeviceFormat *fmt); >>> + >>> + int getFormatMultiplane(V4L2DeviceFormat *fmt); >>> + int setFormatMultiplane(V4L2DeviceFormat *fmt); >> >> >> Can I confirm <or prompt discussion> on our class layouts? >> >> Have we defined a layout anywhere? >> >> Here this creates: >> >> >> class ClassName >> { >> public: >> ClassName(); >> ~ClassName(); >> void publicFunctions(); >> >> int publicData; >> bool publicBool; >> >> private: >> int privateData; >> bool privateBool; >> >> int privateFunctions(); >> int morePrivateFunctions(); >> } >> >> Which is: >> PublicFunctions >> PublicData >> PrivateData >> PrivateFunctions >> >> >> So the 'data' both public and private is sandwiched in the middle. >> I don't mind this - but in my mind I thought we were doing: >> >> >> class ClassName >> { >> public: >> ClassName(); >> ~ClassName(); >> void publicFunctions(); >> >> int publicData; >> bool publicBool; >> >> private: >> int privateFunctions(); >> int morePrivateFunctions(); >> >> int privateData; >> bool privateBool; >> } >> >> Which is: >> PublicFunctions >> PublicData >> PrivateFunctions >> PrivateData >> >> so that the public, and private (or protected) sections follow the same >> sequence? >> >> Any comments from the team here? > > Quoting the Google's C++ style guide (which I refer to because we > actually started from there when we defined our coding guidelines): > https://google.github.io/styleguide/cppguide.html#Declaration_Order > > ... generally prefer the following order: types (including typedef, using, > and nested structs and classes), constants, factory functions, constructors, > assignment operators, destructor, all other methods, data members. > > So your > PublicFunctions > PublicData > PrivateFunctions > PrivateData > > Is accurate. > > I fear we would need a library-wide cleanup, but I can start by making > this right at least. > Aha - great - something was right in my head :) I'd be happy with a push to master with this ordering corrected. -- Thanks Kieran >> >>> }; >>> >>> } /* namespace libcamera */ >>> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp >>> index d6143f2..5c415d0 100644 >>> --- a/src/libcamera/v4l2_device.cpp >>> +++ b/src/libcamera/v4l2_device.cpp >>> @@ -227,6 +227,15 @@ int V4L2Device::open() >>> return -EINVAL; >>> } >>> >>> + if (caps_.isCapture()) >>> + bufferType_ = caps_.isMultiplanar() >>> + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE >>> + : V4L2_BUF_TYPE_VIDEO_CAPTURE; >>> + else >>> + bufferType_ = caps_.isMultiplanar() >>> + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE >>> + : V4L2_BUF_TYPE_VIDEO_OUTPUT; >>> + >>> return 0; >>> } >>> >>> @@ -269,4 +278,123 @@ void V4L2Device::close() >>> * \return The string containing the device location >>> */ >>> >>> +/** >>> + * \brief Retrieve the image format set on the V4L2 device >>> + * \return 0 for success, a negative error code otherwise >>> + */ >>> +int V4L2Device::format(V4L2DeviceFormat *fmt) >>> +{> + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : >> >> I think the precedence is that the : would be below the ? here ? >> >> But I'm doubting myself - so hopefully Laurent will chime in with his >> preferences here. >> >> >> If so perhaps we should set the following change in .clang-format: >> >> -BreakBeforeTernaryOperators: false >> +BreakBeforeTernaryOperators: true >> >> which would produce the following: >> >> >> + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) >> + : getFormatSingleplane(fmt); >> >> >> >> It doesn't however align the ? with the = in the bufferType_ above: >> >> bufferType_ = caps_.isMultiplanar() >> ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE >> : V4L2_BUF_TYPE_VIDEO_OUTPUT; >> ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE >> : V4L2_BUF_TYPE_VIDEO_OUTPUT; >> >> So again - I think that's a non-blocker currently. > > What makes the style checker and most of the team happy, makes me > happy, so I'm open to all this solutions. I think the : on the new line makes sense, as it ensures it can't be confused to be a ; at the end of the line. The indentation - well I think that's authors choice at this stage. Either vertically aligned, or whatever makes clang-format happy. > >> >> >>> + getFormatSingleplane(fmt); >>> +} >>> + >>> +/** >>> + * \brief Configure an image format on the V4L2 device >>> + * \return 0 for success, a negative error code otherwise >>> + */ >>> +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) >>> +{ >>> + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : >>> + setFormatSingleplane(fmt); >>> +} >>> + >>> +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) >>> +{ >>> + struct v4l2_format v4l2Fmt; >>> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; >>> + int ret; >>> + >>> + v4l2Fmt.type = bufferType_; >>> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); >>> + if (ret) { >>> + ret = -errno; >>> + LOG(Error) << "Unable to get format: " << strerror(-ret); >>> + return ret; >>> + } >>> + >>> + fmt->width = pix->width; >>> + fmt->height = pix->height; >>> + fmt->fourcc = pix->pixelformat; >>> + fmt->planes = 1; >>> + fmt->planesFmt[0].bpl = pix->bytesperline; >>> + fmt->planesFmt[0].size = pix->sizeimage; >>> + >> >> I think we might need to cache the V4L2DeviceFormat in the V4L2Device >> somewhere... >> > > Yes, indeed. I would have had a V4L2DataFormat member initialized at > device 'open()' time that could be cached, and re-freshed at every > s_fmt.. > >> But perhaps that's not required by this patch - if something needs to >> access this (like the BufferPool creation) it can handle caching the >> format object. >> > > I left it out from this two patches to ease integration, but I agree > this is a possible optimization, and if any class needs that, it shall > be done here. I agree - not needed by this patch. Just thinking out loud as ever. -- Kieran > > Thanks > j >> >> >>> + return 0; >>> +} >>> + >>> +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) >>> +{ >>> + struct v4l2_format v4l2Fmt; >>> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; >>> + int ret; >>> + >>> + v4l2Fmt.type = bufferType_; >>> + pix->width = fmt->width; >>> + pix->height = fmt->height; >>> + pix->pixelformat = fmt->fourcc; >>> + >>> + 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(V4L2DeviceFormat *fmt) >>> +{ >>> + struct v4l2_format v4l2Fmt; >>> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; >>> + int ret; >>> + >>> + v4l2Fmt.type = bufferType_; >>> + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); >>> + if (ret) { >>> + ret = -errno; >>> + LOG(Error) << "Unable to get format: " << strerror(-ret); >>> + return ret; >>> + } >>> + >>> + fmt->width = pix->width; >>> + fmt->height = pix->height; >>> + fmt->fourcc = pix->pixelformat; >>> + fmt->planes = pix->num_planes; >>> + >>> + for (unsigned int i = 0; i < fmt->planes; ++i) { >>> + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; >>> + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) >>> +{ >>> + struct v4l2_format v4l2Fmt; >>> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; >>> + int ret; >>> + >>> + v4l2Fmt.type = bufferType_; >>> + pix->width = fmt->width; >>> + pix->height = fmt->height; >>> + pix->pixelformat = fmt->fourcc; >>> + pix->num_planes = fmt->planes; >>> + >>> + for (unsigned int i = 0; i < pix->num_planes; ++i) { >>> + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; >>> + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; >>> + } >>> + >>> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); >>> + if (ret) { >>> + ret = -errno; >>> + LOG(Error) << "Unable to set format: " << strerror(-ret); >>> + return ret; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> } /* namespace libcamera */ >>> >> >> -- >> Regards >> -- >> Kieran
Hi Kieran, On Tue, Jan 29, 2019 at 02:01:03PM +0000, Kieran Bingham wrote: > Hi Jacopo, > > On 28/01/2019 16:07, Jacopo Mondi wrote: > > Hi Kieran, > > > > On Mon, Jan 28, 2019 at 03:42:27PM +0000, Kieran Bingham wrote: > >> Hi Jacopo, > >> > >> I only have variable/layout concerns here - which is certainly not a > >> blocker at the moment. > >> > >> Also - if the outcome of the discussion below changes this patches > >> expectations - then we'll need to adapt other patches too - so that > >> would be a global patch fix at that point. > >> > >> Thus I don't think that discussion blocks this patch. > >> > >> > >> On 28/01/2019 15:11, 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@jmondi.org> > >> > >> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > >> > >> > >>> --- > >>> src/libcamera/include/v4l2_device.h | 10 +++ > >>> src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > >>> 2 files changed, 138 insertions(+) > >>> > >>> diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > >>> index c70959e..fe54220 100644 > >>> --- a/src/libcamera/include/v4l2_device.h > >>> +++ b/src/libcamera/include/v4l2_device.h > >>> @@ -86,10 +86,20 @@ public: > >>> const char *deviceName() const { return caps_.card(); } > >>> const char *busName() const { return caps_.bus_info(); } > >>> > >>> + int format(V4L2DeviceFormat *fmt); > >>> + int setFormat(V4L2DeviceFormat *fmt); > >>> + > >>> private: > >>> std::string deviceNode_; > >>> int fd_; > >>> V4L2Capability caps_; > >>> + enum v4l2_buf_type bufferType_; > >>> + > >>> + int getFormatSingleplane(V4L2DeviceFormat *fmt); > >>> + int setFormatSingleplane(V4L2DeviceFormat *fmt); > >>> + > >>> + int getFormatMultiplane(V4L2DeviceFormat *fmt); > >>> + int setFormatMultiplane(V4L2DeviceFormat *fmt); > >> > >> > >> Can I confirm <or prompt discussion> on our class layouts? > >> > >> Have we defined a layout anywhere? > >> > >> Here this creates: > >> > >> > >> class ClassName > >> { > >> public: > >> ClassName(); > >> ~ClassName(); > >> void publicFunctions(); > >> > >> int publicData; > >> bool publicBool; > >> > >> private: > >> int privateData; > >> bool privateBool; > >> > >> int privateFunctions(); > >> int morePrivateFunctions(); > >> } > >> > >> Which is: > >> PublicFunctions > >> PublicData > >> PrivateData > >> PrivateFunctions > >> > >> > >> So the 'data' both public and private is sandwiched in the middle. > >> I don't mind this - but in my mind I thought we were doing: > >> > >> > >> class ClassName > >> { > >> public: > >> ClassName(); > >> ~ClassName(); > >> void publicFunctions(); > >> > >> int publicData; > >> bool publicBool; > >> > >> private: > >> int privateFunctions(); > >> int morePrivateFunctions(); > >> > >> int privateData; > >> bool privateBool; > >> } > >> > >> Which is: > >> PublicFunctions > >> PublicData > >> PrivateFunctions > >> PrivateData > >> > >> so that the public, and private (or protected) sections follow the same > >> sequence? > >> > >> Any comments from the team here? > > > > Quoting the Google's C++ style guide (which I refer to because we > > actually started from there when we defined our coding guidelines): > > https://google.github.io/styleguide/cppguide.html#Declaration_Order > > > > ... generally prefer the following order: types (including typedef, using, > > and nested structs and classes), constants, factory functions, constructors, > > assignment operators, destructor, all other methods, data members. > > > > So your > > PublicFunctions > > PublicData > > PrivateFunctions > > PrivateData > > > > Is accurate. > > > > I fear we would need a library-wide cleanup, but I can start by making > > this right at least. > > > > Aha - great - something was right in my head :) > > I'd be happy with a push to master with this ordering corrected. > Thanks, fixed and pushed! Thanks j
Hello, On Mon, Jan 28, 2019 at 05:07:32PM +0100, Jacopo Mondi wrote: > On Mon, Jan 28, 2019 at 03:42:27PM +0000, Kieran Bingham wrote: > > Hi Jacopo, > > > > I only have variable/layout concerns here - which is certainly not a > > blocker at the moment. > > > > Also - if the outcome of the discussion below changes this patches > > expectations - then we'll need to adapt other patches too - so that > > would be a global patch fix at that point. > > > > Thus I don't think that discussion blocks this patch. > > > > On 28/01/2019 15:11, 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@jmondi.org> > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > >> --- > >> src/libcamera/include/v4l2_device.h | 10 +++ > >> src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > >> 2 files changed, 138 insertions(+) > >> > >> diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > >> index c70959e..fe54220 100644 > >> --- a/src/libcamera/include/v4l2_device.h > >> +++ b/src/libcamera/include/v4l2_device.h > >> @@ -86,10 +86,20 @@ public: > >> const char *deviceName() const { return caps_.card(); } > >> const char *busName() const { return caps_.bus_info(); } > >> > >> + int format(V4L2DeviceFormat *fmt); > >> + int setFormat(V4L2DeviceFormat *fmt); > >> + > >> private: > >> std::string deviceNode_; > >> int fd_; > >> V4L2Capability caps_; > >> + enum v4l2_buf_type bufferType_; > >> + > >> + int getFormatSingleplane(V4L2DeviceFormat *fmt); > >> + int setFormatSingleplane(V4L2DeviceFormat *fmt); > >> + > >> + int getFormatMultiplane(V4L2DeviceFormat *fmt); > >> + int setFormatMultiplane(V4L2DeviceFormat *fmt); > > > > Can I confirm <or prompt discussion> on our class layouts? > > > > Have we defined a layout anywhere? > > > > Here this creates: > > > > > > class ClassName > > { > > public: > > ClassName(); > > ~ClassName(); > > void publicFunctions(); > > > > int publicData; > > bool publicBool; > > > > private: > > int privateData; > > bool privateBool; > > > > int privateFunctions(); > > int morePrivateFunctions(); > > } > > > > Which is: > > PublicFunctions > > PublicData > > PrivateData > > PrivateFunctions > > > > > > So the 'data' both public and private is sandwiched in the middle. > > I don't mind this - but in my mind I thought we were doing: > > > > > > class ClassName > > { > > public: > > ClassName(); > > ~ClassName(); > > void publicFunctions(); > > > > int publicData; > > bool publicBool; > > > > private: > > int privateFunctions(); > > int morePrivateFunctions(); > > > > int privateData; > > bool privateBool; > > } > > > > Which is: > > PublicFunctions > > PublicData > > PrivateFunctions > > PrivateData > > > > so that the public, and private (or protected) sections follow the same > > sequence? > > > > Any comments from the team here? > > Quoting the Google's C++ style guide (which I refer to because we > actually started from there when we defined our coding guidelines): > https://google.github.io/styleguide/cppguide.html#Declaration_Order > > ... generally prefer the following order: types (including typedef, using, > and nested structs and classes), constants, factory functions, constructors, > assignment operators, destructor, all other methods, data members. > > So your > PublicFunctions > PublicData > PrivateFunctions > PrivateData > > Is accurate. That looks good to me. > I fear we would need a library-wide cleanup, but I can start by making > this right at least. The cleanup would be quite simple, so let's do it :-) > >> }; > >> > >> } /* namespace libcamera */ > >> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > >> index d6143f2..5c415d0 100644 > >> --- a/src/libcamera/v4l2_device.cpp > >> +++ b/src/libcamera/v4l2_device.cpp > >> @@ -227,6 +227,15 @@ int V4L2Device::open() > >> return -EINVAL; > >> } > >> > >> + if (caps_.isCapture()) > >> + bufferType_ = caps_.isMultiplanar() > >> + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE > >> + : V4L2_BUF_TYPE_VIDEO_CAPTURE; > >> + else > >> + bufferType_ = caps_.isMultiplanar() > >> + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > >> + : V4L2_BUF_TYPE_VIDEO_OUTPUT; > >> + > >> return 0; > >> } > >> > >> @@ -269,4 +278,123 @@ void V4L2Device::close() > >> * \return The string containing the device location > >> */ > >> > >> +/** > >> + * \brief Retrieve the image format set on the V4L2 device > >> + * \return 0 for success, a negative error code otherwise > >> + */ > >> +int V4L2Device::format(V4L2DeviceFormat *fmt) > >> +{> + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : > > > > I think the precedence is that the : would be below the ? here ? > > > > But I'm doubting myself - so hopefully Laurent will chime in with his > > preferences here. > > > > > > If so perhaps we should set the following change in .clang-format: > > > > -BreakBeforeTernaryOperators: false > > +BreakBeforeTernaryOperators: true > > > > which would produce the following: > > > > > > + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) > > + : getFormatSingleplane(fmt); I also prefer this. In general I find code more readable when the operator is a the beginning of the line, not the end. Jacopo, could you please fix this ? > > > > It doesn't however align the ? with the = in the bufferType_ above: > > > > bufferType_ = caps_.isMultiplanar() > > ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > > : V4L2_BUF_TYPE_VIDEO_OUTPUT; > > ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > > : V4L2_BUF_TYPE_VIDEO_OUTPUT; It should definitely be aligned with the =. > > So again - I think that's a non-blocker currently. > > What makes the style checker and most of the team happy, makes me > happy, so I'm open to all this solutions. > > >> + getFormatSingleplane(fmt); > >> +} > >> + > >> +/** > >> + * \brief Configure an image format on the V4L2 device > >> + * \return 0 for success, a negative error code otherwise > >> + */ > >> +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) > >> +{ > >> + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : > >> + setFormatSingleplane(fmt); > >> +} > >> + > >> +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to get format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > >> + fmt->width = pix->width; > >> + fmt->height = pix->height; > >> + fmt->fourcc = pix->pixelformat; > >> + fmt->planes = 1; > >> + fmt->planesFmt[0].bpl = pix->bytesperline; > >> + fmt->planesFmt[0].size = pix->sizeimage; > >> + > > > > I think we might need to cache the V4L2DeviceFormat in the V4L2Device > > somewhere... > > Yes, indeed. I would have had a V4L2DataFormat member initialized at > device 'open()' time that could be cached, and re-freshed at every > s_fmt.. > > > But perhaps that's not required by this patch - if something needs to > > access this (like the BufferPool creation) it can handle caching the > > format object. > > I left it out from this two patches to ease integration, but I agree > this is a possible optimization, and if any class needs that, it shall > be done here. Could the device allowed to change format without userspace intervention ? > >> + return 0; > >> +} > >> + > >> +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + pix->width = fmt->width; > >> + pix->height = fmt->height; > >> + pix->pixelformat = fmt->fourcc; > >> + > >> + 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(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to get format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > >> + fmt->width = pix->width; > >> + fmt->height = pix->height; > >> + fmt->fourcc = pix->pixelformat; > >> + fmt->planes = pix->num_planes; > >> + > >> + for (unsigned int i = 0; i < fmt->planes; ++i) { > >> + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; > >> + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; > >> + } > >> + > >> + return 0; > >> +} > >> + > >> +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + pix->width = fmt->width; > >> + pix->height = fmt->height; > >> + pix->pixelformat = fmt->fourcc; > >> + pix->num_planes = fmt->planes; > >> + > >> + for (unsigned int i = 0; i < pix->num_planes; ++i) { > >> + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; > >> + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; > >> + } > >> + > >> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to set format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > >> + return 0; > >> +} > >> + > >> } /* namespace libcamera */
Hi Jacopo, Thank you for the patch. On Mon, Jan 28, 2019 at 04:11:37PM +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@jmondi.org> > --- > src/libcamera/include/v4l2_device.h | 10 +++ > src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > 2 files changed, 138 insertions(+) > > diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > index c70959e..fe54220 100644 > --- a/src/libcamera/include/v4l2_device.h > +++ b/src/libcamera/include/v4l2_device.h > @@ -86,10 +86,20 @@ public: > const char *deviceName() const { return caps_.card(); } > const char *busName() const { return caps_.bus_info(); } > > + int format(V4L2DeviceFormat *fmt); As an exception to the general rule, I'd rename format() to getFormat() to follow the V4L2 naming. I won't push hard for this, but I think this was the general preference of the team as well. > + int setFormat(V4L2DeviceFormat *fmt); How about spelling format in full (here and below) for the function parameter ? > + > private: > std::string deviceNode_; > int fd_; > V4L2Capability caps_; > + enum v4l2_buf_type bufferType_; > + > + int getFormatSingleplane(V4L2DeviceFormat *fmt); > + int setFormatSingleplane(V4L2DeviceFormat *fmt); > + > + int getFormatMultiplane(V4L2DeviceFormat *fmt); > + int setFormatMultiplane(V4L2DeviceFormat *fmt); > }; > > } /* namespace libcamera */ > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > index d6143f2..5c415d0 100644 > --- a/src/libcamera/v4l2_device.cpp > +++ b/src/libcamera/v4l2_device.cpp > @@ -227,6 +227,15 @@ int V4L2Device::open() > return -EINVAL; > } > > + if (caps_.isCapture()) > + bufferType_ = caps_.isMultiplanar() > + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE > + : V4L2_BUF_TYPE_VIDEO_CAPTURE; > + else > + bufferType_ = caps_.isMultiplanar() > + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > + : V4L2_BUF_TYPE_VIDEO_OUTPUT; > + > return 0; > } > > @@ -269,4 +278,123 @@ void V4L2Device::close() > * \return The string containing the device location > */ > > +/** > + * \brief Retrieve the image format set on the V4L2 device > + * \return 0 for success, a negative error code otherwise s/for/on/ > + */ > +int V4L2Device::format(V4L2DeviceFormat *fmt) > +{ > + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : > + getFormatSingleplane(fmt); > +} > + > +/** > + * \brief Configure an image format on the V4L2 device > + * \return 0 for success, a negative error code otherwise s/for/on/ > + */ > +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) > +{ > + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : > + setFormatSingleplane(fmt); > +} > + > +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; v4l2Format ? Or maybe just fmt if you rename the function parameter to format ? You need to initialize v4l2Fmt to 0, that's a requirement of the V4L2 API. = {}; will suffice. > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); Shouldn't this be VIDIOC_G_FMT ? This outlines a missing test case :-) > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to get format: " << strerror(-ret); > + return ret; > + } > + > + fmt->width = pix->width; > + fmt->height = pix->height; > + fmt->fourcc = pix->pixelformat; > + fmt->planes = 1; > + fmt->planesFmt[0].bpl = pix->bytesperline; > + fmt->planesFmt[0].size = pix->sizeimage; > + > + return 0; > +} > + > +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + pix->width = fmt->width; > + pix->height = fmt->height; > + pix->pixelformat = fmt->fourcc; How about bytesperline and sizeimage ? > + > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to set format: " << strerror(-ret); > + return ret; > + } > + Shouldn't fmt be updated ? > + return 0; > +} > + > +int V4L2Device::getFormatMultiplane(V4L2DeviceFormat *fmt) The above comments hold for the mplane functions too. > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to get format: " << strerror(-ret); > + return ret; > + } > + > + fmt->width = pix->width; > + fmt->height = pix->height; > + fmt->fourcc = pix->pixelformat; > + fmt->planes = pix->num_planes; > + > + for (unsigned int i = 0; i < fmt->planes; ++i) { > + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; > + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; > + } > + > + return 0; > +} > + > +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) > +{ > + struct v4l2_format v4l2Fmt; > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > + int ret; > + > + v4l2Fmt.type = bufferType_; > + pix->width = fmt->width; > + pix->height = fmt->height; > + pix->pixelformat = fmt->fourcc; > + pix->num_planes = fmt->planes; > + > + for (unsigned int i = 0; i < pix->num_planes; ++i) { > + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; > + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; > + } > + > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > + if (ret) { > + ret = -errno; > + LOG(Error) << "Unable to set format: " << strerror(-ret); > + return ret; > + } > + > + return 0; > +} > + > } /* namespace libcamera */
Hi Laurent, On Wed, Jan 30, 2019 at 01:10:00PM +0200, Laurent Pinchart wrote: > Hi Jacopo, > > Thank you for the patch. > > On Mon, Jan 28, 2019 at 04:11:37PM +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@jmondi.org> > > --- > > src/libcamera/include/v4l2_device.h | 10 +++ > > src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > > 2 files changed, 138 insertions(+) > > > > diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > > index c70959e..fe54220 100644 > > --- a/src/libcamera/include/v4l2_device.h > > +++ b/src/libcamera/include/v4l2_device.h > > @@ -86,10 +86,20 @@ public: > > const char *deviceName() const { return caps_.card(); } > > const char *busName() const { return caps_.bus_info(); } > > > > + int format(V4L2DeviceFormat *fmt); > > As an exception to the general rule, I'd rename format() to getFormat() > to follow the V4L2 naming. I won't push hard for this, but I think this > was the general preference of the team as well. > iirc we discussed that and went for this solution. I can re-change it in case.. > > + int setFormat(V4L2DeviceFormat *fmt); > > How about spelling format in full (here and below) for the function > parameter ? > Ok > > + > > private: > > std::string deviceNode_; > > int fd_; > > V4L2Capability caps_; > > + enum v4l2_buf_type bufferType_; > > + > > + int getFormatSingleplane(V4L2DeviceFormat *fmt); > > + int setFormatSingleplane(V4L2DeviceFormat *fmt); > > + > > + int getFormatMultiplane(V4L2DeviceFormat *fmt); > > + int setFormatMultiplane(V4L2DeviceFormat *fmt); > > }; > > > > } /* namespace libcamera */ > > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > > index d6143f2..5c415d0 100644 > > --- a/src/libcamera/v4l2_device.cpp > > +++ b/src/libcamera/v4l2_device.cpp > > @@ -227,6 +227,15 @@ int V4L2Device::open() > > return -EINVAL; > > } > > > > + if (caps_.isCapture()) > > + bufferType_ = caps_.isMultiplanar() > > + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE > > + : V4L2_BUF_TYPE_VIDEO_CAPTURE; > > + else > > + bufferType_ = caps_.isMultiplanar() > > + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > > + : V4L2_BUF_TYPE_VIDEO_OUTPUT; > > + > > return 0; > > } > > > > @@ -269,4 +278,123 @@ void V4L2Device::close() > > * \return The string containing the device location > > */ > > > > +/** > > + * \brief Retrieve the image format set on the V4L2 device > > + * \return 0 for success, a negative error code otherwise > > s/for/on/ > > > + */ > > +int V4L2Device::format(V4L2DeviceFormat *fmt) > > +{ > > + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : > > + getFormatSingleplane(fmt); > > +} > > + > > +/** > > + * \brief Configure an image format on the V4L2 device > > + * \return 0 for success, a negative error code otherwise > > s/for/on/ > > > + */ > > +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) > > +{ > > + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : > > + setFormatSingleplane(fmt); > > +} > > + > > +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > v4l2Format ? Or maybe just fmt if you rename the function parameter to > format ? > Ok > You need to initialize v4l2Fmt to 0, that's a requirement of the V4L2 > API. = {}; will suffice. > correct. > > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > > Shouldn't this be VIDIOC_G_FMT ? This outlines a missing test case :-) > My bad, I'm sorry. For a test case, how should we make sure we test all possible use cases (planar/multiplanar, capture/output). The device that runs the test might not have all of these... Could VIMC or vivid help us here? > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to get format: " << strerror(-ret); > > + return ret; > > + } > > + > > + fmt->width = pix->width; > > + fmt->height = pix->height; > > + fmt->fourcc = pix->pixelformat; > > + fmt->planes = 1; > > + fmt->planesFmt[0].bpl = pix->bytesperline; > > + fmt->planesFmt[0].size = pix->sizeimage; > > + > > + return 0; > > +} > > + > > +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + pix->width = fmt->width; > > + pix->height = fmt->height; > > + pix->pixelformat = fmt->fourcc; > > How about bytesperline and sizeimage ? > The description here https://www.kernel.org/doc/html/v4.13/media/uapi/v4l/pixfmt-002.html#c.v4l2_pix_format quite confused me. Particularly: "Size in bytes of the buffer to hold a complete image, set by the driver." > > + > > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to set format: " << strerror(-ret); > > + return ret; > > + } > > + > > Shouldn't fmt be updated ? > Good question, what semantic would we want to assign to this functions? A setFormat returns an updated format? I here thought to clearly separate this: to know what is actually set, you have to call g_fmt again. Honestly, now that I re-think this, I am not convinced anymore this is the right way, as the V4L2 S_FMT actually returns an updated format, so it might be worth updating it here before return. > > + return 0; > > +} > > + > > +int V4L2Device::getFormatMultiplane(V4L2DeviceFormat *fmt) > > The above comments hold for the mplane functions too. > > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); At least this one is right... Thanks j > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to get format: " << strerror(-ret); > > + return ret; > > + } > > + > > + fmt->width = pix->width; > > + fmt->height = pix->height; > > + fmt->fourcc = pix->pixelformat; > > + fmt->planes = pix->num_planes; > > + > > + for (unsigned int i = 0; i < fmt->planes; ++i) { > > + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; > > + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; > > + } > > + > > + return 0; > > +} > > + > > +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) > > +{ > > + struct v4l2_format v4l2Fmt; > > + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > > + int ret; > > + > > + v4l2Fmt.type = bufferType_; > > + pix->width = fmt->width; > > + pix->height = fmt->height; > > + pix->pixelformat = fmt->fourcc; > > + pix->num_planes = fmt->planes; > > + > > + for (unsigned int i = 0; i < pix->num_planes; ++i) { > > + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; > > + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; > > + } > > + > > + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > > + if (ret) { > > + ret = -errno; > > + LOG(Error) << "Unable to set format: " << strerror(-ret); > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > } /* namespace libcamera */ > > -- > Regards, > > Laurent Pinchart
Hi Jacopo, On Wed, Jan 30, 2019 at 03:37:13PM +0100, Jacopo Mondi wrote: > On Wed, Jan 30, 2019 at 01:10:00PM +0200, Laurent Pinchart wrote: > > On Mon, Jan 28, 2019 at 04:11:37PM +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@jmondi.org> > >> --- > >> src/libcamera/include/v4l2_device.h | 10 +++ > >> src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ > >> 2 files changed, 138 insertions(+) > >> > >> diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > >> index c70959e..fe54220 100644 > >> --- a/src/libcamera/include/v4l2_device.h > >> +++ b/src/libcamera/include/v4l2_device.h > >> @@ -86,10 +86,20 @@ public: > >> const char *deviceName() const { return caps_.card(); } > >> const char *busName() const { return caps_.bus_info(); } > >> > >> + int format(V4L2DeviceFormat *fmt); > > > > As an exception to the general rule, I'd rename format() to getFormat() > > to follow the V4L2 naming. I won't push hard for this, but I think this > > was the general preference of the team as well. > > iirc we discussed that and went for this solution. I can re-change it > in case.. I think I replied to a previous e-mail explaining that I thought an exception would make sense here, and I recall (possibly incorrectly) that you were in favour of getFormat(). As I said, I won't push, but if we all agree getFormat() makes sense, they I think we should go for it. > >> + int setFormat(V4L2DeviceFormat *fmt); > > > > How about spelling format in full (here and below) for the function > > parameter ? > > Ok > > >> + > >> private: > >> std::string deviceNode_; > >> int fd_; > >> V4L2Capability caps_; > >> + enum v4l2_buf_type bufferType_; > >> + > >> + int getFormatSingleplane(V4L2DeviceFormat *fmt); > >> + int setFormatSingleplane(V4L2DeviceFormat *fmt); > >> + > >> + int getFormatMultiplane(V4L2DeviceFormat *fmt); > >> + int setFormatMultiplane(V4L2DeviceFormat *fmt); > >> }; > >> > >> } /* namespace libcamera */ > >> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > >> index d6143f2..5c415d0 100644 > >> --- a/src/libcamera/v4l2_device.cpp > >> +++ b/src/libcamera/v4l2_device.cpp > >> @@ -227,6 +227,15 @@ int V4L2Device::open() > >> return -EINVAL; > >> } > >> > >> + if (caps_.isCapture()) > >> + bufferType_ = caps_.isMultiplanar() > >> + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE > >> + : V4L2_BUF_TYPE_VIDEO_CAPTURE; > >> + else > >> + bufferType_ = caps_.isMultiplanar() > >> + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE > >> + : V4L2_BUF_TYPE_VIDEO_OUTPUT; > >> + > >> return 0; > >> } > >> > >> @@ -269,4 +278,123 @@ void V4L2Device::close() > >> * \return The string containing the device location > >> */ > >> > >> +/** > >> + * \brief Retrieve the image format set on the V4L2 device > >> + * \return 0 for success, a negative error code otherwise > > > > s/for/on/ > > > >> + */ > >> +int V4L2Device::format(V4L2DeviceFormat *fmt) > >> +{ > >> + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : > >> + getFormatSingleplane(fmt); > >> +} > >> + > >> +/** > >> + * \brief Configure an image format on the V4L2 device > >> + * \return 0 for success, a negative error code otherwise > > > > s/for/on/ > > > >> + */ > >> +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) > >> +{ > >> + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : > >> + setFormatSingleplane(fmt); > >> +} > >> + > >> +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > > > > v4l2Format ? Or maybe just fmt if you rename the function parameter to > > format ? > > Ok > > > You need to initialize v4l2Fmt to 0, that's a requirement of the V4L2 > > API. = {}; will suffice. > > > > correct. > > >> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > > > > Shouldn't this be VIDIOC_G_FMT ? This outlines a missing test case :-) > > > > My bad, I'm sorry. > For a test case, how should we make sure we test all possible use > cases (planar/multiplanar, capture/output). The device that runs the > test might not have all of these... Could VIMC or vivid help us here? I think they could help. I haven't checked which of the single/multi-planar APIs those drivers use, and whether they could help testing both, but we could at least test one of the two. > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to get format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > >> + fmt->width = pix->width; > >> + fmt->height = pix->height; > >> + fmt->fourcc = pix->pixelformat; > >> + fmt->planes = 1; > >> + fmt->planesFmt[0].bpl = pix->bytesperline; > >> + fmt->planesFmt[0].size = pix->sizeimage; > >> + > >> + return 0; > >> +} > >> + > >> +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + pix->width = fmt->width; > >> + pix->height = fmt->height; > >> + pix->pixelformat = fmt->fourcc; > > > > How about bytesperline and sizeimage ? > > The description here > https://www.kernel.org/doc/html/v4.13/media/uapi/v4l/pixfmt-002.html#c.v4l2_pix_format > quite confused me. > > Particularly: "Size in bytes of the buffer to hold a complete image, > set by the driver." You're right about sizeimage. For bytesperline, though, you should pass it to the ioctl. > >> + > >> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to set format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > > > > Shouldn't fmt be updated ? > > Good question, what semantic would we want to assign to this > functions? A setFormat returns an updated format? I here thought to > clearly separate this: to know what is actually set, you have to call > g_fmt again. Honestly, now that I re-think this, I am not convinced > anymore this is the right way, as the V4L2 S_FMT actually returns an > updated format, so it might be worth updating it here before return. I think mimicking the VIDIOC_S_FMT semantics would make sense, as it would save a VIDIOC_G_FMT call for users of this class. > >> + return 0; > >> +} > >> + > >> +int V4L2Device::getFormatMultiplane(V4L2DeviceFormat *fmt) > > > > The above comments hold for the mplane functions too. > > > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); > > At least this one is right... Sometimes copy & paste works ;-) > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to get format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > >> + fmt->width = pix->width; > >> + fmt->height = pix->height; > >> + fmt->fourcc = pix->pixelformat; > >> + fmt->planes = pix->num_planes; > >> + > >> + for (unsigned int i = 0; i < fmt->planes; ++i) { > >> + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; > >> + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; > >> + } > >> + > >> + return 0; > >> +} > >> + > >> +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) > >> +{ > >> + struct v4l2_format v4l2Fmt; > >> + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; > >> + int ret; > >> + > >> + v4l2Fmt.type = bufferType_; > >> + pix->width = fmt->width; > >> + pix->height = fmt->height; > >> + pix->pixelformat = fmt->fourcc; > >> + pix->num_planes = fmt->planes; > >> + > >> + for (unsigned int i = 0; i < pix->num_planes; ++i) { > >> + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; > >> + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; > >> + } > >> + > >> + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); > >> + if (ret) { > >> + ret = -errno; > >> + LOG(Error) << "Unable to set format: " << strerror(-ret); > >> + return ret; > >> + } > >> + > >> + return 0; > >> +} > >> + > >> } /* namespace libcamera */
diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index c70959e..fe54220 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -86,10 +86,20 @@ public: const char *deviceName() const { return caps_.card(); } const char *busName() const { return caps_.bus_info(); } + int format(V4L2DeviceFormat *fmt); + int setFormat(V4L2DeviceFormat *fmt); + private: std::string deviceNode_; int fd_; V4L2Capability caps_; + enum v4l2_buf_type bufferType_; + + int getFormatSingleplane(V4L2DeviceFormat *fmt); + int setFormatSingleplane(V4L2DeviceFormat *fmt); + + int getFormatMultiplane(V4L2DeviceFormat *fmt); + int setFormatMultiplane(V4L2DeviceFormat *fmt); }; } /* namespace libcamera */ diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index d6143f2..5c415d0 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -227,6 +227,15 @@ int V4L2Device::open() return -EINVAL; } + if (caps_.isCapture()) + bufferType_ = caps_.isMultiplanar() + ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + : V4L2_BUF_TYPE_VIDEO_CAPTURE; + else + bufferType_ = caps_.isMultiplanar() + ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE + : V4L2_BUF_TYPE_VIDEO_OUTPUT; + return 0; } @@ -269,4 +278,123 @@ void V4L2Device::close() * \return The string containing the device location */ +/** + * \brief Retrieve the image format set on the V4L2 device + * \return 0 for success, a negative error code otherwise + */ +int V4L2Device::format(V4L2DeviceFormat *fmt) +{ + return caps_.isMultiplanar() ? getFormatMultiplane(fmt) : + getFormatSingleplane(fmt); +} + +/** + * \brief Configure an image format on the V4L2 device + * \return 0 for success, a negative error code otherwise + */ +int V4L2Device::setFormat(V4L2DeviceFormat *fmt) +{ + return caps_.isMultiplanar() ? setFormatMultiplane(fmt) : + setFormatSingleplane(fmt); +} + +int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *fmt) +{ + struct v4l2_format v4l2Fmt; + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; + int ret; + + v4l2Fmt.type = bufferType_; + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); + if (ret) { + ret = -errno; + LOG(Error) << "Unable to get format: " << strerror(-ret); + return ret; + } + + fmt->width = pix->width; + fmt->height = pix->height; + fmt->fourcc = pix->pixelformat; + fmt->planes = 1; + fmt->planesFmt[0].bpl = pix->bytesperline; + fmt->planesFmt[0].size = pix->sizeimage; + + return 0; +} + +int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *fmt) +{ + struct v4l2_format v4l2Fmt; + struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix; + int ret; + + v4l2Fmt.type = bufferType_; + pix->width = fmt->width; + pix->height = fmt->height; + pix->pixelformat = fmt->fourcc; + + 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(V4L2DeviceFormat *fmt) +{ + struct v4l2_format v4l2Fmt; + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; + int ret; + + v4l2Fmt.type = bufferType_; + ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt); + if (ret) { + ret = -errno; + LOG(Error) << "Unable to get format: " << strerror(-ret); + return ret; + } + + fmt->width = pix->width; + fmt->height = pix->height; + fmt->fourcc = pix->pixelformat; + fmt->planes = pix->num_planes; + + for (unsigned int i = 0; i < fmt->planes; ++i) { + fmt->planesFmt[i].bpl = pix->plane_fmt[i].bytesperline; + fmt->planesFmt[i].size = pix->plane_fmt[i].sizeimage; + } + + return 0; +} + +int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt) +{ + struct v4l2_format v4l2Fmt; + struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp; + int ret; + + v4l2Fmt.type = bufferType_; + pix->width = fmt->width; + pix->height = fmt->height; + pix->pixelformat = fmt->fourcc; + pix->num_planes = fmt->planes; + + for (unsigned int i = 0; i < pix->num_planes; ++i) { + pix->plane_fmt[i].bytesperline = fmt->planesFmt[i].bpl; + pix->plane_fmt[i].sizeimage = fmt->planesFmt[i].size; + } + + ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt); + if (ret) { + ret = -errno; + LOG(Error) << "Unable to set format: " << strerror(-ret); + return ret; + } + + return 0; +} + } /* namespace libcamera */
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@jmondi.org> --- src/libcamera/include/v4l2_device.h | 10 +++ src/libcamera/v4l2_device.cpp | 128 ++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+)