[libcamera-devel,1/9] libcamera: pipeline: raspberrypi: Move RPiStream into a separate header

Message ID 20200713084727.232422-2-naush@raspberrypi.com
State Superseded
Headers show
Series
  • Zero-copy RAW stream work
Related show

Commit Message

Naushir Patuck July 13, 2020, 8:47 a.m. UTC
Put RPiStream into the RPi namespace and add a new log category (RPISTREAM)

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 .../pipeline/raspberrypi/raspberrypi.cpp      | 189 ++----------------
 .../pipeline/raspberrypi/rpi_stream.h         | 182 +++++++++++++++++
 2 files changed, 199 insertions(+), 172 deletions(-)
 create mode 100644 src/libcamera/pipeline/raspberrypi/rpi_stream.h

Comments

Niklas Söderlund July 13, 2020, 11:26 a.m. UTC | #1
Hi Naushir,

Thanks for your work.

On 2020-07-13 09:47:20 +0100, Naushir Patuck wrote:
> Put RPiStream into the RPi namespace and add a new log category (RPISTREAM)

I would add that there is no functional change in this patch.

> 
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> ---
>  .../pipeline/raspberrypi/raspberrypi.cpp      | 189 ++----------------
>  .../pipeline/raspberrypi/rpi_stream.h         | 182 +++++++++++++++++

I wonder if it would make sens to move some of the code to a
rpi_stream.cpp file?

