v4l2: Read fixed format when the setter is unsupported
diff mbox series

Message ID 20261015194326.287935-1-halfline@gmail.com
State New
Headers show
Series
  • v4l2: Read fixed format when the setter is unsupported
Related show

Commit Message

Ray Strode Oct. 15, 2026, 7:43 p.m. UTC
From: Ray Strode <rstrode@redhat.com>

V4L2 subdevice format negotiation uses the format setter to obtain an
accepted pad format.

Fixed-format subdevices may omit that ioctl, so their existing format
cannot be returned through the setter path.

This commit reads the existing format when the setter reports ENOTTY,
using the same active or try format selection. Other failures retain the
usual error handling.

Signed-off-by: Ray Strode <rstrode@redhat.com>
---
 src/libcamera/v4l2_subdevice.cpp | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Laurent Pinchart Oct. 15, 2026, 8:23 p.m. UTC | #1
On Thu, Oct 15, 2026 at 03:43:26PM -0400, Ray Strode wrote:
> From: Ray Strode <rstrode@redhat.com>
> 
> V4L2 subdevice format negotiation uses the format setter to obtain an
> accepted pad format.
> 
> Fixed-format subdevices may omit that ioctl, so their existing format
> cannot be returned through the setter path.

That's not the can any more in the kernel.

> This commit reads the existing format when the setter reports ENOTTY,
> using the same active or try format selection. Other failures retain the
> usual error handling.
> 
> Signed-off-by: Ray Strode <rstrode@redhat.com>
> ---
>  src/libcamera/v4l2_subdevice.cpp | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
> index a69de154..12a320d6 100644
> --- a/src/libcamera/v4l2_subdevice.cpp
> +++ b/src/libcamera/v4l2_subdevice.cpp
> @@ -1393,60 +1393,64 @@ int V4L2Subdevice::getFormat(const Stream &stream, V4L2SubdeviceFormat *format,
>   * \param[in] stream The stream the format is to be applied to
>   * \param[inout] format The image bus format to apply to the stream
>   * \param[in] whence The format to set, \ref V4L2Subdevice::ActiveFormat
>   * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat"
>   *
>   * Apply the requested image format to the desired stream and return the
>   * actually applied format parameters, as getFormat() would do.
>   *
>   * \return 0 on success or a negative error code otherwise
>   */
>  int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format,
>  			     Whence whence)
>  {
>  	struct v4l2_subdev_format subdevFmt = {};
>  	subdevFmt.which = whence;
>  	subdevFmt.pad = stream.pad;
>  	subdevFmt.stream = stream.stream;
>  	subdevFmt.format.width = format->size.width;
>  	subdevFmt.format.height = format->size.height;
>  	subdevFmt.format.code = format->code;
>  	subdevFmt.format.field = V4L2_FIELD_NONE;
>  	if (format->colorSpace) {
>  		fromColorSpace(format->colorSpace, subdevFmt.format);
>  
>  		/* The CSC flag is only applicable to source pads. */
>  		if (entity_->pads()[stream.pad]->flags() & MEDIA_PAD_FL_SOURCE)
>  			subdevFmt.format.flags |= V4L2_MBUS_FRAMEFMT_SET_CSC;
>  	}
>  
>  	int ret = ioctl(VIDIOC_SUBDEV_S_FMT, &subdevFmt);

30 lines of context ??

> +	/* Fixed-format subdevices may not implement a format setter. */
> +	if (ret == -ENOTTY)
> +		return getFormat(stream, format, whence);
> +
>  	if (ret) {
>  		LOG(V4L2, Error)
>  			<< "Unable to set format on pad " << stream << ": "
>  			<< strerror(-ret);
>  		return ret;
>  	}
>  
>  	format->size.width = subdevFmt.format.width;
>  	format->size.height = subdevFmt.format.height;
>  	format->code = subdevFmt.format.code;
>  	format->colorSpace = toColorSpace(subdevFmt.format);
>  
>  	return 0;
>  }
>  
>  /**
>   * \fn V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format,
>   * Whence whence)
>   * \brief Set an image format on one of the V4L2 subdevice pads
>   * \param[in] pad The 0-indexed pad number the format is to be applied to
>   * \param[inout] format The image bus format to apply to the subdevice's pad
>   * \param[in] whence The format to set, \ref V4L2Subdevice::ActiveFormat
>   * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat"
>   *
>   * Apply the requested image format to the desired media pad and return the
>   * actually applied format parameters, as getFormat() would do.
>   *
>   * \return 0 on success or a negative error code otherwise
>   */
Ray Strode Oct. 15, 2026, 9:56 p.m. UTC | #2
Hi,

