[v3,01/29] libcamera: pipeline: utilise shared MediaDevice pointers
diff mbox series

Message ID 20251125162851.2301793-2-stefan.klug@ideasonboard.com
State Superseded
Headers show
Series
  • Full dewarper support on imx8mp
Related show

Commit Message

Stefan Klug Nov. 25, 2025, 4:28 p.m. UTC
From: Kieran Bingham <kieran.bingham@ideasonboard.com>

Adapt the PipelineHandler::acquireMediaDevice() support function to
return a shared pointer instead of the underlying raw pointer.

Propagate this update to all pipeline handlers that use the MediaDevice
and store a std::shared_ptr<MediaDevice> accordingly.

This is required to support media devices that are potentially shared
among multiple pipeline handlers, like a dewarper implemented as v4l2
m2m device.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>

---

Changes in v3:
- Call fromEntityName() with a pointer, as the shared_ptr overload was
  dropped
---
 include/libcamera/internal/pipeline_handler.h    |  8 ++++----
 src/libcamera/pipeline/imx8-isi/imx8-isi.cpp     |  8 ++++----
 src/libcamera/pipeline/ipu3/cio2.cpp             |  4 ++--
 src/libcamera/pipeline/ipu3/cio2.h               |  2 +-
 src/libcamera/pipeline/ipu3/imgu.cpp             | 15 ++++++++-------
 src/libcamera/pipeline/ipu3/imgu.h               |  4 ++--
 src/libcamera/pipeline/ipu3/ipu3.cpp             |  4 ++--
 src/libcamera/pipeline/mali-c55/mali-c55.cpp     | 16 ++++++++--------
 src/libcamera/pipeline/rkisp1/rkisp1.cpp         |  8 ++++----
 src/libcamera/pipeline/rkisp1/rkisp1_path.cpp    |  6 +++---
 src/libcamera/pipeline/rkisp1/rkisp1_path.h      |  2 +-
 .../pipeline/rpi/common/pipeline_base.cpp        |  6 ++++--
 .../pipeline/rpi/common/pipeline_base.h          |  9 ++++++---
 src/libcamera/pipeline/rpi/pisp/pisp.cpp         | 10 ++++++----
 src/libcamera/pipeline/rpi/vc4/vc4.cpp           | 13 +++++++++----
 src/libcamera/pipeline/simple/simple.cpp         | 13 +++++++------
 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp     |  6 +++---
 src/libcamera/pipeline/vimc/vimc.cpp             | 14 +++++++-------
 src/libcamera/pipeline_handler.cpp               | 14 ++++++++------
 test/libtest/buffer_source.cpp                   |  3 ++-
 20 files changed, 91 insertions(+), 74 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index b2078577f5a4..b4f97477acec 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -38,8 +38,8 @@  public:
 	virtual ~PipelineHandler();
 
 	virtual bool match(DeviceEnumerator *enumerator) = 0;
-	MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,
-					const DeviceMatch &dm);
+	std::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,
+							const DeviceMatch &dm);
 
 	bool acquire(Camera *camera);
 	void release(Camera *camera);
@@ -72,7 +72,7 @@  public:
 
 protected:
 	void registerCamera(std::shared_ptr<Camera> camera);
-	void hotplugMediaDevice(MediaDevice *media);
+	void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
 	unsigned int useCount() const { return useCount_; }
 
 	virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
@@ -87,7 +87,7 @@  protected:
 private:
 	void unlockMediaDevices();
 
-	void mediaDeviceDisconnected(MediaDevice *media);
+	void mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);
 	virtual void disconnect();
 
 	void doQueueRequest(Request *request);
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
index 9550f54600c4..049d9b1c44cb 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -141,7 +141,7 @@  private:
 
 	void bufferReady(FrameBuffer *buffer);
 
-	MediaDevice *isiDev_;
+	std::shared_ptr<MediaDevice> isiDev_;
 
 	std::unique_ptr<V4L2Subdevice> crossbar_;
 	std::vector<Pipe> pipes_;
