[2/3] libcamera: pipeline: utilise shared MediaDevice pointers
diff mbox series

Message ID 20250404074624.2975182-3-paul.elder@ideasonboard.com
State New
Headers show
Series
  • libcamera: pipeline: Use shared pointers for MediaDevice
Related show

Commit Message

Paul Elder April 4, 2025, 7:46 a.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.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 include/libcamera/internal/pipeline_handler.h      |  8 ++++----
 src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
 src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
 src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
 src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
 src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
 src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
 src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
 src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
 src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
 src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
 .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
 src/libcamera/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               |  6 +++---
 src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
 test/delayed_controls.cpp                          |  2 +-
 test/libtest/buffer_source.cpp                     |  2 +-
 21 files changed, 65 insertions(+), 49 deletions(-)

Comments

Jacopo Mondi April 6, 2025, 4:53 p.m. UTC | #1
Hi Paul

On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> From: Kieran Bingham <kieran.bingham@ideasonboard.com>
>
> Adapt the PipelineHandler::acquireMediaDevice() support function to
> return a shared pointer instead of the underlying raw pointer.

It seems nice, but I wonder if it really is better ? The
PipelineHandler base class already stores a shared_ptr<> instance for
each acquired media device. Is passing it around by value and storing
a copy as classes member in derived classes worth it ?

Or is this about an ownership issue I am missing ?

