diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h
index 27835500..436db409 100644
--- a/include/libcamera/camera_manager.h
+++ b/include/libcamera/camera_manager.h
@@ -7,6 +7,7 @@
 
 #pragma once
 
+#include <map>
 #include <memory>
 #include <string>
 #include <string_view>
@@ -20,6 +21,7 @@
 namespace libcamera {
 
 class Camera;
+class PipelineHandler;
 
 class CameraManager : public Object, public Extensible
 {
@@ -33,6 +35,8 @@ public:
 
 	std::vector<std::shared_ptr<Camera>> cameras() const;
 	std::shared_ptr<Camera> get(std::string_view id);
+	std::vector<std::string> memoryCameras() const;
+	std::shared_ptr<Camera> getMemoryCamera(std::string_view id, std::string_view settings);
 
 	static const std::string &version() { return version_; }
 
diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h
index 755928ce..4dbc1dc8 100644
--- a/include/libcamera/internal/camera_manager.h
+++ b/include/libcamera/internal/camera_manager.h
@@ -55,6 +55,9 @@ private:
 	void pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory);
 	void cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_);
 
+	std::shared_ptr<Camera> getMemoryCamera(const PipelineHandlerFactoryBase *factory,
+						std::string_view settings);
+
 	/*
 	 * This mutex protects
 	 *
@@ -70,6 +73,8 @@ private:
 
 	std::unique_ptr<DeviceEnumerator> enumerator_;
 
+	std::vector<std::string> memoryCameras_;
+
 	std::unique_ptr<IPAManager> ipaManager_;
 
 	const GlobalConfiguration configuration_;
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index b4f97477..cb631529 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -70,6 +70,14 @@ public:
 
 	CameraManager *cameraManager() const { return manager_; }
 
+	virtual bool supportsMemoryCamera() { return false; }
+
+	virtual std::shared_ptr<Camera> createMemoryCamera([[maybe_unused]] DeviceEnumerator *enumerator,
+							   [[maybe_unused]] std::string_view settings)
+	{
+		return nullptr;
+	}
+
 protected:
 	void registerCamera(std::shared_ptr<Camera> camera);
 	void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index 83510e06..734f5836 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -155,6 +155,13 @@ void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBa
 {
 	CameraManager *const o = LIBCAMERA_O_PTR();
 
+	/* First check for any memory-to-memory camera pipelines. */
+	{
+		std::shared_ptr<PipelineHandler> pipe = factory->create(o);
+		if (pipe->supportsMemoryCamera())
+			memoryCameras_.push_back(std::string(pipe->name()));
+	}
+
 	/* Provide as many matching pipelines as possible. */
 	while (1) {
 		std::shared_ptr<PipelineHandler> pipe = factory->create(o);
@@ -167,6 +174,19 @@ void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBa
 	}
 }
 
+std::shared_ptr<Camera> CameraManager::Private::getMemoryCamera(const PipelineHandlerFactoryBase *factory,
+								std::string_view settings)
+{
+	CameraManager *const o = LIBCAMERA_O_PTR();
+
+	std::shared_ptr<PipelineHandler> pipe = factory->create(o);
+
+	pipe->moveToThread(this);
+
+	return pipe->invokeMethod(&PipelineHandler::createMemoryCamera,
+				  ConnectionTypeBlocking, enumerator_.get(), settings);
+}
+
 void CameraManager::Private::cleanup()
 {
 	enumerator_->devicesAdded.disconnect(this);
@@ -371,6 +391,9 @@ void CameraManager::stop()
  * Before calling this function the caller is responsible for ensuring that
  * the camera manager is running.
  *
+ * This function does not list any memory cameras (for processing raw images
+ * held in memory buffers) that may be available.
+ *
  * \context This function is \threadsafe.
  *
  * \return List of all available cameras
@@ -409,6 +432,47 @@ std::shared_ptr<Camera> CameraManager::get(std::string_view id)
 	return nullptr;
 }
 
+/**
+ * \brief List the pipeline handlers that support memory cameras
+ *
+ * Lists the pipeline handlers in the system that have indicated they
+ * support memory cameras. Memory cameras are used for processing raw
+ * camera images stored in memory buffers, where no corresponding
+ * camera is available.
+ *
+ * \return Vector of pipeline handler ids (strings)
+ */
+std::vector<std::string> CameraManager::memoryCameras() const
+{
+	return _d()->memoryCameras_;
+}
+
+/**
+ * \brief Get a memory camera from the named pipeline handler
+ * \param[in] id ID of the pipeline handler that should create the memory camera
+ *
+ * This function causes the named pipeline handler to create and return a
+ * memory camera to the application. Pipeline handlers may support multiple
+ * simultaneous memory cameras, or none at all.
+ *
+ * \return Shared pointer to Camera object or nullptr if no memory camera
+ * could be provided
+ */
+std::shared_ptr<Camera> CameraManager::getMemoryCamera(std::string_view id,
+						       std::string_view settings)
+{
+	for (const auto &name : _d()->memoryCameras_) {
+		if (name == id) {
+			const PipelineHandlerFactoryBase *factory;
+			factory = PipelineHandlerFactoryBase::getFactoryByName(name);
+
+			return _d()->getMemoryCamera(factory, settings);
+		}
+	}
+
+	return nullptr;
+}
+
 /**
  * \var CameraManager::cameraAdded
  * \brief Notify of a new camera added to the system
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 5c469e5b..c0f3c84e 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -835,6 +835,29 @@ void PipelineHandler::disconnect()
  * \return The CameraManager for this pipeline handler
  */
 
+/**
+ * \fn PipelineHandler::supportsMemoryCamera()
+ * \brief Indicate whether this pipeline handler supports memory cameras.
+ * \return True if the pipeline handler supports memory cameras, otherwise false.
+ */
+
+/**
+ * \fn PipelineHandler::createMemoryCamera()
+ * \brief Create a memory camera to process raw camera images from a memory buffer
+ * \param[in] enumerator The enumerator providing all media devices found in the
+ * system
+ * \param[in] settings A string of settings that the pipeline handler should use
+ *
+ * The pipeline handler should create a memory camera, which an application can
+ * use to process raw camera images that are stored in memory buffers (rather
+ * than being delivered from a live camera).
+ *
+ * The settings should indicate exactly what processing the application requires
+ * to be performed on the raw image.
+ *
+ * \return Shared pointer to a camera, or a nullptr if none could be created
+ */
+
 /**
  * \class PipelineHandlerFactoryBase
  * \brief Base class for pipeline handler factories