@@ -996,7 +996,7 @@  bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)
 	 * Acquire the subdevs and video nodes for the crossbar switch and the
 	 * processing pipelines.
 	 */
-	crossbar_ = V4L2Subdevice::fromEntityName(isiDev_, "crossbar");
+	crossbar_ = V4L2Subdevice::fromEntityName(isiDev_.get(), "crossbar");
 	if (!crossbar_)
 		return false;
 
@@ -1007,7 +1007,7 @@  bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)
 	for (unsigned int i = 0; ; ++i) {
 		std::string entityName = "mxc_isi." + std::to_string(i);
 		std::unique_ptr<V4L2Subdevice> isi =
-			V4L2Subdevice::fromEntityName(isiDev_, entityName);
+			V4L2Subdevice::fromEntityName(isiDev_.get(), entityName);
 		if (!isi)
 			break;
 
@@ -1017,7 +1017,7 @@  bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)
 
 		entityName += ".capture";
 		std::unique_ptr<V4L2VideoDevice> capture =
-			V4L2VideoDevice::fromEntityName(isiDev_, entityName);
+			V4L2VideoDevice::fromEntityName(isiDev_.get(), entityName);
 		if (!capture)
 			return false;
 
diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
index aa544d7b0303..6f9c055f4d12 100644
--- a/src/libcamera/pipeline/ipu3/cio2.cpp
+++ b/src/libcamera/pipeline/ipu3/cio2.cpp
@@ -112,7 +112,7 @@  std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const
  * \return 0 on success or a negative error code otherwise
  * \retval -ENODEV No supported image sensor is connected to this CIO2 instance
  */
-int CIO2Device::init(const MediaDevice *media, unsigned int index)
+int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)
 {
 	int ret;
 
@@ -170,7 +170,7 @@  int CIO2Device::init(const MediaDevice *media, unsigned int index)
 		return ret;
 
 	std::string cio2Name = "ipu3-cio2 " + std::to_string(index);
-	output_ = V4L2VideoDevice::fromEntityName(media, cio2Name);
+	output_ = V4L2VideoDevice::fromEntityName(media.get(), cio2Name);
 	return output_->open();
 }
 
diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
index 3aa3a1ca8ef8..d844cb7ae831 100644
--- a/src/libcamera/pipeline/ipu3/cio2.h
+++ b/src/libcamera/pipeline/ipu3/cio2.h
@@ -38,7 +38,7 @@  public:
 	std::vector<PixelFormat> formats() const;
 	std::vector<SizeRange> sizes(const PixelFormat &format) const;
 
-	int init(const MediaDevice *media, unsigned int index);
+	int init(std::shared_ptr<const MediaDevice> media, unsigned int index);
 	int configure(const Size &size, const Transform &transform,
 		      V4L2DeviceFormat *outputFormat);
 
diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp
index 7be780913fae..bb36c06e8dea 100644
--- a/src/libcamera/pipeline/ipu3/imgu.cpp
+++ b/src/libcamera/pipeline/ipu3/imgu.cpp
@@ -330,7 +330,8 @@  FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)
  *
  * \return 0 on success or a negative error code otherwise
  */
