[{"id":33922,"web_url":"https://patchwork.libcamera.org/comment/33922/","msgid":"<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>","date":"2025-04-06T16:53:34","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Paul\n\nOn Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>\n> Adapt the PipelineHandler::acquireMediaDevice() support function to\n> return a shared pointer instead of the underlying raw pointer.\n\nIt seems nice, but I wonder if it really is better ? The\nPipelineHandler base class already stores a shared_ptr<> instance for\neach acquired media device. Is passing it around by value and storing\na copy as classes member in derived classes worth it ?\n\nOr is this about an ownership issue I am missing ?\n\n>\n> Propagate this update to all pipeline handlers that use the MediaDevice\n> and store a std::shared_ptr<MediaDevice> accordingly.\n>\n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> ---\n>  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n>  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n>  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n>  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n>  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n>  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n>  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n>  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n>  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n>  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n>  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n>  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n>  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n>  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n>  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n>  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n>  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n>  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n>  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n>  test/delayed_controls.cpp                          |  2 +-\n>  test/libtest/buffer_source.cpp                     |  2 +-\n>  21 files changed, 65 insertions(+), 49 deletions(-)\n>\n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index 5fa8bc2f66ee..0199ab7911c0 100644\n> --- a/include/libcamera/internal/pipeline_handler.h\n> +++ b/include/libcamera/internal/pipeline_handler.h\n> @@ -38,8 +38,8 @@ public:\n>  \tvirtual ~PipelineHandler();\n>\n>  \tvirtual bool match(DeviceEnumerator *enumerator) = 0;\n> -\tMediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> -\t\t\t\t\tconst DeviceMatch &dm);\n> +\tstd::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> +\t\t\t\t\t\t\tconst DeviceMatch &dm);\n>\n>  \tbool acquire(Camera *camera);\n>  \tvoid release(Camera *camera);\n> @@ -74,7 +74,7 @@ protected:\n>  \tvoid clearMediaDevices();\n>\n>  \tvoid registerCamera(std::shared_ptr<Camera> camera);\n> -\tvoid hotplugMediaDevice(MediaDevice *media);\n> +\tvoid hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n>\n>  \tvirtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n>  \tvirtual void stopDevice(Camera *camera) = 0;\n> @@ -87,7 +87,7 @@ protected:\n>  private:\n>  \tvoid unlockMediaDevices();\n>\n> -\tvoid mediaDeviceDisconnected(MediaDevice *media);\n> +\tvoid mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n>  \tvirtual void disconnect();\n>\n>  \tvoid doQueueRequest(Request *request);\n> diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> index 4e66b3368d5a..850dbfcdc64b 100644\n> --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> @@ -139,7 +139,7 @@ private:\n>\n>  \tvoid bufferReady(FrameBuffer *buffer);\n>\n> -\tMediaDevice *isiDev_;\n> +\tstd::shared_ptr<MediaDevice> isiDev_;\n>\n>  \tstd::unique_ptr<V4L2Subdevice> crossbar_;\n>  \tstd::vector<Pipe> pipes_;\n> diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> index aa544d7b0303..ebbd424c56ea 100644\n> --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n>   * \\return 0 on success or a negative error code otherwise\n>   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n>   */\n> -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n>  {\n>  \tint ret;\n>\n> diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> index 963c2f6b93a4..fdf85f2655f0 100644\n> --- a/src/libcamera/pipeline/ipu3/cio2.h\n> +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> @@ -38,7 +38,7 @@ public:\n>  \tstd::vector<PixelFormat> formats() const;\n>  \tstd::vector<SizeRange> sizes(const PixelFormat &format) const;\n>\n> -\tint init(const MediaDevice *media, unsigned int index);\n> +\tint init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n>  \tint configure(const Size &size, const Transform &transform,\n>  \t\t      V4L2DeviceFormat *outputFormat);\n>\n> diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> index 7be780913fae..391e000f6e12 100644\n> --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n>   *\n>   * \\return 0 on success or a negative error code otherwise\n>   */\n> -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> +\t\t     unsigned int index)\n>  {\n>  \tint ret;\n>\n> diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> index fa508316b301..272f861f98c4 100644\n> --- a/src/libcamera/pipeline/ipu3/imgu.h\n> +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> @@ -64,7 +64,7 @@ public:\n>  \t\tSize viewfinder;\n>  \t};\n>\n> -\tint init(MediaDevice *media, unsigned int index);\n> +\tint init(std::shared_ptr<MediaDevice> media, unsigned int index);\n>\n>  \tPipeConfig calculatePipeConfig(Pipe *pipe);\n>\n> @@ -118,7 +118,7 @@ private:\n>  \t\t\t\t V4L2DeviceFormat *outputFormat);\n>\n>  \tstd::string name_;\n> -\tMediaDevice *media_;\n> +\tstd::shared_ptr<MediaDevice> media_;\n>  };\n>\n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index e31e3879dcc9..17205f96446a 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -164,8 +164,8 @@ private:\n>\n>  \tImgUDevice imgu0_;\n>  \tImgUDevice imgu1_;\n> -\tMediaDevice *cio2MediaDev_;\n> -\tMediaDevice *imguMediaDev_;\n> +\tstd::shared_ptr<MediaDevice> cio2MediaDev_;\n> +\tstd::shared_ptr<MediaDevice> imguMediaDev_;\n>\n>  \tstd::vector<IPABuffer> ipaBuffers_;\n>  };\n> diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> index a05e11fccf8d..7615122d907b 100644\n> --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> @@ -684,7 +684,7 @@ private:\n>  \tbool registerTPGCamera(MediaLink *link);\n>  \tbool registerSensorCamera(MediaLink *link);\n>\n> -\tMediaDevice *media_;\n> +\tstd::shared_ptr<MediaDevice> media_;\n>  \tstd::unique_ptr<V4L2Subdevice> isp_;\n>  \tstd::unique_ptr<V4L2VideoDevice> stats_;\n>  \tstd::unique_ptr<V4L2VideoDevice> params_;\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index 705615b86b0c..d4ec538f478b 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -200,7 +200,7 @@ private:\n>\n>  \tint updateControls(RkISP1CameraData *data);\n>\n> -\tMediaDevice *media_;\n> +\tstd::shared_ptr<MediaDevice> media_;\n>  \tstd::unique_ptr<V4L2Subdevice> isp_;\n>  \tstd::unique_ptr<V4L2VideoDevice> param_;\n>  \tstd::unique_ptr<V4L2VideoDevice> stat_;\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> index eee5b09e2ff0..2e567ace0b78 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n>  {\n>  }\n>\n> -bool RkISP1Path::init(MediaDevice *media)\n> +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n>  {\n>  \tstd::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n>  \tstd::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> index 2a1ef0abe6d1..154310ac37c1 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> @@ -36,7 +36,7 @@ class RkISP1Path\n>  public:\n>  \tRkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n>\n> -\tbool init(MediaDevice *media);\n> +\tbool init(std::shared_ptr<MediaDevice> media);\n>\n>  \tint setEnabled(bool enable) { return link_->setEnabled(enable); }\n>  \tbool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> index 1f13e5230fae..23ce54eca144 100644\n> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n>  }\n>\n>  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> -\t\t\t\t\tMediaDevice *frontend, const std::string &frontendName,\n> -\t\t\t\t\tMediaDevice *backend, MediaEntity *sensorEntity)\n> +\t\t\t\t\tstd::shared_ptr<MediaDevice> frontend,\n> +\t\t\t\t\tconst std::string &frontendName,\n> +\t\t\t\t\tstd::shared_ptr<MediaDevice> backend,\n> +\t\t\t\t\tMediaEntity *sensorEntity)\n>  {\n>  \tCameraData *data = cameraData.get();\n>  \tint ret;\n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> index aae0c2f35888..e422bbf7405f 100644\n> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> @@ -229,13 +229,16 @@ public:\n>\n>  protected:\n>  \tint registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> -\t\t\t   MediaDevice *frontent, const std::string &frontendName,\n> -\t\t\t   MediaDevice *backend, MediaEntity *sensorEntity);\n> +\t\t\t   std::shared_ptr<MediaDevice> frontend,\n> +\t\t\t   const std::string &frontendName,\n> +\t\t\t   std::shared_ptr<MediaDevice> backend,\n> +\t\t\t   MediaEntity *sensorEntity);\n>\n>  \tvoid mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n>\n>  \tvirtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> -\t\t\t\t     MediaDevice *unicam, MediaDevice *isp) = 0;\n> +\t\t\t\t     std::shared_ptr<MediaDevice> unicam,\n> +\t\t\t\t     std::shared_ptr<MediaDevice> isp) = 0;\n>\n>  private:\n>  \tCameraData *cameraData(Camera *camera)\n> diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> index 91e7f4c94d96..d0cb71b49e11 100644\n> --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> @@ -866,7 +866,8 @@ private:\n>\n>  \tint prepareBuffers(Camera *camera) override;\n>  \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> -\t\t\t     MediaDevice *cfe, MediaDevice *isp) override;\n> +\t\t\t     std::shared_ptr<MediaDevice> cfe,\n> +\t\t\t     std::shared_ptr<MediaDevice> isp) override;\n>  };\n>\n>  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n>  \t\tcfe.add(\"rp1-cfe-fe-image0\");\n>  \t\tcfe.add(\"rp1-cfe-fe-stats\");\n>  \t\tcfe.add(\"rp1-cfe-fe-config\");\n> -\t\tMediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> +\t\tstd::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n>\n>  \t\tif (!cfeDevice) {\n>  \t\t\tLOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n>  \t\tisp.add(\"pispbe-tdn_input\");\n>  \t\tisp.add(\"pispbe-stitch_output\");\n>  \t\tisp.add(\"pispbe-stitch_input\");\n> -\t\tMediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> +\t\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n>\n>  \t\tif (!ispDevice) {\n>  \t\t\tLOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n>  }\n>\n>  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> -\t\t\t\t\t  MediaDevice *cfe, MediaDevice *isp)\n> +\t\t\t\t\t  std::shared_ptr<MediaDevice> cfe,\n> +\t\t\t\t\t  std::shared_ptr<MediaDevice> isp)\n>  {\n>  \tPiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n>  \tint ret;\n> diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> index fe910bdf2ff9..d58035ecd198 100644\n> --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> @@ -5,6 +5,8 @@\n>   * Pipeline handler for VC4-based Raspberry Pi devices\n>   */\n>\n> +#include <memory>\n> +\n>  #include <linux/bcm2835-isp.h>\n>  #include <linux/v4l2-controls.h>\n>  #include <linux/videodev2.h>\n> @@ -158,7 +160,8 @@ private:\n>\n>  \tint prepareBuffers(Camera *camera) override;\n>  \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> -\t\t\t     MediaDevice *unicam, MediaDevice *isp) override;\n> +\t\t\t     std::shared_ptr<MediaDevice> unicam,\n> +\t\t\t     std::shared_ptr<MediaDevice> isp) override;\n>  };\n>\n>  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n>  \t */\n>  \tfor (unsigned int i = 0; i < numUnicamDevices; i++) {\n>  \t\tDeviceMatch unicam(\"unicam\");\n> -\t\tMediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> +\t\tstd::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n>\n>  \t\tif (!unicamDevice) {\n>  \t\t\tLOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n>  \t\t}\n>\n>  \t\tDeviceMatch isp(\"bcm2835-isp\");\n> -\t\tMediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> +\t\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n>\n>  \t\tif (!ispDevice) {\n>  \t\t\tLOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n>  \treturn 0;\n>  }\n>\n> -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> +\t\t\t\t\t std::shared_ptr<MediaDevice> unicam,\n> +\t\t\t\t\t std::shared_ptr<MediaDevice> isp)\n>  {\n>  \tVc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n>\n> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> index 451491f5608e..feaa16094b65 100644\n> --- a/src/libcamera/pipeline/simple/simple.cpp\n> +++ b/src/libcamera/pipeline/simple/simple.cpp\n> @@ -407,7 +407,7 @@ public:\n>\n>  \tV4L2VideoDevice *video(const MediaEntity *entity);\n>  \tV4L2Subdevice *subdev(const MediaEntity *entity);\n> -\tMediaDevice *converter() { return converter_; }\n> +\tMediaDevice *converter() { return converter_.get(); }\n>  \tbool swIspEnabled() const { return swIspEnabled_; }\n>\n>  protected:\n> @@ -427,7 +427,8 @@ private:\n>  \t\treturn static_cast<SimpleCameraData *>(camera->_d());\n>  \t}\n>\n> -\tbool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> +\tbool matchDevice(std::shared_ptr<MediaDevice> media,\n> +\t\t\t const SimplePipelineInfo &info,\n>  \t\t\t DeviceEnumerator *enumerator);\n>\n>  \tstd::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> @@ -438,7 +439,7 @@ private:\n>\n>  \tstd::map<const MediaEntity *, EntityData> entities_;\n>\n> -\tMediaDevice *converter_;\n> +\tstd::shared_ptr<MediaDevice> converter_;\n>  \tbool swIspEnabled_;\n>  };\n>\n> @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n>  \treturn 0;\n>  }\n>\n> -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n>  \t\t\t\t\tconst SimplePipelineInfo &info,\n>  \t\t\t\t\tDeviceEnumerator *enumerator)\n>  {\n> @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n>  \tswIspEnabled_ = info.swIspEnabled;\n>\n>  \t/* Locate the sensors. */\n> -\tstd::vector<MediaEntity *> sensors = locateSensors(media);\n> +\tstd::vector<MediaEntity *> sensors = locateSensors(media.get());\n>  \tif (sensors.empty()) {\n>  \t\tLOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n>  \t\treturn false;\n> @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n>\n>  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n>  {\n> -\tMediaDevice *media;\n> +\tstd::shared_ptr<MediaDevice> media;\n>\n>  \tfor (const SimplePipelineInfo &inf : supportedDevices) {\n>  \t\tDeviceMatch dm(inf.driver);\n> diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> index 5adc89fdb29c..a1e036a32d5f 100644\n> --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> @@ -46,7 +46,7 @@ public:\n>  \t{\n>  \t}\n>\n> -\tint init(MediaDevice *media);\n> +\tint init(std::shared_ptr<MediaDevice> media);\n>  \tvoid addControl(uint32_t cid, const ControlInfo &v4l2info,\n>  \t\t\tControlInfoMap::Map *ctrls);\n>  \tvoid imageBufferReady(FrameBuffer *buffer);\n> @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n>\n>  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n>  {\n> -\tMediaDevice *media;\n> +\tstd::shared_ptr<MediaDevice> media;\n>  \tDeviceMatch dm(\"uvcvideo\");\n>\n>  \tmedia = acquireMediaDevice(enumerator, dm);\n> @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n>  \tdata->video_->close();\n>  }\n>\n> -int UVCCameraData::init(MediaDevice *media)\n> +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n>  {\n>  \tint ret;\n>\n> diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> index 07273bd2b6c3..59c564b8a9f6 100644\n> --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n>  class VimcCameraData : public Camera::Private\n>  {\n>  public:\n> -\tVimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> +\tVimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n>  \t\t: Camera::Private(pipe), media_(media)\n>  \t{\n>  \t}\n> @@ -59,7 +59,7 @@ public:\n>  \tvoid imageBufferReady(FrameBuffer *buffer);\n>  \tvoid paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n>\n> -\tMediaDevice *media_;\n> +\tstd::shared_ptr<MediaDevice> media_;\n>  \tstd::unique_ptr<CameraSensor> sensor_;\n>  \tstd::unique_ptr<V4L2Subdevice> debayer_;\n>  \tstd::unique_ptr<V4L2Subdevice> scaler_;\n> @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n>  \tdm.add(\"RGB/YUV Input\");\n>  \tdm.add(\"Scaler\");\n>\n> -\tMediaDevice *media = acquireMediaDevice(enumerator, dm);\n> +\tstd::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n>  \tif (!media)\n>  \t\treturn false;\n>\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index 8f12957b75fa..5fe2c64c8bc6 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n>   *\n>   * \\context This function shall be called from the CameraManager thread.\n>   *\n> - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> + * is found\n>   */\n> -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> -\t\t\t\t\t\t const DeviceMatch &dm)\n> +std::shared_ptr<MediaDevice>\n> +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> +\t\t\t\t    const DeviceMatch &dm)\n>  {\n>  \tstd::shared_ptr<MediaDevice> media = enumerator->search(dm);\n>  \tif (!media)\n> @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n>\n>  \tmediaDevices_.push_back(media);\n>\n> -\treturn media.get();\n> +\treturn media;\n>  }\n>\n>  /**\n> @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n>   * handler gets notified and automatically disconnects all the cameras it has\n>   * registered without requiring any manual intervention.\n>   */\n> -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n>  {\n>  \tmedia->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n>  }\n> @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n>  /**\n>   * \\brief Slot for the MediaDevice disconnected signal\n>   */\n> -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n>  {\n>  \tmedia->disconnected.disconnect(this);\n>\n> diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> index 7bd30e7aead8..b305be48aafc 100644\n> --- a/test/delayed_controls.cpp\n> +++ b/test/delayed_controls.cpp\n> @@ -47,7 +47,7 @@ protected:\n>  \t\t\treturn TestSkip;\n>  \t\t}\n>\n> -\t\tdev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> +\t\tdev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n>  \t\tif (dev_->open()) {\n>  \t\t\tcerr << \"Failed to open video device\" << endl;\n>  \t\t\treturn TestFail;\n> diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> index dde11f365e43..19b25fed50a0 100644\n> --- a/test/libtest/buffer_source.cpp\n> +++ b/test/libtest/buffer_source.cpp\n> @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n>  \t\treturn TestSkip;\n>  \t}\n>\n> -\tstd::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> +\tstd::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n>  \tif (!video) {\n>  \t\tstd::cout << \"Failed to get video device from entity \"\n>  \t\t\t  << videoDeviceName << std::endl;\n> --\n> 2.47.2\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id C64E6C3213\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun,  6 Apr 2025 16:53:40 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 226FC689A8;\n\tSun,  6 Apr 2025 18:53:40 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2389D689A1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  6 Apr 2025 18:53:38 +0200 (CEST)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 080273A2;\n\tSun,  6 Apr 2025 18:51:41 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"ajYN/+Ry\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1743958302;\n\tbh=37Yb1UcraAmt/fvcI3BPejntf9vEcV0xgIixg5QXxJw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=ajYN/+RykPEpRofZ/VlSz4OJqD7DLDswBYaQVhaFsUqt0k/RUxB9uLIACtTt0T8mw\n\tpsvaQwpkx9Jmn357BHRKjgyVpui7dmvWHBrRkNBxV6VwMQWR8d7/eR7uRgBHgA52Qf\n\toAEyt5xdrJAuyxHB/i55qVzIMBM3+wgEIQdB/QMA=","Date":"Sun, 6 Apr 2025 18:53:34 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","Message-ID":"<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20250404074624.2975182-3-paul.elder@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":33924,"web_url":"https://patchwork.libcamera.org/comment/33924/","msgid":"<20250406181629.GP4845@pendragon.ideasonboard.com>","date":"2025-04-06T18:16:29","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:\n> On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> > From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> >\n> > Adapt the PipelineHandler::acquireMediaDevice() support function to\n> > return a shared pointer instead of the underlying raw pointer.\n> \n> It seems nice, but I wonder if it really is better ? The\n> PipelineHandler base class already stores a shared_ptr<> instance for\n> each acquired media device. Is passing it around by value and storing\n> a copy as classes member in derived classes worth it ?\n> \n> Or is this about an ownership issue I am missing ?\n\nI'm also wondering the same. Paul, could you explain the rationale for\nthis patch series ?\n\n> > Propagate this update to all pipeline handlers that use the MediaDevice\n> > and store a std::shared_ptr<MediaDevice> accordingly.\n> >\n> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > ---\n> >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n> >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n> >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n> >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n> >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n> >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n> >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n> >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n> >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n> >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n> >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n> >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n> >  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n> >  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n> >  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n> >  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n> >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n> >  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n> >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n> >  test/delayed_controls.cpp                          |  2 +-\n> >  test/libtest/buffer_source.cpp                     |  2 +-\n> >  21 files changed, 65 insertions(+), 49 deletions(-)\n> >\n> > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > index 5fa8bc2f66ee..0199ab7911c0 100644\n> > --- a/include/libcamera/internal/pipeline_handler.h\n> > +++ b/include/libcamera/internal/pipeline_handler.h\n> > @@ -38,8 +38,8 @@ public:\n> >  \tvirtual ~PipelineHandler();\n> >\n> >  \tvirtual bool match(DeviceEnumerator *enumerator) = 0;\n> > -\tMediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> > -\t\t\t\t\tconst DeviceMatch &dm);\n> > +\tstd::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> > +\t\t\t\t\t\t\tconst DeviceMatch &dm);\n> >\n> >  \tbool acquire(Camera *camera);\n> >  \tvoid release(Camera *camera);\n> > @@ -74,7 +74,7 @@ protected:\n> >  \tvoid clearMediaDevices();\n> >\n> >  \tvoid registerCamera(std::shared_ptr<Camera> camera);\n> > -\tvoid hotplugMediaDevice(MediaDevice *media);\n> > +\tvoid hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> >\n> >  \tvirtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n> >  \tvirtual void stopDevice(Camera *camera) = 0;\n> > @@ -87,7 +87,7 @@ protected:\n> >  private:\n> >  \tvoid unlockMediaDevices();\n> >\n> > -\tvoid mediaDeviceDisconnected(MediaDevice *media);\n> > +\tvoid mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n> >  \tvirtual void disconnect();\n> >\n> >  \tvoid doQueueRequest(Request *request);\n> > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > index 4e66b3368d5a..850dbfcdc64b 100644\n> > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > @@ -139,7 +139,7 @@ private:\n> >\n> >  \tvoid bufferReady(FrameBuffer *buffer);\n> >\n> > -\tMediaDevice *isiDev_;\n> > +\tstd::shared_ptr<MediaDevice> isiDev_;\n> >\n> >  \tstd::unique_ptr<V4L2Subdevice> crossbar_;\n> >  \tstd::vector<Pipe> pipes_;\n> > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > index aa544d7b0303..ebbd424c56ea 100644\n> > --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> > +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n> >   * \\return 0 on success or a negative error code otherwise\n> >   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n> >   */\n> > -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> > +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n> >  {\n> >  \tint ret;\n> >\n> > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> > index 963c2f6b93a4..fdf85f2655f0 100644\n> > --- a/src/libcamera/pipeline/ipu3/cio2.h\n> > +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> > @@ -38,7 +38,7 @@ public:\n> >  \tstd::vector<PixelFormat> formats() const;\n> >  \tstd::vector<SizeRange> sizes(const PixelFormat &format) const;\n> >\n> > -\tint init(const MediaDevice *media, unsigned int index);\n> > +\tint init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n> >  \tint configure(const Size &size, const Transform &transform,\n> >  \t\t      V4L2DeviceFormat *outputFormat);\n> >\n> > diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > index 7be780913fae..391e000f6e12 100644\n> > --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> > +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n> >   *\n> >   * \\return 0 on success or a negative error code otherwise\n> >   */\n> > -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> > +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> > +\t\t     unsigned int index)\n> >  {\n> >  \tint ret;\n> >\n> > diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> > index fa508316b301..272f861f98c4 100644\n> > --- a/src/libcamera/pipeline/ipu3/imgu.h\n> > +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> > @@ -64,7 +64,7 @@ public:\n> >  \t\tSize viewfinder;\n> >  \t};\n> >\n> > -\tint init(MediaDevice *media, unsigned int index);\n> > +\tint init(std::shared_ptr<MediaDevice> media, unsigned int index);\n> >\n> >  \tPipeConfig calculatePipeConfig(Pipe *pipe);\n> >\n> > @@ -118,7 +118,7 @@ private:\n> >  \t\t\t\t V4L2DeviceFormat *outputFormat);\n> >\n> >  \tstd::string name_;\n> > -\tMediaDevice *media_;\n> > +\tstd::shared_ptr<MediaDevice> media_;\n> >  };\n> >\n> >  } /* namespace libcamera */\n> > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > index e31e3879dcc9..17205f96446a 100644\n> > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > @@ -164,8 +164,8 @@ private:\n> >\n> >  \tImgUDevice imgu0_;\n> >  \tImgUDevice imgu1_;\n> > -\tMediaDevice *cio2MediaDev_;\n> > -\tMediaDevice *imguMediaDev_;\n> > +\tstd::shared_ptr<MediaDevice> cio2MediaDev_;\n> > +\tstd::shared_ptr<MediaDevice> imguMediaDev_;\n> >\n> >  \tstd::vector<IPABuffer> ipaBuffers_;\n> >  };\n> > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > index a05e11fccf8d..7615122d907b 100644\n> > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > @@ -684,7 +684,7 @@ private:\n> >  \tbool registerTPGCamera(MediaLink *link);\n> >  \tbool registerSensorCamera(MediaLink *link);\n> >\n> > -\tMediaDevice *media_;\n> > +\tstd::shared_ptr<MediaDevice> media_;\n> >  \tstd::unique_ptr<V4L2Subdevice> isp_;\n> >  \tstd::unique_ptr<V4L2VideoDevice> stats_;\n> >  \tstd::unique_ptr<V4L2VideoDevice> params_;\n> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > index 705615b86b0c..d4ec538f478b 100644\n> > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > @@ -200,7 +200,7 @@ private:\n> >\n> >  \tint updateControls(RkISP1CameraData *data);\n> >\n> > -\tMediaDevice *media_;\n> > +\tstd::shared_ptr<MediaDevice> media_;\n> >  \tstd::unique_ptr<V4L2Subdevice> isp_;\n> >  \tstd::unique_ptr<V4L2VideoDevice> param_;\n> >  \tstd::unique_ptr<V4L2VideoDevice> stat_;\n> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > index eee5b09e2ff0..2e567ace0b78 100644\n> > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n> >  {\n> >  }\n> >\n> > -bool RkISP1Path::init(MediaDevice *media)\n> > +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n> >  {\n> >  \tstd::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n> >  \tstd::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > index 2a1ef0abe6d1..154310ac37c1 100644\n> > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > @@ -36,7 +36,7 @@ class RkISP1Path\n> >  public:\n> >  \tRkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n> >\n> > -\tbool init(MediaDevice *media);\n> > +\tbool init(std::shared_ptr<MediaDevice> media);\n> >\n> >  \tint setEnabled(bool enable) { return link_->setEnabled(enable); }\n> >  \tbool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > index 1f13e5230fae..23ce54eca144 100644\n> > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n> >  }\n> >\n> >  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > -\t\t\t\t\tMediaDevice *frontend, const std::string &frontendName,\n> > -\t\t\t\t\tMediaDevice *backend, MediaEntity *sensorEntity)\n> > +\t\t\t\t\tstd::shared_ptr<MediaDevice> frontend,\n> > +\t\t\t\t\tconst std::string &frontendName,\n> > +\t\t\t\t\tstd::shared_ptr<MediaDevice> backend,\n> > +\t\t\t\t\tMediaEntity *sensorEntity)\n> >  {\n> >  \tCameraData *data = cameraData.get();\n> >  \tint ret;\n> > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > index aae0c2f35888..e422bbf7405f 100644\n> > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > @@ -229,13 +229,16 @@ public:\n> >\n> >  protected:\n> >  \tint registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > -\t\t\t   MediaDevice *frontent, const std::string &frontendName,\n> > -\t\t\t   MediaDevice *backend, MediaEntity *sensorEntity);\n> > +\t\t\t   std::shared_ptr<MediaDevice> frontend,\n> > +\t\t\t   const std::string &frontendName,\n> > +\t\t\t   std::shared_ptr<MediaDevice> backend,\n> > +\t\t\t   MediaEntity *sensorEntity);\n> >\n> >  \tvoid mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n> >\n> >  \tvirtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> > -\t\t\t\t     MediaDevice *unicam, MediaDevice *isp) = 0;\n> > +\t\t\t\t     std::shared_ptr<MediaDevice> unicam,\n> > +\t\t\t\t     std::shared_ptr<MediaDevice> isp) = 0;\n> >\n> >  private:\n> >  \tCameraData *cameraData(Camera *camera)\n> > diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > index 91e7f4c94d96..d0cb71b49e11 100644\n> > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > @@ -866,7 +866,8 @@ private:\n> >\n> >  \tint prepareBuffers(Camera *camera) override;\n> >  \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > -\t\t\t     MediaDevice *cfe, MediaDevice *isp) override;\n> > +\t\t\t     std::shared_ptr<MediaDevice> cfe,\n> > +\t\t\t     std::shared_ptr<MediaDevice> isp) override;\n> >  };\n> >\n> >  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> >  \t\tcfe.add(\"rp1-cfe-fe-image0\");\n> >  \t\tcfe.add(\"rp1-cfe-fe-stats\");\n> >  \t\tcfe.add(\"rp1-cfe-fe-config\");\n> > -\t\tMediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > +\t\tstd::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n> >\n> >  \t\tif (!cfeDevice) {\n> >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> > @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> >  \t\tisp.add(\"pispbe-tdn_input\");\n> >  \t\tisp.add(\"pispbe-stitch_output\");\n> >  \t\tisp.add(\"pispbe-stitch_input\");\n> > -\t\tMediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > +\t\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> >\n> >  \t\tif (!ispDevice) {\n> >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n> >  }\n> >\n> >  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > -\t\t\t\t\t  MediaDevice *cfe, MediaDevice *isp)\n> > +\t\t\t\t\t  std::shared_ptr<MediaDevice> cfe,\n> > +\t\t\t\t\t  std::shared_ptr<MediaDevice> isp)\n> >  {\n> >  \tPiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n> >  \tint ret;\n> > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > index fe910bdf2ff9..d58035ecd198 100644\n> > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > @@ -5,6 +5,8 @@\n> >   * Pipeline handler for VC4-based Raspberry Pi devices\n> >   */\n> >\n> > +#include <memory>\n> > +\n> >  #include <linux/bcm2835-isp.h>\n> >  #include <linux/v4l2-controls.h>\n> >  #include <linux/videodev2.h>\n> > @@ -158,7 +160,8 @@ private:\n> >\n> >  \tint prepareBuffers(Camera *camera) override;\n> >  \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > -\t\t\t     MediaDevice *unicam, MediaDevice *isp) override;\n> > +\t\t\t     std::shared_ptr<MediaDevice> unicam,\n> > +\t\t\t     std::shared_ptr<MediaDevice> isp) override;\n> >  };\n> >\n> >  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> >  \t */\n> >  \tfor (unsigned int i = 0; i < numUnicamDevices; i++) {\n> >  \t\tDeviceMatch unicam(\"unicam\");\n> > -\t\tMediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > +\t\tstd::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n> >\n> >  \t\tif (!unicamDevice) {\n> >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> > @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> >  \t\t}\n> >\n> >  \t\tDeviceMatch isp(\"bcm2835-isp\");\n> > -\t\tMediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > +\t\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> >\n> >  \t\tif (!ispDevice) {\n> >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n> >  \treturn 0;\n> >  }\n> >\n> > -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> > +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > +\t\t\t\t\t std::shared_ptr<MediaDevice> unicam,\n> > +\t\t\t\t\t std::shared_ptr<MediaDevice> isp)\n> >  {\n> >  \tVc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n> >\n> > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > index 451491f5608e..feaa16094b65 100644\n> > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > @@ -407,7 +407,7 @@ public:\n> >\n> >  \tV4L2VideoDevice *video(const MediaEntity *entity);\n> >  \tV4L2Subdevice *subdev(const MediaEntity *entity);\n> > -\tMediaDevice *converter() { return converter_; }\n> > +\tMediaDevice *converter() { return converter_.get(); }\n> >  \tbool swIspEnabled() const { return swIspEnabled_; }\n> >\n> >  protected:\n> > @@ -427,7 +427,8 @@ private:\n> >  \t\treturn static_cast<SimpleCameraData *>(camera->_d());\n> >  \t}\n> >\n> > -\tbool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> > +\tbool matchDevice(std::shared_ptr<MediaDevice> media,\n> > +\t\t\t const SimplePipelineInfo &info,\n> >  \t\t\t DeviceEnumerator *enumerator);\n> >\n> >  \tstd::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > @@ -438,7 +439,7 @@ private:\n> >\n> >  \tstd::map<const MediaEntity *, EntityData> entities_;\n> >\n> > -\tMediaDevice *converter_;\n> > +\tstd::shared_ptr<MediaDevice> converter_;\n> >  \tbool swIspEnabled_;\n> >  };\n> >\n> > @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n> >  \treturn 0;\n> >  }\n> >\n> > -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n> >  \t\t\t\t\tconst SimplePipelineInfo &info,\n> >  \t\t\t\t\tDeviceEnumerator *enumerator)\n> >  {\n> > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> >  \tswIspEnabled_ = info.swIspEnabled;\n> >\n> >  \t/* Locate the sensors. */\n> > -\tstd::vector<MediaEntity *> sensors = locateSensors(media);\n> > +\tstd::vector<MediaEntity *> sensors = locateSensors(media.get());\n> >  \tif (sensors.empty()) {\n> >  \t\tLOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n> >  \t\treturn false;\n> > @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> >\n> >  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n> >  {\n> > -\tMediaDevice *media;\n> > +\tstd::shared_ptr<MediaDevice> media;\n> >\n> >  \tfor (const SimplePipelineInfo &inf : supportedDevices) {\n> >  \t\tDeviceMatch dm(inf.driver);\n> > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > index 5adc89fdb29c..a1e036a32d5f 100644\n> > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > @@ -46,7 +46,7 @@ public:\n> >  \t{\n> >  \t}\n> >\n> > -\tint init(MediaDevice *media);\n> > +\tint init(std::shared_ptr<MediaDevice> media);\n> >  \tvoid addControl(uint32_t cid, const ControlInfo &v4l2info,\n> >  \t\t\tControlInfoMap::Map *ctrls);\n> >  \tvoid imageBufferReady(FrameBuffer *buffer);\n> > @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n> >\n> >  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n> >  {\n> > -\tMediaDevice *media;\n> > +\tstd::shared_ptr<MediaDevice> media;\n> >  \tDeviceMatch dm(\"uvcvideo\");\n> >\n> >  \tmedia = acquireMediaDevice(enumerator, dm);\n> > @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n> >  \tdata->video_->close();\n> >  }\n> >\n> > -int UVCCameraData::init(MediaDevice *media)\n> > +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n> >  {\n> >  \tint ret;\n> >\n> > diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> > index 07273bd2b6c3..59c564b8a9f6 100644\n> > --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> > +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> > @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n> >  class VimcCameraData : public Camera::Private\n> >  {\n> >  public:\n> > -\tVimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> > +\tVimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n> >  \t\t: Camera::Private(pipe), media_(media)\n> >  \t{\n> >  \t}\n> > @@ -59,7 +59,7 @@ public:\n> >  \tvoid imageBufferReady(FrameBuffer *buffer);\n> >  \tvoid paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n> >\n> > -\tMediaDevice *media_;\n> > +\tstd::shared_ptr<MediaDevice> media_;\n> >  \tstd::unique_ptr<CameraSensor> sensor_;\n> >  \tstd::unique_ptr<V4L2Subdevice> debayer_;\n> >  \tstd::unique_ptr<V4L2Subdevice> scaler_;\n> > @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n> >  \tdm.add(\"RGB/YUV Input\");\n> >  \tdm.add(\"Scaler\");\n> >\n> > -\tMediaDevice *media = acquireMediaDevice(enumerator, dm);\n> > +\tstd::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n> >  \tif (!media)\n> >  \t\treturn false;\n> >\n> > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > index 8f12957b75fa..5fe2c64c8bc6 100644\n> > --- a/src/libcamera/pipeline_handler.cpp\n> > +++ b/src/libcamera/pipeline_handler.cpp\n> > @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n> >   *\n> >   * \\context This function shall be called from the CameraManager thread.\n> >   *\n> > - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> > + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> > + * is found\n> >   */\n> > -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > -\t\t\t\t\t\t const DeviceMatch &dm)\n> > +std::shared_ptr<MediaDevice>\n> > +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > +\t\t\t\t    const DeviceMatch &dm)\n> >  {\n> >  \tstd::shared_ptr<MediaDevice> media = enumerator->search(dm);\n> >  \tif (!media)\n> > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> >\n> >  \tmediaDevices_.push_back(media);\n> >\n> > -\treturn media.get();\n> > +\treturn media;\n> >  }\n> >\n> >  /**\n> > @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n> >   * handler gets notified and automatically disconnects all the cameras it has\n> >   * registered without requiring any manual intervention.\n> >   */\n> > -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n> >  {\n> >  \tmedia->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n> >  }\n> > @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> >  /**\n> >   * \\brief Slot for the MediaDevice disconnected signal\n> >   */\n> > -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> > +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n> >  {\n> >  \tmedia->disconnected.disconnect(this);\n> >\n> > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > index 7bd30e7aead8..b305be48aafc 100644\n> > --- a/test/delayed_controls.cpp\n> > +++ b/test/delayed_controls.cpp\n> > @@ -47,7 +47,7 @@ protected:\n> >  \t\t\treturn TestSkip;\n> >  \t\t}\n> >\n> > -\t\tdev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> > +\t\tdev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n> >  \t\tif (dev_->open()) {\n> >  \t\t\tcerr << \"Failed to open video device\" << endl;\n> >  \t\t\treturn TestFail;\n> > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> > index dde11f365e43..19b25fed50a0 100644\n> > --- a/test/libtest/buffer_source.cpp\n> > +++ b/test/libtest/buffer_source.cpp\n> > @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n> >  \t\treturn TestSkip;\n> >  \t}\n> >\n> > -\tstd::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> > +\tstd::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n> >  \tif (!video) {\n> >  \t\tstd::cout << \"Failed to get video device from entity \"\n> >  \t\t\t  << videoDeviceName << std::endl;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 9B203C3213\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun,  6 Apr 2025 18:16:56 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B5690689A8;\n\tSun,  6 Apr 2025 20:16:55 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 535B9689A1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  6 Apr 2025 20:16:54 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1C2B83A2;\n\tSun,  6 Apr 2025 20:14:58 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"EnUzoWaQ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1743963298;\n\tbh=pylZj19+QAVzA2sfFvei82vOK6E3j7+aXeryu97QU1g=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=EnUzoWaQuwEl83t7YZBuKnjD2tyNLzWX8zFHZCsaA1fmcJ+pKtUgZ07sVww9e/OLl\n\t1TZkRL+svipuaxd0JBaklxzeMewPomZA+H7c1ZSvNYrDWN9Vjut/uUMxeqaUrORahA\n\tfDBGGI8CNR/h/R/5qiS62ki5VIRa8/M1vXRUvxRA=","Date":"Sun, 6 Apr 2025 21:16:29 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","Message-ID":"<20250406181629.GP4845@pendragon.ideasonboard.com>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>\n\t<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":33983,"web_url":"https://patchwork.libcamera.org/comment/33983/","msgid":"<aAdj7FovC9TPJj4z@pyrite.rasen.tech>","date":"2025-04-22T09:39:56","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Hi Jacopo and Laurent,\n\nOn Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:\n> On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:\n> > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > >\n> > > Adapt the PipelineHandler::acquireMediaDevice() support function to\n> > > return a shared pointer instead of the underlying raw pointer.\n> > \n> > It seems nice, but I wonder if it really is better ? The\n> > PipelineHandler base class already stores a shared_ptr<> instance for\n> > each acquired media device. Is passing it around by value and storing\n> > a copy as classes member in derived classes worth it ?\n> > \n> > Or is this about an ownership issue I am missing ?\n> \n> I'm also wondering the same. Paul, could you explain the rationale for\n> this patch series ?\n\nI thought I did in the cover letter... oh that's really short huh...\n\nWe had a platform with a really complex media graph that could be\nsummarized as a simple pipeline and an rkisp1 pipeline combined via a\nmux in between the sensors and the CSI receivers. The correct long-term\nsolution is modular pipeline handlers, but since we're not there yet we\nsettled with creating a simple pipeline handler inside the rkisp1\npipeline handler.\n\nTo prevent both pipeline handlers from trying to acquire the media\ndevices that are shared between the two paths, it was better to change\nownership of the media devices to shared so that we could register the\nmedia devices in the second pipeline handler without having to\nre-acquire and manage the lifetime.\n\nIt seemed useful to upstream at least this portion.\n\n\nPaul\n\n> > > Propagate this update to all pipeline handlers that use the MediaDevice\n> > > and store a std::shared_ptr<MediaDevice> accordingly.\n> > >\n> > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > > ---\n> > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n> > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n> > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n> > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n> > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n> > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n> > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n> > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n> > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n> > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n> > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n> > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n> > >  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n> > >  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n> > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n> > >  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n> > >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n> > >  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n> > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n> > >  test/delayed_controls.cpp                          |  2 +-\n> > >  test/libtest/buffer_source.cpp                     |  2 +-\n> > >  21 files changed, 65 insertions(+), 49 deletions(-)\n> > >\n> > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > > index 5fa8bc2f66ee..0199ab7911c0 100644\n> > > --- a/include/libcamera/internal/pipeline_handler.h\n> > > +++ b/include/libcamera/internal/pipeline_handler.h\n> > > @@ -38,8 +38,8 @@ public:\n> > >  \tvirtual ~PipelineHandler();\n> > >\n> > >  \tvirtual bool match(DeviceEnumerator *enumerator) = 0;\n> > > -\tMediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > -\t\t\t\t\tconst DeviceMatch &dm);\n> > > +\tstd::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > +\t\t\t\t\t\t\tconst DeviceMatch &dm);\n> > >\n> > >  \tbool acquire(Camera *camera);\n> > >  \tvoid release(Camera *camera);\n> > > @@ -74,7 +74,7 @@ protected:\n> > >  \tvoid clearMediaDevices();\n> > >\n> > >  \tvoid registerCamera(std::shared_ptr<Camera> camera);\n> > > -\tvoid hotplugMediaDevice(MediaDevice *media);\n> > > +\tvoid hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> > >\n> > >  \tvirtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n> > >  \tvirtual void stopDevice(Camera *camera) = 0;\n> > > @@ -87,7 +87,7 @@ protected:\n> > >  private:\n> > >  \tvoid unlockMediaDevices();\n> > >\n> > > -\tvoid mediaDeviceDisconnected(MediaDevice *media);\n> > > +\tvoid mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n> > >  \tvirtual void disconnect();\n> > >\n> > >  \tvoid doQueueRequest(Request *request);\n> > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > index 4e66b3368d5a..850dbfcdc64b 100644\n> > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > @@ -139,7 +139,7 @@ private:\n> > >\n> > >  \tvoid bufferReady(FrameBuffer *buffer);\n> > >\n> > > -\tMediaDevice *isiDev_;\n> > > +\tstd::shared_ptr<MediaDevice> isiDev_;\n> > >\n> > >  \tstd::unique_ptr<V4L2Subdevice> crossbar_;\n> > >  \tstd::vector<Pipe> pipes_;\n> > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > index aa544d7b0303..ebbd424c56ea 100644\n> > > --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n> > >   * \\return 0 on success or a negative error code otherwise\n> > >   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n> > >   */\n> > > -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> > > +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n> > >  {\n> > >  \tint ret;\n> > >\n> > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> > > index 963c2f6b93a4..fdf85f2655f0 100644\n> > > --- a/src/libcamera/pipeline/ipu3/cio2.h\n> > > +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> > > @@ -38,7 +38,7 @@ public:\n> > >  \tstd::vector<PixelFormat> formats() const;\n> > >  \tstd::vector<SizeRange> sizes(const PixelFormat &format) const;\n> > >\n> > > -\tint init(const MediaDevice *media, unsigned int index);\n> > > +\tint init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n> > >  \tint configure(const Size &size, const Transform &transform,\n> > >  \t\t      V4L2DeviceFormat *outputFormat);\n> > >\n> > > diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > index 7be780913fae..391e000f6e12 100644\n> > > --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n> > >   *\n> > >   * \\return 0 on success or a negative error code otherwise\n> > >   */\n> > > -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> > > +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> > > +\t\t     unsigned int index)\n> > >  {\n> > >  \tint ret;\n> > >\n> > > diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> > > index fa508316b301..272f861f98c4 100644\n> > > --- a/src/libcamera/pipeline/ipu3/imgu.h\n> > > +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> > > @@ -64,7 +64,7 @@ public:\n> > >  \t\tSize viewfinder;\n> > >  \t};\n> > >\n> > > -\tint init(MediaDevice *media, unsigned int index);\n> > > +\tint init(std::shared_ptr<MediaDevice> media, unsigned int index);\n> > >\n> > >  \tPipeConfig calculatePipeConfig(Pipe *pipe);\n> > >\n> > > @@ -118,7 +118,7 @@ private:\n> > >  \t\t\t\t V4L2DeviceFormat *outputFormat);\n> > >\n> > >  \tstd::string name_;\n> > > -\tMediaDevice *media_;\n> > > +\tstd::shared_ptr<MediaDevice> media_;\n> > >  };\n> > >\n> > >  } /* namespace libcamera */\n> > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > index e31e3879dcc9..17205f96446a 100644\n> > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > @@ -164,8 +164,8 @@ private:\n> > >\n> > >  \tImgUDevice imgu0_;\n> > >  \tImgUDevice imgu1_;\n> > > -\tMediaDevice *cio2MediaDev_;\n> > > -\tMediaDevice *imguMediaDev_;\n> > > +\tstd::shared_ptr<MediaDevice> cio2MediaDev_;\n> > > +\tstd::shared_ptr<MediaDevice> imguMediaDev_;\n> > >\n> > >  \tstd::vector<IPABuffer> ipaBuffers_;\n> > >  };\n> > > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > index a05e11fccf8d..7615122d907b 100644\n> > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > @@ -684,7 +684,7 @@ private:\n> > >  \tbool registerTPGCamera(MediaLink *link);\n> > >  \tbool registerSensorCamera(MediaLink *link);\n> > >\n> > > -\tMediaDevice *media_;\n> > > +\tstd::shared_ptr<MediaDevice> media_;\n> > >  \tstd::unique_ptr<V4L2Subdevice> isp_;\n> > >  \tstd::unique_ptr<V4L2VideoDevice> stats_;\n> > >  \tstd::unique_ptr<V4L2VideoDevice> params_;\n> > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > index 705615b86b0c..d4ec538f478b 100644\n> > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > @@ -200,7 +200,7 @@ private:\n> > >\n> > >  \tint updateControls(RkISP1CameraData *data);\n> > >\n> > > -\tMediaDevice *media_;\n> > > +\tstd::shared_ptr<MediaDevice> media_;\n> > >  \tstd::unique_ptr<V4L2Subdevice> isp_;\n> > >  \tstd::unique_ptr<V4L2VideoDevice> param_;\n> > >  \tstd::unique_ptr<V4L2VideoDevice> stat_;\n> > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > index eee5b09e2ff0..2e567ace0b78 100644\n> > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n> > >  {\n> > >  }\n> > >\n> > > -bool RkISP1Path::init(MediaDevice *media)\n> > > +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n> > >  {\n> > >  \tstd::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n> > >  \tstd::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > index 2a1ef0abe6d1..154310ac37c1 100644\n> > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > @@ -36,7 +36,7 @@ class RkISP1Path\n> > >  public:\n> > >  \tRkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n> > >\n> > > -\tbool init(MediaDevice *media);\n> > > +\tbool init(std::shared_ptr<MediaDevice> media);\n> > >\n> > >  \tint setEnabled(bool enable) { return link_->setEnabled(enable); }\n> > >  \tbool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > index 1f13e5230fae..23ce54eca144 100644\n> > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n> > >  }\n> > >\n> > >  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > -\t\t\t\t\tMediaDevice *frontend, const std::string &frontendName,\n> > > -\t\t\t\t\tMediaDevice *backend, MediaEntity *sensorEntity)\n> > > +\t\t\t\t\tstd::shared_ptr<MediaDevice> frontend,\n> > > +\t\t\t\t\tconst std::string &frontendName,\n> > > +\t\t\t\t\tstd::shared_ptr<MediaDevice> backend,\n> > > +\t\t\t\t\tMediaEntity *sensorEntity)\n> > >  {\n> > >  \tCameraData *data = cameraData.get();\n> > >  \tint ret;\n> > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > index aae0c2f35888..e422bbf7405f 100644\n> > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > @@ -229,13 +229,16 @@ public:\n> > >\n> > >  protected:\n> > >  \tint registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > -\t\t\t   MediaDevice *frontent, const std::string &frontendName,\n> > > -\t\t\t   MediaDevice *backend, MediaEntity *sensorEntity);\n> > > +\t\t\t   std::shared_ptr<MediaDevice> frontend,\n> > > +\t\t\t   const std::string &frontendName,\n> > > +\t\t\t   std::shared_ptr<MediaDevice> backend,\n> > > +\t\t\t   MediaEntity *sensorEntity);\n> > >\n> > >  \tvoid mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n> > >\n> > >  \tvirtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> > > -\t\t\t\t     MediaDevice *unicam, MediaDevice *isp) = 0;\n> > > +\t\t\t\t     std::shared_ptr<MediaDevice> unicam,\n> > > +\t\t\t\t     std::shared_ptr<MediaDevice> isp) = 0;\n> > >\n> > >  private:\n> > >  \tCameraData *cameraData(Camera *camera)\n> > > diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > index 91e7f4c94d96..d0cb71b49e11 100644\n> > > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > @@ -866,7 +866,8 @@ private:\n> > >\n> > >  \tint prepareBuffers(Camera *camera) override;\n> > >  \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > -\t\t\t     MediaDevice *cfe, MediaDevice *isp) override;\n> > > +\t\t\t     std::shared_ptr<MediaDevice> cfe,\n> > > +\t\t\t     std::shared_ptr<MediaDevice> isp) override;\n> > >  };\n> > >\n> > >  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > >  \t\tcfe.add(\"rp1-cfe-fe-image0\");\n> > >  \t\tcfe.add(\"rp1-cfe-fe-stats\");\n> > >  \t\tcfe.add(\"rp1-cfe-fe-config\");\n> > > -\t\tMediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > +\t\tstd::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > >\n> > >  \t\tif (!cfeDevice) {\n> > >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> > > @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > >  \t\tisp.add(\"pispbe-tdn_input\");\n> > >  \t\tisp.add(\"pispbe-stitch_output\");\n> > >  \t\tisp.add(\"pispbe-stitch_input\");\n> > > -\t\tMediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > +\t\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > >\n> > >  \t\tif (!ispDevice) {\n> > >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n> > >  }\n> > >\n> > >  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > -\t\t\t\t\t  MediaDevice *cfe, MediaDevice *isp)\n> > > +\t\t\t\t\t  std::shared_ptr<MediaDevice> cfe,\n> > > +\t\t\t\t\t  std::shared_ptr<MediaDevice> isp)\n> > >  {\n> > >  \tPiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n> > >  \tint ret;\n> > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > index fe910bdf2ff9..d58035ecd198 100644\n> > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > @@ -5,6 +5,8 @@\n> > >   * Pipeline handler for VC4-based Raspberry Pi devices\n> > >   */\n> > >\n> > > +#include <memory>\n> > > +\n> > >  #include <linux/bcm2835-isp.h>\n> > >  #include <linux/v4l2-controls.h>\n> > >  #include <linux/videodev2.h>\n> > > @@ -158,7 +160,8 @@ private:\n> > >\n> > >  \tint prepareBuffers(Camera *camera) override;\n> > >  \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > -\t\t\t     MediaDevice *unicam, MediaDevice *isp) override;\n> > > +\t\t\t     std::shared_ptr<MediaDevice> unicam,\n> > > +\t\t\t     std::shared_ptr<MediaDevice> isp) override;\n> > >  };\n> > >\n> > >  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > >  \t */\n> > >  \tfor (unsigned int i = 0; i < numUnicamDevices; i++) {\n> > >  \t\tDeviceMatch unicam(\"unicam\");\n> > > -\t\tMediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > +\t\tstd::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > >\n> > >  \t\tif (!unicamDevice) {\n> > >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> > > @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > >  \t\t}\n> > >\n> > >  \t\tDeviceMatch isp(\"bcm2835-isp\");\n> > > -\t\tMediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > +\t\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > >\n> > >  \t\tif (!ispDevice) {\n> > >  \t\t\tLOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n> > >  \treturn 0;\n> > >  }\n> > >\n> > > -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> > > +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > +\t\t\t\t\t std::shared_ptr<MediaDevice> unicam,\n> > > +\t\t\t\t\t std::shared_ptr<MediaDevice> isp)\n> > >  {\n> > >  \tVc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n> > >\n> > > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > > index 451491f5608e..feaa16094b65 100644\n> > > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > > @@ -407,7 +407,7 @@ public:\n> > >\n> > >  \tV4L2VideoDevice *video(const MediaEntity *entity);\n> > >  \tV4L2Subdevice *subdev(const MediaEntity *entity);\n> > > -\tMediaDevice *converter() { return converter_; }\n> > > +\tMediaDevice *converter() { return converter_.get(); }\n> > >  \tbool swIspEnabled() const { return swIspEnabled_; }\n> > >\n> > >  protected:\n> > > @@ -427,7 +427,8 @@ private:\n> > >  \t\treturn static_cast<SimpleCameraData *>(camera->_d());\n> > >  \t}\n> > >\n> > > -\tbool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> > > +\tbool matchDevice(std::shared_ptr<MediaDevice> media,\n> > > +\t\t\t const SimplePipelineInfo &info,\n> > >  \t\t\t DeviceEnumerator *enumerator);\n> > >\n> > >  \tstd::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > > @@ -438,7 +439,7 @@ private:\n> > >\n> > >  \tstd::map<const MediaEntity *, EntityData> entities_;\n> > >\n> > > -\tMediaDevice *converter_;\n> > > +\tstd::shared_ptr<MediaDevice> converter_;\n> > >  \tbool swIspEnabled_;\n> > >  };\n> > >\n> > > @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n> > >  \treturn 0;\n> > >  }\n> > >\n> > > -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n> > >  \t\t\t\t\tconst SimplePipelineInfo &info,\n> > >  \t\t\t\t\tDeviceEnumerator *enumerator)\n> > >  {\n> > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > >  \tswIspEnabled_ = info.swIspEnabled;\n> > >\n> > >  \t/* Locate the sensors. */\n> > > -\tstd::vector<MediaEntity *> sensors = locateSensors(media);\n> > > +\tstd::vector<MediaEntity *> sensors = locateSensors(media.get());\n> > >  \tif (sensors.empty()) {\n> > >  \t\tLOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n> > >  \t\treturn false;\n> > > @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > >\n> > >  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n> > >  {\n> > > -\tMediaDevice *media;\n> > > +\tstd::shared_ptr<MediaDevice> media;\n> > >\n> > >  \tfor (const SimplePipelineInfo &inf : supportedDevices) {\n> > >  \t\tDeviceMatch dm(inf.driver);\n> > > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > index 5adc89fdb29c..a1e036a32d5f 100644\n> > > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > @@ -46,7 +46,7 @@ public:\n> > >  \t{\n> > >  \t}\n> > >\n> > > -\tint init(MediaDevice *media);\n> > > +\tint init(std::shared_ptr<MediaDevice> media);\n> > >  \tvoid addControl(uint32_t cid, const ControlInfo &v4l2info,\n> > >  \t\t\tControlInfoMap::Map *ctrls);\n> > >  \tvoid imageBufferReady(FrameBuffer *buffer);\n> > > @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n> > >\n> > >  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n> > >  {\n> > > -\tMediaDevice *media;\n> > > +\tstd::shared_ptr<MediaDevice> media;\n> > >  \tDeviceMatch dm(\"uvcvideo\");\n> > >\n> > >  \tmedia = acquireMediaDevice(enumerator, dm);\n> > > @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n> > >  \tdata->video_->close();\n> > >  }\n> > >\n> > > -int UVCCameraData::init(MediaDevice *media)\n> > > +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n> > >  {\n> > >  \tint ret;\n> > >\n> > > diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > index 07273bd2b6c3..59c564b8a9f6 100644\n> > > --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> > > +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n> > >  class VimcCameraData : public Camera::Private\n> > >  {\n> > >  public:\n> > > -\tVimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> > > +\tVimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n> > >  \t\t: Camera::Private(pipe), media_(media)\n> > >  \t{\n> > >  \t}\n> > > @@ -59,7 +59,7 @@ public:\n> > >  \tvoid imageBufferReady(FrameBuffer *buffer);\n> > >  \tvoid paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n> > >\n> > > -\tMediaDevice *media_;\n> > > +\tstd::shared_ptr<MediaDevice> media_;\n> > >  \tstd::unique_ptr<CameraSensor> sensor_;\n> > >  \tstd::unique_ptr<V4L2Subdevice> debayer_;\n> > >  \tstd::unique_ptr<V4L2Subdevice> scaler_;\n> > > @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n> > >  \tdm.add(\"RGB/YUV Input\");\n> > >  \tdm.add(\"Scaler\");\n> > >\n> > > -\tMediaDevice *media = acquireMediaDevice(enumerator, dm);\n> > > +\tstd::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n> > >  \tif (!media)\n> > >  \t\treturn false;\n> > >\n> > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > > index 8f12957b75fa..5fe2c64c8bc6 100644\n> > > --- a/src/libcamera/pipeline_handler.cpp\n> > > +++ b/src/libcamera/pipeline_handler.cpp\n> > > @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n> > >   *\n> > >   * \\context This function shall be called from the CameraManager thread.\n> > >   *\n> > > - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> > > + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> > > + * is found\n> > >   */\n> > > -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > -\t\t\t\t\t\t const DeviceMatch &dm)\n> > > +std::shared_ptr<MediaDevice>\n> > > +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > +\t\t\t\t    const DeviceMatch &dm)\n> > >  {\n> > >  \tstd::shared_ptr<MediaDevice> media = enumerator->search(dm);\n> > >  \tif (!media)\n> > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > >\n> > >  \tmediaDevices_.push_back(media);\n> > >\n> > > -\treturn media.get();\n> > > +\treturn media;\n> > >  }\n> > >\n> > >  /**\n> > > @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n> > >   * handler gets notified and automatically disconnects all the cameras it has\n> > >   * registered without requiring any manual intervention.\n> > >   */\n> > > -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n> > >  {\n> > >  \tmedia->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n> > >  }\n> > > @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > >  /**\n> > >   * \\brief Slot for the MediaDevice disconnected signal\n> > >   */\n> > > -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> > > +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n> > >  {\n> > >  \tmedia->disconnected.disconnect(this);\n> > >\n> > > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > > index 7bd30e7aead8..b305be48aafc 100644\n> > > --- a/test/delayed_controls.cpp\n> > > +++ b/test/delayed_controls.cpp\n> > > @@ -47,7 +47,7 @@ protected:\n> > >  \t\t\treturn TestSkip;\n> > >  \t\t}\n> > >\n> > > -\t\tdev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> > > +\t\tdev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n> > >  \t\tif (dev_->open()) {\n> > >  \t\t\tcerr << \"Failed to open video device\" << endl;\n> > >  \t\t\treturn TestFail;\n> > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> > > index dde11f365e43..19b25fed50a0 100644\n> > > --- a/test/libtest/buffer_source.cpp\n> > > +++ b/test/libtest/buffer_source.cpp\n> > > @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n> > >  \t\treturn TestSkip;\n> > >  \t}\n> > >\n> > > -\tstd::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> > > +\tstd::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n> > >  \tif (!video) {\n> > >  \t\tstd::cout << \"Failed to get video device from entity \"\n> > >  \t\t\t  << videoDeviceName << std::endl;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E8DBDC327D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 22 Apr 2025 09:40:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5360168ACF;\n\tTue, 22 Apr 2025 11:40:07 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4F99668AC7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 22 Apr 2025 11:40:06 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2404:7a81:160:2100:bedf:5f9a:c968:1149])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A303E666;\n\tTue, 22 Apr 2025 11:37:57 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"n5KcmeAz\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1745314679;\n\tbh=ZE5C+qgYncwb/R22nOXuUzOk6TJOMoQ8IedZVoMLils=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=n5KcmeAzTgyZJn6XNCEYTj9JsV8rrO6/r/Z+u9qDGO+BPCrBOZrkYy5wDm8CrTFnG\n\tOwqgkGmTZyJ/GvsrweVND1fTJZj2n8+JN+ne9Xnmf3yPIqhnaNPVHRsmrrXZ/80ynq\n\tEjuidIrWGriOnxQ90UuaDBfrBS/pTHNAXnpCohKs=","Date":"Tue, 22 Apr 2025 18:39:56 +0900","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","Message-ID":"<aAdj7FovC9TPJj4z@pyrite.rasen.tech>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>\n\t<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>\n\t<20250406181629.GP4845@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20250406181629.GP4845@pendragon.ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":34223,"web_url":"https://patchwork.libcamera.org/comment/34223/","msgid":"<174714237995.233090.4884438906870237379@pyrite.rasen.tech>","date":"2025-05-13T13:19:39","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Gentle ping\n\nQuoting Paul Elder (2025-04-22 11:39:56)\n> Hi Jacopo and Laurent,\n> \n> On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:\n> > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:\n> > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > >\n> > > > Adapt the PipelineHandler::acquireMediaDevice() support function to\n> > > > return a shared pointer instead of the underlying raw pointer.\n> > > \n> > > It seems nice, but I wonder if it really is better ? The\n> > > PipelineHandler base class already stores a shared_ptr<> instance for\n> > > each acquired media device. Is passing it around by value and storing\n> > > a copy as classes member in derived classes worth it ?\n> > > \n> > > Or is this about an ownership issue I am missing ?\n> > \n> > I'm also wondering the same. Paul, could you explain the rationale for\n> > this patch series ?\n> \n> I thought I did in the cover letter... oh that's really short huh...\n> \n> We had a platform with a really complex media graph that could be\n> summarized as a simple pipeline and an rkisp1 pipeline combined via a\n> mux in between the sensors and the CSI receivers. The correct long-term\n> solution is modular pipeline handlers, but since we're not there yet we\n> settled with creating a simple pipeline handler inside the rkisp1\n> pipeline handler.\n> \n> To prevent both pipeline handlers from trying to acquire the media\n> devices that are shared between the two paths, it was better to change\n> ownership of the media devices to shared so that we could register the\n> media devices in the second pipeline handler without having to\n> re-acquire and manage the lifetime.\n> \n> It seemed useful to upstream at least this portion.\n> \n> \n> Paul\n> \n> > > > Propagate this update to all pipeline handlers that use the MediaDevice\n> > > > and store a std::shared_ptr<MediaDevice> accordingly.\n> > > >\n> > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > > > ---\n> > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n> > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n> > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n> > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n> > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n> > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n> > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n> > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n> > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n> > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n> > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n> > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n> > > >  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n> > > >  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n> > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n> > > >  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n> > > >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n> > > >  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n> > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n> > > >  test/delayed_controls.cpp                          |  2 +-\n> > > >  test/libtest/buffer_source.cpp                     |  2 +-\n> > > >  21 files changed, 65 insertions(+), 49 deletions(-)\n> > > >\n> > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > > > index 5fa8bc2f66ee..0199ab7911c0 100644\n> > > > --- a/include/libcamera/internal/pipeline_handler.h\n> > > > +++ b/include/libcamera/internal/pipeline_handler.h\n> > > > @@ -38,8 +38,8 @@ public:\n> > > >   virtual ~PipelineHandler();\n> > > >\n> > > >   virtual bool match(DeviceEnumerator *enumerator) = 0;\n> > > > - MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > -                                 const DeviceMatch &dm);\n> > > > + std::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > +                                                 const DeviceMatch &dm);\n> > > >\n> > > >   bool acquire(Camera *camera);\n> > > >   void release(Camera *camera);\n> > > > @@ -74,7 +74,7 @@ protected:\n> > > >   void clearMediaDevices();\n> > > >\n> > > >   void registerCamera(std::shared_ptr<Camera> camera);\n> > > > - void hotplugMediaDevice(MediaDevice *media);\n> > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> > > >\n> > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n> > > >   virtual void stopDevice(Camera *camera) = 0;\n> > > > @@ -87,7 +87,7 @@ protected:\n> > > >  private:\n> > > >   void unlockMediaDevices();\n> > > >\n> > > > - void mediaDeviceDisconnected(MediaDevice *media);\n> > > > + void mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n> > > >   virtual void disconnect();\n> > > >\n> > > >   void doQueueRequest(Request *request);\n> > > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > index 4e66b3368d5a..850dbfcdc64b 100644\n> > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > @@ -139,7 +139,7 @@ private:\n> > > >\n> > > >   void bufferReady(FrameBuffer *buffer);\n> > > >\n> > > > - MediaDevice *isiDev_;\n> > > > + std::shared_ptr<MediaDevice> isiDev_;\n> > > >\n> > > >   std::unique_ptr<V4L2Subdevice> crossbar_;\n> > > >   std::vector<Pipe> pipes_;\n> > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > index aa544d7b0303..ebbd424c56ea 100644\n> > > > --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n> > > >   * \\return 0 on success or a negative error code otherwise\n> > > >   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n> > > >   */\n> > > > -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> > > > +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n> > > >  {\n> > > >   int ret;\n> > > >\n> > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > index 963c2f6b93a4..fdf85f2655f0 100644\n> > > > --- a/src/libcamera/pipeline/ipu3/cio2.h\n> > > > +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > @@ -38,7 +38,7 @@ public:\n> > > >   std::vector<PixelFormat> formats() const;\n> > > >   std::vector<SizeRange> sizes(const PixelFormat &format) const;\n> > > >\n> > > > - int init(const MediaDevice *media, unsigned int index);\n> > > > + int init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n> > > >   int configure(const Size &size, const Transform &transform,\n> > > >                 V4L2DeviceFormat *outputFormat);\n> > > >\n> > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > index 7be780913fae..391e000f6e12 100644\n> > > > --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n> > > >   *\n> > > >   * \\return 0 on success or a negative error code otherwise\n> > > >   */\n> > > > -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> > > > +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> > > > +              unsigned int index)\n> > > >  {\n> > > >   int ret;\n> > > >\n> > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > index fa508316b301..272f861f98c4 100644\n> > > > --- a/src/libcamera/pipeline/ipu3/imgu.h\n> > > > +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > @@ -64,7 +64,7 @@ public:\n> > > >           Size viewfinder;\n> > > >   };\n> > > >\n> > > > - int init(MediaDevice *media, unsigned int index);\n> > > > + int init(std::shared_ptr<MediaDevice> media, unsigned int index);\n> > > >\n> > > >   PipeConfig calculatePipeConfig(Pipe *pipe);\n> > > >\n> > > > @@ -118,7 +118,7 @@ private:\n> > > >                            V4L2DeviceFormat *outputFormat);\n> > > >\n> > > >   std::string name_;\n> > > > - MediaDevice *media_;\n> > > > + std::shared_ptr<MediaDevice> media_;\n> > > >  };\n> > > >\n> > > >  } /* namespace libcamera */\n> > > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > index e31e3879dcc9..17205f96446a 100644\n> > > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > @@ -164,8 +164,8 @@ private:\n> > > >\n> > > >   ImgUDevice imgu0_;\n> > > >   ImgUDevice imgu1_;\n> > > > - MediaDevice *cio2MediaDev_;\n> > > > - MediaDevice *imguMediaDev_;\n> > > > + std::shared_ptr<MediaDevice> cio2MediaDev_;\n> > > > + std::shared_ptr<MediaDevice> imguMediaDev_;\n> > > >\n> > > >   std::vector<IPABuffer> ipaBuffers_;\n> > > >  };\n> > > > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > index a05e11fccf8d..7615122d907b 100644\n> > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > @@ -684,7 +684,7 @@ private:\n> > > >   bool registerTPGCamera(MediaLink *link);\n> > > >   bool registerSensorCamera(MediaLink *link);\n> > > >\n> > > > - MediaDevice *media_;\n> > > > + std::shared_ptr<MediaDevice> media_;\n> > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > >   std::unique_ptr<V4L2VideoDevice> stats_;\n> > > >   std::unique_ptr<V4L2VideoDevice> params_;\n> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > index 705615b86b0c..d4ec538f478b 100644\n> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > @@ -200,7 +200,7 @@ private:\n> > > >\n> > > >   int updateControls(RkISP1CameraData *data);\n> > > >\n> > > > - MediaDevice *media_;\n> > > > + std::shared_ptr<MediaDevice> media_;\n> > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > >   std::unique_ptr<V4L2VideoDevice> param_;\n> > > >   std::unique_ptr<V4L2VideoDevice> stat_;\n> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > index eee5b09e2ff0..2e567ace0b78 100644\n> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n> > > >  {\n> > > >  }\n> > > >\n> > > > -bool RkISP1Path::init(MediaDevice *media)\n> > > > +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n> > > >  {\n> > > >   std::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n> > > >   std::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > index 2a1ef0abe6d1..154310ac37c1 100644\n> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > @@ -36,7 +36,7 @@ class RkISP1Path\n> > > >  public:\n> > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n> > > >\n> > > > - bool init(MediaDevice *media);\n> > > > + bool init(std::shared_ptr<MediaDevice> media);\n> > > >\n> > > >   int setEnabled(bool enable) { return link_->setEnabled(enable); }\n> > > >   bool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > index 1f13e5230fae..23ce54eca144 100644\n> > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n> > > >  }\n> > > >\n> > > >  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > -                                 MediaDevice *frontend, const std::string &frontendName,\n> > > > -                                 MediaDevice *backend, MediaEntity *sensorEntity)\n> > > > +                                 std::shared_ptr<MediaDevice> frontend,\n> > > > +                                 const std::string &frontendName,\n> > > > +                                 std::shared_ptr<MediaDevice> backend,\n> > > > +                                 MediaEntity *sensorEntity)\n> > > >  {\n> > > >   CameraData *data = cameraData.get();\n> > > >   int ret;\n> > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > index aae0c2f35888..e422bbf7405f 100644\n> > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > @@ -229,13 +229,16 @@ public:\n> > > >\n> > > >  protected:\n> > > >   int registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > -                    MediaDevice *frontent, const std::string &frontendName,\n> > > > -                    MediaDevice *backend, MediaEntity *sensorEntity);\n> > > > +                    std::shared_ptr<MediaDevice> frontend,\n> > > > +                    const std::string &frontendName,\n> > > > +                    std::shared_ptr<MediaDevice> backend,\n> > > > +                    MediaEntity *sensorEntity);\n> > > >\n> > > >   void mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n> > > >\n> > > >   virtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> > > > -                              MediaDevice *unicam, MediaDevice *isp) = 0;\n> > > > +                              std::shared_ptr<MediaDevice> unicam,\n> > > > +                              std::shared_ptr<MediaDevice> isp) = 0;\n> > > >\n> > > >  private:\n> > > >   CameraData *cameraData(Camera *camera)\n> > > > diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > index 91e7f4c94d96..d0cb71b49e11 100644\n> > > > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > @@ -866,7 +866,8 @@ private:\n> > > >\n> > > >   int prepareBuffers(Camera *camera) override;\n> > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > -                      MediaDevice *cfe, MediaDevice *isp) override;\n> > > > +                      std::shared_ptr<MediaDevice> cfe,\n> > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > >  };\n> > > >\n> > > >  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > >           cfe.add(\"rp1-cfe-fe-image0\");\n> > > >           cfe.add(\"rp1-cfe-fe-stats\");\n> > > >           cfe.add(\"rp1-cfe-fe-config\");\n> > > > -         MediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > +         std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > >\n> > > >           if (!cfeDevice) {\n> > > >                   LOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> > > > @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > >           isp.add(\"pispbe-tdn_input\");\n> > > >           isp.add(\"pispbe-stitch_output\");\n> > > >           isp.add(\"pispbe-stitch_input\");\n> > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > >\n> > > >           if (!ispDevice) {\n> > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n> > > >  }\n> > > >\n> > > >  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > -                                   MediaDevice *cfe, MediaDevice *isp)\n> > > > +                                   std::shared_ptr<MediaDevice> cfe,\n> > > > +                                   std::shared_ptr<MediaDevice> isp)\n> > > >  {\n> > > >   PiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n> > > >   int ret;\n> > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > index fe910bdf2ff9..d58035ecd198 100644\n> > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > @@ -5,6 +5,8 @@\n> > > >   * Pipeline handler for VC4-based Raspberry Pi devices\n> > > >   */\n> > > >\n> > > > +#include <memory>\n> > > > +\n> > > >  #include <linux/bcm2835-isp.h>\n> > > >  #include <linux/v4l2-controls.h>\n> > > >  #include <linux/videodev2.h>\n> > > > @@ -158,7 +160,8 @@ private:\n> > > >\n> > > >   int prepareBuffers(Camera *camera) override;\n> > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > -                      MediaDevice *unicam, MediaDevice *isp) override;\n> > > > +                      std::shared_ptr<MediaDevice> unicam,\n> > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > >  };\n> > > >\n> > > >  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > >    */\n> > > >   for (unsigned int i = 0; i < numUnicamDevices; i++) {\n> > > >           DeviceMatch unicam(\"unicam\");\n> > > > -         MediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > +         std::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > >\n> > > >           if (!unicamDevice) {\n> > > >                   LOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> > > > @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > >           }\n> > > >\n> > > >           DeviceMatch isp(\"bcm2835-isp\");\n> > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > >\n> > > >           if (!ispDevice) {\n> > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n> > > >   return 0;\n> > > >  }\n> > > >\n> > > > -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> > > > +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > +                                  std::shared_ptr<MediaDevice> unicam,\n> > > > +                                  std::shared_ptr<MediaDevice> isp)\n> > > >  {\n> > > >   Vc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n> > > >\n> > > > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > > > index 451491f5608e..feaa16094b65 100644\n> > > > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > > > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > > > @@ -407,7 +407,7 @@ public:\n> > > >\n> > > >   V4L2VideoDevice *video(const MediaEntity *entity);\n> > > >   V4L2Subdevice *subdev(const MediaEntity *entity);\n> > > > - MediaDevice *converter() { return converter_; }\n> > > > + MediaDevice *converter() { return converter_.get(); }\n> > > >   bool swIspEnabled() const { return swIspEnabled_; }\n> > > >\n> > > >  protected:\n> > > > @@ -427,7 +427,8 @@ private:\n> > > >           return static_cast<SimpleCameraData *>(camera->_d());\n> > > >   }\n> > > >\n> > > > - bool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> > > > + bool matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > +                  const SimplePipelineInfo &info,\n> > > >                    DeviceEnumerator *enumerator);\n> > > >\n> > > >   std::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > > > @@ -438,7 +439,7 @@ private:\n> > > >\n> > > >   std::map<const MediaEntity *, EntityData> entities_;\n> > > >\n> > > > - MediaDevice *converter_;\n> > > > + std::shared_ptr<MediaDevice> converter_;\n> > > >   bool swIspEnabled_;\n> > > >  };\n> > > >\n> > > > @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n> > > >   return 0;\n> > > >  }\n> > > >\n> > > > -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n> > > >                                   const SimplePipelineInfo &info,\n> > > >                                   DeviceEnumerator *enumerator)\n> > > >  {\n> > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > >   swIspEnabled_ = info.swIspEnabled;\n> > > >\n> > > >   /* Locate the sensors. */\n> > > > - std::vector<MediaEntity *> sensors = locateSensors(media);\n> > > > + std::vector<MediaEntity *> sensors = locateSensors(media.get());\n> > > >   if (sensors.empty()) {\n> > > >           LOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n> > > >           return false;\n> > > > @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > >\n> > > >  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n> > > >  {\n> > > > - MediaDevice *media;\n> > > > + std::shared_ptr<MediaDevice> media;\n> > > >\n> > > >   for (const SimplePipelineInfo &inf : supportedDevices) {\n> > > >           DeviceMatch dm(inf.driver);\n> > > > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > index 5adc89fdb29c..a1e036a32d5f 100644\n> > > > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > @@ -46,7 +46,7 @@ public:\n> > > >   {\n> > > >   }\n> > > >\n> > > > - int init(MediaDevice *media);\n> > > > + int init(std::shared_ptr<MediaDevice> media);\n> > > >   void addControl(uint32_t cid, const ControlInfo &v4l2info,\n> > > >                   ControlInfoMap::Map *ctrls);\n> > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n> > > >\n> > > >  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n> > > >  {\n> > > > - MediaDevice *media;\n> > > > + std::shared_ptr<MediaDevice> media;\n> > > >   DeviceMatch dm(\"uvcvideo\");\n> > > >\n> > > >   media = acquireMediaDevice(enumerator, dm);\n> > > > @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n> > > >   data->video_->close();\n> > > >  }\n> > > >\n> > > > -int UVCCameraData::init(MediaDevice *media)\n> > > > +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n> > > >  {\n> > > >   int ret;\n> > > >\n> > > > diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > index 07273bd2b6c3..59c564b8a9f6 100644\n> > > > --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n> > > >  class VimcCameraData : public Camera::Private\n> > > >  {\n> > > >  public:\n> > > > - VimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> > > > + VimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n> > > >           : Camera::Private(pipe), media_(media)\n> > > >   {\n> > > >   }\n> > > > @@ -59,7 +59,7 @@ public:\n> > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > >   void paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n> > > >\n> > > > - MediaDevice *media_;\n> > > > + std::shared_ptr<MediaDevice> media_;\n> > > >   std::unique_ptr<CameraSensor> sensor_;\n> > > >   std::unique_ptr<V4L2Subdevice> debayer_;\n> > > >   std::unique_ptr<V4L2Subdevice> scaler_;\n> > > > @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n> > > >   dm.add(\"RGB/YUV Input\");\n> > > >   dm.add(\"Scaler\");\n> > > >\n> > > > - MediaDevice *media = acquireMediaDevice(enumerator, dm);\n> > > > + std::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n> > > >   if (!media)\n> > > >           return false;\n> > > >\n> > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > > > index 8f12957b75fa..5fe2c64c8bc6 100644\n> > > > --- a/src/libcamera/pipeline_handler.cpp\n> > > > +++ b/src/libcamera/pipeline_handler.cpp\n> > > > @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n> > > >   *\n> > > >   * \\context This function shall be called from the CameraManager thread.\n> > > >   *\n> > > > - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> > > > + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> > > > + * is found\n> > > >   */\n> > > > -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > -                                          const DeviceMatch &dm)\n> > > > +std::shared_ptr<MediaDevice>\n> > > > +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > +                             const DeviceMatch &dm)\n> > > >  {\n> > > >   std::shared_ptr<MediaDevice> media = enumerator->search(dm);\n> > > >   if (!media)\n> > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > >\n> > > >   mediaDevices_.push_back(media);\n> > > >\n> > > > - return media.get();\n> > > > + return media;\n> > > >  }\n> > > >\n> > > >  /**\n> > > > @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n> > > >   * handler gets notified and automatically disconnects all the cameras it has\n> > > >   * registered without requiring any manual intervention.\n> > > >   */\n> > > > -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n> > > >  {\n> > > >   media->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n> > > >  }\n> > > > @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > >  /**\n> > > >   * \\brief Slot for the MediaDevice disconnected signal\n> > > >   */\n> > > > -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> > > > +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n> > > >  {\n> > > >   media->disconnected.disconnect(this);\n> > > >\n> > > > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > > > index 7bd30e7aead8..b305be48aafc 100644\n> > > > --- a/test/delayed_controls.cpp\n> > > > +++ b/test/delayed_controls.cpp\n> > > > @@ -47,7 +47,7 @@ protected:\n> > > >                   return TestSkip;\n> > > >           }\n> > > >\n> > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n> > > >           if (dev_->open()) {\n> > > >                   cerr << \"Failed to open video device\" << endl;\n> > > >                   return TestFail;\n> > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> > > > index dde11f365e43..19b25fed50a0 100644\n> > > > --- a/test/libtest/buffer_source.cpp\n> > > > +++ b/test/libtest/buffer_source.cpp\n> > > > @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n> > > >           return TestSkip;\n> > > >   }\n> > > >\n> > > > - std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> > > > + std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n> > > >   if (!video) {\n> > > >           std::cout << \"Failed to get video device from entity \"\n> > > >                     << videoDeviceName << std::endl;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 97CE7C3200\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 13 May 2025 13:19:46 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BE8BE68B59;\n\tTue, 13 May 2025 15:19:45 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E885D6175C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 13 May 2025 15:19:43 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2001:861:3a80:3300:4f2f:8c2c:b3ef:17d4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E9E7E4C9;\n\tTue, 13 May 2025 15:19:27 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"X30KEenA\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1747142368;\n\tbh=pZkl3Kza25nMiJGkTrUvrynNvDxhNRwDyrFhrZ0JKCA=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=X30KEenA3Dr+Up7LWB4FBWl5zwxGtwB6Uyk2zBxbw+VIBnveH3DI7am4op41Urzlt\n\t3oIQZRBFRIsuDIJWtUTCCxapUy96W5USIl8OTzobZiKN6d3rm9AtJ3+0tPqQqfT1Ew\n\tGWZiUqq1A5ibrvqrmEvwMfJka4zO6oTS9aSBpM6k=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<aAdj7FovC9TPJj4z@pyrite.rasen.tech>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>\n\t<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>\n\t<20250406181629.GP4845@pendragon.ideasonboard.com>\n\t<aAdj7FovC9TPJj4z@pyrite.rasen.tech>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","From":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Date":"Tue, 13 May 2025 15:19:39 +0200","Message-ID":"<174714237995.233090.4884438906870237379@pyrite.rasen.tech>","User-Agent":"alot/0.0.0","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35827,"web_url":"https://patchwork.libcamera.org/comment/35827/","msgid":"<175794737274.653594.10680797466701805213@localhost>","date":"2025-09-15T14:42:52","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"content":"Hi all,\n\nQuoting Paul Elder (2025-05-13 15:19:39)\n> Gentle ping\n> \n> Quoting Paul Elder (2025-04-22 11:39:56)\n> > Hi Jacopo and Laurent,\n> > \n> > On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:\n> > > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:\n> > > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> > > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > >\n> > > > > Adapt the PipelineHandler::acquireMediaDevice() support function to\n> > > > > return a shared pointer instead of the underlying raw pointer.\n> > > > \n> > > > It seems nice, but I wonder if it really is better ? The\n> > > > PipelineHandler base class already stores a shared_ptr<> instance for\n> > > > each acquired media device. Is passing it around by value and storing\n> > > > a copy as classes member in derived classes worth it ?\n> > > > \n> > > > Or is this about an ownership issue I am missing ?\n> > > \n> > > I'm also wondering the same. Paul, could you explain the rationale for\n> > > this patch series ?\n> > \n> > I thought I did in the cover letter... oh that's really short huh...\n> > \n> > We had a platform with a really complex media graph that could be\n> > summarized as a simple pipeline and an rkisp1 pipeline combined via a\n> > mux in between the sensors and the CSI receivers. The correct long-term\n> > solution is modular pipeline handlers, but since we're not there yet we\n> > settled with creating a simple pipeline handler inside the rkisp1\n> > pipeline handler.\n> > \n> > To prevent both pipeline handlers from trying to acquire the media\n> > devices that are shared between the two paths, it was better to change\n> > ownership of the media devices to shared so that we could register the\n> > media devices in the second pipeline handler without having to\n> > re-acquire and manage the lifetime.\n> > \n> > It seemed useful to upstream at least this portion.\n\nI have another use case for this change. In my work to bring the full\ndewarper support upstream I needed to add V4L2 requests support to the\ndewarper. These requests are allocated with a call to the medie device.\nSo the dewarper (which is implemented as V4L2M2MConverter) needs to hold\na pointer to the media device it was constructed for. Normally the\nconverter only gets a MediaDevice pointer passed to the constructor.\nHolding on that plain pointer in the converter feels not good at all,\neven though the lifetime of the converter will be tried to the pipeline\nhandler if I'm not mistaken. So overall I'd like to advocate for this\nswitch from raw pointers to shared pointers :-)\n\nReviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> \nTested-by: Stefan Klug <stefan.klug@ideasonboard.com> \n\nBest regards,\nStefan\n\n> > \n> > \n> > Paul\n> > \n> > > > > Propagate this update to all pipeline handlers that use the MediaDevice\n> > > > > and store a std::shared_ptr<MediaDevice> accordingly.\n> > > > >\n> > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > > > > ---\n> > > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n> > > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n> > > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n> > > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n> > > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n> > > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n> > > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n> > > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n> > > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n> > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n> > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n> > > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n> > > > >  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n> > > > >  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n> > > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n> > > > >  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n> > > > >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n> > > > >  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n> > > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n> > > > >  test/delayed_controls.cpp                          |  2 +-\n> > > > >  test/libtest/buffer_source.cpp                     |  2 +-\n> > > > >  21 files changed, 65 insertions(+), 49 deletions(-)\n> > > > >\n> > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > > > > index 5fa8bc2f66ee..0199ab7911c0 100644\n> > > > > --- a/include/libcamera/internal/pipeline_handler.h\n> > > > > +++ b/include/libcamera/internal/pipeline_handler.h\n> > > > > @@ -38,8 +38,8 @@ public:\n> > > > >   virtual ~PipelineHandler();\n> > > > >\n> > > > >   virtual bool match(DeviceEnumerator *enumerator) = 0;\n> > > > > - MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > -                                 const DeviceMatch &dm);\n> > > > > + std::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > +                                                 const DeviceMatch &dm);\n> > > > >\n> > > > >   bool acquire(Camera *camera);\n> > > > >   void release(Camera *camera);\n> > > > > @@ -74,7 +74,7 @@ protected:\n> > > > >   void clearMediaDevices();\n> > > > >\n> > > > >   void registerCamera(std::shared_ptr<Camera> camera);\n> > > > > - void hotplugMediaDevice(MediaDevice *media);\n> > > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> > > > >\n> > > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n> > > > >   virtual void stopDevice(Camera *camera) = 0;\n> > > > > @@ -87,7 +87,7 @@ protected:\n> > > > >  private:\n> > > > >   void unlockMediaDevices();\n> > > > >\n> > > > > - void mediaDeviceDisconnected(MediaDevice *media);\n> > > > > + void mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n> > > > >   virtual void disconnect();\n> > > > >\n> > > > >   void doQueueRequest(Request *request);\n> > > > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > index 4e66b3368d5a..850dbfcdc64b 100644\n> > > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > @@ -139,7 +139,7 @@ private:\n> > > > >\n> > > > >   void bufferReady(FrameBuffer *buffer);\n> > > > >\n> > > > > - MediaDevice *isiDev_;\n> > > > > + std::shared_ptr<MediaDevice> isiDev_;\n> > > > >\n> > > > >   std::unique_ptr<V4L2Subdevice> crossbar_;\n> > > > >   std::vector<Pipe> pipes_;\n> > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > index aa544d7b0303..ebbd424c56ea 100644\n> > > > > --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n> > > > >   * \\return 0 on success or a negative error code otherwise\n> > > > >   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n> > > > >   */\n> > > > > -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> > > > > +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n> > > > >  {\n> > > > >   int ret;\n> > > > >\n> > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > index 963c2f6b93a4..fdf85f2655f0 100644\n> > > > > --- a/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > @@ -38,7 +38,7 @@ public:\n> > > > >   std::vector<PixelFormat> formats() const;\n> > > > >   std::vector<SizeRange> sizes(const PixelFormat &format) const;\n> > > > >\n> > > > > - int init(const MediaDevice *media, unsigned int index);\n> > > > > + int init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n> > > > >   int configure(const Size &size, const Transform &transform,\n> > > > >                 V4L2DeviceFormat *outputFormat);\n> > > > >\n> > > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > index 7be780913fae..391e000f6e12 100644\n> > > > > --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n> > > > >   *\n> > > > >   * \\return 0 on success or a negative error code otherwise\n> > > > >   */\n> > > > > -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> > > > > +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> > > > > +              unsigned int index)\n> > > > >  {\n> > > > >   int ret;\n> > > > >\n> > > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > index fa508316b301..272f861f98c4 100644\n> > > > > --- a/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > @@ -64,7 +64,7 @@ public:\n> > > > >           Size viewfinder;\n> > > > >   };\n> > > > >\n> > > > > - int init(MediaDevice *media, unsigned int index);\n> > > > > + int init(std::shared_ptr<MediaDevice> media, unsigned int index);\n> > > > >\n> > > > >   PipeConfig calculatePipeConfig(Pipe *pipe);\n> > > > >\n> > > > > @@ -118,7 +118,7 @@ private:\n> > > > >                            V4L2DeviceFormat *outputFormat);\n> > > > >\n> > > > >   std::string name_;\n> > > > > - MediaDevice *media_;\n> > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > >  };\n> > > > >\n> > > > >  } /* namespace libcamera */\n> > > > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > index e31e3879dcc9..17205f96446a 100644\n> > > > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > @@ -164,8 +164,8 @@ private:\n> > > > >\n> > > > >   ImgUDevice imgu0_;\n> > > > >   ImgUDevice imgu1_;\n> > > > > - MediaDevice *cio2MediaDev_;\n> > > > > - MediaDevice *imguMediaDev_;\n> > > > > + std::shared_ptr<MediaDevice> cio2MediaDev_;\n> > > > > + std::shared_ptr<MediaDevice> imguMediaDev_;\n> > > > >\n> > > > >   std::vector<IPABuffer> ipaBuffers_;\n> > > > >  };\n> > > > > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > index a05e11fccf8d..7615122d907b 100644\n> > > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > @@ -684,7 +684,7 @@ private:\n> > > > >   bool registerTPGCamera(MediaLink *link);\n> > > > >   bool registerSensorCamera(MediaLink *link);\n> > > > >\n> > > > > - MediaDevice *media_;\n> > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > > >   std::unique_ptr<V4L2VideoDevice> stats_;\n> > > > >   std::unique_ptr<V4L2VideoDevice> params_;\n> > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > index 705615b86b0c..d4ec538f478b 100644\n> > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > @@ -200,7 +200,7 @@ private:\n> > > > >\n> > > > >   int updateControls(RkISP1CameraData *data);\n> > > > >\n> > > > > - MediaDevice *media_;\n> > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > > >   std::unique_ptr<V4L2VideoDevice> param_;\n> > > > >   std::unique_ptr<V4L2VideoDevice> stat_;\n> > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > index eee5b09e2ff0..2e567ace0b78 100644\n> > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n> > > > >  {\n> > > > >  }\n> > > > >\n> > > > > -bool RkISP1Path::init(MediaDevice *media)\n> > > > > +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n> > > > >  {\n> > > > >   std::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n> > > > >   std::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > index 2a1ef0abe6d1..154310ac37c1 100644\n> > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > @@ -36,7 +36,7 @@ class RkISP1Path\n> > > > >  public:\n> > > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n> > > > >\n> > > > > - bool init(MediaDevice *media);\n> > > > > + bool init(std::shared_ptr<MediaDevice> media);\n> > > > >\n> > > > >   int setEnabled(bool enable) { return link_->setEnabled(enable); }\n> > > > >   bool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> > > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > index 1f13e5230fae..23ce54eca144 100644\n> > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n> > > > >  }\n> > > > >\n> > > > >  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > -                                 MediaDevice *frontend, const std::string &frontendName,\n> > > > > -                                 MediaDevice *backend, MediaEntity *sensorEntity)\n> > > > > +                                 std::shared_ptr<MediaDevice> frontend,\n> > > > > +                                 const std::string &frontendName,\n> > > > > +                                 std::shared_ptr<MediaDevice> backend,\n> > > > > +                                 MediaEntity *sensorEntity)\n> > > > >  {\n> > > > >   CameraData *data = cameraData.get();\n> > > > >   int ret;\n> > > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > index aae0c2f35888..e422bbf7405f 100644\n> > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > @@ -229,13 +229,16 @@ public:\n> > > > >\n> > > > >  protected:\n> > > > >   int registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > -                    MediaDevice *frontent, const std::string &frontendName,\n> > > > > -                    MediaDevice *backend, MediaEntity *sensorEntity);\n> > > > > +                    std::shared_ptr<MediaDevice> frontend,\n> > > > > +                    const std::string &frontendName,\n> > > > > +                    std::shared_ptr<MediaDevice> backend,\n> > > > > +                    MediaEntity *sensorEntity);\n> > > > >\n> > > > >   void mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n> > > > >\n> > > > >   virtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> > > > > -                              MediaDevice *unicam, MediaDevice *isp) = 0;\n> > > > > +                              std::shared_ptr<MediaDevice> unicam,\n> > > > > +                              std::shared_ptr<MediaDevice> isp) = 0;\n> > > > >\n> > > > >  private:\n> > > > >   CameraData *cameraData(Camera *camera)\n> > > > > diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > index 91e7f4c94d96..d0cb71b49e11 100644\n> > > > > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > @@ -866,7 +866,8 @@ private:\n> > > > >\n> > > > >   int prepareBuffers(Camera *camera) override;\n> > > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > -                      MediaDevice *cfe, MediaDevice *isp) override;\n> > > > > +                      std::shared_ptr<MediaDevice> cfe,\n> > > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > > >  };\n> > > > >\n> > > > >  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > >           cfe.add(\"rp1-cfe-fe-image0\");\n> > > > >           cfe.add(\"rp1-cfe-fe-stats\");\n> > > > >           cfe.add(\"rp1-cfe-fe-config\");\n> > > > > -         MediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > > +         std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > >\n> > > > >           if (!cfeDevice) {\n> > > > >                   LOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> > > > > @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > >           isp.add(\"pispbe-tdn_input\");\n> > > > >           isp.add(\"pispbe-stitch_output\");\n> > > > >           isp.add(\"pispbe-stitch_input\");\n> > > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > >\n> > > > >           if (!ispDevice) {\n> > > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > > @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n> > > > >  }\n> > > > >\n> > > > >  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > -                                   MediaDevice *cfe, MediaDevice *isp)\n> > > > > +                                   std::shared_ptr<MediaDevice> cfe,\n> > > > > +                                   std::shared_ptr<MediaDevice> isp)\n> > > > >  {\n> > > > >   PiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n> > > > >   int ret;\n> > > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > index fe910bdf2ff9..d58035ecd198 100644\n> > > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > @@ -5,6 +5,8 @@\n> > > > >   * Pipeline handler for VC4-based Raspberry Pi devices\n> > > > >   */\n> > > > >\n> > > > > +#include <memory>\n> > > > > +\n> > > > >  #include <linux/bcm2835-isp.h>\n> > > > >  #include <linux/v4l2-controls.h>\n> > > > >  #include <linux/videodev2.h>\n> > > > > @@ -158,7 +160,8 @@ private:\n> > > > >\n> > > > >   int prepareBuffers(Camera *camera) override;\n> > > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > -                      MediaDevice *unicam, MediaDevice *isp) override;\n> > > > > +                      std::shared_ptr<MediaDevice> unicam,\n> > > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > > >  };\n> > > > >\n> > > > >  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > >    */\n> > > > >   for (unsigned int i = 0; i < numUnicamDevices; i++) {\n> > > > >           DeviceMatch unicam(\"unicam\");\n> > > > > -         MediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > > +         std::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > >\n> > > > >           if (!unicamDevice) {\n> > > > >                   LOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> > > > > @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > >           }\n> > > > >\n> > > > >           DeviceMatch isp(\"bcm2835-isp\");\n> > > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > >\n> > > > >           if (!ispDevice) {\n> > > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > > @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n> > > > >   return 0;\n> > > > >  }\n> > > > >\n> > > > > -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> > > > > +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > +                                  std::shared_ptr<MediaDevice> unicam,\n> > > > > +                                  std::shared_ptr<MediaDevice> isp)\n> > > > >  {\n> > > > >   Vc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n> > > > >\n> > > > > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > > > > index 451491f5608e..feaa16094b65 100644\n> > > > > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > > > > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > > > > @@ -407,7 +407,7 @@ public:\n> > > > >\n> > > > >   V4L2VideoDevice *video(const MediaEntity *entity);\n> > > > >   V4L2Subdevice *subdev(const MediaEntity *entity);\n> > > > > - MediaDevice *converter() { return converter_; }\n> > > > > + MediaDevice *converter() { return converter_.get(); }\n> > > > >   bool swIspEnabled() const { return swIspEnabled_; }\n> > > > >\n> > > > >  protected:\n> > > > > @@ -427,7 +427,8 @@ private:\n> > > > >           return static_cast<SimpleCameraData *>(camera->_d());\n> > > > >   }\n> > > > >\n> > > > > - bool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> > > > > + bool matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > > +                  const SimplePipelineInfo &info,\n> > > > >                    DeviceEnumerator *enumerator);\n> > > > >\n> > > > >   std::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > > > > @@ -438,7 +439,7 @@ private:\n> > > > >\n> > > > >   std::map<const MediaEntity *, EntityData> entities_;\n> > > > >\n> > > > > - MediaDevice *converter_;\n> > > > > + std::shared_ptr<MediaDevice> converter_;\n> > > > >   bool swIspEnabled_;\n> > > > >  };\n> > > > >\n> > > > > @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n> > > > >   return 0;\n> > > > >  }\n> > > > >\n> > > > > -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > >                                   const SimplePipelineInfo &info,\n> > > > >                                   DeviceEnumerator *enumerator)\n> > > > >  {\n> > > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > >   swIspEnabled_ = info.swIspEnabled;\n> > > > >\n> > > > >   /* Locate the sensors. */\n> > > > > - std::vector<MediaEntity *> sensors = locateSensors(media);\n> > > > > + std::vector<MediaEntity *> sensors = locateSensors(media.get());\n> > > > >   if (sensors.empty()) {\n> > > > >           LOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n> > > > >           return false;\n> > > > > @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > >\n> > > > >  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n> > > > >  {\n> > > > > - MediaDevice *media;\n> > > > > + std::shared_ptr<MediaDevice> media;\n> > > > >\n> > > > >   for (const SimplePipelineInfo &inf : supportedDevices) {\n> > > > >           DeviceMatch dm(inf.driver);\n> > > > > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > index 5adc89fdb29c..a1e036a32d5f 100644\n> > > > > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > @@ -46,7 +46,7 @@ public:\n> > > > >   {\n> > > > >   }\n> > > > >\n> > > > > - int init(MediaDevice *media);\n> > > > > + int init(std::shared_ptr<MediaDevice> media);\n> > > > >   void addControl(uint32_t cid, const ControlInfo &v4l2info,\n> > > > >                   ControlInfoMap::Map *ctrls);\n> > > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > > @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n> > > > >\n> > > > >  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n> > > > >  {\n> > > > > - MediaDevice *media;\n> > > > > + std::shared_ptr<MediaDevice> media;\n> > > > >   DeviceMatch dm(\"uvcvideo\");\n> > > > >\n> > > > >   media = acquireMediaDevice(enumerator, dm);\n> > > > > @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n> > > > >   data->video_->close();\n> > > > >  }\n> > > > >\n> > > > > -int UVCCameraData::init(MediaDevice *media)\n> > > > > +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n> > > > >  {\n> > > > >   int ret;\n> > > > >\n> > > > > diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > index 07273bd2b6c3..59c564b8a9f6 100644\n> > > > > --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n> > > > >  class VimcCameraData : public Camera::Private\n> > > > >  {\n> > > > >  public:\n> > > > > - VimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> > > > > + VimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n> > > > >           : Camera::Private(pipe), media_(media)\n> > > > >   {\n> > > > >   }\n> > > > > @@ -59,7 +59,7 @@ public:\n> > > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > >   void paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n> > > > >\n> > > > > - MediaDevice *media_;\n> > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > >   std::unique_ptr<CameraSensor> sensor_;\n> > > > >   std::unique_ptr<V4L2Subdevice> debayer_;\n> > > > >   std::unique_ptr<V4L2Subdevice> scaler_;\n> > > > > @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n> > > > >   dm.add(\"RGB/YUV Input\");\n> > > > >   dm.add(\"Scaler\");\n> > > > >\n> > > > > - MediaDevice *media = acquireMediaDevice(enumerator, dm);\n> > > > > + std::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n> > > > >   if (!media)\n> > > > >           return false;\n> > > > >\n> > > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > > > > index 8f12957b75fa..5fe2c64c8bc6 100644\n> > > > > --- a/src/libcamera/pipeline_handler.cpp\n> > > > > +++ b/src/libcamera/pipeline_handler.cpp\n> > > > > @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n> > > > >   *\n> > > > >   * \\context This function shall be called from the CameraManager thread.\n> > > > >   *\n> > > > > - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> > > > > + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> > > > > + * is found\n> > > > >   */\n> > > > > -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > -                                          const DeviceMatch &dm)\n> > > > > +std::shared_ptr<MediaDevice>\n> > > > > +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > +                             const DeviceMatch &dm)\n> > > > >  {\n> > > > >   std::shared_ptr<MediaDevice> media = enumerator->search(dm);\n> > > > >   if (!media)\n> > > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > >\n> > > > >   mediaDevices_.push_back(media);\n> > > > >\n> > > > > - return media.get();\n> > > > > + return media;\n> > > > >  }\n> > > > >\n> > > > >  /**\n> > > > > @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n> > > > >   * handler gets notified and automatically disconnects all the cameras it has\n> > > > >   * registered without requiring any manual intervention.\n> > > > >   */\n> > > > > -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > > +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n> > > > >  {\n> > > > >   media->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n> > > > >  }\n> > > > > @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > >  /**\n> > > > >   * \\brief Slot for the MediaDevice disconnected signal\n> > > > >   */\n> > > > > -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> > > > > +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n> > > > >  {\n> > > > >   media->disconnected.disconnect(this);\n> > > > >\n> > > > > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > > > > index 7bd30e7aead8..b305be48aafc 100644\n> > > > > --- a/test/delayed_controls.cpp\n> > > > > +++ b/test/delayed_controls.cpp\n> > > > > @@ -47,7 +47,7 @@ protected:\n> > > > >                   return TestSkip;\n> > > > >           }\n> > > > >\n> > > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> > > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n> > > > >           if (dev_->open()) {\n> > > > >                   cerr << \"Failed to open video device\" << endl;\n> > > > >                   return TestFail;\n> > > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> > > > > index dde11f365e43..19b25fed50a0 100644\n> > > > > --- a/test/libtest/buffer_source.cpp\n> > > > > +++ b/test/libtest/buffer_source.cpp\n> > > > > @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n> > > > >           return TestSkip;\n> > > > >   }\n> > > > >\n> > > > > - std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> > > > > + std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n> > > > >   if (!video) {\n> > > > >           std::cout << \"Failed to get video device from entity \"\n> > > > >                     << videoDeviceName << std::endl;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 664E5C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 15 Sep 2025 14:42:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5A21D6936F;\n\tMon, 15 Sep 2025 16:42:58 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 94A37613A0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 15 Sep 2025 16:42:56 +0200 (CEST)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:2a47:b7e5:c39c:d1b3])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id BE72F6DF;\n\tMon, 15 Sep 2025 16:41:38 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"p9XjEa3L\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1757947298;\n\tbh=M4RzVLnTYvN2DxrHFo0sTUc8UrmlAapIxokJHeSXVYY=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=p9XjEa3LuDBZ+7wCxRlHLqc9StlKv9R78m5DPMEF57OxDTQelf5yD5oobbM37+riz\n\tvXuUHp5bXqcwfTSrqMrEPll0mxghXV29GSguLfuxSuKORPf12nMb/ekG18coZGkilb\n\tm5c63TGhpm8C6enXG8R7zpwqFR0peExGTeNaYiEM=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<174714237995.233090.4884438906870237379@pyrite.rasen.tech>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>\n\t<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>\n\t<20250406181629.GP4845@pendragon.ideasonboard.com>\n\t<aAdj7FovC9TPJj4z@pyrite.rasen.tech>\n\t<174714237995.233090.4884438906870237379@pyrite.rasen.tech>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","From":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tPaul Elder <paul.elder@ideasonboard.com>","Date":"Mon, 15 Sep 2025 16:42:52 +0200","Message-ID":"<175794737274.653594.10680797466701805213@localhost>","User-Agent":"alot/0.12.dev8+g2c003385c862.d20250602","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35831,"web_url":"https://patchwork.libcamera.org/comment/35831/","msgid":"<20250915145439.GB8821@pendragon.ideasonboard.com>","date":"2025-09-15T14:54:39","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Mon, Sep 15, 2025 at 04:42:52PM +0200, Stefan Klug wrote:\n> Quoting Paul Elder (2025-05-13 15:19:39)\n> > Quoting Paul Elder (2025-04-22 11:39:56)\n> > > On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:\n> > > > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:\n> > > > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> > > > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > > >\n> > > > > > Adapt the PipelineHandler::acquireMediaDevice() support function to\n> > > > > > return a shared pointer instead of the underlying raw pointer.\n> > > > > \n> > > > > It seems nice, but I wonder if it really is better ? The\n> > > > > PipelineHandler base class already stores a shared_ptr<> instance for\n> > > > > each acquired media device. Is passing it around by value and storing\n> > > > > a copy as classes member in derived classes worth it ?\n> > > > > \n> > > > > Or is this about an ownership issue I am missing ?\n> > > > \n> > > > I'm also wondering the same. Paul, could you explain the rationale for\n> > > > this patch series ?\n> > > \n> > > I thought I did in the cover letter... oh that's really short huh...\n> > > \n> > > We had a platform with a really complex media graph that could be\n> > > summarized as a simple pipeline and an rkisp1 pipeline combined via a\n> > > mux in between the sensors and the CSI receivers. The correct long-term\n> > > solution is modular pipeline handlers, but since we're not there yet we\n> > > settled with creating a simple pipeline handler inside the rkisp1\n> > > pipeline handler.\n> > > \n> > > To prevent both pipeline handlers from trying to acquire the media\n> > > devices that are shared between the two paths, it was better to change\n> > > ownership of the media devices to shared so that we could register the\n> > > media devices in the second pipeline handler without having to\n> > > re-acquire and manage the lifetime.\n> > > \n> > > It seemed useful to upstream at least this portion.\n> \n> I have another use case for this change. In my work to bring the full\n> dewarper support upstream I needed to add V4L2 requests support to the\n> dewarper. These requests are allocated with a call to the medie device.\n> So the dewarper (which is implemented as V4L2M2MConverter) needs to hold\n> a pointer to the media device it was constructed for. Normally the\n> converter only gets a MediaDevice pointer passed to the constructor.\n> Holding on that plain pointer in the converter feels not good at all,\n> even though the lifetime of the converter will be tried to the pipeline\n> handler if I'm not mistaken.\n\nI don't want to use shared pointers as a magic solution without a proper\nanalysis, given how intrusive they are. For your particular use case,\nhow do you plan for the converter to reach to the media device removal ?\n\n> So overall I'd like to advocate for this\n> switch from raw pointers to shared pointers :-)\n> \n> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> \n> Tested-by: Stefan Klug <stefan.klug@ideasonboard.com> \n> \n> > > > > > Propagate this update to all pipeline handlers that use the MediaDevice\n> > > > > > and store a std::shared_ptr<MediaDevice> accordingly.\n> > > > > >\n> > > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > > > > > ---\n> > > > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n> > > > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n> > > > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n> > > > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n> > > > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n> > > > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n> > > > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n> > > > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n> > > > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n> > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n> > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n> > > > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n> > > > > >  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n> > > > > >  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n> > > > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n> > > > > >  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n> > > > > >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n> > > > > >  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n> > > > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n> > > > > >  test/delayed_controls.cpp                          |  2 +-\n> > > > > >  test/libtest/buffer_source.cpp                     |  2 +-\n> > > > > >  21 files changed, 65 insertions(+), 49 deletions(-)\n> > > > > >\n> > > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > > > > > index 5fa8bc2f66ee..0199ab7911c0 100644\n> > > > > > --- a/include/libcamera/internal/pipeline_handler.h\n> > > > > > +++ b/include/libcamera/internal/pipeline_handler.h\n> > > > > > @@ -38,8 +38,8 @@ public:\n> > > > > >   virtual ~PipelineHandler();\n> > > > > >\n> > > > > >   virtual bool match(DeviceEnumerator *enumerator) = 0;\n> > > > > > - MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > -                                 const DeviceMatch &dm);\n> > > > > > + std::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > +                                                 const DeviceMatch &dm);\n> > > > > >\n> > > > > >   bool acquire(Camera *camera);\n> > > > > >   void release(Camera *camera);\n> > > > > > @@ -74,7 +74,7 @@ protected:\n> > > > > >   void clearMediaDevices();\n> > > > > >\n> > > > > >   void registerCamera(std::shared_ptr<Camera> camera);\n> > > > > > - void hotplugMediaDevice(MediaDevice *media);\n> > > > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> > > > > >\n> > > > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n> > > > > >   virtual void stopDevice(Camera *camera) = 0;\n> > > > > > @@ -87,7 +87,7 @@ protected:\n> > > > > >  private:\n> > > > > >   void unlockMediaDevices();\n> > > > > >\n> > > > > > - void mediaDeviceDisconnected(MediaDevice *media);\n> > > > > > + void mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n> > > > > >   virtual void disconnect();\n> > > > > >\n> > > > > >   void doQueueRequest(Request *request);\n> > > > > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > > index 4e66b3368d5a..850dbfcdc64b 100644\n> > > > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > > @@ -139,7 +139,7 @@ private:\n> > > > > >\n> > > > > >   void bufferReady(FrameBuffer *buffer);\n> > > > > >\n> > > > > > - MediaDevice *isiDev_;\n> > > > > > + std::shared_ptr<MediaDevice> isiDev_;\n> > > > > >\n> > > > > >   std::unique_ptr<V4L2Subdevice> crossbar_;\n> > > > > >   std::vector<Pipe> pipes_;\n> > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > > index aa544d7b0303..ebbd424c56ea 100644\n> > > > > > --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > > +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > > @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n> > > > > >   * \\return 0 on success or a negative error code otherwise\n> > > > > >   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n> > > > > >   */\n> > > > > > -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> > > > > > +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n> > > > > >  {\n> > > > > >   int ret;\n> > > > > >\n> > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > > index 963c2f6b93a4..fdf85f2655f0 100644\n> > > > > > --- a/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > > +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > > @@ -38,7 +38,7 @@ public:\n> > > > > >   std::vector<PixelFormat> formats() const;\n> > > > > >   std::vector<SizeRange> sizes(const PixelFormat &format) const;\n> > > > > >\n> > > > > > - int init(const MediaDevice *media, unsigned int index);\n> > > > > > + int init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n> > > > > >   int configure(const Size &size, const Transform &transform,\n> > > > > >                 V4L2DeviceFormat *outputFormat);\n> > > > > >\n> > > > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > > index 7be780913fae..391e000f6e12 100644\n> > > > > > --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > > +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > > @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n> > > > > >   *\n> > > > > >   * \\return 0 on success or a negative error code otherwise\n> > > > > >   */\n> > > > > > -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> > > > > > +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> > > > > > +              unsigned int index)\n> > > > > >  {\n> > > > > >   int ret;\n> > > > > >\n> > > > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > > index fa508316b301..272f861f98c4 100644\n> > > > > > --- a/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > > +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > > @@ -64,7 +64,7 @@ public:\n> > > > > >           Size viewfinder;\n> > > > > >   };\n> > > > > >\n> > > > > > - int init(MediaDevice *media, unsigned int index);\n> > > > > > + int init(std::shared_ptr<MediaDevice> media, unsigned int index);\n> > > > > >\n> > > > > >   PipeConfig calculatePipeConfig(Pipe *pipe);\n> > > > > >\n> > > > > > @@ -118,7 +118,7 @@ private:\n> > > > > >                            V4L2DeviceFormat *outputFormat);\n> > > > > >\n> > > > > >   std::string name_;\n> > > > > > - MediaDevice *media_;\n> > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > >  };\n> > > > > >\n> > > > > >  } /* namespace libcamera */\n> > > > > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > > index e31e3879dcc9..17205f96446a 100644\n> > > > > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > > @@ -164,8 +164,8 @@ private:\n> > > > > >\n> > > > > >   ImgUDevice imgu0_;\n> > > > > >   ImgUDevice imgu1_;\n> > > > > > - MediaDevice *cio2MediaDev_;\n> > > > > > - MediaDevice *imguMediaDev_;\n> > > > > > + std::shared_ptr<MediaDevice> cio2MediaDev_;\n> > > > > > + std::shared_ptr<MediaDevice> imguMediaDev_;\n> > > > > >\n> > > > > >   std::vector<IPABuffer> ipaBuffers_;\n> > > > > >  };\n> > > > > > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > > index a05e11fccf8d..7615122d907b 100644\n> > > > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > > @@ -684,7 +684,7 @@ private:\n> > > > > >   bool registerTPGCamera(MediaLink *link);\n> > > > > >   bool registerSensorCamera(MediaLink *link);\n> > > > > >\n> > > > > > - MediaDevice *media_;\n> > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > > > >   std::unique_ptr<V4L2VideoDevice> stats_;\n> > > > > >   std::unique_ptr<V4L2VideoDevice> params_;\n> > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > > index 705615b86b0c..d4ec538f478b 100644\n> > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > > @@ -200,7 +200,7 @@ private:\n> > > > > >\n> > > > > >   int updateControls(RkISP1CameraData *data);\n> > > > > >\n> > > > > > - MediaDevice *media_;\n> > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > > > >   std::unique_ptr<V4L2VideoDevice> param_;\n> > > > > >   std::unique_ptr<V4L2VideoDevice> stat_;\n> > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > > index eee5b09e2ff0..2e567ace0b78 100644\n> > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > > @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n> > > > > >  {\n> > > > > >  }\n> > > > > >\n> > > > > > -bool RkISP1Path::init(MediaDevice *media)\n> > > > > > +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n> > > > > >  {\n> > > > > >   std::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n> > > > > >   std::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > > index 2a1ef0abe6d1..154310ac37c1 100644\n> > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > > @@ -36,7 +36,7 @@ class RkISP1Path\n> > > > > >  public:\n> > > > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n> > > > > >\n> > > > > > - bool init(MediaDevice *media);\n> > > > > > + bool init(std::shared_ptr<MediaDevice> media);\n> > > > > >\n> > > > > >   int setEnabled(bool enable) { return link_->setEnabled(enable); }\n> > > > > >   bool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> > > > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > > index 1f13e5230fae..23ce54eca144 100644\n> > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > > @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n> > > > > >  }\n> > > > > >\n> > > > > >  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > -                                 MediaDevice *frontend, const std::string &frontendName,\n> > > > > > -                                 MediaDevice *backend, MediaEntity *sensorEntity)\n> > > > > > +                                 std::shared_ptr<MediaDevice> frontend,\n> > > > > > +                                 const std::string &frontendName,\n> > > > > > +                                 std::shared_ptr<MediaDevice> backend,\n> > > > > > +                                 MediaEntity *sensorEntity)\n> > > > > >  {\n> > > > > >   CameraData *data = cameraData.get();\n> > > > > >   int ret;\n> > > > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > > index aae0c2f35888..e422bbf7405f 100644\n> > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > > @@ -229,13 +229,16 @@ public:\n> > > > > >\n> > > > > >  protected:\n> > > > > >   int registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > -                    MediaDevice *frontent, const std::string &frontendName,\n> > > > > > -                    MediaDevice *backend, MediaEntity *sensorEntity);\n> > > > > > +                    std::shared_ptr<MediaDevice> frontend,\n> > > > > > +                    const std::string &frontendName,\n> > > > > > +                    std::shared_ptr<MediaDevice> backend,\n> > > > > > +                    MediaEntity *sensorEntity);\n> > > > > >\n> > > > > >   void mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n> > > > > >\n> > > > > >   virtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> > > > > > -                              MediaDevice *unicam, MediaDevice *isp) = 0;\n> > > > > > +                              std::shared_ptr<MediaDevice> unicam,\n> > > > > > +                              std::shared_ptr<MediaDevice> isp) = 0;\n> > > > > >\n> > > > > >  private:\n> > > > > >   CameraData *cameraData(Camera *camera)\n> > > > > > diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > > index 91e7f4c94d96..d0cb71b49e11 100644\n> > > > > > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > > @@ -866,7 +866,8 @@ private:\n> > > > > >\n> > > > > >   int prepareBuffers(Camera *camera) override;\n> > > > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > -                      MediaDevice *cfe, MediaDevice *isp) override;\n> > > > > > +                      std::shared_ptr<MediaDevice> cfe,\n> > > > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > > > >  };\n> > > > > >\n> > > > > >  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > > @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > >           cfe.add(\"rp1-cfe-fe-image0\");\n> > > > > >           cfe.add(\"rp1-cfe-fe-stats\");\n> > > > > >           cfe.add(\"rp1-cfe-fe-config\");\n> > > > > > -         MediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > > > +         std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > > >\n> > > > > >           if (!cfeDevice) {\n> > > > > >                   LOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> > > > > > @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > >           isp.add(\"pispbe-tdn_input\");\n> > > > > >           isp.add(\"pispbe-stitch_output\");\n> > > > > >           isp.add(\"pispbe-stitch_input\");\n> > > > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > >\n> > > > > >           if (!ispDevice) {\n> > > > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > > > @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n> > > > > >  }\n> > > > > >\n> > > > > >  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > -                                   MediaDevice *cfe, MediaDevice *isp)\n> > > > > > +                                   std::shared_ptr<MediaDevice> cfe,\n> > > > > > +                                   std::shared_ptr<MediaDevice> isp)\n> > > > > >  {\n> > > > > >   PiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n> > > > > >   int ret;\n> > > > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > > index fe910bdf2ff9..d58035ecd198 100644\n> > > > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > > @@ -5,6 +5,8 @@\n> > > > > >   * Pipeline handler for VC4-based Raspberry Pi devices\n> > > > > >   */\n> > > > > >\n> > > > > > +#include <memory>\n> > > > > > +\n> > > > > >  #include <linux/bcm2835-isp.h>\n> > > > > >  #include <linux/v4l2-controls.h>\n> > > > > >  #include <linux/videodev2.h>\n> > > > > > @@ -158,7 +160,8 @@ private:\n> > > > > >\n> > > > > >   int prepareBuffers(Camera *camera) override;\n> > > > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > -                      MediaDevice *unicam, MediaDevice *isp) override;\n> > > > > > +                      std::shared_ptr<MediaDevice> unicam,\n> > > > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > > > >  };\n> > > > > >\n> > > > > >  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > > @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > >    */\n> > > > > >   for (unsigned int i = 0; i < numUnicamDevices; i++) {\n> > > > > >           DeviceMatch unicam(\"unicam\");\n> > > > > > -         MediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > > > +         std::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > > >\n> > > > > >           if (!unicamDevice) {\n> > > > > >                   LOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> > > > > > @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > >           }\n> > > > > >\n> > > > > >           DeviceMatch isp(\"bcm2835-isp\");\n> > > > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > >\n> > > > > >           if (!ispDevice) {\n> > > > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > > > @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n> > > > > >   return 0;\n> > > > > >  }\n> > > > > >\n> > > > > > -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> > > > > > +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > +                                  std::shared_ptr<MediaDevice> unicam,\n> > > > > > +                                  std::shared_ptr<MediaDevice> isp)\n> > > > > >  {\n> > > > > >   Vc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n> > > > > >\n> > > > > > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > > > > > index 451491f5608e..feaa16094b65 100644\n> > > > > > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > > > > > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > > > > > @@ -407,7 +407,7 @@ public:\n> > > > > >\n> > > > > >   V4L2VideoDevice *video(const MediaEntity *entity);\n> > > > > >   V4L2Subdevice *subdev(const MediaEntity *entity);\n> > > > > > - MediaDevice *converter() { return converter_; }\n> > > > > > + MediaDevice *converter() { return converter_.get(); }\n> > > > > >   bool swIspEnabled() const { return swIspEnabled_; }\n> > > > > >\n> > > > > >  protected:\n> > > > > > @@ -427,7 +427,8 @@ private:\n> > > > > >           return static_cast<SimpleCameraData *>(camera->_d());\n> > > > > >   }\n> > > > > >\n> > > > > > - bool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> > > > > > + bool matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > > > +                  const SimplePipelineInfo &info,\n> > > > > >                    DeviceEnumerator *enumerator);\n> > > > > >\n> > > > > >   std::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > > > > > @@ -438,7 +439,7 @@ private:\n> > > > > >\n> > > > > >   std::map<const MediaEntity *, EntityData> entities_;\n> > > > > >\n> > > > > > - MediaDevice *converter_;\n> > > > > > + std::shared_ptr<MediaDevice> converter_;\n> > > > > >   bool swIspEnabled_;\n> > > > > >  };\n> > > > > >\n> > > > > > @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n> > > > > >   return 0;\n> > > > > >  }\n> > > > > >\n> > > > > > -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > > +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > > >                                   const SimplePipelineInfo &info,\n> > > > > >                                   DeviceEnumerator *enumerator)\n> > > > > >  {\n> > > > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > >   swIspEnabled_ = info.swIspEnabled;\n> > > > > >\n> > > > > >   /* Locate the sensors. */\n> > > > > > - std::vector<MediaEntity *> sensors = locateSensors(media);\n> > > > > > + std::vector<MediaEntity *> sensors = locateSensors(media.get());\n> > > > > >   if (sensors.empty()) {\n> > > > > >           LOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n> > > > > >           return false;\n> > > > > > @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > >\n> > > > > >  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n> > > > > >  {\n> > > > > > - MediaDevice *media;\n> > > > > > + std::shared_ptr<MediaDevice> media;\n> > > > > >\n> > > > > >   for (const SimplePipelineInfo &inf : supportedDevices) {\n> > > > > >           DeviceMatch dm(inf.driver);\n> > > > > > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > > index 5adc89fdb29c..a1e036a32d5f 100644\n> > > > > > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > > @@ -46,7 +46,7 @@ public:\n> > > > > >   {\n> > > > > >   }\n> > > > > >\n> > > > > > - int init(MediaDevice *media);\n> > > > > > + int init(std::shared_ptr<MediaDevice> media);\n> > > > > >   void addControl(uint32_t cid, const ControlInfo &v4l2info,\n> > > > > >                   ControlInfoMap::Map *ctrls);\n> > > > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > > > @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n> > > > > >\n> > > > > >  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n> > > > > >  {\n> > > > > > - MediaDevice *media;\n> > > > > > + std::shared_ptr<MediaDevice> media;\n> > > > > >   DeviceMatch dm(\"uvcvideo\");\n> > > > > >\n> > > > > >   media = acquireMediaDevice(enumerator, dm);\n> > > > > > @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n> > > > > >   data->video_->close();\n> > > > > >  }\n> > > > > >\n> > > > > > -int UVCCameraData::init(MediaDevice *media)\n> > > > > > +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n> > > > > >  {\n> > > > > >   int ret;\n> > > > > >\n> > > > > > diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > > index 07273bd2b6c3..59c564b8a9f6 100644\n> > > > > > --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > > +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > > @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n> > > > > >  class VimcCameraData : public Camera::Private\n> > > > > >  {\n> > > > > >  public:\n> > > > > > - VimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> > > > > > + VimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n> > > > > >           : Camera::Private(pipe), media_(media)\n> > > > > >   {\n> > > > > >   }\n> > > > > > @@ -59,7 +59,7 @@ public:\n> > > > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > > >   void paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n> > > > > >\n> > > > > > - MediaDevice *media_;\n> > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > >   std::unique_ptr<CameraSensor> sensor_;\n> > > > > >   std::unique_ptr<V4L2Subdevice> debayer_;\n> > > > > >   std::unique_ptr<V4L2Subdevice> scaler_;\n> > > > > > @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n> > > > > >   dm.add(\"RGB/YUV Input\");\n> > > > > >   dm.add(\"Scaler\");\n> > > > > >\n> > > > > > - MediaDevice *media = acquireMediaDevice(enumerator, dm);\n> > > > > > + std::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n> > > > > >   if (!media)\n> > > > > >           return false;\n> > > > > >\n> > > > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > > > > > index 8f12957b75fa..5fe2c64c8bc6 100644\n> > > > > > --- a/src/libcamera/pipeline_handler.cpp\n> > > > > > +++ b/src/libcamera/pipeline_handler.cpp\n> > > > > > @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n> > > > > >   *\n> > > > > >   * \\context This function shall be called from the CameraManager thread.\n> > > > > >   *\n> > > > > > - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> > > > > > + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> > > > > > + * is found\n> > > > > >   */\n> > > > > > -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > -                                          const DeviceMatch &dm)\n> > > > > > +std::shared_ptr<MediaDevice>\n> > > > > > +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > +                             const DeviceMatch &dm)\n> > > > > >  {\n> > > > > >   std::shared_ptr<MediaDevice> media = enumerator->search(dm);\n> > > > > >   if (!media)\n> > > > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > >\n> > > > > >   mediaDevices_.push_back(media);\n> > > > > >\n> > > > > > - return media.get();\n> > > > > > + return media;\n> > > > > >  }\n> > > > > >\n> > > > > >  /**\n> > > > > > @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n> > > > > >   * handler gets notified and automatically disconnects all the cameras it has\n> > > > > >   * registered without requiring any manual intervention.\n> > > > > >   */\n> > > > > > -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > > > +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n> > > > > >  {\n> > > > > >   media->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n> > > > > >  }\n> > > > > > @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > > >  /**\n> > > > > >   * \\brief Slot for the MediaDevice disconnected signal\n> > > > > >   */\n> > > > > > -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> > > > > > +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n> > > > > >  {\n> > > > > >   media->disconnected.disconnect(this);\n> > > > > >\n> > > > > > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > > > > > index 7bd30e7aead8..b305be48aafc 100644\n> > > > > > --- a/test/delayed_controls.cpp\n> > > > > > +++ b/test/delayed_controls.cpp\n> > > > > > @@ -47,7 +47,7 @@ protected:\n> > > > > >                   return TestSkip;\n> > > > > >           }\n> > > > > >\n> > > > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> > > > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n> > > > > >           if (dev_->open()) {\n> > > > > >                   cerr << \"Failed to open video device\" << endl;\n> > > > > >                   return TestFail;\n> > > > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> > > > > > index dde11f365e43..19b25fed50a0 100644\n> > > > > > --- a/test/libtest/buffer_source.cpp\n> > > > > > +++ b/test/libtest/buffer_source.cpp\n> > > > > > @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n> > > > > >           return TestSkip;\n> > > > > >   }\n> > > > > >\n> > > > > > - std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> > > > > > + std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n> > > > > >   if (!video) {\n> > > > > >           std::cout << \"Failed to get video device from entity \"\n> > > > > >                     << videoDeviceName << std::endl;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 9545DC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 15 Sep 2025 14:55:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5101F6936F;\n\tMon, 15 Sep 2025 16:55:08 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 492DA613A0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 15 Sep 2025 16:55:06 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 5B422B0B;\n\tMon, 15 Sep 2025 16:53:48 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"P1wxUrzo\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1757948028;\n\tbh=kXBE/bRXjFd05F9PpFy74HyjQCnd1JtZtTpOBbJxaks=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=P1wxUrzoRlvIth0L6xl8G/hAUKs9emlVY6MWPsoCLNdHzViLzHLdv2KNsmx326bkf\n\t1XjxrxJUY6JiIMn1/qR5PQsMulQ0k8w+iXXpLHKKZ0IrrqzQQwPHP58EQCypbjgkD0\n\t/Qgr1TuVOZlVzsI2ACNy3EZU2QgGnPWyJyfaxbCE=","Date":"Mon, 15 Sep 2025 17:54:39 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","Message-ID":"<20250915145439.GB8821@pendragon.ideasonboard.com>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>\n\t<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>\n\t<20250406181629.GP4845@pendragon.ideasonboard.com>\n\t<aAdj7FovC9TPJj4z@pyrite.rasen.tech>\n\t<174714237995.233090.4884438906870237379@pyrite.rasen.tech>\n\t<175794737274.653594.10680797466701805213@localhost>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<175794737274.653594.10680797466701805213@localhost>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35832,"web_url":"https://patchwork.libcamera.org/comment/35832/","msgid":"<175795001868.653594.15823523647901359434@localhost>","date":"2025-09-15T15:26:58","subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2025-09-15 16:54:39)\n> On Mon, Sep 15, 2025 at 04:42:52PM +0200, Stefan Klug wrote:\n> > Quoting Paul Elder (2025-05-13 15:19:39)\n> > > Quoting Paul Elder (2025-04-22 11:39:56)\n> > > > On Sun, Apr 06, 2025 at 09:16:29PM +0300, Laurent Pinchart wrote:\n> > > > > On Sun, Apr 06, 2025 at 06:53:34PM +0200, Jacopo Mondi wrote:\n> > > > > > On Fri, Apr 04, 2025 at 04:46:22PM +0900, Paul Elder wrote:\n> > > > > > > From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > > > >\n> > > > > > > Adapt the PipelineHandler::acquireMediaDevice() support function to\n> > > > > > > return a shared pointer instead of the underlying raw pointer.\n> > > > > > \n> > > > > > It seems nice, but I wonder if it really is better ? The\n> > > > > > PipelineHandler base class already stores a shared_ptr<> instance for\n> > > > > > each acquired media device. Is passing it around by value and storing\n> > > > > > a copy as classes member in derived classes worth it ?\n> > > > > > \n> > > > > > Or is this about an ownership issue I am missing ?\n> > > > > \n> > > > > I'm also wondering the same. Paul, could you explain the rationale for\n> > > > > this patch series ?\n> > > > \n> > > > I thought I did in the cover letter... oh that's really short huh...\n> > > > \n> > > > We had a platform with a really complex media graph that could be\n> > > > summarized as a simple pipeline and an rkisp1 pipeline combined via a\n> > > > mux in between the sensors and the CSI receivers. The correct long-term\n> > > > solution is modular pipeline handlers, but since we're not there yet we\n> > > > settled with creating a simple pipeline handler inside the rkisp1\n> > > > pipeline handler.\n> > > > \n> > > > To prevent both pipeline handlers from trying to acquire the media\n> > > > devices that are shared between the two paths, it was better to change\n> > > > ownership of the media devices to shared so that we could register the\n> > > > media devices in the second pipeline handler without having to\n> > > > re-acquire and manage the lifetime.\n> > > > \n> > > > It seemed useful to upstream at least this portion.\n> > \n> > I have another use case for this change. In my work to bring the full\n> > dewarper support upstream I needed to add V4L2 requests support to the\n> > dewarper. These requests are allocated with a call to the medie device.\n> > So the dewarper (which is implemented as V4L2M2MConverter) needs to hold\n> > a pointer to the media device it was constructed for. Normally the\n> > converter only gets a MediaDevice pointer passed to the constructor.\n> > Holding on that plain pointer in the converter feels not good at all,\n> > even though the lifetime of the converter will be tried to the pipeline\n> > handler if I'm not mistaken.\n> \n> I don't want to use shared pointers as a magic solution without a proper\n> analysis, given how intrusive they are. For your particular use case,\n> how do you plan for the converter to reach to the media device removal ?\n\nI guess it is not sufficient to say \"I did not plan for media device\nremoval\"... :-) So let me quickly whip up my idea of how I would\nenvision media device removal. I'd expect that converters aka \"clients\"\nwould be able to listen on a removal signal and should let go of the\nshared pointer, or the pipeline handler needs to delete them. We could\neven go the extra step and advocate that no entity must hold a pointer\nto a media object after that signal was sent. Then we could check the\nuse_count on our shared pointer to see if there are still entities\nincorrectly holding on to it (The aquire/release pair is something I'm\nmore concerned about and don't yet know if we will need some kind of\nrefcounting there, too).\n\nOverall I don't think that passing raw pointers around helps in keeping\nthe architecture sane. It only creates a unmanaged C-ish world that\nfeels more like kernel code. I think raw pointers should only be used if\nthe related shared_prt is close by (like the FrameBuffer pointers in the\npipeline handlers). So if we create reusable components then they\nshouldn't store raw pointers to anything they didn't allocate.\n\nBest regards,\nStefan\n\n> \n> > So overall I'd like to advocate for this\n> > switch from raw pointers to shared pointers :-)\n> > \n> > Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> \n> > Tested-by: Stefan Klug <stefan.klug@ideasonboard.com> \n> > \n> > > > > > > Propagate this update to all pipeline handlers that use the MediaDevice\n> > > > > > > and store a std::shared_ptr<MediaDevice> accordingly.\n> > > > > > >\n> > > > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > > > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > > > > > > ---\n> > > > > > >  include/libcamera/internal/pipeline_handler.h      |  8 ++++----\n> > > > > > >  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp       |  2 +-\n> > > > > > >  src/libcamera/pipeline/ipu3/cio2.cpp               |  2 +-\n> > > > > > >  src/libcamera/pipeline/ipu3/cio2.h                 |  2 +-\n> > > > > > >  src/libcamera/pipeline/ipu3/imgu.cpp               |  3 ++-\n> > > > > > >  src/libcamera/pipeline/ipu3/imgu.h                 |  4 ++--\n> > > > > > >  src/libcamera/pipeline/ipu3/ipu3.cpp               |  4 ++--\n> > > > > > >  src/libcamera/pipeline/mali-c55/mali-c55.cpp       |  2 +-\n> > > > > > >  src/libcamera/pipeline/rkisp1/rkisp1.cpp           |  2 +-\n> > > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.cpp      |  2 +-\n> > > > > > >  src/libcamera/pipeline/rkisp1/rkisp1_path.h        |  2 +-\n> > > > > > >  .../pipeline/rpi/common/pipeline_base.cpp          |  6 ++++--\n> > > > > > >  src/libcamera/pipeline/rpi/common/pipeline_base.h  |  9 ++++++---\n> > > > > > >  src/libcamera/pipeline/rpi/pisp/pisp.cpp           | 10 ++++++----\n> > > > > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp             | 13 +++++++++----\n> > > > > > >  src/libcamera/pipeline/simple/simple.cpp           | 13 +++++++------\n> > > > > > >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp       |  6 +++---\n> > > > > > >  src/libcamera/pipeline/vimc/vimc.cpp               |  6 +++---\n> > > > > > >  src/libcamera/pipeline_handler.cpp                 | 14 ++++++++------\n> > > > > > >  test/delayed_controls.cpp                          |  2 +-\n> > > > > > >  test/libtest/buffer_source.cpp                     |  2 +-\n> > > > > > >  21 files changed, 65 insertions(+), 49 deletions(-)\n> > > > > > >\n> > > > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > > > > > > index 5fa8bc2f66ee..0199ab7911c0 100644\n> > > > > > > --- a/include/libcamera/internal/pipeline_handler.h\n> > > > > > > +++ b/include/libcamera/internal/pipeline_handler.h\n> > > > > > > @@ -38,8 +38,8 @@ public:\n> > > > > > >   virtual ~PipelineHandler();\n> > > > > > >\n> > > > > > >   virtual bool match(DeviceEnumerator *enumerator) = 0;\n> > > > > > > - MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > > -                                 const DeviceMatch &dm);\n> > > > > > > + std::shared_ptr<MediaDevice> acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > > +                                                 const DeviceMatch &dm);\n> > > > > > >\n> > > > > > >   bool acquire(Camera *camera);\n> > > > > > >   void release(Camera *camera);\n> > > > > > > @@ -74,7 +74,7 @@ protected:\n> > > > > > >   void clearMediaDevices();\n> > > > > > >\n> > > > > > >   void registerCamera(std::shared_ptr<Camera> camera);\n> > > > > > > - void hotplugMediaDevice(MediaDevice *media);\n> > > > > > > + void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> > > > > > >\n> > > > > > >   virtual int queueRequestDevice(Camera *camera, Request *request) = 0;\n> > > > > > >   virtual void stopDevice(Camera *camera) = 0;\n> > > > > > > @@ -87,7 +87,7 @@ protected:\n> > > > > > >  private:\n> > > > > > >   void unlockMediaDevices();\n> > > > > > >\n> > > > > > > - void mediaDeviceDisconnected(MediaDevice *media);\n> > > > > > > + void mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media);\n> > > > > > >   virtual void disconnect();\n> > > > > > >\n> > > > > > >   void doQueueRequest(Request *request);\n> > > > > > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > > > index 4e66b3368d5a..850dbfcdc64b 100644\n> > > > > > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > > > > > @@ -139,7 +139,7 @@ private:\n> > > > > > >\n> > > > > > >   void bufferReady(FrameBuffer *buffer);\n> > > > > > >\n> > > > > > > - MediaDevice *isiDev_;\n> > > > > > > + std::shared_ptr<MediaDevice> isiDev_;\n> > > > > > >\n> > > > > > >   std::unique_ptr<V4L2Subdevice> crossbar_;\n> > > > > > >   std::vector<Pipe> pipes_;\n> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > > > index aa544d7b0303..ebbd424c56ea 100644\n> > > > > > > --- a/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/ipu3/cio2.cpp\n> > > > > > > @@ -112,7 +112,7 @@ std::vector<SizeRange> CIO2Device::sizes(const PixelFormat &format) const\n> > > > > > >   * \\return 0 on success or a negative error code otherwise\n> > > > > > >   * \\retval -ENODEV No supported image sensor is connected to this CIO2 instance\n> > > > > > >   */\n> > > > > > > -int CIO2Device::init(const MediaDevice *media, unsigned int index)\n> > > > > > > +int CIO2Device::init(std::shared_ptr<const MediaDevice> media, unsigned int index)\n> > > > > > >  {\n> > > > > > >   int ret;\n> > > > > > >\n> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > > > index 963c2f6b93a4..fdf85f2655f0 100644\n> > > > > > > --- a/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > > > +++ b/src/libcamera/pipeline/ipu3/cio2.h\n> > > > > > > @@ -38,7 +38,7 @@ public:\n> > > > > > >   std::vector<PixelFormat> formats() const;\n> > > > > > >   std::vector<SizeRange> sizes(const PixelFormat &format) const;\n> > > > > > >\n> > > > > > > - int init(const MediaDevice *media, unsigned int index);\n> > > > > > > + int init(std::shared_ptr<const MediaDevice> media, unsigned int index);\n> > > > > > >   int configure(const Size &size, const Transform &transform,\n> > > > > > >                 V4L2DeviceFormat *outputFormat);\n> > > > > > >\n> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > > > index 7be780913fae..391e000f6e12 100644\n> > > > > > > --- a/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> > > > > > > @@ -330,7 +330,8 @@ FOV calcFOV(const Size &in, const ImgUDevice::PipeConfig &pipe)\n> > > > > > >   *\n> > > > > > >   * \\return 0 on success or a negative error code otherwise\n> > > > > > >   */\n> > > > > > > -int ImgUDevice::init(MediaDevice *media, unsigned int index)\n> > > > > > > +int ImgUDevice::init(std::shared_ptr<libcamera::MediaDevice> media,\n> > > > > > > +              unsigned int index)\n> > > > > > >  {\n> > > > > > >   int ret;\n> > > > > > >\n> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/imgu.h b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > > > index fa508316b301..272f861f98c4 100644\n> > > > > > > --- a/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > > > +++ b/src/libcamera/pipeline/ipu3/imgu.h\n> > > > > > > @@ -64,7 +64,7 @@ public:\n> > > > > > >           Size viewfinder;\n> > > > > > >   };\n> > > > > > >\n> > > > > > > - int init(MediaDevice *media, unsigned int index);\n> > > > > > > + int init(std::shared_ptr<MediaDevice> media, unsigned int index);\n> > > > > > >\n> > > > > > >   PipeConfig calculatePipeConfig(Pipe *pipe);\n> > > > > > >\n> > > > > > > @@ -118,7 +118,7 @@ private:\n> > > > > > >                            V4L2DeviceFormat *outputFormat);\n> > > > > > >\n> > > > > > >   std::string name_;\n> > > > > > > - MediaDevice *media_;\n> > > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > > >  };\n> > > > > > >\n> > > > > > >  } /* namespace libcamera */\n> > > > > > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > > > index e31e3879dcc9..17205f96446a 100644\n> > > > > > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > > > > > @@ -164,8 +164,8 @@ private:\n> > > > > > >\n> > > > > > >   ImgUDevice imgu0_;\n> > > > > > >   ImgUDevice imgu1_;\n> > > > > > > - MediaDevice *cio2MediaDev_;\n> > > > > > > - MediaDevice *imguMediaDev_;\n> > > > > > > + std::shared_ptr<MediaDevice> cio2MediaDev_;\n> > > > > > > + std::shared_ptr<MediaDevice> imguMediaDev_;\n> > > > > > >\n> > > > > > >   std::vector<IPABuffer> ipaBuffers_;\n> > > > > > >  };\n> > > > > > > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > > > index a05e11fccf8d..7615122d907b 100644\n> > > > > > > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > > > > > > @@ -684,7 +684,7 @@ private:\n> > > > > > >   bool registerTPGCamera(MediaLink *link);\n> > > > > > >   bool registerSensorCamera(MediaLink *link);\n> > > > > > >\n> > > > > > > - MediaDevice *media_;\n> > > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > > > > >   std::unique_ptr<V4L2VideoDevice> stats_;\n> > > > > > >   std::unique_ptr<V4L2VideoDevice> params_;\n> > > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > > > index 705615b86b0c..d4ec538f478b 100644\n> > > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> > > > > > > @@ -200,7 +200,7 @@ private:\n> > > > > > >\n> > > > > > >   int updateControls(RkISP1CameraData *data);\n> > > > > > >\n> > > > > > > - MediaDevice *media_;\n> > > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > > >   std::unique_ptr<V4L2Subdevice> isp_;\n> > > > > > >   std::unique_ptr<V4L2VideoDevice> param_;\n> > > > > > >   std::unique_ptr<V4L2VideoDevice> stat_;\n> > > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > > > index eee5b09e2ff0..2e567ace0b78 100644\n> > > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n> > > > > > > @@ -59,7 +59,7 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats)\n> > > > > > >  {\n> > > > > > >  }\n> > > > > > >\n> > > > > > > -bool RkISP1Path::init(MediaDevice *media)\n> > > > > > > +bool RkISP1Path::init(std::shared_ptr<MediaDevice> media)\n> > > > > > >  {\n> > > > > > >   std::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n> > > > > > >   std::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n> > > > > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > > > index 2a1ef0abe6d1..154310ac37c1 100644\n> > > > > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n> > > > > > > @@ -36,7 +36,7 @@ class RkISP1Path\n> > > > > > >  public:\n> > > > > > >   RkISP1Path(const char *name, const Span<const PixelFormat> &formats);\n> > > > > > >\n> > > > > > > - bool init(MediaDevice *media);\n> > > > > > > + bool init(std::shared_ptr<MediaDevice> media);\n> > > > > > >\n> > > > > > >   int setEnabled(bool enable) { return link_->setEnabled(enable); }\n> > > > > > >   bool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n> > > > > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > > > index 1f13e5230fae..23ce54eca144 100644\n> > > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > > > > > > @@ -784,8 +784,10 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n> > > > > > >  }\n> > > > > > >\n> > > > > > >  int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > > -                                 MediaDevice *frontend, const std::string &frontendName,\n> > > > > > > -                                 MediaDevice *backend, MediaEntity *sensorEntity)\n> > > > > > > +                                 std::shared_ptr<MediaDevice> frontend,\n> > > > > > > +                                 const std::string &frontendName,\n> > > > > > > +                                 std::shared_ptr<MediaDevice> backend,\n> > > > > > > +                                 MediaEntity *sensorEntity)\n> > > > > > >  {\n> > > > > > >   CameraData *data = cameraData.get();\n> > > > > > >   int ret;\n> > > > > > > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > > > index aae0c2f35888..e422bbf7405f 100644\n> > > > > > > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > > > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> > > > > > > @@ -229,13 +229,16 @@ public:\n> > > > > > >\n> > > > > > >  protected:\n> > > > > > >   int registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > > -                    MediaDevice *frontent, const std::string &frontendName,\n> > > > > > > -                    MediaDevice *backend, MediaEntity *sensorEntity);\n> > > > > > > +                    std::shared_ptr<MediaDevice> frontend,\n> > > > > > > +                    const std::string &frontendName,\n> > > > > > > +                    std::shared_ptr<MediaDevice> backend,\n> > > > > > > +                    MediaEntity *sensorEntity);\n> > > > > > >\n> > > > > > >   void mapBuffers(Camera *camera, const BufferMap &buffers, unsigned int mask);\n> > > > > > >\n> > > > > > >   virtual int platformRegister(std::unique_ptr<CameraData> &cameraData,\n> > > > > > > -                              MediaDevice *unicam, MediaDevice *isp) = 0;\n> > > > > > > +                              std::shared_ptr<MediaDevice> unicam,\n> > > > > > > +                              std::shared_ptr<MediaDevice> isp) = 0;\n> > > > > > >\n> > > > > > >  private:\n> > > > > > >   CameraData *cameraData(Camera *camera)\n> > > > > > > diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > > > index 91e7f4c94d96..d0cb71b49e11 100644\n> > > > > > > --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> > > > > > > @@ -866,7 +866,8 @@ private:\n> > > > > > >\n> > > > > > >   int prepareBuffers(Camera *camera) override;\n> > > > > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > > -                      MediaDevice *cfe, MediaDevice *isp) override;\n> > > > > > > +                      std::shared_ptr<MediaDevice> cfe,\n> > > > > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > > > > >  };\n> > > > > > >\n> > > > > > >  bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > > > @@ -884,7 +885,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > > >           cfe.add(\"rp1-cfe-fe-image0\");\n> > > > > > >           cfe.add(\"rp1-cfe-fe-stats\");\n> > > > > > >           cfe.add(\"rp1-cfe-fe-config\");\n> > > > > > > -         MediaDevice *cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > > > > +         std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);\n> > > > > > >\n> > > > > > >           if (!cfeDevice) {\n> > > > > > >                   LOG(RPI, Debug) << \"Unable to acquire a CFE instance\";\n> > > > > > > @@ -900,7 +901,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n> > > > > > >           isp.add(\"pispbe-tdn_input\");\n> > > > > > >           isp.add(\"pispbe-stitch_output\");\n> > > > > > >           isp.add(\"pispbe-stitch_input\");\n> > > > > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > > >\n> > > > > > >           if (!ispDevice) {\n> > > > > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > > > > @@ -1065,7 +1066,8 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n> > > > > > >  }\n> > > > > > >\n> > > > > > >  int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > > -                                   MediaDevice *cfe, MediaDevice *isp)\n> > > > > > > +                                   std::shared_ptr<MediaDevice> cfe,\n> > > > > > > +                                   std::shared_ptr<MediaDevice> isp)\n> > > > > > >  {\n> > > > > > >   PiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n> > > > > > >   int ret;\n> > > > > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > > > index fe910bdf2ff9..d58035ecd198 100644\n> > > > > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> > > > > > > @@ -5,6 +5,8 @@\n> > > > > > >   * Pipeline handler for VC4-based Raspberry Pi devices\n> > > > > > >   */\n> > > > > > >\n> > > > > > > +#include <memory>\n> > > > > > > +\n> > > > > > >  #include <linux/bcm2835-isp.h>\n> > > > > > >  #include <linux/v4l2-controls.h>\n> > > > > > >  #include <linux/videodev2.h>\n> > > > > > > @@ -158,7 +160,8 @@ private:\n> > > > > > >\n> > > > > > >   int prepareBuffers(Camera *camera) override;\n> > > > > > >   int platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > > -                      MediaDevice *unicam, MediaDevice *isp) override;\n> > > > > > > +                      std::shared_ptr<MediaDevice> unicam,\n> > > > > > > +                      std::shared_ptr<MediaDevice> isp) override;\n> > > > > > >  };\n> > > > > > >\n> > > > > > >  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > > > @@ -173,7 +176,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > > >    */\n> > > > > > >   for (unsigned int i = 0; i < numUnicamDevices; i++) {\n> > > > > > >           DeviceMatch unicam(\"unicam\");\n> > > > > > > -         MediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > > > > +         std::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);\n> > > > > > >\n> > > > > > >           if (!unicamDevice) {\n> > > > > > >                   LOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n> > > > > > > @@ -181,7 +184,7 @@ bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)\n> > > > > > >           }\n> > > > > > >\n> > > > > > >           DeviceMatch isp(\"bcm2835-isp\");\n> > > > > > > -         MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > > > +         std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n> > > > > > >\n> > > > > > >           if (!ispDevice) {\n> > > > > > >                   LOG(RPI, Debug) << \"Unable to acquire ISP instance\";\n> > > > > > > @@ -303,7 +306,9 @@ int PipelineHandlerVc4::prepareBuffers(Camera *camera)\n> > > > > > >   return 0;\n> > > > > > >  }\n> > > > > > >\n> > > > > > > -int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData, MediaDevice *unicam, MediaDevice *isp)\n> > > > > > > +int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n> > > > > > > +                                  std::shared_ptr<MediaDevice> unicam,\n> > > > > > > +                                  std::shared_ptr<MediaDevice> isp)\n> > > > > > >  {\n> > > > > > >   Vc4CameraData *data = static_cast<Vc4CameraData *>(cameraData.get());\n> > > > > > >\n> > > > > > > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> > > > > > > index 451491f5608e..feaa16094b65 100644\n> > > > > > > --- a/src/libcamera/pipeline/simple/simple.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/simple/simple.cpp\n> > > > > > > @@ -407,7 +407,7 @@ public:\n> > > > > > >\n> > > > > > >   V4L2VideoDevice *video(const MediaEntity *entity);\n> > > > > > >   V4L2Subdevice *subdev(const MediaEntity *entity);\n> > > > > > > - MediaDevice *converter() { return converter_; }\n> > > > > > > + MediaDevice *converter() { return converter_.get(); }\n> > > > > > >   bool swIspEnabled() const { return swIspEnabled_; }\n> > > > > > >\n> > > > > > >  protected:\n> > > > > > > @@ -427,7 +427,8 @@ private:\n> > > > > > >           return static_cast<SimpleCameraData *>(camera->_d());\n> > > > > > >   }\n> > > > > > >\n> > > > > > > - bool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n> > > > > > > + bool matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > > > > +                  const SimplePipelineInfo &info,\n> > > > > > >                    DeviceEnumerator *enumerator);\n> > > > > > >\n> > > > > > >   std::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > > > > > > @@ -438,7 +439,7 @@ private:\n> > > > > > >\n> > > > > > >   std::map<const MediaEntity *, EntityData> entities_;\n> > > > > > >\n> > > > > > > - MediaDevice *converter_;\n> > > > > > > + std::shared_ptr<MediaDevice> converter_;\n> > > > > > >   bool swIspEnabled_;\n> > > > > > >  };\n> > > > > > >\n> > > > > > > @@ -1663,7 +1664,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n> > > > > > >   return 0;\n> > > > > > >  }\n> > > > > > >\n> > > > > > > -bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > > > +bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,\n> > > > > > >                                   const SimplePipelineInfo &info,\n> > > > > > >                                   DeviceEnumerator *enumerator)\n> > > > > > >  {\n> > > > > > > @@ -1681,7 +1682,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > > >   swIspEnabled_ = info.swIspEnabled;\n> > > > > > >\n> > > > > > >   /* Locate the sensors. */\n> > > > > > > - std::vector<MediaEntity *> sensors = locateSensors(media);\n> > > > > > > + std::vector<MediaEntity *> sensors = locateSensors(media.get());\n> > > > > > >   if (sensors.empty()) {\n> > > > > > >           LOG(SimplePipeline, Info) << \"No sensor found for \" << media->deviceNode();\n> > > > > > >           return false;\n> > > > > > > @@ -1799,7 +1800,7 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n> > > > > > >\n> > > > > > >  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n> > > > > > >  {\n> > > > > > > - MediaDevice *media;\n> > > > > > > + std::shared_ptr<MediaDevice> media;\n> > > > > > >\n> > > > > > >   for (const SimplePipelineInfo &inf : supportedDevices) {\n> > > > > > >           DeviceMatch dm(inf.driver);\n> > > > > > > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > > > index 5adc89fdb29c..a1e036a32d5f 100644\n> > > > > > > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> > > > > > > @@ -46,7 +46,7 @@ public:\n> > > > > > >   {\n> > > > > > >   }\n> > > > > > >\n> > > > > > > - int init(MediaDevice *media);\n> > > > > > > + int init(std::shared_ptr<MediaDevice> media);\n> > > > > > >   void addControl(uint32_t cid, const ControlInfo &v4l2info,\n> > > > > > >                   ControlInfoMap::Map *ctrls);\n> > > > > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > > > > @@ -449,7 +449,7 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)\n> > > > > > >\n> > > > > > >  bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n> > > > > > >  {\n> > > > > > > - MediaDevice *media;\n> > > > > > > + std::shared_ptr<MediaDevice> media;\n> > > > > > >   DeviceMatch dm(\"uvcvideo\");\n> > > > > > >\n> > > > > > >   media = acquireMediaDevice(enumerator, dm);\n> > > > > > > @@ -491,7 +491,7 @@ void PipelineHandlerUVC::releaseDevice(Camera *camera)\n> > > > > > >   data->video_->close();\n> > > > > > >  }\n> > > > > > >\n> > > > > > > -int UVCCameraData::init(MediaDevice *media)\n> > > > > > > +int UVCCameraData::init(std::shared_ptr<MediaDevice> media)\n> > > > > > >  {\n> > > > > > >   int ret;\n> > > > > > >\n> > > > > > > diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > > > index 07273bd2b6c3..59c564b8a9f6 100644\n> > > > > > > --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > > > +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> > > > > > > @@ -49,7 +49,7 @@ LOG_DEFINE_CATEGORY(VIMC)\n> > > > > > >  class VimcCameraData : public Camera::Private\n> > > > > > >  {\n> > > > > > >  public:\n> > > > > > > - VimcCameraData(PipelineHandler *pipe, MediaDevice *media)\n> > > > > > > + VimcCameraData(PipelineHandler *pipe, std::shared_ptr<MediaDevice> media)\n> > > > > > >           : Camera::Private(pipe), media_(media)\n> > > > > > >   {\n> > > > > > >   }\n> > > > > > > @@ -59,7 +59,7 @@ public:\n> > > > > > >   void imageBufferReady(FrameBuffer *buffer);\n> > > > > > >   void paramsComputed(unsigned int id, const Flags<ipa::vimc::TestFlag> flags);\n> > > > > > >\n> > > > > > > - MediaDevice *media_;\n> > > > > > > + std::shared_ptr<MediaDevice> media_;\n> > > > > > >   std::unique_ptr<CameraSensor> sensor_;\n> > > > > > >   std::unique_ptr<V4L2Subdevice> debayer_;\n> > > > > > >   std::unique_ptr<V4L2Subdevice> scaler_;\n> > > > > > > @@ -476,7 +476,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)\n> > > > > > >   dm.add(\"RGB/YUV Input\");\n> > > > > > >   dm.add(\"Scaler\");\n> > > > > > >\n> > > > > > > - MediaDevice *media = acquireMediaDevice(enumerator, dm);\n> > > > > > > + std::shared_ptr<MediaDevice> media = acquireMediaDevice(enumerator, dm);\n> > > > > > >   if (!media)\n> > > > > > >           return false;\n> > > > > > >\n> > > > > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > > > > > > index 8f12957b75fa..5fe2c64c8bc6 100644\n> > > > > > > --- a/src/libcamera/pipeline_handler.cpp\n> > > > > > > +++ b/src/libcamera/pipeline_handler.cpp\n> > > > > > > @@ -125,10 +125,12 @@ PipelineHandler::~PipelineHandler()\n> > > > > > >   *\n> > > > > > >   * \\context This function shall be called from the CameraManager thread.\n> > > > > > >   *\n> > > > > > > - * \\return A pointer to the matching MediaDevice, or nullptr if no match is found\n> > > > > > > + * \\return A shared pointer to the matching MediaDevice, or nullptr if no match\n> > > > > > > + * is found\n> > > > > > >   */\n> > > > > > > -MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > > -                                          const DeviceMatch &dm)\n> > > > > > > +std::shared_ptr<MediaDevice>\n> > > > > > > +PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > > +                             const DeviceMatch &dm)\n> > > > > > >  {\n> > > > > > >   std::shared_ptr<MediaDevice> media = enumerator->search(dm);\n> > > > > > >   if (!media)\n> > > > > > > @@ -139,7 +141,7 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,\n> > > > > > >\n> > > > > > >   mediaDevices_.push_back(media);\n> > > > > > >\n> > > > > > > - return media.get();\n> > > > > > > + return media;\n> > > > > > >  }\n> > > > > > >\n> > > > > > >  /**\n> > > > > > > @@ -712,7 +714,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n> > > > > > >   * handler gets notified and automatically disconnects all the cameras it has\n> > > > > > >   * registered without requiring any manual intervention.\n> > > > > > >   */\n> > > > > > > -void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > > > > +void PipelineHandler::hotplugMediaDevice(std::shared_ptr<MediaDevice> media)\n> > > > > > >  {\n> > > > > > >   media->disconnected.connect(this, [this, media] { mediaDeviceDisconnected(media); });\n> > > > > > >  }\n> > > > > > > @@ -720,7 +722,7 @@ void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n> > > > > > >  /**\n> > > > > > >   * \\brief Slot for the MediaDevice disconnected signal\n> > > > > > >   */\n> > > > > > > -void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n> > > > > > > +void PipelineHandler::mediaDeviceDisconnected(std::shared_ptr<MediaDevice> media)\n> > > > > > >  {\n> > > > > > >   media->disconnected.disconnect(this);\n> > > > > > >\n> > > > > > > diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> > > > > > > index 7bd30e7aead8..b305be48aafc 100644\n> > > > > > > --- a/test/delayed_controls.cpp\n> > > > > > > +++ b/test/delayed_controls.cpp\n> > > > > > > @@ -47,7 +47,7 @@ protected:\n> > > > > > >                   return TestSkip;\n> > > > > > >           }\n> > > > > > >\n> > > > > > > -         dev_ = V4L2VideoDevice::fromEntityName(media_.get(), \"vivid-000-vid-cap\");\n> > > > > > > +         dev_ = V4L2VideoDevice::fromEntityName(media_, \"vivid-000-vid-cap\");\n> > > > > > >           if (dev_->open()) {\n> > > > > > >                   cerr << \"Failed to open video device\" << endl;\n> > > > > > >                   return TestFail;\n> > > > > > > diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp\n> > > > > > > index dde11f365e43..19b25fed50a0 100644\n> > > > > > > --- a/test/libtest/buffer_source.cpp\n> > > > > > > +++ b/test/libtest/buffer_source.cpp\n> > > > > > > @@ -52,7 +52,7 @@ int BufferSource::allocate(const StreamConfiguration &config)\n> > > > > > >           return TestSkip;\n> > > > > > >   }\n> > > > > > >\n> > > > > > > - std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);\n> > > > > > > + std::unique_ptr<V4L2VideoDevice> video = V4L2VideoDevice::fromEntityName(media_, videoDeviceName);\n> > > > > > >   if (!video) {\n> > > > > > >           std::cout << \"Failed to get video device from entity \"\n> > > > > > >                     << videoDeviceName << std::endl;\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id B7B5FBE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 15 Sep 2025 15:27:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6BB096936F;\n\tMon, 15 Sep 2025 17:27:03 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 25F52613A0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 15 Sep 2025 17:27:02 +0200 (CEST)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:2a47:b7e5:c39c:d1b3])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 6FB3A710;\n\tMon, 15 Sep 2025 17:25:44 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"J4IfY+T3\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1757949944;\n\tbh=jQyuURFrZkLHi1CS51mr5JVirT29LmvXGvl31+WkCSo=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=J4IfY+T3jeRUr8mx/ozCfeh1Wv6yODbxkbEffpsHBZW52pM9ULihGQ94PFcd0XUc0\n\tpISD/A5IN+72QmQOwSSEGN2JMK4BxnS/r9WT6BEk6yxV2bmRGbSuLdzXriRHNd/l43\n\tzOqAmqoCZPyxGPTsPQccQotbFZLJ4+H8g6BcmQXw=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20250915145439.GB8821@pendragon.ideasonboard.com>","References":"<20250404074624.2975182-1-paul.elder@ideasonboard.com>\n\t<20250404074624.2975182-3-paul.elder@ideasonboard.com>\n\t<7v7p2wzhxou7ql5zakwq2rehmjornpvmvncvhcyqamw332rwjq@saa2g2g5d7ci>\n\t<20250406181629.GP4845@pendragon.ideasonboard.com>\n\t<aAdj7FovC9TPJj4z@pyrite.rasen.tech>\n\t<174714237995.233090.4884438906870237379@pyrite.rasen.tech>\n\t<175794737274.653594.10680797466701805213@localhost>\n\t<20250915145439.GB8821@pendragon.ideasonboard.com>","Subject":"Re: [PATCH 2/3] libcamera: pipeline: utilise shared MediaDevice\n\tpointers","From":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Date":"Mon, 15 Sep 2025 17:26:58 +0200","Message-ID":"<175795001868.653594.15823523647901359434@localhost>","User-Agent":"alot/0.12.dev8+g2c003385c862.d20250602","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]