diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp
index a4aa44af25828f23..e455612b36238157 100644
--- a/src/cam/capture.cpp
+++ b/src/cam/capture.cpp
@@ -15,8 +15,8 @@
 
 using namespace libcamera;
 
-Capture::Capture(Camera *camera)
-	: camera_(camera), writer_(nullptr), last_(0)
+Capture::Capture(Camera *camera, CameraConfiguration *config)
+	: camera_(camera), config_(config), writer_(nullptr), last_(0)
 {
 }
 
@@ -29,13 +29,13 @@ int Capture::run(EventLoop *loop, const OptionsParser::Options &options)
 		return -ENODEV;
 	}
 
-	ret = prepareConfig(options);
-	if (ret) {
-		std::cout << "Failed to prepare camera configuration" << std::endl;
-		return -EINVAL;
+	streamName_.clear();
+	for (unsigned int index = 0; index < config_->size(); ++index) {
+		StreamConfiguration &cfg = config_->at(index);
+		streamName_[cfg.stream()] = "stream" + std::to_string(index);
 	}
 
-	ret = camera_->configure(config_.get());
+	ret = camera_->configure(config_);
 	if (ret < 0) {
 		std::cout << "Failed to configure camera" << std::endl;
 		return ret;
@@ -64,80 +64,10 @@ int Capture::run(EventLoop *loop, const OptionsParser::Options &options)
 	}
 
 	camera_->freeBuffers();
-	config_.reset();
 
 	return ret;
 }
 
-int Capture::prepareConfig(const OptionsParser::Options &options)
-{
-	StreamRoles roles;
-
-	if (options.isSet(OptStream)) {
-		const std::vector<OptionValue> &streamOptions =
-			options[OptStream].toArray();
-
-		/* Use roles and get a default configuration. */
-		for (auto const &value : streamOptions) {
-			KeyValueParser::Options opt = value.toKeyValues();
-
-			if (!opt.isSet("role")) {
-				roles.push_back(StreamRole::VideoRecording);
-			} else if (opt["role"].toString() == "viewfinder") {
-				roles.push_back(StreamRole::Viewfinder);
-			} else if (opt["role"].toString() == "video") {
-				roles.push_back(StreamRole::VideoRecording);
-			} else if (opt["role"].toString() == "still") {
-				roles.push_back(StreamRole::StillCapture);
-			} else {
-				std::cerr << "Unknown stream role "
-					  << opt["role"].toString() << std::endl;
-				return -EINVAL;
-			}
-		}
-	} else {
-		/* If no configuration is provided assume a single video stream. */
-		roles.push_back(StreamRole::VideoRecording);
-	}
-
-	config_ = camera_->generateConfiguration(roles);
-	if (!config_ || config_->size() != roles.size()) {
-		std::cerr << "Failed to get default stream configuration"
-			  << std::endl;
-		return -EINVAL;
-	}
-
-	/* Apply configuration if explicitly requested. */
-	if (options.isSet(OptStream)) {
-		const std::vector<OptionValue> &streamOptions =
-			options[OptStream].toArray();
-
-		unsigned int i = 0;
-		for (auto const &value : streamOptions) {
-			KeyValueParser::Options opt = value.toKeyValues();
-			StreamConfiguration &cfg = config_->at(i++);
-
-			if (opt.isSet("width"))
-				cfg.size.width = opt["width"];
-
-			if (opt.isSet("height"))
-				cfg.size.height = opt["height"];
-
-			/* TODO: Translate 4CC string to ID. */
-			if (opt.isSet("pixelformat"))
-				cfg.pixelFormat = opt["pixelformat"];
-		}
-	}
-
-	streamName_.clear();
-	for (unsigned int index = 0; index < config_->size(); ++index) {
-		StreamConfiguration &cfg = config_->at(index);
-		streamName_[cfg.stream()] = "stream" + std::to_string(index);
-	}
-
-	return 0;
-}
-
 int Capture::capture(EventLoop *loop)
 {
 	int ret;
diff --git a/src/cam/capture.h b/src/cam/capture.h
index a97d1f44d229c214..1d4a25a84a51403b 100644
--- a/src/cam/capture.h
+++ b/src/cam/capture.h
@@ -20,19 +20,18 @@
 class Capture
 {
 public:
-	Capture(libcamera::Camera *camera);
+	Capture(libcamera::Camera *camera,
+		libcamera::CameraConfiguration *config);
 
 	int run(EventLoop *loop, const OptionsParser::Options &options);
 private:
-	int prepareConfig(const OptionsParser::Options &options);
-
 	int capture(EventLoop *loop);
 
 	void requestComplete(libcamera::Request *request,
 			     const std::map<libcamera::Stream *, libcamera::Buffer *> &buffers);
 
 	libcamera::Camera *camera_;
-	std::unique_ptr<libcamera::CameraConfiguration> config_;
+	libcamera::CameraConfiguration *config_;
 
 	std::map<libcamera::Stream *, std::string> streamName_;
 	BufferWriter *writer_;
diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index cd0afcb9bec2b148..784f58cb2d8758e4 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -33,19 +33,21 @@ public:
 
 private:
 	int parseOptions(int argc, char *argv[]);
+	int prepareConfig();
 	int run();
 
 	static CamApp *app_;
 	OptionsParser::Options options_;
 	CameraManager *cm_;
 	std::shared_ptr<Camera> camera_;
+	std::unique_ptr<libcamera::CameraConfiguration> config_;
 	EventLoop *loop_;
 };
 
 CamApp *CamApp::app_ = nullptr;
 
 CamApp::CamApp()
-	: cm_(nullptr), camera_(nullptr), loop_(nullptr)
+	: cm_(nullptr), camera_(nullptr), config_(nullptr), loop_(nullptr)
 {
 	CamApp::app_ = this;
 }
@@ -97,6 +99,10 @@ int CamApp::init(int argc, char **argv)
 		}
 
 		std::cout << "Using camera " << camera_->name() << std::endl;