-int ImgUDevice::init(MediaDevice *media, unsigned int index)
+int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,
+		     unsigned int index)
 {
 	int ret;
 
@@ -342,32 +343,32 @@  int ImgUDevice::init(MediaDevice *media, unsigned int index)
 	 * by the match() function: no need to check for newly created
 	 * video devices and subdevice validity here.
 	 */
-	imgu_ = V4L2Subdevice::fromEntityName(media, name_);
+	imgu_ = V4L2Subdevice::fromEntityName(media.get(), name_);
 	ret = imgu_->open();
 	if (ret)
 		return ret;
 
-	input_ = V4L2VideoDevice::fromEntityName(media, name_ + " input");
+	input_ = V4L2VideoDevice::fromEntityName(media.get(), name_ + " input");
 	ret = input_->open();
 	if (ret)
 		return ret;
 
-	output_ = V4L2VideoDevice::fromEntityName(media, name_ + " output");
+	output_ = V4L2VideoDevice::fromEntityName(media.get(), name_ + " output");
 	ret = output_->open();
 	if (ret)
 		return ret;
 
-	viewfinder_ = V4L2VideoDevice::fromEntityName(media, name_ + " viewfinder");
+	viewfinder_ = V4L2VideoDevice::fromEntityName(media.get(), name_ + " viewfinder");
 	ret = viewfinder_->open();
 	if (ret)
 		return ret;
 
-	param_ = V4L2VideoDevice::fromEntityName(media, name_ + " parameters");
+	param_ = V4L2VideoDevice::fromEntityName(media.get(), name_ + " parameters");
 	ret = param_->open();
 	if (ret)
 		return ret;
 
-	stat_ = V4L2VideoDevice::fromEntityName(media, name_ + " 3a stat");
+	stat_ = V4L2VideoDevice::fromEntityName(media.get(), name_ + " 3a stat");
 	ret = stat_->open();
 	if (ret)
 		return ret;
diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h
index fa508316b301..272f861f98c4 100644
--- a/src/libcamera/pipeline/ipu3/imgu.h
+++ b/src/libcamera/pipeline/ipu3/imgu.h
@@ -64,7 +64,7 @@  public:
 		Size viewfinder;
 	};
 
-	int init(MediaDevice *media, unsigned int index);
+	int init(std::shared_ptr<MediaDevice> media, unsigned int index);
 
 	PipeConfig calculatePipeConfig(Pipe *pipe);
 
@@ -118,7 +118,7 @@  private:
 				 V4L2DeviceFormat *outputFormat);
 
 	std::string name_;
-	MediaDevice *media_;
+	std::shared_ptr<MediaDevice> media_;
 };
 
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index d6b7edcb5a7f..695762c750f8 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -164,8 +164,8 @@  private:
 
 	ImgUDevice imgu0_;
 	ImgUDevice imgu1_;
-	MediaDevice *cio2MediaDev_;
-	MediaDevice *imguMediaDev_;
+	std::shared_ptr<MediaDevice> cio2MediaDev_;
+	std::shared_ptr<MediaDevice> imguMediaDev_;
 
 	std::vector<IPABuffer> ipaBuffers_;
 };
diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
index 38bdc6138ed1..cf0cb15f8bb3 100644
--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
@@ -682,7 +682,7 @@  private:
 	bool registerTPGCamera(MediaLink *link);
 	bool registerSensorCamera(MediaLink *link);
 
-	MediaDevice *media_;
+	std::shared_ptr<MediaDevice> media_;
 	std::unique_ptr<V4L2Subdevice> isp_;
 	std::unique_ptr<V4L2VideoDevice> stats_;
 	std::unique_ptr<V4L2VideoDevice> params_;
@@ -1647,24 +1647,24 @@  bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
 	if (!media_)
 		return false;
 
-	isp_ = V4L2Subdevice::fromEntityName(media_, "mali-c55 isp");
+	isp_ = V4L2Subdevice::fromEntityName(media_.get(), "mali-c55 isp");
 	if (isp_->open() < 0)
 		return false;
 
-	stats_ = V4L2VideoDevice::fromEntityName(media_, "mali-c55 3a stats");
+	stats_ = V4L2VideoDevice::fromEntityName(media_.get(), "mali-c55 3a stats");
 	if (stats_->open() < 0)
 		return false;
 
-	params_ = V4L2VideoDevice::fromEntityName(media_, "mali-c55 3a params");
+	params_ = V4L2VideoDevice::fromEntityName(media_.get(), "mali-c55 3a params");
 	if (params_->open() < 0)
 		return false;
 
 	MaliC55Pipe *frPipe = &pipes_[MaliC55FR];