>  2 files changed, 199 insertions(+), 172 deletions(-)
>  create mode 100644 src/libcamera/pipeline/raspberrypi/rpi_stream.h
> 
> diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> index a08ad6a8..7bae72f9 100644
> --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> @@ -17,7 +17,6 @@
>  #include <libcamera/ipa/raspberrypi.h>
>  #include <libcamera/logging.h>
>  #include <libcamera/request.h>
> -#include <libcamera/stream.h>
>  
>  #include <linux/videodev2.h>
>  
> @@ -30,6 +29,7 @@
>  #include "libcamera/internal/v4l2_controls.h"
>  #include "libcamera/internal/v4l2_videodevice.h"
>  
> +#include "rpi_stream.h"
>  #include "staggered_ctrl.h"
>  #include "vcsm.h"
>  
> @@ -121,165 +121,10 @@ V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
>  	return bestMode;
>  }
>  
> -} /* namespace */
> -
> -/*
> - * Device stream abstraction for either an internal or external stream.
> - * Used for both Unicam and the ISP.
> - */
> -class RPiStream : public Stream
> -{
> -public:
> -	RPiStream()
> -	{
> -	}
> -
> -	RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
> -		: external_(false), importOnly_(importOnly), name_(name),
> -		  dev_(std::make_unique<V4L2VideoDevice>(dev))
> -	{
> -	}
> -
> -	V4L2VideoDevice *dev() const
> -	{
> -		return dev_.get();
> -	}
> -
> -	void setExternal(bool external)
> -	{
> -		external_ = external;
> -	}
> -
> -	bool isExternal() const
> -	{
> -		/*
> -		 * Import streams cannot be external.
> -		 *
> -		 * RAW capture is a special case where we simply copy the RAW
> -		 * buffer out of the request. All other buffer handling happens
> -		 * as if the stream is internal.
> -		 */
> -		return external_ && !importOnly_;
> -	}
> -
> -	bool isImporter() const
> -	{
> -		return importOnly_;
> -	}
> -
> -	void reset()
> -	{
> -		external_ = false;
> -		internalBuffers_.clear();
> -	}
> -
> -	std::string name() const
> -	{
> -		return name_;
> -	}
> -
> -	void setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> -	{
> -		externalBuffers_ = buffers;
> -	}
> -
> -	const std::vector<std::unique_ptr<FrameBuffer>> *getBuffers() const
> -	{
> -		return external_ ? externalBuffers_ : &internalBuffers_;
> -	}
> -
> -	void releaseBuffers()
> -	{
> -		dev_->releaseBuffers();
> -		if (!external_ && !importOnly_)
> -			internalBuffers_.clear();
> -	}
> -
> -	int importBuffers(unsigned int count)
> -	{
> -		return dev_->importBuffers(count);
> -	}
> -
> -	int allocateBuffers(unsigned int count)
> -	{
> -		return dev_->allocateBuffers(count, &internalBuffers_);
> -	}
> -
> -	int queueBuffers()
> -	{
> -		if (external_)
> -			return 0;
> -
> -		for (auto &b : internalBuffers_) {
> -			int ret = dev_->queueBuffer(b.get());
> -			if (ret) {
> -				LOG(RPI, Error) << "Failed to queue buffers for "
> -						<< name_;
> -				return ret;
> -			}
> -		}
> -
> -		return 0;
> -	}
> -
> -	bool findFrameBuffer(FrameBuffer *buffer) const
> -	{
> -		auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
> -		auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
> -
> -		if (importOnly_)
> -			return false;
> -
> -		if (std::find_if(start, end,
> -				 [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
> -			return true;
> -
> -		return false;
> -	}
> -
> -private:
> -	/*
> -	 * Indicates that this stream is active externally, i.e. the buffers
> -	 * are provided by the application.
> -	 */
> -	bool external_;
> -	/* Indicates that this stream only imports buffers, e.g. ISP input. */
> -	bool importOnly_;
> -	/* Stream name identifier. */
> -	std::string name_;
> -	/* The actual device stream. */
> -	std::unique_ptr<V4L2VideoDevice> dev_;
> -	/* Internally allocated framebuffers associated with this device stream. */
> -	std::vector<std::unique_ptr<FrameBuffer>> internalBuffers_;
> -	/* Externally allocated framebuffers associated with this device stream. */
> -	std::vector<std::unique_ptr<FrameBuffer>> *externalBuffers_;
> -};
> -
> -/*
> - * The following class is just a convenient (and typesafe) array of device
> - * streams indexed with an enum class.
> - */
>  enum class Unicam : unsigned int { Image, Embedded };
>  enum class Isp : unsigned int { Input, Output0, Output1, Stats };
>  
> -template<typename E, std::size_t N>
> -class RPiDevice : public std::array<class RPiStream, N>
> -{
> -private:
> -	constexpr auto index(E e) const noexcept
> -	{
> -		return static_cast<std::underlying_type_t<E>>(e);
> -	}
> -public:
> -	RPiStream &operator[](E e)
> -	{
> -		return std::array<class RPiStream, N>::operator[](index(e));
> -	}
> -	const RPiStream &operator[](E e) const
> -	{
> -		return std::array<class RPiStream, N>::operator[](index(e));
> -	}
> -};
> +} /* namespace */
>  
>  class RPiCameraData : public CameraData
>  {
> @@ -318,7 +163,7 @@ public:
>  	void ispOutputDequeue(FrameBuffer *buffer);
>  
>  	void clearIncompleteRequests();
> -	void handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream);
> +	void handleStreamBuffer(FrameBuffer *buffer, const RPi::RPiStream *stream);
>  	void handleState();
>  
>  	CameraSensor *sensor_;
> @@ -326,7 +171,7 @@ public:
>  	RPiDevice<Unicam, 2> unicam_;
>  	RPiDevice<Isp, 4> isp_;
>  	/* The vector below is just for convenience when iterating over all streams. */
> -	std::vector<RPiStream *> streams_;
> +	std::vector<RPi::RPiStream *> streams_;
>  	/* Buffers passed to the IPA. */
>  	std::vector<IPABuffer> ipaBuffers_;
>  
> @@ -782,7 +627,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
>  int PipelineHandlerRPi::exportFrameBuffers(Camera *camera, Stream *stream,
>  					   std::vector<std::unique_ptr<FrameBuffer>> *buffers)
>  {
> -	RPiStream *s = static_cast<RPiStream *>(stream);
> +	RPi::RPiStream *s = static_cast<RPi::RPiStream *>(stream);
>  	unsigned int count = stream->configuration().bufferCount;
>  	int ret = s->dev()->exportBuffers(count, buffers);
>  
> @@ -914,14 +759,14 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)
>  	std::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);
>  
>  	/* Locate and open the unicam video streams. */
> -	data->unicam_[Unicam::Embedded] = RPiStream("Unicam Embedded", unicam_->getEntityByName("unicam-embedded"));
> -	data->unicam_[Unicam::Image] = RPiStream("Unicam Image", unicam_->getEntityByName("unicam-image"));
> +	data->unicam_[Unicam::Embedded] = RPi::RPiStream("Unicam Embedded", unicam_->getEntityByName("unicam-embedded"));
> +	data->unicam_[Unicam::Image] = RPi::RPiStream("Unicam Image", unicam_->getEntityByName("unicam-image"));
>  
>  	/* Tag the ISP input stream as an import stream. */
> -	data->isp_[Isp::Input] = RPiStream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
> -	data->isp_[Isp::Output0] = RPiStream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
> -	data->isp_[Isp::Output1] = RPiStream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
> -	data->isp_[Isp::Stats] = RPiStream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
> +	data->isp_[Isp::Input] = RPi::RPiStream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
> +	data->isp_[Isp::Output0] = RPi::RPiStream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
> +	data->isp_[Isp::Output1] = RPi::RPiStream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
> +	data->isp_[Isp::Stats] = RPi::RPiStream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
>  
>  	/* This is just for convenience so that we can easily iterate over all streams. */
>  	for (auto &stream : data->unicam_)
> @@ -1070,7 +915,7 @@ int PipelineHandlerRPi::prepareBuffers(Camera *camera)
>  	 */
>  	unsigned int maxBuffers = 0;
>  	for (const Stream *s : camera->streams())
> -		if (static_cast<const RPiStream *>(s)->isExternal())
> +		if (static_cast<const RPi::RPiStream *>(s)->isExternal())
>  			maxBuffers = std::max(maxBuffers, s->configuration().bufferCount);
>  
>  	for (auto const stream : data->streams_) {
> @@ -1271,12 +1116,12 @@ done:
>  
>  void RPiCameraData::unicamBufferDequeue(FrameBuffer *buffer)
>  {
> -	const RPiStream *stream = nullptr;
> +	const RPi::RPiStream *stream = nullptr;
>  
>  	if (state_ == State::Stopped)
>  		return;
>  
> -	for (RPiStream const &s : unicam_) {
> +	for (RPi::RPiStream const &s : unicam_) {
>  		if (s.findFrameBuffer(buffer)) {
>  			stream = &s;
>  			break;
> @@ -1332,12 +1177,12 @@ void RPiCameraData::ispInputDequeue(FrameBuffer *buffer)
>  
>  void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)
>  {
> -	const RPiStream *stream = nullptr;
> +	const RPi::RPiStream *stream = nullptr;
>  
>  	if (state_ == State::Stopped)
>  		return;
>  
> -	for (RPiStream const &s : isp_) {
> +	for (RPi::RPiStream const &s : isp_) {
>  		if (s.findFrameBuffer(buffer)) {
>  			stream = &s;
>  			break;
> @@ -1418,7 +1263,7 @@ void RPiCameraData::clearIncompleteRequests()
>  	}
>  }
>  
> -void RPiCameraData::handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream)
> +void RPiCameraData::handleStreamBuffer(FrameBuffer *buffer, const RPi::RPiStream *stream)
>  {
>  	if (stream->isExternal()) {
>  		if (!dropFrame_) {
> diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> new file mode 100644
> index 00000000..ed4f4987
> --- /dev/null
> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> @@ -0,0 +1,182 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Raspberry Pi (Trading) Ltd.
> + *
> + * rpi_stream.h - Raspberry Pi device stream abstraction class.
> + */
> +#ifndef __LIBCAMERA_PIPELINE_RPI_STREAM_H__
> +#define __LIBCAMERA_PIPELINE_RPI_STREAM_H__
> +
> +#include <queue>
> +#include <string>
> +#include <vector>
> +
> +#include "libcamera/internal/v4l2_videodevice.h"
> +#include <libcamera/stream.h>
> +
> +namespace libcamera {
> +
> +LOG_DEFINE_CATEGORY(RPISTREAM)
> +
> +namespace RPi {
> +
> +/*
> + * Device stream abstraction for either an internal or external stream.
> + * Used for both Unicam and the ISP.
> + */
> +class RPiStream : public Stream
> +{
> +public:
> +	RPiStream()
> +	{
> +	}
> +
> +	RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
> +		: external_(false), importOnly_(importOnly), name_(name),
> +		  dev_(std::make_unique<V4L2VideoDevice>(dev))
> +	{
> +	}
> +
> +	V4L2VideoDevice *dev() const
> +	{
> +		return dev_.get();
> +	}
> +
> +	void setExternal(bool external)
> +	{
> +		external_ = external;
> +	}
> +
> +	bool isExternal() const
> +	{
> +		/*
> +		 * Import streams cannot be external.
> +		 *
> +		 * RAW capture is a special case where we simply copy the RAW
> +		 * buffer out of the request. All other buffer handling happens
> +		 * as if the stream is internal.
> +		 */
> +		return external_ && !importOnly_;
> +	}
> +
> +	bool isImporter() const
> +	{
> +		return importOnly_;
> +	}
> +
> +	void reset()
> +	{
> +		external_ = false;
> +		internalBuffers_.clear();
> +	}
> +
> +	std::string name() const
> +	{
> +		return name_;
> +	}
> +
> +	void setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> +	{
> +		externalBuffers_ = buffers;
> +	}
> +
> +	const std::vector<std::unique_ptr<FrameBuffer>> *getBuffers() const
> +	{
> +		return external_ ? externalBuffers_ : &internalBuffers_;
> +	}
> +
> +	void releaseBuffers()
> +	{
> +		dev_->releaseBuffers();
> +		if (!external_ && !importOnly_)
> +			internalBuffers_.clear();
> +	}
> +
> +	int importBuffers(unsigned int count)
> +	{
> +		return dev_->importBuffers(count);
> +	}
> +
> +	int allocateBuffers(unsigned int count)
> +	{
> +		return dev_->allocateBuffers(count, &internalBuffers_);
> +	}
> +
> +	int queueBuffers()
> +	{
> +		if (external_)
> +			return 0;
> +
> +		for (auto &b : internalBuffers_) {
> +			int ret = dev_->queueBuffer(b.get());
> +			if (ret) {
> +				LOG(RPISTREAM, Error) << "Failed to queue buffers for "
> +						      << name_;
> +				return ret;
> +			}
> +		}
> +
> +		return 0;
> +	}
> +
> +	bool findFrameBuffer(FrameBuffer *buffer) const
> +	{
> +		auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
> +		auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
> +
> +		if (importOnly_)
> +			return false;
> +
> +		if (std::find_if(start, end,
> +				 [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
> +			return true;
> +
> +		return false;
> +	}
> +
> +private:
> +	/*
> +	 * Indicates that this stream is active externally, i.e. the buffers
> +	 * are provided by the application.
> +	 */
> +	bool external_;
> +	/* Indicates that this stream only imports buffers, e.g. ISP input. */
> +	bool importOnly_;
> +	/* Stream name identifier. */
> +	std::string name_;
> +	/* The actual device stream. */
> +	std::unique_ptr<V4L2VideoDevice> dev_;
> +	/* Internally allocated framebuffers associated with this device stream. */
> +	std::vector<std::unique_ptr<FrameBuffer>> internalBuffers_;
> +	/* Externally allocated framebuffers associated with this device stream. */
> +	std::vector<std::unique_ptr<FrameBuffer>> *externalBuffers_;
> +};
> +
> +/*
> + * The following class is just a convenient (and typesafe) array of device
> + * streams indexed with an enum class.
> + */
> +template<typename E, std::size_t N>
> +class RPiDevice : public std::array<class RPiStream, N>
> +{
> +private:
> +	constexpr auto index(E e) const noexcept
> +	{
> +		return static_cast<std::underlying_type_t<E>>(e);
> +	}
> +public:
> +	RPiStream &operator[](E e)
> +	{
> +		return std::array<class RPiStream, N>::operator[](index(e));
> +	}
> +	const RPiStream &operator[](E e) const
> +	{
> +		return std::array<class RPiStream, N>::operator[](index(e));
> +	}
> +};
> +
> +} /* namespace RPi */
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_PIPELINE_RPI_STREAM_H__ */
> -- 
> 2.25.1
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Naushir Patuck July 13, 2020, 11:32 a.m. UTC | #2
Hi Niklas,

On Mon, 13 Jul 2020 at 12:26, Niklas Söderlund
<niklas.soderlund@ragnatech.se> wrote:
>
> Hi Naushir,
>
> Thanks for your work.
>
> On 2020-07-13 09:47:20 +0100, Naushir Patuck wrote:
> > Put RPiStream into the RPi namespace and add a new log category (RPISTREAM)
>
> I would add that there is no functional change in this patch.
>
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > ---
> >  .../pipeline/raspberrypi/raspberrypi.cpp      | 189 ++----------------
> >  .../pipeline/raspberrypi/rpi_stream.h         | 182 +++++++++++++++++
>
> I wonder if it would make sens to move some of the code to a
> rpi_stream.cpp file?

Indeed you are correct.  Please see patch 9 :)

Regards,
Naush

>
> >  2 files changed, 199 insertions(+), 172 deletions(-)
> >  create mode 100644 src/libcamera/pipeline/raspberrypi/rpi_stream.h
> >
> > diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > index a08ad6a8..7bae72f9 100644
> > --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > @@ -17,7 +17,6 @@
> >  #include <libcamera/ipa/raspberrypi.h>
> >  #include <libcamera/logging.h>
> >  #include <libcamera/request.h>
> > -#include <libcamera/stream.h>
> >
> >  #include <linux/videodev2.h>
> >
> > @@ -30,6 +29,7 @@
> >  #include "libcamera/internal/v4l2_controls.h"
> >  #include "libcamera/internal/v4l2_videodevice.h"
> >
> > +#include "rpi_stream.h"
> >  #include "staggered_ctrl.h"
> >  #include "vcsm.h"
> >
> > @@ -121,165 +121,10 @@ V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
> >       return bestMode;
> >  }
> >
> > -} /* namespace */
> > -
> > -/*
> > - * Device stream abstraction for either an internal or external stream.
> > - * Used for both Unicam and the ISP.
> > - */
> > -class RPiStream : public Stream
> > -{
> > -public:
> > -     RPiStream()
> > -     {
> > -     }
> > -
> > -     RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
> > -             : external_(false), importOnly_(importOnly), name_(name),
> > -               dev_(std::make_unique<V4L2VideoDevice>(dev))
> > -     {
> > -     }
> > -
> > -     V4L2VideoDevice *dev() const
> > -     {
> > -             return dev_.get();
> > -     }
> > -
> > -     void setExternal(bool external)
> > -     {
> > -             external_ = external;
> > -     }
> > -
> > -     bool isExternal() const
> > -     {
> > -             /*
> > -              * Import streams cannot be external.
> > -              *
> > -              * RAW capture is a special case where we simply copy the RAW
> > -              * buffer out of the request. All other buffer handling happens
> > -              * as if the stream is internal.
> > -              */
> > -             return external_ && !importOnly_;
> > -     }
> > -
> > -     bool isImporter() const
> > -     {
> > -             return importOnly_;
> > -     }
> > -
> > -     void reset()
> > -     {
> > -             external_ = false;
> > -             internalBuffers_.clear();
> > -     }
> > -
> > -     std::string name() const
> > -     {
> > -             return name_;
> > -     }
> > -
> > -     void setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> > -     {
> > -             externalBuffers_ = buffers;
> > -     }
> > -
> > -     const std::vector<std::unique_ptr<FrameBuffer>> *getBuffers() const
> > -     {
> > -             return external_ ? externalBuffers_ : &internalBuffers_;
> > -     }
> > -
> > -     void releaseBuffers()
> > -     {
> > -             dev_->releaseBuffers();
> > -             if (!external_ && !importOnly_)
> > -                     internalBuffers_.clear();
> > -     }
> > -
> > -     int importBuffers(unsigned int count)
> > -     {
> > -             return dev_->importBuffers(count);
> > -     }
> > -
> > -     int allocateBuffers(unsigned int count)
> > -     {
> > -             return dev_->allocateBuffers(count, &internalBuffers_);
> > -     }
> > -
> > -     int queueBuffers()
> > -     {
> > -             if (external_)
> > -                     return 0;
> > -
> > -             for (auto &b : internalBuffers_) {
> > -                     int ret = dev_->queueBuffer(b.get());
> > -                     if (ret) {
> > -                             LOG(RPI, Error) << "Failed to queue buffers for "
> > -                                             << name_;
> > -                             return ret;
> > -                     }
> > -             }
> > -
> > -             return 0;
> > -     }
> > -
> > -     bool findFrameBuffer(FrameBuffer *buffer) const
> > -     {
> > -             auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
> > -             auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
> > -
> > -             if (importOnly_)
> > -                     return false;
> > -
> > -             if (std::find_if(start, end,
> > -                              [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
> > -                     return true;
> > -
> > -             return false;
> > -     }
> > -
> > -private:
> > -     /*
> > -      * Indicates that this stream is active externally, i.e. the buffers
> > -      * are provided by the application.
> > -      */
> > -     bool external_;
> > -     /* Indicates that this stream only imports buffers, e.g. ISP input. */
> > -     bool importOnly_;
> > -     /* Stream name identifier. */
> > -     std::string name_;
> > -     /* The actual device stream. */
> > -     std::unique_ptr<V4L2VideoDevice> dev_;
> > -     /* Internally allocated framebuffers associated with this device stream. */
> > -     std::vector<std::unique_ptr<FrameBuffer>> internalBuffers_;
> > -     /* Externally allocated framebuffers associated with this device stream. */
> > -     std::vector<std::unique_ptr<FrameBuffer>> *externalBuffers_;
> > -};
> > -
> > -/*
> > - * The following class is just a convenient (and typesafe) array of device
> > - * streams indexed with an enum class.
> > - */
> >  enum class Unicam : unsigned int { Image, Embedded };
> >  enum class Isp : unsigned int { Input, Output0, Output1, Stats };
> >
> > -template<typename E, std::size_t N>
> > -class RPiDevice : public std::array<class RPiStream, N>
> > -{
> > -private:
> > -     constexpr auto index(E e) const noexcept
> > -     {
> > -             return static_cast<std::underlying_type_t<E>>(e);
> > -     }
> > -public:
> > -     RPiStream &operator[](E e)
> > -     {
> > -             return std::array<class RPiStream, N>::operator[](index(e));
> > -     }
> > -     const RPiStream &operator[](E e) const
> > -     {
> > -             return std::array<class RPiStream, N>::operator[](index(e));
> > -     }
> > -};
> > +} /* namespace */
> >
> >  class RPiCameraData : public CameraData
> >  {
> > @@ -318,7 +163,7 @@ public:
> >       void ispOutputDequeue(FrameBuffer *buffer);
> >
> >       void clearIncompleteRequests();
> > -     void handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream);
> > +     void handleStreamBuffer(FrameBuffer *buffer, const RPi::RPiStream *stream);
> >       void handleState();
> >
> >       CameraSensor *sensor_;
> > @@ -326,7 +171,7 @@ public:
> >       RPiDevice<Unicam, 2> unicam_;
> >       RPiDevice<Isp, 4> isp_;
> >       /* The vector below is just for convenience when iterating over all streams. */
> > -     std::vector<RPiStream *> streams_;
> > +     std::vector<RPi::RPiStream *> streams_;
> >       /* Buffers passed to the IPA. */
> >       std::vector<IPABuffer> ipaBuffers_;
> >
> > @@ -782,7 +627,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
> >  int PipelineHandlerRPi::exportFrameBuffers(Camera *camera, Stream *stream,
> >                                          std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> >  {
> > -     RPiStream *s = static_cast<RPiStream *>(stream);
> > +     RPi::RPiStream *s = static_cast<RPi::RPiStream *>(stream);
> >       unsigned int count = stream->configuration().bufferCount;
> >       int ret = s->dev()->exportBuffers(count, buffers);
> >
> > @@ -914,14 +759,14 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)
> >       std::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);
> >
> >       /* Locate and open the unicam video streams. */
> > -     data->unicam_[Unicam::Embedded] = RPiStream("Unicam Embedded", unicam_->getEntityByName("unicam-embedded"));
> > -     data->unicam_[Unicam::Image] = RPiStream("Unicam Image", unicam_->getEntityByName("unicam-image"));
> > +     data->unicam_[Unicam::Embedded] = RPi::RPiStream("Unicam Embedded", unicam_->getEntityByName("unicam-embedded"));
> > +     data->unicam_[Unicam::Image] = RPi::RPiStream("Unicam Image", unicam_->getEntityByName("unicam-image"));
> >
> >       /* Tag the ISP input stream as an import stream. */
> > -     data->isp_[Isp::Input] = RPiStream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
> > -     data->isp_[Isp::Output0] = RPiStream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
> > -     data->isp_[Isp::Output1] = RPiStream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
> > -     data->isp_[Isp::Stats] = RPiStream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
> > +     data->isp_[Isp::Input] = RPi::RPiStream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
> > +     data->isp_[Isp::Output0] = RPi::RPiStream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
> > +     data->isp_[Isp::Output1] = RPi::RPiStream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
> > +     data->isp_[Isp::Stats] = RPi::RPiStream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
> >
> >       /* This is just for convenience so that we can easily iterate over all streams. */
> >       for (auto &stream : data->unicam_)
> > @@ -1070,7 +915,7 @@ int PipelineHandlerRPi::prepareBuffers(Camera *camera)
> >        */
> >       unsigned int maxBuffers = 0;
> >       for (const Stream *s : camera->streams())
> > -             if (static_cast<const RPiStream *>(s)->isExternal())
> > +             if (static_cast<const RPi::RPiStream *>(s)->isExternal())
> >                       maxBuffers = std::max(maxBuffers, s->configuration().bufferCount);
> >
> >       for (auto const stream : data->streams_) {
> > @@ -1271,12 +1116,12 @@ done:
> >
> >  void RPiCameraData::unicamBufferDequeue(FrameBuffer *buffer)
> >  {
> > -     const RPiStream *stream = nullptr;
> > +     const RPi::RPiStream *stream = nullptr;
> >
> >       if (state_ == State::Stopped)
> >               return;
> >
> > -     for (RPiStream const &s : unicam_) {
> > +     for (RPi::RPiStream const &s : unicam_) {
> >               if (s.findFrameBuffer(buffer)) {
> >                       stream = &s;
> >                       break;
> > @@ -1332,12 +1177,12 @@ void RPiCameraData::ispInputDequeue(FrameBuffer *buffer)
> >
> >  void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)
> >  {
> > -     const RPiStream *stream = nullptr;
> > +     const RPi::RPiStream *stream = nullptr;
> >
> >       if (state_ == State::Stopped)
> >               return;
> >
> > -     for (RPiStream const &s : isp_) {
> > +     for (RPi::RPiStream const &s : isp_) {
> >               if (s.findFrameBuffer(buffer)) {
> >                       stream = &s;
> >                       break;
> > @@ -1418,7 +1263,7 @@ void RPiCameraData::clearIncompleteRequests()
> >       }
> >  }
> >
> > -void RPiCameraData::handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream)
> > +void RPiCameraData::handleStreamBuffer(FrameBuffer *buffer, const RPi::RPiStream *stream)
> >  {
> >       if (stream->isExternal()) {
> >               if (!dropFrame_) {
> > diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> > new file mode 100644
> > index 00000000..ed4f4987
> > --- /dev/null
> > +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> > @@ -0,0 +1,182 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2020, Raspberry Pi (Trading) Ltd.
> > + *
> > + * rpi_stream.h - Raspberry Pi device stream abstraction class.
> > + */
> > +#ifndef __LIBCAMERA_PIPELINE_RPI_STREAM_H__
> > +#define __LIBCAMERA_PIPELINE_RPI_STREAM_H__
> > +
> > +#include <queue>
> > +#include <string>
> > +#include <vector>
> > +
> > +#include "libcamera/internal/v4l2_videodevice.h"
> > +#include <libcamera/stream.h>
> > +
> > +namespace libcamera {
> > +
> > +LOG_DEFINE_CATEGORY(RPISTREAM)
> > +
> > +namespace RPi {
> > +
> > +/*
> > + * Device stream abstraction for either an internal or external stream.
> > + * Used for both Unicam and the ISP.
> > + */
> > +class RPiStream : public Stream
> > +{
> > +public:
> > +     RPiStream()
> > +     {
> > +     }
> > +
> > +     RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
> > +             : external_(false), importOnly_(importOnly), name_(name),
> > +               dev_(std::make_unique<V4L2VideoDevice>(dev))
> > +     {
> > +     }
> > +
> > +     V4L2VideoDevice *dev() const
> > +     {
> > +             return dev_.get();
> > +     }
> > +
> > +     void setExternal(bool external)
> > +     {
> > +             external_ = external;
> > +     }
> > +
> > +     bool isExternal() const
> > +     {
> > +             /*
> > +              * Import streams cannot be external.
> > +              *
> > +              * RAW capture is a special case where we simply copy the RAW
> > +              * buffer out of the request. All other buffer handling happens
> > +              * as if the stream is internal.
> > +              */
> > +             return external_ && !importOnly_;
> > +     }
> > +
> > +     bool isImporter() const
> > +     {
> > +             return importOnly_;
> > +     }
> > +
> > +     void reset()
> > +     {
> > +             external_ = false;
> > +             internalBuffers_.clear();
> > +     }
> > +
> > +     std::string name() const
> > +     {
> > +             return name_;
> > +     }
> > +
> > +     void setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> > +     {
> > +             externalBuffers_ = buffers;
> > +     }
> > +
> > +     const std::vector<std::unique_ptr<FrameBuffer>> *getBuffers() const
> > +     {
> > +             return external_ ? externalBuffers_ : &internalBuffers_;
> > +     }
> > +
> > +     void releaseBuffers()
> > +     {
> > +             dev_->releaseBuffers();
> > +             if (!external_ && !importOnly_)
> > +                     internalBuffers_.clear();
> > +     }
> > +
> > +     int importBuffers(unsigned int count)
> > +     {
> > +             return dev_->importBuffers(count);
> > +     }
> > +
> > +     int allocateBuffers(unsigned int count)
> > +     {
> > +             return dev_->allocateBuffers(count, &internalBuffers_);
> > +     }
> > +
> > +     int queueBuffers()
> > +     {
> > +             if (external_)
> > +                     return 0;
> > +
> > +             for (auto &b : internalBuffers_) {
> > +                     int ret = dev_->queueBuffer(b.get());
> > +                     if (ret) {
> > +                             LOG(RPISTREAM, Error) << "Failed to queue buffers for "
> > +                                                   << name_;
> > +                             return ret;
> > +                     }
> > +             }
> > +
> > +             return 0;
> > +     }
> > +
> > +     bool findFrameBuffer(FrameBuffer *buffer) const
> > +     {
> > +             auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
> > +             auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
> > +
> > +             if (importOnly_)
> > +                     return false;
> > +
> > +             if (std::find_if(start, end,
> > +                              [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
> > +                     return true;
> > +
> > +             return false;
> > +     }
> > +
> > +private:
> > +     /*
> > +      * Indicates that this stream is active externally, i.e. the buffers
> > +      * are provided by the application.
> > +      */
> > +     bool external_;
> > +     /* Indicates that this stream only imports buffers, e.g. ISP input. */
> > +     bool importOnly_;
> > +     /* Stream name identifier. */
> > +     std::string name_;
> > +     /* The actual device stream. */
> > +     std::unique_ptr<V4L2VideoDevice> dev_;
> > +     /* Internally allocated framebuffers associated with this device stream. */
> > +     std::vector<std::unique_ptr<FrameBuffer>> internalBuffers_;
> > +     /* Externally allocated framebuffers associated with this device stream. */
> > +     std::vector<std::unique_ptr<FrameBuffer>> *externalBuffers_;
> > +};
> > +
> > +/*
> > + * The following class is just a convenient (and typesafe) array of device
> > + * streams indexed with an enum class.
> > + */
> > +template<typename E, std::size_t N>
> > +class RPiDevice : public std::array<class RPiStream, N>
> > +{
> > +private:
> > +     constexpr auto index(E e) const noexcept
> > +     {
> > +             return static_cast<std::underlying_type_t<E>>(e);
> > +     }
> > +public:
> > +     RPiStream &operator[](E e)
> > +     {
> > +             return std::array<class RPiStream, N>::operator[](index(e));
> > +     }
> > +     const RPiStream &operator[](E e) const
> > +     {
> > +             return std::array<class RPiStream, N>::operator[](index(e));
> > +     }
> > +};
> > +
> > +} /* namespace RPi */
> > +
> > +} /* namespace libcamera */
> > +
> > +#endif /* __LIBCAMERA_PIPELINE_RPI_STREAM_H__ */
> > --
> > 2.25.1
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel
>
> --
> Regards,
> Niklas Söderlund

Patch

diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index a08ad6a8..7bae72f9 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -17,7 +17,6 @@ 
 #include <libcamera/ipa/raspberrypi.h>
 #include <libcamera/logging.h>
 #include <libcamera/request.h>
-#include <libcamera/stream.h>
 
 #include <linux/videodev2.h>
 
@@ -30,6 +29,7 @@ 
 #include "libcamera/internal/v4l2_controls.h"
 #include "libcamera/internal/v4l2_videodevice.h"
 
+#include "rpi_stream.h"
 #include "staggered_ctrl.h"
 #include "vcsm.h"
 
@@ -121,165 +121,10 @@  V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
 	return bestMode;
 }
 
-} /* namespace */
-
-/*
- * Device stream abstraction for either an internal or external stream.
- * Used for both Unicam and the ISP.
- */
-class RPiStream : public Stream
-{
-public:
-	RPiStream()
-	{
-	}
-
-	RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
-		: external_(false), importOnly_(importOnly), name_(name),
-		  dev_(std::make_unique<V4L2VideoDevice>(dev))
-	{
-	}
-
-	V4L2VideoDevice *dev() const
-	{
-		return dev_.get();
-	}
-
-	void setExternal(bool external)
-	{
-		external_ = external;
-	}
-
-	bool isExternal() const
-	{
-		/*
-		 * Import streams cannot be external.
-		 *
-		 * RAW capture is a special case where we simply copy the RAW
-		 * buffer out of the request. All other buffer handling happens
-		 * as if the stream is internal.
-		 */
-		return external_ && !importOnly_;
-	}
-
-	bool isImporter() const
-	{
-		return importOnly_;
-	}
-
-	void reset()
-	{
-		external_ = false;
-		internalBuffers_.clear();
-	}
-
-	std::string name() const
-	{
-		return name_;
-	}
-
-	void setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
-	{
-		externalBuffers_ = buffers;
-	}
-
-	const std::vector<std::unique_ptr<FrameBuffer>> *getBuffers() const
-	{
-		return external_ ? externalBuffers_ : &internalBuffers_;
-	}
-
-	void releaseBuffers()
-	{
-		dev_->releaseBuffers();
-		if (!external_ && !importOnly_)
-			internalBuffers_.clear();
-	}
-
-	int importBuffers(unsigned int count)
-	{
-		return dev_->importBuffers(count);
-	}
-
-	int allocateBuffers(unsigned int count)
-	{
-		return dev_->allocateBuffers(count, &internalBuffers_);
-	}
-
-	int queueBuffers()
-	{
-		if (external_)
-			return 0;
-
-		for (auto &b : internalBuffers_) {
-			int ret = dev_->queueBuffer(b.get());
-			if (ret) {
-				LOG(RPI, Error) << "Failed to queue buffers for "
-						<< name_;
-				return ret;
-			}
-		}
-
-		return 0;
-	}
-
-	bool findFrameBuffer(FrameBuffer *buffer) const
-	{
-		auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
-		auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
-
-		if (importOnly_)
-			return false;
-
-		if (std::find_if(start, end,
-				 [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
-			return true;
-
-		return false;
-	}
-
-private:
-	/*
-	 * Indicates that this stream is active externally, i.e. the buffers
-	 * are provided by the application.
-	 */
-	bool external_;
-	/* Indicates that this stream only imports buffers, e.g. ISP input. */
-	bool importOnly_;
-	/* Stream name identifier. */
-	std::string name_;
-	/* The actual device stream. */
-	std::unique_ptr<V4L2VideoDevice> dev_;
-	/* Internally allocated framebuffers associated with this device stream. */
-	std::vector<std::unique_ptr<FrameBuffer>> internalBuffers_;
-	/* Externally allocated framebuffers associated with this device stream. */
-	std::vector<std::unique_ptr<FrameBuffer>> *externalBuffers_;
-};
-
-/*
- * The following class is just a convenient (and typesafe) array of device
- * streams indexed with an enum class.
- */
 enum class Unicam : unsigned int { Image, Embedded };
 enum class Isp : unsigned int { Input, Output0, Output1, Stats };
 
-template<typename E, std::size_t N>
-class RPiDevice : public std::array<class RPiStream, N>
-{
-private:
-	constexpr auto index(E e) const noexcept
-	{
-		return static_cast<std::underlying_type_t<E>>(e);
-	}
-public:
-	RPiStream &operator[](E e)
-	{
-		return std::array<class RPiStream, N>::operator[](index(e));
-	}
-	const RPiStream &operator[](E e) const
-	{
-		return std::array<class RPiStream, N>::operator[](index(e));
-	}
-};
+} /* namespace */
 
 class RPiCameraData : public CameraData
 {
@@ -318,7 +163,7 @@  public:
 	void ispOutputDequeue(FrameBuffer *buffer);
 
 	void clearIncompleteRequests();
-	void handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream);
+	void handleStreamBuffer(FrameBuffer *buffer, const RPi::RPiStream *stream);
 	void handleState();
 
 	CameraSensor *sensor_;
@@ -326,7 +171,7 @@  public:
 	RPiDevice<Unicam, 2> unicam_;
 	RPiDevice<Isp, 4> isp_;
 	/* The vector below is just for convenience when iterating over all streams. */
-	std::vector<RPiStream *> streams_;
+	std::vector<RPi::RPiStream *> streams_;
 	/* Buffers passed to the IPA. */
 	std::vector<IPABuffer> ipaBuffers_;
 
@@ -782,7 +627,7 @@  int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
 int PipelineHandlerRPi::exportFrameBuffers(Camera *camera, Stream *stream,
 					   std::vector<std::unique_ptr<FrameBuffer>> *buffers)
 {
-	RPiStream *s = static_cast<RPiStream *>(stream);
+	RPi::RPiStream *s = static_cast<RPi::RPiStream *>(stream);
 	unsigned int count = stream->configuration().bufferCount;
 	int ret = s->dev()->exportBuffers(count, buffers);
 
@@ -914,14 +759,14 @@  bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)
 	std::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);
 
 	/* Locate and open the unicam video streams. */
-	data->unicam_[Unicam::Embedded] = RPiStream("Unicam Embedded", unicam_->getEntityByName("unicam-embedded"));
-	data->unicam_[Unicam::Image] = RPiStream("Unicam Image", unicam_->getEntityByName("unicam-image"));
+	data->unicam_[Unicam::Embedded] = RPi::RPiStream("Unicam Embedded", unicam_->getEntityByName("unicam-embedded"));
+	data->unicam_[Unicam::Image] = RPi::RPiStream("Unicam Image", unicam_->getEntityByName("unicam-image"));
 
 	/* Tag the ISP input stream as an import stream. */
-	data->isp_[Isp::Input] = RPiStream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
-	data->isp_[Isp::Output0] = RPiStream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
-	data->isp_[Isp::Output1] = RPiStream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
-	data->isp_[Isp::Stats] = RPiStream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
+	data->isp_[Isp::Input] = RPi::RPiStream("ISP Input", isp_->getEntityByName("bcm2835-isp0-output0"), true);
+	data->isp_[Isp::Output0] = RPi::RPiStream("ISP Output0", isp_->getEntityByName("bcm2835-isp0-capture1"));
+	data->isp_[Isp::Output1] = RPi::RPiStream("ISP Output1", isp_->getEntityByName("bcm2835-isp0-capture2"));
+	data->isp_[Isp::Stats] = RPi::RPiStream("ISP Stats", isp_->getEntityByName("bcm2835-isp0-capture3"));
 
 	/* This is just for convenience so that we can easily iterate over all streams. */
 	for (auto &stream : data->unicam_)
@@ -1070,7 +915,7 @@  int PipelineHandlerRPi::prepareBuffers(Camera *camera)
 	 */
 	unsigned int maxBuffers = 0;
 	for (const Stream *s : camera->streams())
-		if (static_cast<const RPiStream *>(s)->isExternal())
+		if (static_cast<const RPi::RPiStream *>(s)->isExternal())
 			maxBuffers = std::max(maxBuffers, s->configuration().bufferCount);
 
 	for (auto const stream : data->streams_) {
@@ -1271,12 +1116,12 @@  done:
 
 void RPiCameraData::unicamBufferDequeue(FrameBuffer *buffer)
 {
-	const RPiStream *stream = nullptr;
+	const RPi::RPiStream *stream = nullptr;
 
 	if (state_ == State::Stopped)
 		return;
 
-	for (RPiStream const &s : unicam_) {
+	for (RPi::RPiStream const &s : unicam_) {
 		if (s.findFrameBuffer(buffer)) {
 			stream = &s;
 			break;
@@ -1332,12 +1177,12 @@  void RPiCameraData::ispInputDequeue(FrameBuffer *buffer)
 
 void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)
 {
-	const RPiStream *stream = nullptr;
+	const RPi::RPiStream *stream = nullptr;
 
 	if (state_ == State::Stopped)
 		return;
 
-	for (RPiStream const &s : isp_) {
+	for (RPi::RPiStream const &s : isp_) {
 		if (s.findFrameBuffer(buffer)) {
 			stream = &s;
 			break;
@@ -1418,7 +1263,7 @@  void RPiCameraData::clearIncompleteRequests()
 	}
 }
 
-void RPiCameraData::handleStreamBuffer(FrameBuffer *buffer, const RPiStream *stream)
+void RPiCameraData::handleStreamBuffer(FrameBuffer *buffer, const RPi::RPiStream *stream)
 {
 	if (stream->isExternal()) {
 		if (!dropFrame_) {
diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
new file mode 100644
index 00000000..ed4f4987
--- /dev/null
+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
@@ -0,0 +1,182 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Raspberry Pi (Trading) Ltd.
+ *
+ * rpi_stream.h - Raspberry Pi device stream abstraction class.
+ */
+#ifndef __LIBCAMERA_PIPELINE_RPI_STREAM_H__
+#define __LIBCAMERA_PIPELINE_RPI_STREAM_H__
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "libcamera/internal/v4l2_videodevice.h"
+#include <libcamera/stream.h>
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(RPISTREAM)
+
+namespace RPi {
+
+/*
+ * Device stream abstraction for either an internal or external stream.
+ * Used for both Unicam and the ISP.
+ */
+class RPiStream : public Stream
+{
+public:
+	RPiStream()
+	{
+	}
+
+	RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
+		: external_(false), importOnly_(importOnly), name_(name),
+		  dev_(std::make_unique<V4L2VideoDevice>(dev))
+	{
+	}
+
+	V4L2VideoDevice *dev() const
+	{
+		return dev_.get();
+	}
+
+	void setExternal(bool external)
+	{
+		external_ = external;
+	}
+
+	bool isExternal() const
+	{
+		/*
+		 * Import streams cannot be external.
+		 *
+		 * RAW capture is a special case where we simply copy the RAW
+		 * buffer out of the request. All other buffer handling happens
+		 * as if the stream is internal.
+		 */
+		return external_ && !importOnly_;
+	}
+
+	bool isImporter() const
+	{
+		return importOnly_;
+	}
+
+	void reset()
+	{
+		external_ = false;
+		internalBuffers_.clear();
+	}
+
+	std::string name() const
+	{
+		return name_;
+	}
+
+	void setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
+	{
+		externalBuffers_ = buffers;
+	}
+
+	const std::vector<std::unique_ptr<FrameBuffer>> *getBuffers() const
+	{
+		return external_ ? externalBuffers_ : &internalBuffers_;
+	}
+
+	void releaseBuffers()
+	{
+		dev_->releaseBuffers();
+		if (!external_ && !importOnly_)
+			internalBuffers_.clear();
+	}
+
+	int importBuffers(unsigned int count)
+	{
+		return dev_->importBuffers(count);
+	}
+
+	int allocateBuffers(unsigned int count)
+	{
+		return dev_->allocateBuffers(count, &internalBuffers_);
+	}
+
+	int queueBuffers()
+	{
+		if (external_)
+			return 0;
+
+		for (auto &b : internalBuffers_) {
+			int ret = dev_->queueBuffer(b.get());
+			if (ret) {
+				LOG(RPISTREAM, Error) << "Failed to queue buffers for "
+						      << name_;
+				return ret;
+			}
+		}
+
+		return 0;
+	}
+
+	bool findFrameBuffer(FrameBuffer *buffer) const
+	{
+		auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
+		auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
+
+		if (importOnly_)
+			return false;
+
+		if (std::find_if(start, end,
+				 [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
+			return true;
+
+		return false;
+	}
+
+private:
+	/*
+	 * Indicates that this stream is active externally, i.e. the buffers
+	 * are provided by the application.
+	 */
+	bool external_;
+	/* Indicates that this stream only imports buffers, e.g. ISP input. */
+	bool importOnly_;
+	/* Stream name identifier. */
+	std::string name_;
+	/* The actual device stream. */
+	std::unique_ptr<V4L2VideoDevice> dev_;
+	/* Internally allocated framebuffers associated with this device stream. */
+	std::vector<std::unique_ptr<FrameBuffer>> internalBuffers_;
+	/* Externally allocated framebuffers associated with this device stream. */
+	std::vector<std::unique_ptr<FrameBuffer>> *externalBuffers_;
+};
+
+/*
+ * The following class is just a convenient (and typesafe) array of device
+ * streams indexed with an enum class.
+ */
+template<typename E, std::size_t N>
+class RPiDevice : public std::array<class RPiStream, N>
+{
+private:
+	constexpr auto index(E e) const noexcept
+	{
+		return static_cast<std::underlying_type_t<E>>(e);
+	}
+public:
+	RPiStream &operator[](E e)
+	{
+		return std::array<class RPiStream, N>::operator[](index(e));
+	}
+	const RPiStream &operator[](E e) const
+	{
+		return std::array<class RPiStream, N>::operator[](index(e));
+	}
+};
+
+} /* namespace RPi */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_PIPELINE_RPI_STREAM_H__ */