On Thu, Oct 15, 2026 at 4:24 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> That's not the case any more in the kernel.
ah ok.. just found this:

https://git.linuxtv.org/media.git/commit/drivers/media/v4l2-core/v4l2-subdev.c?id=48d8b2418f55efb7e4c437ab19e8c39ba271656d

which i guess is what you're referring to. Good enough, though it's
not in linus tree yet.

Thanks,
--Ray

Patch
diff mbox series

diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
index a69de154..12a320d6 100644
--- a/src/libcamera/v4l2_subdevice.cpp
+++ b/src/libcamera/v4l2_subdevice.cpp
@@ -1393,60 +1393,64 @@  int V4L2Subdevice::getFormat(const Stream &stream, V4L2SubdeviceFormat *format,
  * \param[in] stream The stream the format is to be applied to
  * \param[inout] format The image bus format to apply to the stream
  * \param[in] whence The format to set, \ref V4L2Subdevice::ActiveFormat
  * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat"
  *
  * Apply the requested image format to the desired stream and return the
  * actually applied format parameters, as getFormat() would do.
  *
  * \return 0 on success or a negative error code otherwise
  */
 int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format,
 			     Whence whence)
 {
 	struct v4l2_subdev_format subdevFmt = {};
 	subdevFmt.which = whence;
 	subdevFmt.pad = stream.pad;
 	subdevFmt.stream = stream.stream;
 	subdevFmt.format.width = format->size.width;
 	subdevFmt.format.height = format->size.height;
 	subdevFmt.format.code = format->code;
 	subdevFmt.format.field = V4L2_FIELD_NONE;
 	if (format->colorSpace) {
 		fromColorSpace(format->colorSpace, subdevFmt.format);
 
 		/* The CSC flag is only applicable to source pads. */
 		if (entity_->pads()[stream.pad]->flags() & MEDIA_PAD_FL_SOURCE)
 			subdevFmt.format.flags |= V4L2_MBUS_FRAMEFMT_SET_CSC;
 	}
 
 	int ret = ioctl(VIDIOC_SUBDEV_S_FMT, &subdevFmt);
+	/* Fixed-format subdevices may not implement a format setter. */
+	if (ret == -ENOTTY)
+		return getFormat(stream, format, whence);
+
 	if (ret) {
 		LOG(V4L2, Error)
 			<< "Unable to set format on pad " << stream << ": "
 			<< strerror(-ret);
 		return ret;
 	}
 
 	format->size.width = subdevFmt.format.width;
 	format->size.height = subdevFmt.format.height;
 	format->code = subdevFmt.format.code;
 	format->colorSpace = toColorSpace(subdevFmt.format);
 
 	return 0;
 }
 
 /**
  * \fn V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format,
  * Whence whence)
  * \brief Set an image format on one of the V4L2 subdevice pads
  * \param[in] pad The 0-indexed pad number the format is to be applied to
  * \param[inout] format The image bus format to apply to the subdevice's pad
  * \param[in] whence The format to set, \ref V4L2Subdevice::ActiveFormat
  * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat"
  *
  * Apply the requested image format to the desired media pad and return the
  * actually applied format parameters, as getFormat() would do.
  *
  * \return 0 on success or a negative error code otherwise
  */