+
+		ret = prepareConfig();
+		if (ret)
+			return ret;
 	}
 
 	loop_ = new EventLoop(cm_->eventDispatcher());
@@ -114,6 +120,8 @@ void CamApp::cleanup()
 		camera_.reset();
 	}
 
+	config_.reset();
+
 	cm_->stop();
 }
 
@@ -175,6 +183,69 @@ int CamApp::parseOptions(int argc, char *argv[])
 	return 0;
 }
 
+int CamApp::prepareConfig()
+{
+	StreamRoles roles;
+
+	if (options_.isSet(OptStream)) {
+		const std::vector<OptionValue> &streamOptions =
+			options_[OptStream].toArray();
+
+		/* Use roles and get a default configuration. */
+		for (auto const &value : streamOptions) {
+			KeyValueParser::Options opt = value.toKeyValues();
+
+			if (!opt.isSet("role")) {
+				roles.push_back(StreamRole::VideoRecording);
+			} else if (opt["role"].toString() == "viewfinder") {
+				roles.push_back(StreamRole::Viewfinder);
+			} else if (opt["role"].toString() == "video") {
+				roles.push_back(StreamRole::VideoRecording);
+			} else if (opt["role"].toString() == "still") {
+				roles.push_back(StreamRole::StillCapture);
+			} else {
+				std::cerr << "Unknown stream role "
+					  << opt["role"].toString() << std::endl;
+				return -EINVAL;
+			}
+		}
+	} else {
+		/* If no configuration is provided assume a single video stream. */
+		roles.push_back(StreamRole::VideoRecording);
+	}
+
+	config_ = camera_->generateConfiguration(roles);
+	if (!config_ || config_->size() != roles.size()) {
+		std::cerr << "Failed to get default stream configuration"
+			  << std::endl;
+		return -EINVAL;
+	}
+
+	/* Apply configuration if explicitly requested. */
+	if (options_.isSet(OptStream)) {
+		const std::vector<OptionValue> &streamOptions =
+			options_[OptStream].toArray();
+
+		unsigned int i = 0;
+		for (auto const &value : streamOptions) {
+			KeyValueParser::Options opt = value.toKeyValues();
+			StreamConfiguration &cfg = config_->at(i++);
+
+			if (opt.isSet("width"))
+				cfg.size.width = opt["width"];
+
+			if (opt.isSet("height"))
+				cfg.size.height = opt["height"];
+
+			/* TODO: Translate 4CC string to ID. */
+			if (opt.isSet("pixelformat"))
+				cfg.pixelFormat = opt["pixelformat"];
+		}
+	}
+
+	return 0;
+}
+
 int CamApp::run()
 {
 	if (options_.isSet(OptList)) {
@@ -188,7 +259,7 @@ int CamApp::run()
 	}
 
 	if (options_.isSet(OptCapture)) {
-		Capture capture(camera_.get());
+		Capture capture(camera_.get(), config_.get());
 		return capture.run(loop_, options_);
 	}
 
