diff --git a/src/libcamera/pipeline/vivid/vivid.cpp b/src/libcamera/pipeline/vivid/vivid.cpp
index 9811f6ef5095..a8922ce70ed4 100644
--- a/src/libcamera/pipeline/vivid/vivid.cpp
+++ b/src/libcamera/pipeline/vivid/vivid.cpp
@@ -5,14 +5,46 @@
  * vivid.cpp - Pipeline handler for the vivid capture device
  */
 
+#include <libcamera/camera.h>
+
 #include "libcamera/internal/device_enumerator.h"
 #include "libcamera/internal/log.h"
+#include "libcamera/internal/media_device.h"
 #include "libcamera/internal/pipeline_handler.h"
+#include "libcamera/internal/v4l2_videodevice.h"
 
 namespace libcamera {
 
 LOG_DEFINE_CATEGORY(VIVID)
 
+class VividCameraData : public CameraData
+{
+public:
+	VividCameraData(PipelineHandler *pipe, MediaDevice *media)
+		: CameraData(pipe), media_(media), video_(nullptr)
+	{
+	}
+
+	~VividCameraData()
+	{
+		delete video_;
+	}
+
+	int init();
+
+	MediaDevice *media_;
+	V4L2VideoDevice *video_;
+	Stream stream_;
+};
+
+class VividCameraConfiguration : public CameraConfiguration
+{
+public:
+	VividCameraConfiguration();
+
+	Status validate() override;
+};
+
 class PipelineHandlerVivid : public PipelineHandler
 {
 public:
@@ -78,9 +110,27 @@ bool PipelineHandlerVivid::match(DeviceEnumerator *enumerator)
 	if (!media)
 		return false;
 
-	LOG(VIVID, Debug) << "Obtained Vivid Device";
+	std::unique_ptr<VividCameraData> data = std::make_unique<VividCameraData>(this, media);
+
+	/* Locate and open the capture video node. */
+	if (data->init())
+		return false;
+
+	/* Create and register the camera. */
+	std::set<Stream *> streams{ &data->stream_ };
+	std::shared_ptr<Camera> camera = Camera::create(this, data->video_->deviceName(), streams);
+	registerCamera(std::move(camera), std::move(data));
+
+	return true;
+}
+
+int VividCameraData::init()
+{
+	video_ = new V4L2VideoDevice(media_->getEntityByName("vivid-000-vid-cap"));
+	if (video_->open())
+		return -ENODEV;
 
-	return false; // Prevent infinite loops for now
+	return 0;
 }
 
 REGISTER_PIPELINE_HANDLER(PipelineHandlerVivid);
