[libcamera-devel,v4,4/6] libcamera: pipeline: virtual: Generate and validate StreamConfigurations
diff mbox series

Message ID 20230315102300.2265491-5-chenghaoyang@google.com
State Superseded
Headers show
Series
  • Virtual pipeline handler
Related show

Commit Message

Harvey Yang March 15, 2023, 10:22 a.m. UTC
Implement the support for Generating and Validating the streams the
Camera can provide.

Currently use only one camera with fixed configuration. Will add a
configuration file to specify virtual cameras.

In |PipelineHandlerVirtual::configure|, nothing needs to be done.

Test the configurations can be generated and reported with cam -I:
"""
build/src/apps/cam/cam -c 1 -I
[45:19:28.901456135] [2611530]  INFO IPAManager ipa_manager.cpp:143
libcamera is not installed. Adding
'/usr/local/google/home/chenghaoyang/cros2/src/third_party/libcamera/build/src
/ipa' to the IPA search path
[45:19:28.904364465] [2611530]  INFO Camera camera_manager.cpp:293
libcamera v0.0.1+56-4f4554fa-dirty (2022-12-07T06:55:04+00:00)
Using camera Virtual0 as cam0
0: 1920x1080-NV12
 * Pixelformat: NV12 (1280x720)-(1920x1080)/(+1,+1)
  - 1280x720
  - 1280x800
  - 1360x768
  - 1366x768
  - 1440x900
  - 1280x1024
  - 1536x864
  - 1280x1080
  - 1600x900
  - 1400x1050
  - 1680x1050
  - 1920x1080
"""

Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>
---
 src/libcamera/pipeline/virtual/virtual.cpp | 141 +++++++++++++++++++--
 1 file changed, 133 insertions(+), 8 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp
index 1d66a60e..b0e6de20 100644
--- a/src/libcamera/pipeline/virtual/virtual.cpp
+++ b/src/libcamera/pipeline/virtual/virtual.cpp
@@ -8,6 +8,7 @@ 
 #include <libcamera/base/log.h>
 
 #include <libcamera/camera.h>
+#include <libcamera/formats.h>
 
 #include "libcamera/internal/camera.h"
 #include "libcamera/internal/pipeline_handler.h"
@@ -19,6 +20,11 @@  LOG_DEFINE_CATEGORY(VIRTUAL)
 class VirtualCameraData : public Camera::Private
 {
 public:
+	struct Resolution {
+		Size size;
+		std::vector<int> frame_rates;
+		std::vector<std::string> formats;
+	};
 	VirtualCameraData(PipelineHandler *pipe)
 		: Camera::Private(pipe)
 	{
@@ -26,15 +32,22 @@  public:
 
 	~VirtualCameraData() = default;
 
+	std::vector<Resolution> supportedResolutions_;
+
 	Stream stream_;
 };
 
 class VirtualCameraConfiguration : public CameraConfiguration
 {
 public:
-	VirtualCameraConfiguration();
+	static constexpr unsigned int kBufferCount = 4; // 4~6
+
+	VirtualCameraConfiguration(VirtualCameraData *data);
 
 	Status validate() override;
+
+private:
+	const VirtualCameraData *data_;
 };
 
 class PipelineHandlerVirtual : public PipelineHandler
@@ -55,16 +68,56 @@  public:
 	int queueRequestDevice(Camera *camera, Request *request) override;
 
 	bool match(DeviceEnumerator *enumerator) override;
+
+private:
+	VirtualCameraData *cameraData(Camera *camera)
+	{
+		return static_cast<VirtualCameraData *>(camera->_d());
+	}
 };
 
-VirtualCameraConfiguration::VirtualCameraConfiguration()
-	: CameraConfiguration()
+VirtualCameraConfiguration::VirtualCameraConfiguration(VirtualCameraData *data)
+	: CameraConfiguration(), data_(data)
 {
 }
 
 CameraConfiguration::Status VirtualCameraConfiguration::validate()
 {
-	return Invalid;
+	Status status = Valid;
+
+	if (config_.empty()) {
+		LOG(VIRTUAL, Error) << "Empty config";
+		return Invalid;
+	}
+
+	// TODO: check if we should limit |config_.size()|
+
+	Size maxSize;
+	for (const auto &resolution : data_->supportedResolutions_)
+		maxSize = std::max(maxSize, resolution.size);
+
+	for (StreamConfiguration &cfg : config_) {
+		// TODO: check |cfg.pixelFormat|.
+
+		bool found = false;
+		for (const auto &resolution : data_->supportedResolutions_) {
+			if (resolution.size.width >= cfg.size.width && resolution.size.height >= cfg.size.height) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			cfg.size = maxSize;
+			status = Adjusted;
+		}
+
+		cfg.setStream(const_cast<Stream *>(&data_->stream_));
+
+		cfg.bufferCount = VirtualCameraConfiguration::kBufferCount;
+	}
+
+	return status;
 }
 
 PipelineHandlerVirtual::PipelineHandlerVirtual(CameraManager *manager)