-	frPipe->resizer = V4L2Subdevice::fromEntityName(media_, "mali-c55 resizer fr");
+	frPipe->resizer = V4L2Subdevice::fromEntityName(media_.get(), "mali-c55 resizer fr");
 	if (frPipe->resizer->open() < 0)
 		return false;
 
-	frPipe->cap = V4L2VideoDevice::fromEntityName(media_, "mali-c55 fr");
+	frPipe->cap = V4L2VideoDevice::fromEntityName(media_.get(), "mali-c55 fr");
 	if (frPipe->cap->open() < 0)
 		return false;
 
@@ -1682,11 +1682,11 @@  bool PipelineHandlerMaliC55::match(DeviceEnumerator *enumerator)
 
 		MaliC55Pipe *dsPipe = &pipes_[MaliC55DS];
 
-		dsPipe->resizer = V4L2Subdevice::fromEntityName(media_, "mali-c55 resizer ds");
+		dsPipe->resizer = V4L2Subdevice::fromEntityName(media_.get(), "mali-c55 resizer ds");
 		if (dsPipe->resizer->open() < 0)
 			return false;
 
-		dsPipe->cap = V4L2VideoDevice::fromEntityName(media_, "mali-c55 ds");
+		dsPipe->cap = V4L2VideoDevice::fromEntityName(media_.get(), "mali-c55 ds");
 		if (dsPipe->cap->open() < 0)
 			return false;
 
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index d7195b6c484d..d108acfbad9f 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -218,7 +218,7 @@  private:
 
 	int updateControls(RkISP1CameraData *data);
 
-	MediaDevice *media_;
+	std::shared_ptr<MediaDevice> media_;
 	std::unique_ptr<V4L2Subdevice> isp_;
 	std::unique_ptr<V4L2VideoDevice> param_;
 	std::unique_ptr<V4L2VideoDevice> stat_;
@@ -1412,16 +1412,16 @@  bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)
 	hasSelfPath_ = !!media_->getEntityByName("rkisp1_selfpath");
 
 	/* Create the V4L2 subdevices we will need. */
-	isp_ = V4L2Subdevice::fromEntityName(media_, "rkisp1_isp");
+	isp_ = V4L2Subdevice::fromEntityName(media_.get(), "rkisp1_isp");
 	if (isp_->open() < 0)
 		return false;
 
 	/* Locate and open the stats and params video nodes. */
-	stat_ = V4L2VideoDevice::fromEntityName(media_, "rkisp1_stats");
+	stat_ = V4L2VideoDevice::fromEntityName(media_.get(), "rkisp1_stats");
 	if (stat_->open() < 0)
 		return false;
 
-	param_ = V4L2VideoDevice::fromEntityName(media_, "rkisp1_params");
+	param_ = V4L2VideoDevice::fromEntityName(media_.get(), "rkisp1_params");
 	if (param_->open() < 0)
 		return false;
 
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
index d318bea92446..ef9cfbdc327a 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
@@ -64,16 +64,16 @@  RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats,
 {
 }
 
-bool RkISP1Path::init(MediaDevice *media)
+bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)
 {
 	std::string resizer = std::string("rkisp1_resizer_") + name_ + "path";
 	std::string video = std::string("rkisp1_") + name_ + "path";
 
-	resizer_ = V4L2Subdevice::fromEntityName(media, resizer);
+	resizer_ = V4L2Subdevice::fromEntityName(media.get(), resizer);
 	if (resizer_->open() < 0)
 		return false;
 
-	video_ = V4L2VideoDevice::fromEntityName(media, video);
+	video_ = V4L2VideoDevice::fromEntityName(media.get(), video);
 	if (video_->open() < 0)
 		return false;
 
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
index 0b60c499ac64..0c68e9eb99af 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
@@ -37,7 +37,7 @@  public:
 	RkISP1Path(const char *name, const Span<const PixelFormat> &formats,
 		   const Size &minResolution, const Size &maxResolution);
 
-	bool init(MediaDevice *media);
+	bool init(std::shared_ptr<MediaDevice> media);
 
 	int setEnabled(bool enable) { return link_->setEnabled(enable); }
 	bool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
index c209aa596311..9d65dc83573b 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -786,8 +786,10 @@  int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)
 }
 
 int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,