>
> Propagate this update to all pipeline handlers that use the MediaDevice
> and store a std::shared_ptr<MediaDevice> accordingly.
>
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> ---
>  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
>  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
>  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
>  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
>  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
>  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
>  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
>  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
>  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
>  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
>  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
>  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
>  src/libcamera/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               |  6 +++---
>  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
>  test/delayed_controls.cpp                          |  2 +-
>  test/libtest/buffer_source.cpp                     |  2 +-
>  21 files changed, 65 insertions(+), 49 deletions(-)
>
> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> index 5fa8bc2f66ee..0199ab7911c0 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);
> @@ -74,7 +74,7 @@ protected:
>  	void clearMediaDevices();
>
>  	void registerCamera(std::shared_ptr<Camera> camera);
> -	void hotplugMediaDevice(MediaDevice *media);
> +	void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
>
>  	virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
>  	virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> @@ -139,7 +139,7 @@ private:
>
>  	void bufferReady(FrameBuffer *buffer);
>
> -	MediaDevice *isiDev_;
> +	std::shared_ptr<MediaDevice> isiDev_;
>
>  	std::unique_ptr<V4L2Subdevice> crossbar_;
>  	std::vector<Pipe> pipes_;
> diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> index aa544d7b0303..ebbd424c56ea 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;
>
> diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
>
> 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> @@ -684,7 +684,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_;
> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> index 705615b86b0c..d4ec538f478b 100644
> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> @@ -200,7 +200,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_;
> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> index eee5b09e2ff0..2e567ace0b78 100644
> --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> @@ -59,7 +59,7 @@ 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";
> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> index 2a1ef0abe6d1..154310ac37c1 100644
> --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> @@ -36,7 +36,7 @@ class RkISP1Path
>  public:
>  	RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
>
> -	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 1f13e5230fae..23ce54eca144 100644
> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> --- a/src/libcamera/pipeline/simple/simple.cpp
> +++ b/src/libcamera/pipeline/simple/simple.cpp
> @@ -407,7 +407,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:
> @@ -427,7 +427,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);
> @@ -438,7 +439,7 @@ private:
>
>  	std::map<const MediaEntity *, EntityData> entities_;
>
> -	MediaDevice *converter_;
> +	std::shared_ptr<MediaDevice> converter_;
>  	bool swIspEnabled_;
>  };
>
> @@ -1663,7 +1664,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)
>  {
> @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
>  	swIspEnabled_ = info.swIspEnabled;
>
>  	/* 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;
> @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> @@ -449,7 +449,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);
> @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> @@ -476,7 +476,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;
>
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index 8f12957b75fa..5fe2c64c8bc6 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -125,10 +125,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)
> @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
>
>  	mediaDevices_.push_back(media);
>
> -	return media.get();
> +	return media;
>  }
>
>  /**
> @@ -712,7 +714,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); });
>  }
> @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> index 7bd30e7aead8..b305be48aafc 100644
> --- a/test/delayed_controls.cpp
> +++ b/test/delayed_controls.cpp
> @@ -47,7 +47,7 @@ protected:
>  			return TestSkip;
>  		}
>
> -		dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> +		dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
>  		if (dev_->open()) {
>  			cerr << "Failed to open video device" << endl;
>  			return TestFail;
> diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> index dde11f365e43..19b25fed50a0 100644
> --- a/test/libtest/buffer_source.cpp
> +++ b/test/libtest/buffer_source.cpp
> @@ -52,7 +52,7 @@ 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_, videoDeviceName);
>  	if (!video) {
>  		std::cout << "Failed to get video device from entity "
>  			  << videoDeviceName << std::endl;
> --
> 2.47.2
>
Laurent Pinchart April 6, 2025, 6:16 p.m. UTC | #2
On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:
> On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> >
> > Adapt the PipelineHandler::acquireMediaDevice() support function to
> > return a shared pointer instead of the underlying raw pointer.
> 
> It seems nice, but I wonder if it really is better ? The
> PipelineHandler base class already stores a shared_ptr<> instance for
> each acquired media device. Is passing it around by value and storing
> a copy as classes member in derived classes worth it ?
> 
> Or is this about an ownership issue I am missing ?

I'm also wondering the same. Paul, could you explain the rationale for
this patch series ?

> > Propagate this update to all pipeline handlers that use the MediaDevice
> > and store a std::shared_ptr<MediaDevice> accordingly.
> >
> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > ---
> >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
> >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
> >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
> >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
> >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
> >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
> >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
> >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
> >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
> >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
> >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
> >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
> >  src/libcamera/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               |  6 +++---
> >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
> >  test/delayed_controls.cpp                          |  2 +-
> >  test/libtest/buffer_source.cpp                     |  2 +-
> >  21 files changed, 65 insertions(+), 49 deletions(-)
> >
> > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > index 5fa8bc2f66ee..0199ab7911c0 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);
> > @@ -74,7 +74,7 @@ protected:
> >  	void clearMediaDevices();
> >
> >  	void registerCamera(std::shared_ptr<Camera> camera);
> > -	void hotplugMediaDevice(MediaDevice *media);
> > +	void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
> >
> >  	virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
> >  	virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > @@ -139,7 +139,7 @@ private:
> >
> >  	void bufferReady(FrameBuffer *buffer);
> >
> > -	MediaDevice *isiDev_;
> > +	std::shared_ptr<MediaDevice> isiDev_;
> >
> >  	std::unique_ptr<V4L2Subdevice> crossbar_;
> >  	std::vector<Pipe> pipes_;
> > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> > index aa544d7b0303..ebbd424c56ea 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;
> >
> > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> > index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
> >
> > 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > @@ -684,7 +684,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_;
> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > index 705615b86b0c..d4ec538f478b 100644
> > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > @@ -200,7 +200,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_;
> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > index eee5b09e2ff0..2e567ace0b78 100644
> > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > @@ -59,7 +59,7 @@ 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";
> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > index 2a1ef0abe6d1..154310ac37c1 100644
> > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > @@ -36,7 +36,7 @@ class RkISP1Path
> >  public:
> >  	RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
> >
> > -	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 1f13e5230fae..23ce54eca144 100644
> > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> > --- a/src/libcamera/pipeline/simple/simple.cpp
> > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > @@ -407,7 +407,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:
> > @@ -427,7 +427,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);
> > @@ -438,7 +439,7 @@ private:
> >
> >  	std::map<const MediaEntity *, EntityData> entities_;
> >
> > -	MediaDevice *converter_;
> > +	std::shared_ptr<MediaDevice> converter_;
> >  	bool swIspEnabled_;
> >  };
> >
> > @@ -1663,7 +1664,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)
> >  {
> > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
> >  	swIspEnabled_ = info.swIspEnabled;
> >
> >  	/* 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;
> > @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> > @@ -449,7 +449,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);
> > @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> > @@ -476,7 +476,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;
> >
> > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > index 8f12957b75fa..5fe2c64c8bc6 100644
> > --- a/src/libcamera/pipeline_handler.cpp
> > +++ b/src/libcamera/pipeline_handler.cpp
> > @@ -125,10 +125,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)
> > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> >
> >  	mediaDevices_.push_back(media);
> >
> > -	return media.get();
> > +	return media;
> >  }
> >
> >  /**
> > @@ -712,7 +714,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); });
> >  }
> > @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> > index 7bd30e7aead8..b305be48aafc 100644
> > --- a/test/delayed_controls.cpp
> > +++ b/test/delayed_controls.cpp
> > @@ -47,7 +47,7 @@ protected:
> >  			return TestSkip;
> >  		}
> >
> > -		dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> > +		dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
> >  		if (dev_->open()) {
> >  			cerr << "Failed to open video device" << endl;
> >  			return TestFail;
> > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> > index dde11f365e43..19b25fed50a0 100644
> > --- a/test/libtest/buffer_source.cpp
> > +++ b/test/libtest/buffer_source.cpp
> > @@ -52,7 +52,7 @@ 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_, videoDeviceName);
> >  	if (!video) {
> >  		std::cout << "Failed to get video device from entity "
> >  			  << videoDeviceName << std::endl;
Paul Elder April 22, 2025, 9:39 a.m. UTC | #3
Hi Jacopo and Laurent,

On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:
> On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:
> > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > >
> > > Adapt the PipelineHandler::acquireMediaDevice() support function to
> > > return a shared pointer instead of the underlying raw pointer.
> > 
> > It seems nice, but I wonder if it really is better ? The
> > PipelineHandler base class already stores a shared_ptr<> instance for
> > each acquired media device. Is passing it around by value and storing
> > a copy as classes member in derived classes worth it ?
> > 
> > Or is this about an ownership issue I am missing ?
> 
> I'm also wondering the same. Paul, could you explain the rationale for
> this patch series ?

I thought I did in the cover letter... oh that's really short huh...

We had a platform with a really complex media graph that could be
summarized as a simple pipeline and an rkisp1 pipeline combined via a
mux in between the sensors and the CSI receivers. The correct long-term
solution is modular pipeline handlers, but since we're not there yet we
settled with creating a simple pipeline handler inside the rkisp1
pipeline handler.

To prevent both pipeline handlers from trying to acquire the media
devices that are shared between the two paths, it was better to change
ownership of the media devices to shared so that we could register the
media devices in the second pipeline handler without having to
re-acquire and manage the lifetime.

It seemed useful to upstream at least this portion.


Paul

> > > Propagate this update to all pipeline handlers that use the MediaDevice
> > > and store a std::shared_ptr<MediaDevice> accordingly.
> > >
> > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > > ---
> > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
> > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
> > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
> > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
> > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
> > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
> > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
> > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
> > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
> > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
> > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
> > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
> > >  src/libcamera/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               |  6 +++---
> > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
> > >  test/delayed_controls.cpp                          |  2 +-
> > >  test/libtest/buffer_source.cpp                     |  2 +-
> > >  21 files changed, 65 insertions(+), 49 deletions(-)
> > >
> > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > > index 5fa8bc2f66ee..0199ab7911c0 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);
> > > @@ -74,7 +74,7 @@ protected:
> > >  	void clearMediaDevices();
> > >
> > >  	void registerCamera(std::shared_ptr<Camera> camera);
> > > -	void hotplugMediaDevice(MediaDevice *media);
> > > +	void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
> > >
> > >  	virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
> > >  	virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > @@ -139,7 +139,7 @@ private:
> > >
> > >  	void bufferReady(FrameBuffer *buffer);
> > >
> > > -	MediaDevice *isiDev_;
> > > +	std::shared_ptr<MediaDevice> isiDev_;
> > >
> > >  	std::unique_ptr<V4L2Subdevice> crossbar_;
> > >  	std::vector<Pipe> pipes_;
> > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> > > index aa544d7b0303..ebbd424c56ea 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;
> > >
> > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> > > index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
> > >
> > > 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > @@ -684,7 +684,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_;
> > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > index 705615b86b0c..d4ec538f478b 100644
> > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > @@ -200,7 +200,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_;
> > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > index eee5b09e2ff0..2e567ace0b78 100644
> > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > @@ -59,7 +59,7 @@ 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";
> > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > index 2a1ef0abe6d1..154310ac37c1 100644
> > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > @@ -36,7 +36,7 @@ class RkISP1Path
> > >  public:
> > >  	RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
> > >
> > > -	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 1f13e5230fae..23ce54eca144 100644
> > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> > > --- a/src/libcamera/pipeline/simple/simple.cpp
> > > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > > @@ -407,7 +407,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:
> > > @@ -427,7 +427,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);
> > > @@ -438,7 +439,7 @@ private:
> > >
> > >  	std::map<const MediaEntity *, EntityData> entities_;
> > >
> > > -	MediaDevice *converter_;
> > > +	std::shared_ptr<MediaDevice> converter_;
> > >  	bool swIspEnabled_;
> > >  };
> > >
> > > @@ -1663,7 +1664,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)
> > >  {
> > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
> > >  	swIspEnabled_ = info.swIspEnabled;
> > >
> > >  	/* 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;
> > > @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> > > @@ -449,7 +449,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);
> > > @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> > > @@ -476,7 +476,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;
> > >
> > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > > index 8f12957b75fa..5fe2c64c8bc6 100644
> > > --- a/src/libcamera/pipeline_handler.cpp
> > > +++ b/src/libcamera/pipeline_handler.cpp
> > > @@ -125,10 +125,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)
> > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> > >
> > >  	mediaDevices_.push_back(media);
> > >
> > > -	return media.get();
> > > +	return media;
> > >  }
> > >
> > >  /**
> > > @@ -712,7 +714,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); });
> > >  }
> > > @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> > > index 7bd30e7aead8..b305be48aafc 100644
> > > --- a/test/delayed_controls.cpp
> > > +++ b/test/delayed_controls.cpp
> > > @@ -47,7 +47,7 @@ protected:
> > >  			return TestSkip;
> > >  		}
> > >
> > > -		dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> > > +		dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
> > >  		if (dev_->open()) {
> > >  			cerr << "Failed to open video device" << endl;
> > >  			return TestFail;
> > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> > > index dde11f365e43..19b25fed50a0 100644
> > > --- a/test/libtest/buffer_source.cpp
> > > +++ b/test/libtest/buffer_source.cpp
> > > @@ -52,7 +52,7 @@ 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_, videoDeviceName);
> > >  	if (!video) {
> > >  		std::cout << "Failed to get video device from entity "
> > >  			  << videoDeviceName << std::endl;
Paul Elder May 13, 2025, 1:19 p.m. UTC | #4
Gentle ping

Quoting Paul Elder (2025-04-22 11:39:56)
> Hi Jacopo and Laurent,
> 
> On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:
> > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:
> > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > >
> > > > Adapt the PipelineHandler::acquireMediaDevice() support function to
> > > > return a shared pointer instead of the underlying raw pointer.
> > > 
> > > It seems nice, but I wonder if it really is better ? The
> > > PipelineHandler base class already stores a shared_ptr<> instance for
> > > each acquired media device. Is passing it around by value and storing
> > > a copy as classes member in derived classes worth it ?
> > > 
> > > Or is this about an ownership issue I am missing ?
> > 
> > I'm also wondering the same. Paul, could you explain the rationale for
> > this patch series ?
> 
> I thought I did in the cover letter... oh that's really short huh...
> 
> We had a platform with a really complex media graph that could be
> summarized as a simple pipeline and an rkisp1 pipeline combined via a
> mux in between the sensors and the CSI receivers. The correct long-term
> solution is modular pipeline handlers, but since we're not there yet we
> settled with creating a simple pipeline handler inside the rkisp1
> pipeline handler.
> 
> To prevent both pipeline handlers from trying to acquire the media
> devices that are shared between the two paths, it was better to change
> ownership of the media devices to shared so that we could register the
> media devices in the second pipeline handler without having to
> re-acquire and manage the lifetime.
> 
> It seemed useful to upstream at least this portion.
> 
> 
> Paul
> 
> > > > Propagate this update to all pipeline handlers that use the MediaDevice
> > > > and store a std::shared_ptr<MediaDevice> accordingly.
> > > >
> > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > ---
> > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
> > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
> > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
> > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
> > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
> > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
> > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
> > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
> > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
> > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
> > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
> > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
> > > >  src/libcamera/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               |  6 +++---
> > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
> > > >  test/delayed_controls.cpp                          |  2 +-
> > > >  test/libtest/buffer_source.cpp                     |  2 +-
> > > >  21 files changed, 65 insertions(+), 49 deletions(-)
> > > >
> > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > > > index 5fa8bc2f66ee..0199ab7911c0 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);
> > > > @@ -74,7 +74,7 @@ protected:
> > > >   void clearMediaDevices();
> > > >
> > > >   void registerCamera(std::shared_ptr<Camera> camera);
> > > > - void hotplugMediaDevice(MediaDevice *media);
> > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
> > > >
> > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
> > > >   virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > @@ -139,7 +139,7 @@ private:
> > > >
> > > >   void bufferReady(FrameBuffer *buffer);
> > > >
> > > > - MediaDevice *isiDev_;
> > > > + std::shared_ptr<MediaDevice> isiDev_;
> > > >
> > > >   std::unique_ptr<V4L2Subdevice> crossbar_;
> > > >   std::vector<Pipe> pipes_;
> > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> > > > index aa544d7b0303..ebbd424c56ea 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;
> > > >
> > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> > > > index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
> > > >
> > > > 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > @@ -684,7 +684,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_;
> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > index 705615b86b0c..d4ec538f478b 100644
> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > @@ -200,7 +200,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_;
> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > index eee5b09e2ff0..2e567ace0b78 100644
> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > @@ -59,7 +59,7 @@ 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";
> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > index 2a1ef0abe6d1..154310ac37c1 100644
> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > @@ -36,7 +36,7 @@ class RkISP1Path
> > > >  public:
> > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
> > > >
> > > > - 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 1f13e5230fae..23ce54eca144 100644
> > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> > > > --- a/src/libcamera/pipeline/simple/simple.cpp
> > > > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > > > @@ -407,7 +407,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:
> > > > @@ -427,7 +427,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);
> > > > @@ -438,7 +439,7 @@ private:
> > > >
> > > >   std::map<const MediaEntity *, EntityData> entities_;
> > > >
> > > > - MediaDevice *converter_;
> > > > + std::shared_ptr<MediaDevice> converter_;
> > > >   bool swIspEnabled_;
> > > >  };
> > > >
> > > > @@ -1663,7 +1664,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)
> > > >  {
> > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
> > > >   swIspEnabled_ = info.swIspEnabled;
> > > >
> > > >   /* 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;
> > > > @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> > > > @@ -449,7 +449,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);
> > > > @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> > > > @@ -476,7 +476,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;
> > > >
> > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > > > index 8f12957b75fa..5fe2c64c8bc6 100644
> > > > --- a/src/libcamera/pipeline_handler.cpp
> > > > +++ b/src/libcamera/pipeline_handler.cpp
> > > > @@ -125,10 +125,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)
> > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> > > >
> > > >   mediaDevices_.push_back(media);
> > > >
> > > > - return media.get();
> > > > + return media;
> > > >  }
> > > >
> > > >  /**
> > > > @@ -712,7 +714,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); });
> > > >  }
> > > > @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> > > > index 7bd30e7aead8..b305be48aafc 100644
> > > > --- a/test/delayed_controls.cpp
> > > > +++ b/test/delayed_controls.cpp
> > > > @@ -47,7 +47,7 @@ protected:
> > > >                   return TestSkip;
> > > >           }
> > > >
> > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
> > > >           if (dev_->open()) {
> > > >                   cerr << "Failed to open video device" << endl;
> > > >                   return TestFail;
> > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> > > > index dde11f365e43..19b25fed50a0 100644
> > > > --- a/test/libtest/buffer_source.cpp
> > > > +++ b/test/libtest/buffer_source.cpp
> > > > @@ -52,7 +52,7 @@ 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_, videoDeviceName);
> > > >   if (!video) {
> > > >           std::cout << "Failed to get video device from entity "
> > > >                     << videoDeviceName << std::endl;
Stefan Klug Sept. 15, 2025, 2:42 p.m. UTC | #5
Hi all,

Quoting Paul Elder (2025-05-13 15:19:39)
> Gentle ping
> 
> Quoting Paul Elder (2025-04-22 11:39:56)
> > Hi Jacopo and Laurent,
> > 
> > On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:
> > > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:
> > > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> > > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > >
> > > > > Adapt the PipelineHandler::acquireMediaDevice() support function to
> > > > > return a shared pointer instead of the underlying raw pointer.
> > > > 
> > > > It seems nice, but I wonder if it really is better ? The
> > > > PipelineHandler base class already stores a shared_ptr<> instance for
> > > > each acquired media device. Is passing it around by value and storing
> > > > a copy as classes member in derived classes worth it ?
> > > > 
> > > > Or is this about an ownership issue I am missing ?
> > > 
> > > I'm also wondering the same. Paul, could you explain the rationale for
> > > this patch series ?
> > 
> > I thought I did in the cover letter... oh that's really short huh...
> > 
> > We had a platform with a really complex media graph that could be
> > summarized as a simple pipeline and an rkisp1 pipeline combined via a
> > mux in between the sensors and the CSI receivers. The correct long-term
> > solution is modular pipeline handlers, but since we're not there yet we
> > settled with creating a simple pipeline handler inside the rkisp1
> > pipeline handler.
> > 
> > To prevent both pipeline handlers from trying to acquire the media
> > devices that are shared between the two paths, it was better to change
> > ownership of the media devices to shared so that we could register the
> > media devices in the second pipeline handler without having to
> > re-acquire and manage the lifetime.
> > 
> > It seemed useful to upstream at least this portion.

I have another use case for this change. In my work to bring the full
dewarper support upstream I needed to add V4L2 requests support to the
dewarper. These requests are allocated with a call to the medie device.
So the dewarper (which is implemented as V4L2M2MConverter) needs to hold
a pointer to the media device it was constructed for. Normally the
converter only gets a MediaDevice pointer passed to the constructor.
Holding on that plain pointer in the converter feels not good at all,
even though the lifetime of the converter will be tried to the pipeline
handler if I'm not mistaken. So overall I'd like to advocate for this
switch from raw pointers to shared pointers :-)

Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> 
Tested-by: Stefan Klug <stefan.klug@ideasonboard.com> 

Best regards,
Stefan

> > 
> > 
> > Paul
> > 
> > > > > Propagate this update to all pipeline handlers that use the MediaDevice
> > > > > and store a std::shared_ptr<MediaDevice> accordingly.
> > > > >
> > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > ---
> > > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
> > > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
> > > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
> > > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
> > > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
> > > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
> > > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
> > > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
> > > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
> > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
> > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
> > > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
> > > > >  src/libcamera/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               |  6 +++---
> > > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
> > > > >  test/delayed_controls.cpp                          |  2 +-
> > > > >  test/libtest/buffer_source.cpp                     |  2 +-
> > > > >  21 files changed, 65 insertions(+), 49 deletions(-)
> > > > >
> > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > > > > index 5fa8bc2f66ee..0199ab7911c0 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);
> > > > > @@ -74,7 +74,7 @@ protected:
> > > > >   void clearMediaDevices();
> > > > >
> > > > >   void registerCamera(std::shared_ptr<Camera> camera);
> > > > > - void hotplugMediaDevice(MediaDevice *media);
> > > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
> > > > >
> > > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
> > > > >   virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> > > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > > @@ -139,7 +139,7 @@ private:
> > > > >
> > > > >   void bufferReady(FrameBuffer *buffer);
> > > > >
> > > > > - MediaDevice *isiDev_;
> > > > > + std::shared_ptr<MediaDevice> isiDev_;
> > > > >
> > > > >   std::unique_ptr<V4L2Subdevice> crossbar_;
> > > > >   std::vector<Pipe> pipes_;
> > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> > > > > index aa544d7b0303..ebbd424c56ea 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;
> > > > >
> > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> > > > > index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
> > > > >
> > > > > 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> > > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > > @@ -684,7 +684,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_;
> > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > index 705615b86b0c..d4ec538f478b 100644
> > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > @@ -200,7 +200,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_;
> > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > index eee5b09e2ff0..2e567ace0b78 100644
> > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > @@ -59,7 +59,7 @@ 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";
> > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > index 2a1ef0abe6d1..154310ac37c1 100644
> > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > @@ -36,7 +36,7 @@ class RkISP1Path
> > > > >  public:
> > > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
> > > > >
> > > > > - 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 1f13e5230fae..23ce54eca144 100644
> > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > > @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > > @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> > > > > --- a/src/libcamera/pipeline/simple/simple.cpp
> > > > > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > > > > @@ -407,7 +407,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:
> > > > > @@ -427,7 +427,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);
> > > > > @@ -438,7 +439,7 @@ private:
> > > > >
> > > > >   std::map<const MediaEntity *, EntityData> entities_;
> > > > >
> > > > > - MediaDevice *converter_;
> > > > > + std::shared_ptr<MediaDevice> converter_;
> > > > >   bool swIspEnabled_;
> > > > >  };
> > > > >
> > > > > @@ -1663,7 +1664,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)
> > > > >  {
> > > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
> > > > >   swIspEnabled_ = info.swIspEnabled;
> > > > >
> > > > >   /* 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;
> > > > > @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> > > > > @@ -449,7 +449,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);
> > > > > @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> > > > > @@ -476,7 +476,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;
> > > > >
> > > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > > > > index 8f12957b75fa..5fe2c64c8bc6 100644
> > > > > --- a/src/libcamera/pipeline_handler.cpp
> > > > > +++ b/src/libcamera/pipeline_handler.cpp
> > > > > @@ -125,10 +125,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)
> > > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> > > > >
> > > > >   mediaDevices_.push_back(media);
> > > > >
> > > > > - return media.get();
> > > > > + return media;
> > > > >  }
> > > > >
> > > > >  /**
> > > > > @@ -712,7 +714,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); });
> > > > >  }
> > > > > @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> > > > > index 7bd30e7aead8..b305be48aafc 100644
> > > > > --- a/test/delayed_controls.cpp
> > > > > +++ b/test/delayed_controls.cpp
> > > > > @@ -47,7 +47,7 @@ protected:
> > > > >                   return TestSkip;
> > > > >           }
> > > > >
> > > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> > > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
> > > > >           if (dev_->open()) {
> > > > >                   cerr << "Failed to open video device" << endl;
> > > > >                   return TestFail;
> > > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> > > > > index dde11f365e43..19b25fed50a0 100644
> > > > > --- a/test/libtest/buffer_source.cpp
> > > > > +++ b/test/libtest/buffer_source.cpp
> > > > > @@ -52,7 +52,7 @@ 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_, videoDeviceName);
> > > > >   if (!video) {
> > > > >           std::cout << "Failed to get video device from entity "
> > > > >                     << videoDeviceName << std::endl;
Laurent Pinchart Sept. 15, 2025, 2:54 p.m. UTC | #6
On Mon, Sep 15, 2025 at 04:42:52PM +0200, Stefan Klug wrote:
> Quoting Paul Elder (2025-05-13 15:19:39)
> > Quoting Paul Elder (2025-04-22 11:39:56)
> > > On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:
> > > > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:
> > > > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> > > > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > >
> > > > > > Adapt the PipelineHandler::acquireMediaDevice() support function to
> > > > > > return a shared pointer instead of the underlying raw pointer.
> > > > > 
> > > > > It seems nice, but I wonder if it really is better ? The
> > > > > PipelineHandler base class already stores a shared_ptr<> instance for
> > > > > each acquired media device. Is passing it around by value and storing
> > > > > a copy as classes member in derived classes worth it ?
> > > > > 
> > > > > Or is this about an ownership issue I am missing ?
> > > > 
> > > > I'm also wondering the same. Paul, could you explain the rationale for
> > > > this patch series ?
> > > 
> > > I thought I did in the cover letter... oh that's really short huh...
> > > 
> > > We had a platform with a really complex media graph that could be
> > > summarized as a simple pipeline and an rkisp1 pipeline combined via a
> > > mux in between the sensors and the CSI receivers. The correct long-term
> > > solution is modular pipeline handlers, but since we're not there yet we
> > > settled with creating a simple pipeline handler inside the rkisp1
> > > pipeline handler.
> > > 
> > > To prevent both pipeline handlers from trying to acquire the media
> > > devices that are shared between the two paths, it was better to change
> > > ownership of the media devices to shared so that we could register the
> > > media devices in the second pipeline handler without having to
> > > re-acquire and manage the lifetime.
> > > 
> > > It seemed useful to upstream at least this portion.
> 
> I have another use case for this change. In my work to bring the full
> dewarper support upstream I needed to add V4L2 requests support to the
> dewarper. These requests are allocated with a call to the medie device.
> So the dewarper (which is implemented as V4L2M2MConverter) needs to hold
> a pointer to the media device it was constructed for. Normally the
> converter only gets a MediaDevice pointer passed to the constructor.
> Holding on that plain pointer in the converter feels not good at all,
> even though the lifetime of the converter will be tried to the pipeline
> handler if I'm not mistaken.

I don't want to use shared pointers as a magic solution without a proper
analysis, given how intrusive they are. For your particular use case,
how do you plan for the converter to reach to the media device removal ?

> So overall I'd like to advocate for this
> switch from raw pointers to shared pointers :-)
> 
> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> 
> Tested-by: Stefan Klug <stefan.klug@ideasonboard.com> 
> 
> > > > > > Propagate this update to all pipeline handlers that use the MediaDevice
> > > > > > and store a std::shared_ptr<MediaDevice> accordingly.
> > > > > >
> > > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > > ---
> > > > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
> > > > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
> > > > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
> > > > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
> > > > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
> > > > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
> > > > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
> > > > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
> > > > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
> > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
> > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
> > > > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
> > > > > >  src/libcamera/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               |  6 +++---
> > > > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
> > > > > >  test/delayed_controls.cpp                          |  2 +-
> > > > > >  test/libtest/buffer_source.cpp                     |  2 +-
> > > > > >  21 files changed, 65 insertions(+), 49 deletions(-)
> > > > > >
> > > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > > > > > index 5fa8bc2f66ee..0199ab7911c0 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);
> > > > > > @@ -74,7 +74,7 @@ protected:
> > > > > >   void clearMediaDevices();
> > > > > >
> > > > > >   void registerCamera(std::shared_ptr<Camera> camera);
> > > > > > - void hotplugMediaDevice(MediaDevice *media);
> > > > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
> > > > > >
> > > > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
> > > > > >   virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> > > > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > > > @@ -139,7 +139,7 @@ private:
> > > > > >
> > > > > >   void bufferReady(FrameBuffer *buffer);
> > > > > >
> > > > > > - MediaDevice *isiDev_;
> > > > > > + std::shared_ptr<MediaDevice> isiDev_;
> > > > > >
> > > > > >   std::unique_ptr<V4L2Subdevice> crossbar_;
> > > > > >   std::vector<Pipe> pipes_;
> > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> > > > > > index aa544d7b0303..ebbd424c56ea 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;
> > > > > >
> > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> > > > > > index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
> > > > > >
> > > > > > 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> > > > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > > > @@ -684,7 +684,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_;
> > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > > index 705615b86b0c..d4ec538f478b 100644
> > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > > @@ -200,7 +200,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_;
> > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > > index eee5b09e2ff0..2e567ace0b78 100644
> > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > > @@ -59,7 +59,7 @@ 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";
> > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > > index 2a1ef0abe6d1..154310ac37c1 100644
> > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > > @@ -36,7 +36,7 @@ class RkISP1Path
> > > > > >  public:
> > > > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
> > > > > >
> > > > > > - 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 1f13e5230fae..23ce54eca144 100644
> > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > > > @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > > > @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> > > > > > --- a/src/libcamera/pipeline/simple/simple.cpp
> > > > > > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > > > > > @@ -407,7 +407,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:
> > > > > > @@ -427,7 +427,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);
> > > > > > @@ -438,7 +439,7 @@ private:
> > > > > >
> > > > > >   std::map<const MediaEntity *, EntityData> entities_;
> > > > > >
> > > > > > - MediaDevice *converter_;
> > > > > > + std::shared_ptr<MediaDevice> converter_;
> > > > > >   bool swIspEnabled_;
> > > > > >  };
> > > > > >
> > > > > > @@ -1663,7 +1664,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)
> > > > > >  {
> > > > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
> > > > > >   swIspEnabled_ = info.swIspEnabled;
> > > > > >
> > > > > >   /* 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;
> > > > > > @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> > > > > > @@ -449,7 +449,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);
> > > > > > @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> > > > > > @@ -476,7 +476,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;
> > > > > >
> > > > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > > > > > index 8f12957b75fa..5fe2c64c8bc6 100644
> > > > > > --- a/src/libcamera/pipeline_handler.cpp
> > > > > > +++ b/src/libcamera/pipeline_handler.cpp
> > > > > > @@ -125,10 +125,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)
> > > > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> > > > > >
> > > > > >   mediaDevices_.push_back(media);
> > > > > >
> > > > > > - return media.get();
> > > > > > + return media;
> > > > > >  }
> > > > > >
> > > > > >  /**
> > > > > > @@ -712,7 +714,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); });
> > > > > >  }
> > > > > > @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> > > > > > index 7bd30e7aead8..b305be48aafc 100644
> > > > > > --- a/test/delayed_controls.cpp
> > > > > > +++ b/test/delayed_controls.cpp
> > > > > > @@ -47,7 +47,7 @@ protected:
> > > > > >                   return TestSkip;
> > > > > >           }
> > > > > >
> > > > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> > > > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
> > > > > >           if (dev_->open()) {
> > > > > >                   cerr << "Failed to open video device" << endl;
> > > > > >                   return TestFail;
> > > > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> > > > > > index dde11f365e43..19b25fed50a0 100644
> > > > > > --- a/test/libtest/buffer_source.cpp
> > > > > > +++ b/test/libtest/buffer_source.cpp
> > > > > > @@ -52,7 +52,7 @@ 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_, videoDeviceName);
> > > > > >   if (!video) {
> > > > > >           std::cout << "Failed to get video device from entity "
> > > > > >                     << videoDeviceName << std::endl;
Stefan Klug Sept. 15, 2025, 3:26 p.m. UTC | #7
Quoting Laurent Pinchart (2025-09-15 16:54:39)
> On Mon, Sep 15, 2025 at 04:42:52PM +0200, Stefan Klug wrote:
> > Quoting Paul Elder (2025-05-13 15:19:39)
> > > Quoting Paul Elder (2025-04-22 11:39:56)
> > > > On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:
> > > > > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:
> > > > > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:
> > > > > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > > >
> > > > > > > Adapt the PipelineHandler::acquireMediaDevice() support function to
> > > > > > > return a shared pointer instead of the underlying raw pointer.
> > > > > > 
> > > > > > It seems nice, but I wonder if it really is better ? The
> > > > > > PipelineHandler base class already stores a shared_ptr<> instance for
> > > > > > each acquired media device. Is passing it around by value and storing
> > > > > > a copy as classes member in derived classes worth it ?
> > > > > > 
> > > > > > Or is this about an ownership issue I am missing ?
> > > > > 
> > > > > I'm also wondering the same. Paul, could you explain the rationale for
> > > > > this patch series ?
> > > > 
> > > > I thought I did in the cover letter... oh that's really short huh...
> > > > 
> > > > We had a platform with a really complex media graph that could be
> > > > summarized as a simple pipeline and an rkisp1 pipeline combined via a
> > > > mux in between the sensors and the CSI receivers. The correct long-term
> > > > solution is modular pipeline handlers, but since we're not there yet we
> > > > settled with creating a simple pipeline handler inside the rkisp1
> > > > pipeline handler.
> > > > 
> > > > To prevent both pipeline handlers from trying to acquire the media
> > > > devices that are shared between the two paths, it was better to change
> > > > ownership of the media devices to shared so that we could register the
> > > > media devices in the second pipeline handler without having to
> > > > re-acquire and manage the lifetime.
> > > > 
> > > > It seemed useful to upstream at least this portion.
> > 
> > I have another use case for this change. In my work to bring the full
> > dewarper support upstream I needed to add V4L2 requests support to the
> > dewarper. These requests are allocated with a call to the medie device.
> > So the dewarper (which is implemented as V4L2M2MConverter) needs to hold
> > a pointer to the media device it was constructed for. Normally the
> > converter only gets a MediaDevice pointer passed to the constructor.
> > Holding on that plain pointer in the converter feels not good at all,
> > even though the lifetime of the converter will be tried to the pipeline
> > handler if I'm not mistaken.
> 
> I don't want to use shared pointers as a magic solution without a proper
> analysis, given how intrusive they are. For your particular use case,
> how do you plan for the converter to reach to the media device removal ?

I guess it is not sufficient to say "I did not plan for media device
removal"... :-) So let me quickly whip up my idea of how I would
envision media device removal. I'd expect that converters aka "clients"
would be able to listen on a removal signal and should let go of the
shared pointer, or the pipeline handler needs to delete them. We could
even go the extra step and advocate that no entity must hold a pointer
to a media object after that signal was sent. Then we could check the
use_count on our shared pointer to see if there are still entities
incorrectly holding on to it (The aquire/release pair is something I'm
more concerned about and don't yet know if we will need some kind of
refcounting there, too).

Overall I don't think that passing raw pointers around helps in keeping
the architecture sane. It only creates a unmanaged C-ish world that
feels more like kernel code. I think raw pointers should only be used if
the related shared_prt is close by (like the FrameBuffer pointers in the
pipeline handlers). So if we create reusable components then they
shouldn't store raw pointers to anything they didn't allocate.

Best regards,
Stefan

> 
> > So overall I'd like to advocate for this
> > switch from raw pointers to shared pointers :-)
> > 
> > Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> 
> > Tested-by: Stefan Klug <stefan.klug@ideasonboard.com> 
> > 
> > > > > > > Propagate this update to all pipeline handlers that use the MediaDevice
> > > > > > > and store a std::shared_ptr<MediaDevice> accordingly.
> > > > > > >
> > > > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > > > ---
> > > > > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----
> > > > > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-
> > > > > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-
> > > > > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-
> > > > > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-
> > > > > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--
> > > > > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--
> > > > > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-
> > > > > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-
> > > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-
> > > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-
> > > > > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--
> > > > > > >  src/libcamera/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               |  6 +++---
> > > > > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------
> > > > > > >  test/delayed_controls.cpp                          |  2 +-
> > > > > > >  test/libtest/buffer_source.cpp                     |  2 +-
> > > > > > >  21 files changed, 65 insertions(+), 49 deletions(-)
> > > > > > >
> > > > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> > > > > > > index 5fa8bc2f66ee..0199ab7911c0 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);
> > > > > > > @@ -74,7 +74,7 @@ protected:
> > > > > > >   void clearMediaDevices();
> > > > > > >
> > > > > > >   void registerCamera(std::shared_ptr<Camera> camera);
> > > > > > > - void hotplugMediaDevice(MediaDevice *media);
> > > > > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
> > > > > > >
> > > > > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
> > > > > > >   virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
> > > > > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
> > > > > > > @@ -139,7 +139,7 @@ private:
> > > > > > >
> > > > > > >   void bufferReady(FrameBuffer *buffer);
> > > > > > >
> > > > > > > - MediaDevice *isiDev_;
> > > > > > > + std::shared_ptr<MediaDevice> isiDev_;
> > > > > > >
> > > > > > >   std::unique_ptr<V4L2Subdevice> crossbar_;
> > > > > > >   std::vector<Pipe> pipes_;
> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
> > > > > > > index aa544d7b0303..ebbd424c56ea 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;
> > > > > > >
> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
> > > > > > > index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
> > > > > > >
> > > > > > > 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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
> > > > > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> > > > > > > @@ -684,7 +684,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_;
> > > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > > > index 705615b86b0c..d4ec538f478b 100644
> > > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > > > > @@ -200,7 +200,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_;
> > > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > > > index eee5b09e2ff0..2e567ace0b78 100644
> > > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
> > > > > > > @@ -59,7 +59,7 @@ 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";
> > > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > > > index 2a1ef0abe6d1..154310ac37c1 100644
> > > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
> > > > > > > @@ -36,7 +36,7 @@ class RkISP1Path
> > > > > > >  public:
> > > > > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
> > > > > > >
> > > > > > > - 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 1f13e5230fae..23ce54eca144 100644
> > > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
> > > > > > > @@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
> > > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
> > > > > > > @@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
> > > > > > > --- a/src/libcamera/pipeline/simple/simple.cpp
> > > > > > > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > > > > > > @@ -407,7 +407,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:
> > > > > > > @@ -427,7 +427,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);
> > > > > > > @@ -438,7 +439,7 @@ private:
> > > > > > >
> > > > > > >   std::map<const MediaEntity *, EntityData> entities_;
> > > > > > >
> > > > > > > - MediaDevice *converter_;
> > > > > > > + std::shared_ptr<MediaDevice> converter_;
> > > > > > >   bool swIspEnabled_;
> > > > > > >  };
> > > > > > >
> > > > > > > @@ -1663,7 +1664,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)
> > > > > > >  {
> > > > > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,
> > > > > > >   swIspEnabled_ = info.swIspEnabled;
> > > > > > >
> > > > > > >   /* 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;
> > > > > > > @@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
> > > > > > > @@ -449,7 +449,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);
> > > > > > > @@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
> > > > > > > @@ -476,7 +476,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;
> > > > > > >
> > > > > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > > > > > > index 8f12957b75fa..5fe2c64c8bc6 100644
> > > > > > > --- a/src/libcamera/pipeline_handler.cpp
> > > > > > > +++ b/src/libcamera/pipeline_handler.cpp
> > > > > > > @@ -125,10 +125,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)
> > > > > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
> > > > > > >
> > > > > > >   mediaDevices_.push_back(media);
> > > > > > >
> > > > > > > - return media.get();
> > > > > > > + return media;
> > > > > > >  }
> > > > > > >
> > > > > > >  /**
> > > > > > > @@ -712,7 +714,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); });
> > > > > > >  }
> > > > > > > @@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
> > > > > > > index 7bd30e7aead8..b305be48aafc 100644
> > > > > > > --- a/test/delayed_controls.cpp
> > > > > > > +++ b/test/delayed_controls.cpp
> > > > > > > @@ -47,7 +47,7 @@ protected:
> > > > > > >                   return TestSkip;
> > > > > > >           }
> > > > > > >
> > > > > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
> > > > > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
> > > > > > >           if (dev_->open()) {
> > > > > > >                   cerr << "Failed to open video device" << endl;
> > > > > > >                   return TestFail;
> > > > > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
> > > > > > > index dde11f365e43..19b25fed50a0 100644
> > > > > > > --- a/test/libtest/buffer_source.cpp
> > > > > > > +++ b/test/libtest/buffer_source.cpp
> > > > > > > @@ -52,7 +52,7 @@ 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_, videoDeviceName);
> > > > > > >   if (!video) {
> > > > > > >           std::cout << "Failed to get video device from entity "
> > > > > > >                     << videoDeviceName << std::endl;
> 
> -- 
> Regards,
> 
> Laurent Pinchart

Patch
diff mbox series

diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index 5fa8bc2f66ee..0199ab7911c0 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);
@@ -74,7 +74,7 @@  protected:
 	void clearMediaDevices();
 
 	void registerCamera(std::shared_ptr<Camera> camera);
-	void hotplugMediaDevice(MediaDevice *media);
+	void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);
 
 	virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
 	virtual void stopDevice(Camera *camera) = 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 4e66b3368d5a..850dbfcdc64b 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -139,7 +139,7 @@  private:
 
 	void bufferReady(FrameBuffer *buffer);
 
-	MediaDevice *isiDev_;
+	std::shared_ptr<MediaDevice> isiDev_;
 
 	std::unique_ptr<V4L2Subdevice> crossbar_;
 	std::vector<Pipe> pipes_;
diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
index aa544d7b0303..ebbd424c56ea 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;
 
diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h
index 963c2f6b93a4..fdf85f2655f0 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..391e000f6e12 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;
 
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 e31e3879dcc9..17205f96446a 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 a05e11fccf8d..7615122d907b 100644
--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
@@ -684,7 +684,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_;
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 705615b86b0c..d4ec538f478b 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -200,7 +200,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_;
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
index eee5b09e2ff0..2e567ace0b78 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp
@@ -59,7 +59,7 @@  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";
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
index 2a1ef0abe6d1..154310ac37c1 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h
+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h
@@ -36,7 +36,7 @@  class RkISP1Path
 public:
 	RkISP1Path(const char *name, const Span<const PixelFormat> &formats);
 
-	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 1f13e5230fae..23ce54eca144 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -784,8 +784,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 aae0c2f35888..e422bbf7405f 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
@@ -229,13 +229,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 91e7f4c94d96..d0cb71b49e11 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 fe910bdf2ff9..d58035ecd198 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 451491f5608e..feaa16094b65 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -407,7 +407,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:
@@ -427,7 +427,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);
@@ -438,7 +439,7 @@  private:
 
 	std::map<const MediaEntity *, EntityData> entities_;
 
-	MediaDevice *converter_;
+	std::shared_ptr<MediaDevice> converter_;
 	bool swIspEnabled_;
 };
 
@@ -1663,7 +1664,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)
 {
@@ -1681,7 +1682,7 @@  bool SimplePipelineHandler::matchDevice(MediaDevice *media,
 	swIspEnabled_ = info.swIspEnabled;
 
 	/* 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;
@@ -1799,7 +1800,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 5adc89fdb29c..a1e036a32d5f 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);
@@ -449,7 +449,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);
@@ -491,7 +491,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 07273bd2b6c3..59c564b8a9f6 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_;
@@ -476,7 +476,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;
 
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 8f12957b75fa..5fe2c64c8bc6 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -125,10 +125,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)
@@ -139,7 +141,7 @@  MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
 
 	mediaDevices_.push_back(media);
 
-	return media.get();
+	return media;
 }
 
 /**
@@ -712,7 +714,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); });
 }
@@ -720,7 +722,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/delayed_controls.cpp b/test/delayed_controls.cpp
index 7bd30e7aead8..b305be48aafc 100644
--- a/test/delayed_controls.cpp
+++ b/test/delayed_controls.cpp
@@ -47,7 +47,7 @@  protected:
 			return TestSkip;
 		}
 
-		dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
+		dev_ = V4L2VideoDevice::fromEntityName(media_, "vivid-000-vid-cap");
 		if (dev_->open()) {
 			cerr << "Failed to open video device" << endl;
 			return TestFail;
diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
index dde11f365e43..19b25fed50a0 100644
--- a/test/libtest/buffer_source.cpp
+++ b/test/libtest/buffer_source.cpp
@@ -52,7 +52,7 @@  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_, videoDeviceName);
 	if (!video) {
 		std::cout << "Failed to get video device from entity "
 			  << videoDeviceName << std::endl;