diff options
-rw-r--r-- | src/libcamera/pipeline/ipu3/ipu3.cpp | 111 |
1 files changed, 101 insertions, 10 deletions
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0933a03c..b490a801 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -33,6 +33,13 @@ LOG_DEFINE_CATEGORY(IPU3) class IPU3CameraData; +static const std::map<uint32_t, PixelFormat> sensorMbusToPixel = { + { MEDIA_BUS_FMT_SBGGR10_1X10, PixelFormat(DRM_FORMAT_SBGGR10, { IPU3_FORMAT_MOD_PACKED }) }, + { MEDIA_BUS_FMT_SGBRG10_1X10, PixelFormat(DRM_FORMAT_SGBRG10, { IPU3_FORMAT_MOD_PACKED }) }, + { MEDIA_BUS_FMT_SGRBG10_1X10, PixelFormat(DRM_FORMAT_SGRBG10, { IPU3_FORMAT_MOD_PACKED }) }, + { MEDIA_BUS_FMT_SRGGB10_1X10, PixelFormat(DRM_FORMAT_SRGGB10, { IPU3_FORMAT_MOD_PACKED }) }, +}; + class ImgUDevice { public: @@ -140,11 +147,12 @@ class IPU3Stream : public Stream { public: IPU3Stream() - : active_(false), device_(nullptr) + : active_(false), raw_(false), device_(nullptr) { } bool active_; + bool raw_; std::string name_; ImgUDevice::ImgUOutput *device_; }; @@ -166,6 +174,7 @@ public: IPU3Stream outStream_; IPU3Stream vfStream_; + IPU3Stream rawStream_; }; class IPU3CameraConfiguration : public CameraConfiguration @@ -180,6 +189,7 @@ public: private: static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_MAX_STREAMS = 3; void adjustStream(StreamConfiguration &cfg, bool scale); @@ -291,8 +301,6 @@ void IPU3CameraConfiguration::adjustStream(StreamConfiguration &cfg, bool scale) cfg.size.width &= ~7; cfg.size.height &= ~3; } - - cfg.bufferCount = IPU3_BUFFER_COUNT; } CameraConfiguration::Status IPU3CameraConfiguration::validate() @@ -304,8 +312,8 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() return Invalid; /* Cap the number of entries to the available streams. */ - if (config_.size() > 2) { - config_.resize(2); + if (config_.size() > IPU3_MAX_STREAMS) { + config_.resize(IPU3_MAX_STREAMS); status = Adjusted; } @@ -345,6 +353,7 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() std::set<const IPU3Stream *> availableStreams = { &data_->outStream_, &data_->vfStream_, + &data_->rawStream_, }; streams_.clear(); @@ -356,7 +365,9 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() const Size size = cfg.size; const IPU3Stream *stream; - if (cfg.size == sensorFormat_.size) + if (cfg.pixelFormat.modifiers().count(IPU3_FORMAT_MOD_PACKED)) + stream = &data_->rawStream_; + else if (cfg.size == sensorFormat_.size) stream = &data_->outStream_; else stream = &data_->vfStream_; @@ -367,8 +378,20 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() LOG(IPU3, Debug) << "Assigned '" << stream->name_ << "' to stream " << i; - bool scale = stream == &data_->vfStream_; - adjustStream(config_[i], scale); + if (stream->raw_) { + const auto &itFormat = + sensorMbusToPixel.find(sensorFormat_.mbus_code); + if (itFormat == sensorMbusToPixel.end()) + return Invalid; + + cfg.pixelFormat = itFormat->second; + cfg.size = sensorFormat_.size; + } else { + bool scale = stream == &data_->vfStream_; + adjustStream(config_[i], scale); + } + + cfg.bufferCount = IPU3_BUFFER_COUNT; if (cfg.pixelFormat != pixelFormat || cfg.size != size) { LOG(IPU3, Debug) @@ -397,6 +420,7 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera, std::set<IPU3Stream *> streams = { &data->outStream_, &data->vfStream_, + &data->rawStream_, }; config = new IPU3CameraConfiguration(camera, data); @@ -438,6 +462,29 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera, break; + case StreamRole::StillCaptureRaw: { + if (streams.find(&data->rawStream_) == streams.end()) { + LOG(IPU3, Error) + << "No stream available for requested role " + << role; + break; + } + + stream = &data->rawStream_; + + cfg.size = data->cio2_.sensor_->resolution(); + + V4L2SubdeviceFormat sensorFormat = + data->cio2_.sensor_->getFormat({ MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10 }, + cfg.size); + cfg.pixelFormat = + sensorMbusToPixel.at(sensorFormat.mbus_code); + break; + } + case StreamRole::Viewfinder: case StreamRole::VideoRecording: { /* @@ -535,6 +582,9 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) /* * \todo: Enable links selectively based on the requested streams. * As of now, enable all links unconditionally. + * \todo Don't configure the ImgU at all if we only have a single + * stream which is for raw capture, in which case no buffers will + * ever be queued to the ImgU. */ ret = data->imgu_->enableLinks(true); if (ret) @@ -571,6 +621,13 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) stream->active_ = true; cfg.setStream(stream); + /* + * The RAW still capture stream just copies buffers from the + * internal queue and doesn't need any specific configuration. + */ + if (stream->raw_) + continue; + ret = imgu->configureOutput(stream->device_, cfg); if (ret) return ret; @@ -621,9 +678,15 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) int PipelineHandlerIPU3::exportFrameBuffers(Camera *camera, Stream *stream, std::vector<std::unique_ptr<FrameBuffer>> *buffers) { + IPU3CameraData *data = cameraData(camera); IPU3Stream *ipu3stream = static_cast<IPU3Stream *>(stream); - V4L2VideoDevice *video = ipu3stream->device_->dev; unsigned int count = stream->configuration().bufferCount; + V4L2VideoDevice *video; + + if (ipu3stream->raw_) + video = data->cio2_.output_; + else + video = ipu3stream->device_->dev; return video->exportBuffers(count, buffers); } @@ -737,6 +800,10 @@ int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request) IPU3Stream *stream = static_cast<IPU3Stream *>(it.first); buffer = it.second; + /* Skip raw streams, they are copied from the CIO2 buffer. */ + if (stream->raw_) + continue; + int ret = stream->device_->dev->queueBuffer(buffer); if (ret < 0) error = ret; @@ -831,6 +898,7 @@ int PipelineHandlerIPU3::registerCameras() std::set<Stream *> streams = { &data->outStream_, &data->vfStream_, + &data->rawStream_, }; CIO2Device *cio2 = &data->cio2_; @@ -852,6 +920,8 @@ int PipelineHandlerIPU3::registerCameras() data->outStream_.name_ = "output"; data->vfStream_.device_ = &data->imgu_->viewfinder_; data->vfStream_.name_ = "viewfinder"; + data->rawStream_.raw_ = true; + data->rawStream_.name_ = "raw"; /* * Connect video devices' 'bufferReady' signals to their @@ -941,7 +1011,28 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer) if (buffer->metadata().status == FrameMetadata::FrameCancelled) return; - imgu_->input_->queueBuffer(buffer); + Request *request = buffer->request(); + FrameBuffer *raw = request->findBuffer(&rawStream_); + + if (!raw) { + /* No RAW buffers present, just queue to IMGU. */ + imgu_->input_->queueBuffer(buffer); + return; + } + + /* RAW buffers present, special care is needed. */ + if (request->buffers().size() > 1) + imgu_->input_->queueBuffer(buffer); + + if (raw->copyFrom(buffer)) + LOG(IPU3, Debug) << "Copy of FrameBuffer failed"; + + pipe_->completeBuffer(camera_, request, raw); + + if (request->buffers().size() == 1) { + cio2_.putBuffer(buffer); + pipe_->completeRequest(camera_, request); + } } /* ----------------------------------------------------------------------------- |