-					MediaDevice *frontend, const std::string &frontendName,
-					MediaDevice *backend, MediaEntity *sensorEntity)
+					std::shared_ptr<MediaDevice> frontend,
+					const std::string &frontendName,
+					std::shared_ptr<MediaDevice> backend,
+					MediaEntity *sensorEntity)
 {
 	CameraData *data = cameraData.get();
 	int ret;
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h
index 4bce4ec4f978..15628259afc6 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
@@ -224,13 +224,16 @@  public:
 
 protected:
 	int registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,
-			   MediaDevice *frontent, const std::string &frontendName,
-			   MediaDevice *backend, MediaEntity *sensorEntity);
+			   std::shared_ptr<MediaDevice> frontend,
+			   const std::string &frontendName,
+			   std::shared_ptr<MediaDevice> backend,
+			   MediaEntity *sensorEntity);
 
 	void mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);
 
 	virtual int platformRegister(std::unique_ptr<CameraData> &cameraData,
-				     MediaDevice *unicam, MediaDevice *isp) = 0;
+				     std::shared_ptr<MediaDevice> unicam,
+				     std::shared_ptr<MediaDevice> isp) = 0;
 
 private:
 	CameraData *cameraData(Camera *camera)
diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
index 082724c5a0fb..77acd2f64092 100644
--- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp
+++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
@@ -866,7 +866,8 @@  private:
 
 	int prepareBuffers(Camera *camera) override;
 	int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,
-			     MediaDevice *cfe, MediaDevice *isp) override;
+			     std::shared_ptr<MediaDevice> cfe,
+			     std::shared_ptr<MediaDevice> isp) override;
 };
 
 bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)
@@ -884,7 +885,7 @@  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)
 		cfe.add("rp1-cfe-fe-image0");
 		cfe.add("rp1-cfe-fe-stats");
 		cfe.add("rp1-cfe-fe-config");
-		MediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);
+		std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);
 
 		if (!cfeDevice) {
 			LOG(RPI, Debug) << "Unable to acquire a CFE instance";
@@ -900,7 +901,7 @@  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)
 		isp.add("pispbe-tdn_input");
 		isp.add("pispbe-stitch_output");
 		isp.add("pispbe-stitch_input");
-		MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);
+		std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);
 
 		if (!ispDevice) {
 			LOG(RPI, Debug) << "Unable to acquire ISP instance";
@@ -1065,7 +1066,8 @@  int PipelineHandlerPiSP::prepareBuffers(Camera *camera)
 }
 
 int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,
-					  MediaDevice *cfe, MediaDevice *isp)
+					  std::shared_ptr<MediaDevice> cfe,
+					  std::shared_ptr<MediaDevice> isp)
 {
 	PiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());
 	int ret;
diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
index 99d43bd0a2f5..f0cb99d59e74 100644
--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
@@ -5,6 +5,8 @@ 
  * Pipeline handler for VC4-based Raspberry Pi devices
  */
 
+#include <memory>
+
 #include <linux/bcm2835-isp.h>
 #include <linux/v4l2-controls.h>
 #include <linux/videodev2.h>
@@ -158,7 +160,8 @@  private:
 
 	int prepareBuffers(Camera *camera) override;
 	int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,
-			     MediaDevice *unicam, MediaDevice *isp) override;
+			     std::shared_ptr<MediaDevice> unicam,
+			     std::shared_ptr<MediaDevice> isp) override;
 };
 
 bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)
@@ -173,7 +176,7 @@  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)
 	 */
 	for (unsigned int i = 0; i < numUnicamDevices; i++) {
 		DeviceMatch unicam("unicam");
-		MediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);
+		std::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);
 
 		if (!unicamDevice) {
 			LOG(RPI, Debug) << "Unable to acquire a Unicam instance";
@@ -181,7 +184,7 @@  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)
 		}
 
 		DeviceMatch isp("bcm2835-isp");
