Message ID | 20200704133140.1738660-5-paul.elder@ideasonboard.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Paul, Thank you for the patch. On Sat, Jul 04, 2020 at 10:31:22PM +0900, Paul Elder wrote: > Add tryFormat and its variations (meta, single-plane, multi-plane) to > V4L2VideoDevice. > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> > > --- > New in v3 > --- > include/libcamera/internal/v4l2_videodevice.h | 4 + > src/libcamera/v4l2_videodevice.cpp | 121 ++++++++++++++++++ > 2 files changed, 125 insertions(+) > > diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h > index 4d21f5a..56c3aee 100644 > --- a/include/libcamera/internal/v4l2_videodevice.h > +++ b/include/libcamera/internal/v4l2_videodevice.h > @@ -186,6 +186,7 @@ public: > const V4L2Capability &caps() const { return caps_; } > > int getFormat(V4L2DeviceFormat *format); > + int tryFormat(V4L2DeviceFormat *format); > int setFormat(V4L2DeviceFormat *format); > std::map<V4L2PixelFormat, std::vector<SizeRange>> formats(uint32_t code = 0); > > @@ -217,12 +218,15 @@ protected: > > private: > int getFormatMeta(V4L2DeviceFormat *format); > + int tryFormatMeta(V4L2DeviceFormat *format); > int setFormatMeta(V4L2DeviceFormat *format); > > int getFormatMultiplane(V4L2DeviceFormat *format); > + int tryFormatMultiplane(V4L2DeviceFormat *format); > int setFormatMultiplane(V4L2DeviceFormat *format); > > int getFormatSingleplane(V4L2DeviceFormat *format); > + int tryFormatSingleplane(V4L2DeviceFormat *format); > int setFormatSingleplane(V4L2DeviceFormat *format); > > std::vector<V4L2PixelFormat> enumPixelformats(uint32_t code); > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp > index 3614b2e..f25914c 100644 > --- a/src/libcamera/v4l2_videodevice.cpp > +++ b/src/libcamera/v4l2_videodevice.cpp > @@ -723,6 +723,26 @@ int V4L2VideoDevice::getFormat(V4L2DeviceFormat *format) > return getFormatSingleplane(format); > } > > +/** > + * \brief Try an image format on the V4L2 video device > + * \param[inout] format The image format to test applicablity to the video device s/applicablity/applicability/ > + * > + * Test if the supplied \a format to the video device is acceptable, and return > + * the actually applied format parameters, as \ref V4L2VideoDevice::tryFormat This is the documentation of V4L2VideoDevice::tryFormat... Did you mean setFormat() ? You shouldn't need \ref or the V4L2VideoDevice prefix, writing setFormat() should generate the right link. Also, the parameters are not "applied". How about * Try the supplied \a format on the video device without applying it, returning * the format that would be applied. This is equivalent to setFormat(), except * that the device configuration is not changed. > + * would do. > + * > + * \return 0 on success or a negative error code otherwise > + */ > +int V4L2VideoDevice::tryFormat(V4L2DeviceFormat *format) > +{ > + if (caps_.isMeta()) > + return tryFormatMeta(format); > + else if (caps_.isMultiplanar()) > + return tryFormatMultiplane(format); > + else > + return tryFormatSingleplane(format); > +} > + > /** > * \brief Configure an image format on the V4L2 video device > * \param[inout] format The image format to apply to the video device > @@ -765,6 +785,35 @@ int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) > return 0; > } > > +int V4L2VideoDevice::tryFormatMeta(V4L2DeviceFormat *format) > +{ > + struct v4l2_format v4l2Format = {}; > + struct v4l2_meta_format *pix = &v4l2Format.fmt.meta; > + int ret; > + > + v4l2Format.type = bufferType_; > + pix->dataformat = format->fourcc; > + pix->buffersize = format->planes[0].size; > + ret = ioctl(VIDIOC_TRY_FMT, &v4l2Format); > + if (ret) { > + LOG(V4L2, Error) << "Unable to try format: " << strerror(-ret); > + return ret; > + } > + > + /* > + * Return to caller the format actually applied on the video device, > + * which might differ from the requested one. > + */ > + format->size.width = 0; > + format->size.height = 0; > + format->fourcc = V4L2PixelFormat(pix->dataformat); > + format->planesCount = 1; > + format->planes[0].bpl = pix->buffersize; > + format->planes[0].size = pix->buffersize; > + > + return 0; > +} > + This is duplicating quite a bit of code. How about turning the existing setFormatMeta(), setFormatMultiplane() and setFormatSinglePlane() functions into trySetFormat*(), with a parameter to tell whether to try the format or set it (can be a "bool set" as these are private functions, if it was a public API an enum would be better) ? As the error message is also different (the functions here print "Unable to try format"), if you want to avoid a (set ? "set" : "try") conditional, you can move the error messages from the low-level functions to setFormat() and tryFormat(). Up to you. With these changes, Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > int V4L2VideoDevice::setFormatMeta(V4L2DeviceFormat *format) > { > struct v4l2_format v4l2Format = {}; > @@ -820,6 +869,46 @@ int V4L2VideoDevice::getFormatMultiplane(V4L2DeviceFormat *format) > return 0; > } > > +int V4L2VideoDevice::tryFormatMultiplane(V4L2DeviceFormat *format) > +{ > + struct v4l2_format v4l2Format = {}; > + struct v4l2_pix_format_mplane *pix = &v4l2Format.fmt.pix_mp; > + int ret; > + > + v4l2Format.type = bufferType_; > + pix->width = format->size.width; > + pix->height = format->size.height; > + pix->pixelformat = format->fourcc; > + pix->num_planes = format->planesCount; > + pix->field = V4L2_FIELD_NONE; > + > + for (unsigned int i = 0; i < pix->num_planes; ++i) { > + pix->plane_fmt[i].bytesperline = format->planes[i].bpl; > + pix->plane_fmt[i].sizeimage = format->planes[i].size; > + } > + > + ret = ioctl(VIDIOC_TRY_FMT, &v4l2Format); > + if (ret) { > + LOG(V4L2, Error) << "Unable to try format: " << strerror(-ret); > + return ret; > + } > + > + /* > + * Return to caller the format actually applied on the video device, > + * which might differ from the requested one. > + */ > + format->size.width = pix->width; > + format->size.height = pix->height; > + format->fourcc = V4L2PixelFormat(pix->pixelformat); > + format->planesCount = pix->num_planes; > + for (unsigned int i = 0; i < format->planesCount; ++i) { > + format->planes[i].bpl = pix->plane_fmt[i].bytesperline; > + format->planes[i].size = pix->plane_fmt[i].sizeimage; > + } > + > + return 0; > +} > + > int V4L2VideoDevice::setFormatMultiplane(V4L2DeviceFormat *format) > { > struct v4l2_format v4l2Format = {}; > @@ -883,6 +972,38 @@ int V4L2VideoDevice::getFormatSingleplane(V4L2DeviceFormat *format) > return 0; > } > > +int V4L2VideoDevice::tryFormatSingleplane(V4L2DeviceFormat *format) > +{ > + struct v4l2_format v4l2Format = {}; > + struct v4l2_pix_format *pix = &v4l2Format.fmt.pix; > + int ret; > + > + v4l2Format.type = bufferType_; > + pix->width = format->size.width; > + pix->height = format->size.height; > + pix->pixelformat = format->fourcc; > + pix->bytesperline = format->planes[0].bpl; > + pix->field = V4L2_FIELD_NONE; > + ret = ioctl(VIDIOC_TRY_FMT, &v4l2Format); > + if (ret) { > + LOG(V4L2, Error) << "Unable to try format: " << strerror(-ret); > + return ret; > + } > + > + /* > + * Return to caller the format actually applied on the device, > + * which might differ from the requested one. > + */ > + format->size.width = pix->width; > + format->size.height = pix->height; > + format->fourcc = V4L2PixelFormat(pix->pixelformat); > + format->planesCount = 1; > + format->planes[0].bpl = pix->bytesperline; > + format->planes[0].size = pix->sizeimage; > + > + return 0; > +} > + > int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format) > { > struct v4l2_format v4l2Format = {};
diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h index 4d21f5a..56c3aee 100644 --- a/include/libcamera/internal/v4l2_videodevice.h +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -186,6 +186,7 @@ public: const V4L2Capability &caps() const { return caps_; } int getFormat(V4L2DeviceFormat *format); + int tryFormat(V4L2DeviceFormat *format); int setFormat(V4L2DeviceFormat *format); std::map<V4L2PixelFormat, std::vector<SizeRange>> formats(uint32_t code = 0); @@ -217,12 +218,15 @@ protected: private: int getFormatMeta(V4L2DeviceFormat *format); + int tryFormatMeta(V4L2DeviceFormat *format); int setFormatMeta(V4L2DeviceFormat *format); int getFormatMultiplane(V4L2DeviceFormat *format); + int tryFormatMultiplane(V4L2DeviceFormat *format); int setFormatMultiplane(V4L2DeviceFormat *format); int getFormatSingleplane(V4L2DeviceFormat *format); + int tryFormatSingleplane(V4L2DeviceFormat *format); int setFormatSingleplane(V4L2DeviceFormat *format); std::vector<V4L2PixelFormat> enumPixelformats(uint32_t code); diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 3614b2e..f25914c 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -723,6 +723,26 @@ int V4L2VideoDevice::getFormat(V4L2DeviceFormat *format) return getFormatSingleplane(format); } +/** + * \brief Try an image format on the V4L2 video device + * \param[inout] format The image format to test applicablity to the video device + * + * Test if the supplied \a format to the video device is acceptable, and return + * the actually applied format parameters, as \ref V4L2VideoDevice::tryFormat + * would do. + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2VideoDevice::tryFormat(V4L2DeviceFormat *format) +{ + if (caps_.isMeta()) + return tryFormatMeta(format); + else if (caps_.isMultiplanar()) + return tryFormatMultiplane(format); + else + return tryFormatSingleplane(format); +} + /** * \brief Configure an image format on the V4L2 video device * \param[inout] format The image format to apply to the video device @@ -765,6 +785,35 @@ int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) return 0; } +int V4L2VideoDevice::tryFormatMeta(V4L2DeviceFormat *format) +{ + struct v4l2_format v4l2Format = {}; + struct v4l2_meta_format *pix = &v4l2Format.fmt.meta; + int ret; + + v4l2Format.type = bufferType_; + pix->dataformat = format->fourcc; + pix->buffersize = format->planes[0].size; + ret = ioctl(VIDIOC_TRY_FMT, &v4l2Format); + if (ret) { + LOG(V4L2, Error) << "Unable to try format: " << strerror(-ret); + return ret; + } + + /* + * Return to caller the format actually applied on the video device, + * which might differ from the requested one. + */ + format->size.width = 0; + format->size.height = 0; + format->fourcc = V4L2PixelFormat(pix->dataformat); + format->planesCount = 1; + format->planes[0].bpl = pix->buffersize; + format->planes[0].size = pix->buffersize; + + return 0; +} + int V4L2VideoDevice::setFormatMeta(V4L2DeviceFormat *format) { struct v4l2_format v4l2Format = {}; @@ -820,6 +869,46 @@ int V4L2VideoDevice::getFormatMultiplane(V4L2DeviceFormat *format) return 0; } +int V4L2VideoDevice::tryFormatMultiplane(V4L2DeviceFormat *format) +{ + struct v4l2_format v4l2Format = {}; + struct v4l2_pix_format_mplane *pix = &v4l2Format.fmt.pix_mp; + int ret; + + v4l2Format.type = bufferType_; + pix->width = format->size.width; + pix->height = format->size.height; + pix->pixelformat = format->fourcc; + pix->num_planes = format->planesCount; + pix->field = V4L2_FIELD_NONE; + + for (unsigned int i = 0; i < pix->num_planes; ++i) { + pix->plane_fmt[i].bytesperline = format->planes[i].bpl; + pix->plane_fmt[i].sizeimage = format->planes[i].size; + } + + ret = ioctl(VIDIOC_TRY_FMT, &v4l2Format); + if (ret) { + LOG(V4L2, Error) << "Unable to try format: " << strerror(-ret); + return ret; + } + + /* + * Return to caller the format actually applied on the video device, + * which might differ from the requested one. + */ + format->size.width = pix->width; + format->size.height = pix->height; + format->fourcc = V4L2PixelFormat(pix->pixelformat); + format->planesCount = pix->num_planes; + for (unsigned int i = 0; i < format->planesCount; ++i) { + format->planes[i].bpl = pix->plane_fmt[i].bytesperline; + format->planes[i].size = pix->plane_fmt[i].sizeimage; + } + + return 0; +} + int V4L2VideoDevice::setFormatMultiplane(V4L2DeviceFormat *format) { struct v4l2_format v4l2Format = {}; @@ -883,6 +972,38 @@ int V4L2VideoDevice::getFormatSingleplane(V4L2DeviceFormat *format) return 0; } +int V4L2VideoDevice::tryFormatSingleplane(V4L2DeviceFormat *format) +{ + struct v4l2_format v4l2Format = {}; + struct v4l2_pix_format *pix = &v4l2Format.fmt.pix; + int ret; + + v4l2Format.type = bufferType_; + pix->width = format->size.width; + pix->height = format->size.height; + pix->pixelformat = format->fourcc; + pix->bytesperline = format->planes[0].bpl; + pix->field = V4L2_FIELD_NONE; + ret = ioctl(VIDIOC_TRY_FMT, &v4l2Format); + if (ret) { + LOG(V4L2, Error) << "Unable to try format: " << strerror(-ret); + return ret; + } + + /* + * Return to caller the format actually applied on the device, + * which might differ from the requested one. + */ + format->size.width = pix->width; + format->size.height = pix->height; + format->fourcc = V4L2PixelFormat(pix->pixelformat); + format->planesCount = 1; + format->planes[0].bpl = pix->bytesperline; + format->planes[0].size = pix->sizeimage; + + return 0; +} + int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format) { struct v4l2_format v4l2Format = {};
Add tryFormat and its variations (meta, single-plane, multi-plane) to V4L2VideoDevice. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> --- New in v3 --- include/libcamera/internal/v4l2_videodevice.h | 4 + src/libcamera/v4l2_videodevice.cpp | 121 ++++++++++++++++++ 2 files changed, 125 insertions(+)