@@ -75,16 +128,81 @@  PipelineHandlerVirtual::PipelineHandlerVirtual(CameraManager *manager)
 std::unique_ptr<CameraConfiguration> PipelineHandlerVirtual::generateConfiguration(Camera *camera,
 										   const StreamRoles &roles)
 {
-	(void)camera;
-	(void)roles;
-	return std::unique_ptr<VirtualCameraConfiguration>(nullptr);
+	VirtualCameraData *data = cameraData(camera);
+	auto config =
+		std::make_unique<VirtualCameraConfiguration>(data);
+
+	if (roles.empty())
+		return config;
+
+	Size minSize, sensorResolution;
+	for (const auto &resolution : data->supportedResolutions_) {
+		if (minSize.isNull() || minSize > resolution.size)
+			minSize = resolution.size;
+
+		sensorResolution = std::max(sensorResolution, resolution.size);
+	}
+
+	for (const StreamRole role : roles) {
+		std::map<PixelFormat, std::vector<SizeRange>> streamFormats;
+		unsigned int bufferCount;
+		PixelFormat pixelFormat;
+
+		switch (role) {
+		case StreamRole::StillCapture:
+			pixelFormat = formats::NV12;
+			bufferCount = VirtualCameraConfiguration::kBufferCount;
+			streamFormats[pixelFormat] = { { minSize, sensorResolution } };
+
+			break;
+
+		case StreamRole::Raw: {
+			// TODO: check
+			pixelFormat = formats::SBGGR10;
+			bufferCount = VirtualCameraConfiguration::kBufferCount;
+			streamFormats[pixelFormat] = { { minSize, sensorResolution } };
+
+			break;
+		}
+
+		case StreamRole::Viewfinder:
+		case StreamRole::VideoRecording: {
+			pixelFormat = formats::NV12;
+			bufferCount = VirtualCameraConfiguration::kBufferCount;
+			streamFormats[pixelFormat] = { { minSize, sensorResolution } };
+
+			break;
+		}
+
+		default:
+			LOG(VIRTUAL, Error)
+				<< "Requested stream role not supported: " << role;
+			config.reset();
+			return config;
+		}
+
+		StreamFormats formats(streamFormats);
+		StreamConfiguration cfg(formats);
+		cfg.size = sensorResolution;
+		cfg.pixelFormat = pixelFormat;
+		cfg.bufferCount = bufferCount;
+		config->addConfiguration(cfg);
+	}
+
+	if (config->validate() == CameraConfiguration::Invalid) {
+		config.reset();
+		return config;
+	}
+
+	return config;
 }
 
 int PipelineHandlerVirtual::configure(Camera *camera, CameraConfiguration *config)
 {
 	(void)camera;
 	(void)config;
-	return -1;
+	// Nothing to be done.
+	return 0;
 }
 
 int PipelineHandlerVirtual::exportFrameBuffers(Camera *camera, Stream *stream,
@@ -119,7 +237,14 @@  bool PipelineHandlerVirtual::match(DeviceEnumerator *enumerator)
 {
 	(void)enumerator;
 
+	// TODO: Add virtual cameras according to a config file.
+
 	std::unique_ptr<VirtualCameraData> data = std::make_unique<VirtualCameraData>(this);
+
+	data->supportedResolutions_.resize(2);
+	data->supportedResolutions_[0] = { .size = Size(1920, 1080), .frame_rates = { 30 }, .formats = { "YCbCr_420_888" } };
+	data->supportedResolutions_[1] = { .size = Size(1280, 720), .frame_rates = { 30, 60 }, .formats = { "YCbCr_420_888" } };
+
 	/* Create and register the camera. */
 	std::set<Stream *> streams{ &data->stream_ };
 	const std::string id = "Virtual0";