-		MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);
+		std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);
 
 		if (!ispDevice) {
 			LOG(RPI, Debug) << "Unable to acquire ISP instance";
@@ -303,7 +306,9 @@  int PipelineHandlerVc4::prepareBuffers(Camera *camera)
 	return 0;
 }
 
-int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)
+int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,
+					 std::shared_ptr<MediaDevice> unicam,
+					 std::shared_ptr<MediaDevice> isp)
 {
 	Vc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());
 
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 118b4186c8bf..5e81a6b25920 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -413,7 +413,7 @@  public:
 
 	V4L2VideoDevice *video(const MediaEntity *entity);
 	V4L2Subdevice *subdev(const MediaEntity *entity);
-	MediaDevice *converter() { return converter_; }
+	MediaDevice *converter() { return converter_.get(); }
 	bool swIspEnabled() const { return swIspEnabled_; }
 
 protected:
@@ -434,7 +434,8 @@  private:
 		return static_cast<SimpleCameraData *>(camera->_d());
 	}
 
-	bool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,
+	bool matchDevice(std::shared_ptr<MediaDevice> media,
+			 const SimplePipelineInfo &info,
 			 DeviceEnumerator *enumerator);
 
 	std::vector<MediaEntity *> locateSensors(MediaDevice *media);
@@ -445,7 +446,7 @@  private:
 
 	std::map<const MediaEntity *, EntityData> entities_;
 
-	MediaDevice *converter_;
+	std::shared_ptr<MediaDevice> converter_;
 	bool swIspEnabled_;
 };
 
@@ -1690,7 +1691,7 @@  int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)
 	return 0;
 }
 
