diff options
-rw-r--r-- | src/libcamera/pipeline/rpi/vc4/vc4.cpp | 78 |
1 files changed, 68 insertions, 10 deletions
diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 392d3486..f55cd4a4 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -5,6 +5,8 @@ * Pipeline handler for VC4-based Raspberry Pi devices */ +#include <memory> + #include <linux/bcm2835-isp.h> #include <linux/v4l2-controls.h> #include <linux/videodev2.h> @@ -13,6 +15,7 @@ #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/dma_buf_allocator.h" +#include "libcamera/internal/v4l2_subdevice.h" #include "../common/pipeline_base.h" #include "../common/rpi_stream.h" @@ -31,6 +34,10 @@ namespace { enum class Unicam : unsigned int { Image, Embedded }; enum class Isp : unsigned int { Input, Output0, Output1, Stats }; +static constexpr unsigned int kUnicamSinkPad = 0; +static constexpr unsigned int kUnicamSourceImagePad = 1; +static constexpr unsigned int kUnicamSourceMetadataPad = 2; + } /* namespace */ class Vc4CameraData final : public RPi::CameraData @@ -81,6 +88,8 @@ public: void setIspControls(const ControlList &controls); void setCameraTimeout(uint32_t maxFrameLengthMs); + std::unique_ptr<V4L2Subdevice> unicamSubdev_; + /* Array of Unicam and ISP device streams and associated buffers/streams. */ RPi::Device<Unicam, 2> unicam_; RPi::Device<Isp, 4> isp_; @@ -309,6 +318,7 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer if (!data->dmaHeap_.isValid()) return -ENOMEM; + MediaEntity *unicamSubdev = unicam->getEntityByName("unicam"); MediaEntity *unicamImage = unicam->getEntityByName("unicam-image"); MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam-embedded"); MediaEntity *ispOutput0 = isp->getEntityByName("bcm2835-isp0-output0"); @@ -320,7 +330,13 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3) return -ENOENT; - /* Create the unicam video streams. */ + if (!unicamSubdev) { + LOG(RPI, Error) << "Downstream Unicam driver not supported, please update your kernel!"; + return -EINVAL; + } + + /* Create the unicam subdev and video streams. */ + data->unicamSubdev_ = std::make_unique<V4L2Subdevice>(unicamSubdev); data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicamImage); data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded); @@ -349,6 +365,10 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer * The below grouping is just for convenience so that we can easily * iterate over all streams in one go. */ + int ret = data->unicamSubdev_->open(); + if (ret < 0) + return ret; + data->streams_.push_back(&data->unicam_[Unicam::Image]); if (data->sensorMetadata_) data->streams_.push_back(&data->unicam_[Unicam::Embedded]); @@ -357,16 +377,11 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer data->streams_.push_back(&stream); for (auto stream : data->streams_) { - int ret = stream->dev()->open(); + ret = stream->dev()->open(); if (ret) return ret; } - if (!data->unicam_[Unicam::Image].dev()->caps().hasMediaController()) { - LOG(RPI, Error) << "Unicam driver does not use the MediaController, please update your kernel!"; - return -EINVAL; - } - /* Write up all the IPA connections. */ data->ipa_->processStatsComplete.connect(data, &Vc4CameraData::processStatsComplete); data->ipa_->prepareIspComplete.connect(data, &Vc4CameraData::prepareIspComplete); @@ -529,7 +544,50 @@ int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr<YamlObject> & int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig) { /* - * 1. Configure the Unicam video devices. + * 1. Configure the Unicam subdev. + * + * Start by setting up routes, and then set the formats on the sink pad + * streams. They will be automatically propagated to the source pads by + * the kernel. + */ + + const V4L2Subdevice::Stream imageStream{ + kUnicamSinkPad, + sensor_->imageStream().stream + }; + const V4L2Subdevice::Stream embeddedDataStream{ + kUnicamSinkPad, + sensor_->embeddedDataStream().value_or(V4L2Subdevice::Stream{}).stream + }; + + V4L2Subdevice::Routing routing; + + routing.emplace_back(imageStream, V4L2Subdevice::Stream{ kUnicamSourceImagePad, 0 }, + V4L2_SUBDEV_ROUTE_FL_ACTIVE); + + if (sensorMetadata_) + routing.emplace_back(embeddedDataStream, + V4L2Subdevice::Stream{ kUnicamSourceMetadataPad, 0 }, + V4L2_SUBDEV_ROUTE_FL_ACTIVE); + + int ret = unicamSubdev_->setRouting(&routing); + if (ret) + return ret; + + V4L2SubdeviceFormat subdevFormat = rpiConfig->sensorFormat_; + ret = unicamSubdev_->setFormat(imageStream, &subdevFormat); + if (ret) + return ret; + + if (sensorMetadata_) { + subdevFormat = sensor_->embeddedDataFormat(); + ret = unicamSubdev_->setFormat(embeddedDataStream, &subdevFormat); + if (ret) + return ret; + } + + /* + * 2. Configure the Unicam video devices. */ V4L2VideoDevice *unicam = unicam_[Unicam::Image].dev(); @@ -552,7 +610,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi BayerFormat::Packing::CSI2); } - int ret = unicam->setFormat(&unicamFormat); + ret = unicam->setFormat(&unicamFormat); if (ret) return ret; @@ -580,7 +638,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi } /* - * 2. Configure the ISP. + * 3. Configure the ISP. */ ret = isp_[Isp::Input].dev()->setFormat(&unicamFormat); |