[libcamera-devel,v5,22/23] v4l2: v4l2_camera_proxy: Use stream config in tryFormat

Message ID 20200709132835.112593-23-paul.elder@ideasonboard.com
State Accepted
Headers show
Series
  • Clean up formats in v4l2-compat and pipeline handlers
Related show

Commit Message

Paul Elder July 9, 2020, 1:28 p.m. UTC
For handling try_fmt, the values should be filled in by validating the
stream configuration, and not by recalculating them or manually checking
against the cached list of formats and sizes. Add a new
V4L2Camera::validateConfiguration() function to validate a configuration
and use it to obtain size, format, stride, and frameSize values.

If the format negotiation fails, return error from try_fmt and s_fmt.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

---
Changes in v5:
- change commit message wording a bit
- re-order patches to avoid potential regressions
- return error from try_fmt and s_fmt if negotiation fails

Changes in v4:
- clean up code a bit
- squash the implementation and usage

New in v3
---
 src/v4l2/v4l2_camera.cpp       | 20 +++++++++++++++++
 src/v4l2/v4l2_camera.h         |  3 +++
 src/v4l2/v4l2_camera_proxy.cpp | 41 ++++++++++++++++++++--------------
 src/v4l2/v4l2_camera_proxy.h   |  2 +-
 4 files changed, 48 insertions(+), 18 deletions(-)

Patch

diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp
index a923256..61bca07 100644
--- a/src/v4l2/v4l2_camera.cpp
+++ b/src/v4l2/v4l2_camera.cpp
@@ -138,6 +138,26 @@  int V4L2Camera::configure(StreamConfiguration *streamConfigOut,
 	return 0;
 }
 
+int V4L2Camera::validateConfiguration(const PixelFormat &pixelFormat,
+				      const Size &size,
+				      StreamConfiguration *streamConfigOut)
+{
+	std::unique_ptr<CameraConfiguration> config =
+		camera_->generateConfiguration({ StreamRole::Viewfinder });
+	StreamConfiguration &cfg = config->at(0);
+	cfg.size = size;
+	cfg.pixelFormat = pixelFormat;
+	cfg.bufferCount = 1;
+
+	CameraConfiguration::Status validation = config->validate();
+	if (validation == CameraConfiguration::Invalid)
+		return -EINVAL;
+
+	*streamConfigOut = cfg;
+
+	return 0;
+}
+
 int V4L2Camera::allocBuffers(unsigned int count)
 {
 	Stream *stream = config_->at(0).stream();
diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h
index 515e906..be6c4e1 100644
--- a/src/v4l2/v4l2_camera.h
+++ b/src/v4l2/v4l2_camera.h
@@ -47,6 +47,9 @@  public:
 	int configure(StreamConfiguration *streamConfigOut,
 		      const Size &size, const PixelFormat &pixelformat,
 		      unsigned int bufferCount);
+	int validateConfiguration(const PixelFormat &pixelformat,
+				  const Size &size,
+				  StreamConfiguration *streamConfigOut);
 
 	int allocBuffers(unsigned int count);
 	void freeBuffers();
diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index 8c55a06..50ab7e6 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -296,33 +296,36 @@  int V4L2CameraProxy::vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
 	return 0;
 }
 
-void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
+int V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
 {
 	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->fmt.pix.pixelformat);
 	PixelFormat format = PixelFormatInfo::info(v4l2Format).format;
-	const std::vector<PixelFormat> &formats =
-		streamConfig_.formats().pixelformats();
-	if (std::find(formats.begin(), formats.end(), format) == formats.end())
-		format = streamConfig_.formats().pixelformats()[0];
-
 	Size size(arg->fmt.pix.width, arg->fmt.pix.height);
-	const std::vector<Size> &sizes = streamConfig_.formats().sizes(format);
-	if (std::find(sizes.begin(), sizes.end(), size) == sizes.end())
-		size = streamConfig_.formats().sizes(format)[0];
 
-	const PixelFormatInfo &formatInfo = PixelFormatInfo::info(format);
+	StreamConfiguration config;
+	int ret = vcam_->validateConfiguration(format, size, &config);
+	if (ret < 0) {
+		LOG(V4L2Compat, Error)
+			<< "Failed to negotiate a valid format: "
+			<< format.toString();
+		return -EINVAL;
+	}
+
+	const PixelFormatInfo &info = PixelFormatInfo::info(config.pixelFormat);
 
-	arg->fmt.pix.width        = size.width;
-	arg->fmt.pix.height       = size.height;
-	arg->fmt.pix.pixelformat  = formatInfo.v4l2Format;
+	arg->fmt.pix.width        = config.size.width;
+	arg->fmt.pix.height       = config.size.height;
+	arg->fmt.pix.pixelformat  = info.v4l2Format;
 	arg->fmt.pix.field        = V4L2_FIELD_NONE;
-	arg->fmt.pix.bytesperline = formatInfo.stride(size.width, 0);
-	arg->fmt.pix.sizeimage    = formatInfo.frameSize(size);
+	arg->fmt.pix.bytesperline = config.stride;
+	arg->fmt.pix.sizeimage    = config.frameSize;
 	arg->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
 	arg->fmt.pix.priv         = V4L2_PIX_FMT_PRIV_MAGIC;
 	arg->fmt.pix.ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
 	arg->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
 	arg->fmt.pix.xfer_func    = V4L2_XFER_FUNC_DEFAULT;
+
+	return 0;
 }
 
 int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
@@ -339,7 +342,9 @@  int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
 	if (ret < 0)
 		return ret;
 
-	tryFormat(arg);
+	ret = tryFormat(arg);
+	if (ret < 0)
+		return ret;
 
 	Size size(arg->fmt.pix.width, arg->fmt.pix.height);
 	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->fmt.pix.pixelformat);
@@ -361,7 +366,9 @@  int V4L2CameraProxy::vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *ar
 	if (!validateBufferType(arg->type))
 		return -EINVAL;
 
-	tryFormat(arg);
+	int ret = tryFormat(arg);
+	if (ret < 0)
+		return ret;
 
 	return 0;
 }
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index e962694..f06b5b8 100644
--- a/src/v4l2/v4l2_camera_proxy.h
+++ b/src/v4l2/v4l2_camera_proxy.h
@@ -41,7 +41,7 @@  private:
 	bool validateMemoryType(uint32_t memory);
 	void setFmtFromConfig(StreamConfiguration &streamConfig);
 	void querycap(std::shared_ptr<Camera> camera);
-	void tryFormat(struct v4l2_format *arg);
+	int tryFormat(struct v4l2_format *arg);
 	enum v4l2_priority maxPriority();
 	void updateBuffers();
 	void freeBuffers();