-bool SimplePipelineHandler::matchDevice(MediaDevice *media,
+bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,
 					const SimplePipelineInfo &info,
 					DeviceEnumerator *enumerator)
 {
@@ -1721,7 +1722,7 @@  bool SimplePipelineHandler::matchDevice(MediaDevice *media,
 	}
 
 	/* Locate the sensors. */
-	std::vector<MediaEntity *> sensors = locateSensors(media);
+	std::vector<MediaEntity *> sensors = locateSensors(media.get());
 	if (sensors.empty()) {
 		LOG(SimplePipeline, Info) << "No sensor found for " << media->deviceNode();
 		return false;
@@ -1839,7 +1840,7 @@  bool SimplePipelineHandler::matchDevice(MediaDevice *media,
 
 bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)
 {
-	MediaDevice *media;
+	std::shared_ptr<MediaDevice> media;
 
 	for (const SimplePipelineInfo &inf : supportedDevices) {
 		DeviceMatch dm(inf.driver);
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 4b5816dfdde0..034f9c39d3e9 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -46,7 +46,7 @@  public:
 	{
 	}
 
-	int init(MediaDevice *media);
+	int init(std::shared_ptr<MediaDevice> media);
 	void addControl(uint32_t cid, const ControlInfo &v4l2info,
 			ControlInfoMap::Map *ctrls);
 	void imageBufferReady(FrameBuffer *buffer);
@@ -466,7 +466,7 @@  int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)
 
 bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)
 {
-	MediaDevice *media;
+	std::shared_ptr<MediaDevice> media;
 	DeviceMatch dm("uvcvideo");
 
 	media = acquireMediaDevice(enumerator, dm);
@@ -508,7 +508,7 @@  void PipelineHandlerUVC::releaseDevice(Camera *camera)
 	data->video_->close();
 }
 
-int UVCCameraData::init(MediaDevice *media)
+int UVCCameraData::init(std::shared_ptr<MediaDevice> media)
 {
 	int ret;
 
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 5022101505a1..cd3370e3d419 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -49,7 +49,7 @@  LOG_DEFINE_CATEGORY(VIMC)
 class VimcCameraData : public Camera::Private
 {
 public:
-	VimcCameraData(PipelineHandler *pipe, MediaDevice *media)
+	VimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)
 		: Camera::Private(pipe), media_(media)
 	{
 	}
@@ -59,7 +59,7 @@  public:
 	void imageBufferReady(FrameBuffer *buffer);
 	void paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);
 
-	MediaDevice *media_;
+	std::shared_ptr<MediaDevice> media_;
 	std::unique_ptr<CameraSensor> sensor_;
 	std::unique_ptr<V4L2Subdevice> debayer_;
 	std::unique_ptr<V4L2Subdevice> scaler_;
@@ -479,7 +479,7 @@  bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
 	dm.add("RGB/YUV Input");
 	dm.add("Scaler");
 
-	MediaDevice *media = acquireMediaDevice(enumerator, dm);
+	std::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);
 	if (!media)
 		return false;
 
@@ -539,21 +539,21 @@  int VimcCameraData::init()
 	if (!sensor_)
 		return -ENODEV;
 
-	debayer_ = V4L2Subdevice::fromEntityName(media_, "Debayer B");
+	debayer_ = V4L2Subdevice::fromEntityName(media_.get(), "Debayer B");
 	if (debayer_->open())
 		return -ENODEV;
 
-	scaler_ = V4L2Subdevice::fromEntityName(media_, "Scaler");
+	scaler_ = V4L2Subdevice::fromEntityName(media_.get(), "Scaler");
 	if (scaler_->open())
 		return -ENODEV;
 
-	video_ = V4L2VideoDevice::fromEntityName(media_, "RGB/YUV Capture");
+	video_ = V4L2VideoDevice::fromEntityName(media_.get(), "RGB/YUV Capture");
 	if (video_->open())
 		return -ENODEV;
 
 	video_->bufferReady.connect(this, &VimcCameraData::imageBufferReady);
 
-	raw_ = V4L2VideoDevice::fromEntityName(media_, "Raw Capture 1");
+	raw_ = V4L2VideoDevice::fromEntityName(media_.get(), "Raw Capture 1");
 	if (raw_->open())
 		return -ENODEV;
 
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index ca6215ec69ee..5c469e5bad24 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -129,10 +129,12 @@  PipelineHandler::~PipelineHandler()
  *
  * \context This function shall be called from the CameraManager thread.
  *
- * \return A pointer to the matching MediaDevice, or nullptr if no match is found
+ * \return A shared pointer to the matching MediaDevice, or nullptr if no match
+ * is found
  */
-MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
-						 const DeviceMatch &dm)
+std::shared_ptr<MediaDevice>
+PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
+				    const DeviceMatch &dm)
 {
 	std::shared_ptr<MediaDevice> media = enumerator->search(dm);
 	if (!media)
@@ -143,7 +145,7 @@  MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
 
 	mediaDevices_.push_back(media);
 
-	return media.get();
+	return media;
 }
 
 /**
@@ -734,7 +736,7 @@  void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)
  * handler gets notified and automatically disconnects all the cameras it has
  * registered without requiring any manual intervention.
  */
-void PipelineHandler::hotplugMediaDevice(MediaDevice *media)
+void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)
 {
 	media->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });
 }
@@ -742,7 +744,7 @@  void PipelineHandler::hotplugMediaDevice(MediaDevice *media)
 /**
  * \brief Slot for the MediaDevice disconnected signal
  */
-void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)
+void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)
 {
 	media->disconnected.disconnect(this);
 
diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
index dde11f365e43..97c8ae1cbd31 100644
--- a/test/libtest/buffer_source.cpp
+++ b/test/libtest/buffer_source.cpp
@@ -52,7 +52,8 @@  int BufferSource::allocate(const StreamConfiguration &config)
 		return TestSkip;
 	}
 
-	std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);
+	std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(),
+										 videoDeviceName);
 	if (!video) {
 		std::cout << "Failed to get video device from entity "
 			  << videoDeviceName << std::endl;