Message ID | 20230313091944.9530-6-jacopo.mondi@ideasonboard.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Jacopo, Thank you for the patch. On Mon, Mar 13, 2023 at 10:19:43AM +0100, Jacopo Mondi wrote: > At generateConfiguration() a YUV/RGB pixel format is preferred for the > StillCapture/VideoRecording/Viewfinder roles, but currently there are no > guarantees in place that the sensor provides a non-Bayer bus format from > which YUV/RGB can be generated. > > This makes the default configuration generated for those roles not to > work if the sensor is a RAW-only one. > > To improve the situation split the configuration generation in two, > one for YUV modes and one for Raw Bayer mode. > > StreamRoles assigned to a YUV mode will try to first generate a YUV > configuration and then fallback to RAW if that's what the sensor can > provide. > > As an additional requirement, for YUV streams, the generated mode has to > be validated with the sensor to confirm the desired sizes can be > generated. In order to test a format use the newly introduced > CameraSensor::tryFormat(). Please explain in the commit message (and/or a comment in the code) why this is needed. I'm also tempted to ask for this new requirement to be split to a separate patch, to ease review. > Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> > Tested-by: Daniel Scally <dan.scally@ideasonboard.com> > --- > src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 231 +++++++++++++------ > 1 file changed, 155 insertions(+), 76 deletions(-) > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > index 146ba7465012..a4f437f55b26 100644 > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > @@ -145,6 +145,10 @@ private: > > Pipe *pipeFromStream(Camera *camera, const Stream *stream); > > + StreamConfiguration generateYUVConfiguration(Camera *camera, > + const Size &size); > + StreamConfiguration generateRawConfiguration(Camera *camera); > + > void bufferReady(FrameBuffer *buffer); > > MediaDevice *isiDev_; > @@ -705,6 +709,129 @@ PipelineHandlerISI::PipelineHandlerISI(CameraManager *manager) > { > } > > +/* > + * Generate a StreamConfiguration for YUV/RGB use case. > + * > + * Verify it the sensor can produce a YUV/RGB media bus format and collect > + * all the processed pixel formats the ISI can generate as supported stream > + * configurations. > + */ > +StreamConfiguration PipelineHandlerISI::generateYUVConfiguration(Camera *camera, > + const Size &size) > +{ > + ISICameraData *data = cameraData(camera); > + PixelFormat pixelFormat = formats::YUYV; > + unsigned int mbusCode; > + > + mbusCode = data->getYuvMediaBusFormat(&pixelFormat); > + if (!mbusCode) > + return {}; > + > + /* Adjust the requested size to the sensor's capabilities. */ > + const CameraSensor *sensor = data->sensor_.get(); > + > + V4L2SubdeviceFormat sensorFmt; > + sensorFmt.mbus_code = mbusCode; > + sensorFmt.size = size; > + > + int ret = sensor->tryFormat(&sensorFmt); int ret = data->sensor_->tryFormat(&sensorFmt); and drop the local sensor variable. > + if (ret) { > + LOG(ISI, Error) << "Failed to try sensor format."; > + return {}; > + } > + > + Size sensorSize = sensorFmt.size; > + > + /* > + * Populate the StreamConfiguration. > + * > + * As the sensor supports at least one YUV/RGB media bus format all the > + * processed ones in formatsMap_ can be generated from it. > + */ > + std::map<PixelFormat, std::vector<SizeRange>> streamFormats; > + > + for (const auto &[pixFmt, pipeFmt] : ISICameraConfiguration::formatsMap_) { > + const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt); > + if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) > + continue; > + > + streamFormats[pixFmt] = { { kMinISISize, sensorSize } }; > + } > + > + StreamFormats formats(streamFormats); > + > + StreamConfiguration cfg(formats); > + cfg.pixelFormat = pixelFormat; > + cfg.size = sensorSize; > + cfg.bufferCount = 4; > + > + return cfg; > +} > + > +/* > + * Generate a StreamConfiguration for Raw Bayer use case. Verify if the sensor > + * can produce the requested RAW bayer format and eventually adjust it to > + * the one with the largest bit-depth the sensor can produce. > + */ > +StreamConfiguration PipelineHandlerISI::generateRawConfiguration(Camera *camera) > +{ > + static const std::map<unsigned int, PixelFormat> rawFormats = { > + { MEDIA_BUS_FMT_SBGGR8_1X8, formats::SBGGR8 }, > + { MEDIA_BUS_FMT_SGBRG8_1X8, formats::SGBRG8 }, > + { MEDIA_BUS_FMT_SGRBG8_1X8, formats::SGRBG8 }, > + { MEDIA_BUS_FMT_SRGGB8_1X8, formats::SRGGB8 }, > + { MEDIA_BUS_FMT_SBGGR10_1X10, formats::SBGGR10 }, > + { MEDIA_BUS_FMT_SGBRG10_1X10, formats::SGBRG10 }, > + { MEDIA_BUS_FMT_SGRBG10_1X10, formats::SGRBG10 }, > + { MEDIA_BUS_FMT_SRGGB10_1X10, formats::SRGGB10 }, > + { MEDIA_BUS_FMT_SBGGR12_1X12, formats::SBGGR12 }, > + { MEDIA_BUS_FMT_SGBRG12_1X12, formats::SGBRG12 }, > + { MEDIA_BUS_FMT_SGRBG12_1X12, formats::SGRBG12 }, > + { MEDIA_BUS_FMT_SRGGB12_1X12, formats::SRGGB12 }, Now that libcamera has RAW14 formats, could you add them here ? > + }; > + > + ISICameraData *data = cameraData(camera); > + PixelFormat pixelFormat = formats::SBGGR10; > + unsigned int mbusCode; > + > + /* pixelFormat will be adjusted, if the sensor can produce RAW. */ > + mbusCode = data->getRawMediaBusFormat(&pixelFormat); > + if (!mbusCode) > + return {}; > + > + /* > + * Populate the StreamConfiguration with all the supported Bayer > + * formats the sensor can produce. > + */ > + std::map<PixelFormat, std::vector<SizeRange>> streamFormats; > + const CameraSensor *sensor = data->sensor_.get(); > + > + for (unsigned int code : sensor->mbusCodes()) { > + /* Find a Bayer media bus code from the sensor. */ > + const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(code); > + if (!bayerFormat.isValid()) > + continue; > + > + auto it = rawFormats.find(code); > + if (it == rawFormats.end()) { > + LOG(ISI, Warning) << bayerFormat > + << " not supported in ISI formats map."; > + continue; > + } > + > + streamFormats[it->second] = { { sensor->resolution(), sensor->resolution() } }; > + } > + > + StreamFormats formats(streamFormats); > + > + StreamConfiguration cfg(formats); > + cfg.size = sensor->resolution(); > + cfg.pixelFormat = pixelFormat; > + cfg.bufferCount = 4; > + > + return cfg; > +} > + > std::unique_ptr<CameraConfiguration> > PipelineHandlerISI::generateConfiguration(Camera *camera, > const StreamRoles &roles) > @@ -722,79 +849,45 @@ PipelineHandlerISI::generateConfiguration(Camera *camera, > return nullptr; > } > > - bool isRaw = false; > for (const auto &role : roles) { > /* > - * Prefer the following formats > + * Prefer the following formats: > * - Still Capture: Full resolution YUYV > * - ViewFinder/VideoRecording: 1080p YUYV > - * - RAW: sensor's native format and resolution > + * - RAW: Full resolution Bayer > */ > - std::map<PixelFormat, std::vector<SizeRange>> streamFormats; > - PixelFormat pixelFormat; > - Size size; > + StreamConfiguration cfg; > > switch (role) { > case StreamRole::StillCapture: > - /* > - * \todo Make sure the sensor can produce non-RAW formats > - * compatible with the ones supported by the pipeline. > - */ > - size = data->sensor_->resolution(); > - pixelFormat = formats::YUYV; > + cfg = generateYUVConfiguration(camera, > + data->sensor_->resolution()); > + if (!cfg.pixelFormat.isValid()) { > + /* > + * Fallback to use a Bayer format if that's what > + * the sensor supports. > + */ > + cfg = generateRawConfiguration(camera); > + } > + > break; > > case StreamRole::Viewfinder: > case StreamRole::VideoRecording: > - /* > - * \todo Make sure the sensor can produce non-RAW formats > - * compatible with the ones supported by the pipeline. > - */ > - size = PipelineHandlerISI::kPreviewSize; > - pixelFormat = formats::YUYV; > - break; > - > - case StreamRole::Raw: { > - /* > - * Make sure the sensor can generate a RAW format and > - * prefer the ones with a larger bitdepth. > - */ > - const ISICameraConfiguration::FormatMap::value_type *rawPipeFormat = nullptr; > - unsigned int maxDepth = 0; > - > - for (unsigned int code : data->sensor_->mbusCodes()) { > - const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(code); > - if (!bayerFormat.isValid()) > - continue; > - > - /* Make sure the format is supported by the pipeline handler. */ > - auto it = std::find_if(ISICameraConfiguration::formatsMap_.begin(), > - ISICameraConfiguration::formatsMap_.end(), > - [code](auto &isiFormat) { > - auto &pipe = isiFormat.second; > - return pipe.sensorCode == code; > - }); > - if (it == ISICameraConfiguration::formatsMap_.end()) > - continue; > - > - if (bayerFormat.bitDepth > maxDepth) { > - maxDepth = bayerFormat.bitDepth; > - rawPipeFormat = &(*it); > - } > - } > - > - if (!rawPipeFormat) { > - LOG(ISI, Error) > - << "Cannot generate a configuration for RAW stream"; > - return nullptr; > + cfg = generateYUVConfiguration(camera, > + PipelineHandlerISI::kPreviewSize); > + if (!cfg.pixelFormat.isValid()) { > + /* > + * Fallback to use a Bayer format if that's what > + * the sensor supports. > + */ > + cfg = generateRawConfiguration(camera); > } > > - size = data->sensor_->resolution(); > - pixelFormat = rawPipeFormat->first; > - > - streamFormats[pixelFormat] = { { kMinISISize, size } }; > - isRaw = true; > + break; > > + case StreamRole::Raw: { > + cfg = generateRawConfiguration(camera); > break; > } > Would this be clearer ? switch (role) { case StreamRole::StillCapture: case StreamRole::Viewfinder: case StreamRole::VideoRecording: Size size = role == StreamRole::StillCapture ? data->sensor_->resolution() : PipelineHandlerISI::kPreviewSize; cfg = generateYUVConfiguration(camera, size); if (cfg.pixelFormat.isValid()) break; /* * Fallback to use a Bayer format if that's what the * sensor supports. */ [[fallthrough]] case StreamRole::Raw: { cfg = generateRawConfiguration(camera); break; } Up to you. > @@ -803,26 +896,12 @@ PipelineHandlerISI::generateConfiguration(Camera *camera, > return nullptr; > } > > - /* > - * For non-RAW configurations the ISI can perform colorspace > - * conversion. List all the supported output formats here. > - */ > - if (!isRaw) { > - for (const auto &[pixFmt, pipeFmt] : ISICameraConfiguration::formatsMap_) { > - const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt); > - if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) > - continue; > - > - streamFormats[pixFmt] = { { kMinISISize, size } }; > - } > + if (!cfg.pixelFormat.isValid()) { > + LOG(ISI, Error) > + << "Cannot generate configuration for role: " << role; > + return nullptr; > } > > - StreamFormats formats(streamFormats); > - > - StreamConfiguration cfg(formats); > - cfg.pixelFormat = pixelFormat; > - cfg.size = size; > - cfg.bufferCount = 4; > config->addConfiguration(cfg); > } >
Hi Laurent On Mon, Apr 24, 2023 at 09:06:44AM +0300, Laurent Pinchart via libcamera-devel wrote: > Hi Jacopo, > > Thank you for the patch. > > On Mon, Mar 13, 2023 at 10:19:43AM +0100, Jacopo Mondi wrote: > > At generateConfiguration() a YUV/RGB pixel format is preferred for the > > StillCapture/VideoRecording/Viewfinder roles, but currently there are no > > guarantees in place that the sensor provides a non-Bayer bus format from > > which YUV/RGB can be generated. > > > > This makes the default configuration generated for those roles not to > > work if the sensor is a RAW-only one. > > > > To improve the situation split the configuration generation in two, > > one for YUV modes and one for Raw Bayer mode. > > > > StreamRoles assigned to a YUV mode will try to first generate a YUV > > configuration and then fallback to RAW if that's what the sensor can > > provide. > > > > As an additional requirement, for YUV streams, the generated mode has to > > be validated with the sensor to confirm the desired sizes can be > > generated. In order to test a format use the newly introduced > > CameraSensor::tryFormat(). > > Please explain in the commit message (and/or a comment in the code) why > this is needed. > What do you mean ? "for YUV streams, the generated mode has to be validated with the sensor to confirm the desired sizes can be generated." The ISI cannot upscale, what's controversial here ? > I'm also tempted to ask for this new requirement to be split to a > separate patch, to ease review. > It's not a new requirement, it was simply ignored by the existing and known-to-be-broken implementation > > Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > > Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> > > Tested-by: Daniel Scally <dan.scally@ideasonboard.com> > > --- > > src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 231 +++++++++++++------ > > 1 file changed, 155 insertions(+), 76 deletions(-) > > > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > > index 146ba7465012..a4f437f55b26 100644 > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > > @@ -145,6 +145,10 @@ private: > > > > Pipe *pipeFromStream(Camera *camera, const Stream *stream); > > > > + StreamConfiguration generateYUVConfiguration(Camera *camera, > > + const Size &size); > > + StreamConfiguration generateRawConfiguration(Camera *camera); > > + > > void bufferReady(FrameBuffer *buffer); > > > > MediaDevice *isiDev_; > > @@ -705,6 +709,129 @@ PipelineHandlerISI::PipelineHandlerISI(CameraManager *manager) > > { > > } > > > > +/* > > + * Generate a StreamConfiguration for YUV/RGB use case. > > + * > > + * Verify it the sensor can produce a YUV/RGB media bus format and collect > > + * all the processed pixel formats the ISI can generate as supported stream > > + * configurations. > > + */ > > +StreamConfiguration PipelineHandlerISI::generateYUVConfiguration(Camera *camera, > > + const Size &size) > > +{ > > + ISICameraData *data = cameraData(camera); > > + PixelFormat pixelFormat = formats::YUYV; > > + unsigned int mbusCode; > > + > > + mbusCode = data->getYuvMediaBusFormat(&pixelFormat); > > + if (!mbusCode) > > + return {}; > > + > > + /* Adjust the requested size to the sensor's capabilities. */ > > + const CameraSensor *sensor = data->sensor_.get(); > > + > > + V4L2SubdeviceFormat sensorFmt; > > + sensorFmt.mbus_code = mbusCode; > > + sensorFmt.size = size; > > + > > + int ret = sensor->tryFormat(&sensorFmt); > > int ret = data->sensor_->tryFormat(&sensorFmt); > > and drop the local sensor variable. > > > + if (ret) { > > + LOG(ISI, Error) << "Failed to try sensor format."; > > + return {}; > > + } > > + > > + Size sensorSize = sensorFmt.size; > > + > > + /* > > + * Populate the StreamConfiguration. > > + * > > + * As the sensor supports at least one YUV/RGB media bus format all the > > + * processed ones in formatsMap_ can be generated from it. > > + */ > > + std::map<PixelFormat, std::vector<SizeRange>> streamFormats; > > + > > + for (const auto &[pixFmt, pipeFmt] : ISICameraConfiguration::formatsMap_) { > > + const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt); > > + if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) > > + continue; > > + > > + streamFormats[pixFmt] = { { kMinISISize, sensorSize } }; > > + } > > + > > + StreamFormats formats(streamFormats); > > + > > + StreamConfiguration cfg(formats); > > + cfg.pixelFormat = pixelFormat; > > + cfg.size = sensorSize; > > + cfg.bufferCount = 4; > > + > > + return cfg; > > +} > > + > > +/* > > + * Generate a StreamConfiguration for Raw Bayer use case. Verify if the sensor > > + * can produce the requested RAW bayer format and eventually adjust it to > > + * the one with the largest bit-depth the sensor can produce. > > + */ > > +StreamConfiguration PipelineHandlerISI::generateRawConfiguration(Camera *camera) > > +{ > > + static const std::map<unsigned int, PixelFormat> rawFormats = { > > + { MEDIA_BUS_FMT_SBGGR8_1X8, formats::SBGGR8 }, > > + { MEDIA_BUS_FMT_SGBRG8_1X8, formats::SGBRG8 }, > > + { MEDIA_BUS_FMT_SGRBG8_1X8, formats::SGRBG8 }, > > + { MEDIA_BUS_FMT_SRGGB8_1X8, formats::SRGGB8 }, > > + { MEDIA_BUS_FMT_SBGGR10_1X10, formats::SBGGR10 }, > > + { MEDIA_BUS_FMT_SGBRG10_1X10, formats::SGBRG10 }, > > + { MEDIA_BUS_FMT_SGRBG10_1X10, formats::SGRBG10 }, > > + { MEDIA_BUS_FMT_SRGGB10_1X10, formats::SRGGB10 }, > > + { MEDIA_BUS_FMT_SBGGR12_1X12, formats::SBGGR12 }, > > + { MEDIA_BUS_FMT_SGBRG12_1X12, formats::SGBRG12 }, > > + { MEDIA_BUS_FMT_SGRBG12_1X12, formats::SGRBG12 }, > > + { MEDIA_BUS_FMT_SRGGB12_1X12, formats::SRGGB12 }, > > Now that libcamera has RAW14 formats, could you add them here ? > > > + }; > > + > > + ISICameraData *data = cameraData(camera); > > + PixelFormat pixelFormat = formats::SBGGR10; > > + unsigned int mbusCode; > > + > > + /* pixelFormat will be adjusted, if the sensor can produce RAW. */ > > + mbusCode = data->getRawMediaBusFormat(&pixelFormat); > > + if (!mbusCode) > > + return {}; > > + > > + /* > > + * Populate the StreamConfiguration with all the supported Bayer > > + * formats the sensor can produce. > > + */ > > + std::map<PixelFormat, std::vector<SizeRange>> streamFormats; > > + const CameraSensor *sensor = data->sensor_.get(); > > + > > + for (unsigned int code : sensor->mbusCodes()) { > > + /* Find a Bayer media bus code from the sensor. */ > > + const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(code); > > + if (!bayerFormat.isValid()) > > + continue; > > + > > + auto it = rawFormats.find(code); > > + if (it == rawFormats.end()) { > > + LOG(ISI, Warning) << bayerFormat > > + << " not supported in ISI formats map."; > > + continue; > > + } > > + > > + streamFormats[it->second] = { { sensor->resolution(), sensor->resolution() } }; > > + } > > + > > + StreamFormats formats(streamFormats); > > + > > + StreamConfiguration cfg(formats); > > + cfg.size = sensor->resolution(); > > + cfg.pixelFormat = pixelFormat; > > + cfg.bufferCount = 4; > > + > > + return cfg; > > +} > > + > > std::unique_ptr<CameraConfiguration> > > PipelineHandlerISI::generateConfiguration(Camera *camera, > > const StreamRoles &roles) > > @@ -722,79 +849,45 @@ PipelineHandlerISI::generateConfiguration(Camera *camera, > > return nullptr; > > } > > > > - bool isRaw = false; > > for (const auto &role : roles) { > > /* > > - * Prefer the following formats > > + * Prefer the following formats: > > * - Still Capture: Full resolution YUYV > > * - ViewFinder/VideoRecording: 1080p YUYV > > - * - RAW: sensor's native format and resolution > > + * - RAW: Full resolution Bayer > > */ > > - std::map<PixelFormat, std::vector<SizeRange>> streamFormats; > > - PixelFormat pixelFormat; > > - Size size; > > + StreamConfiguration cfg; > > > > switch (role) { > > case StreamRole::StillCapture: > > - /* > > - * \todo Make sure the sensor can produce non-RAW formats > > - * compatible with the ones supported by the pipeline. > > - */ > > - size = data->sensor_->resolution(); > > - pixelFormat = formats::YUYV; > > + cfg = generateYUVConfiguration(camera, > > + data->sensor_->resolution()); > > + if (!cfg.pixelFormat.isValid()) { > > + /* > > + * Fallback to use a Bayer format if that's what > > + * the sensor supports. > > + */ > > + cfg = generateRawConfiguration(camera); > > + } > > + > > break; > > > > case StreamRole::Viewfinder: > > case StreamRole::VideoRecording: > > - /* > > - * \todo Make sure the sensor can produce non-RAW formats > > - * compatible with the ones supported by the pipeline. > > - */ > > - size = PipelineHandlerISI::kPreviewSize; > > - pixelFormat = formats::YUYV; > > - break; > > - > > - case StreamRole::Raw: { > > - /* > > - * Make sure the sensor can generate a RAW format and > > - * prefer the ones with a larger bitdepth. > > - */ > > - const ISICameraConfiguration::FormatMap::value_type *rawPipeFormat = nullptr; > > - unsigned int maxDepth = 0; > > - > > - for (unsigned int code : data->sensor_->mbusCodes()) { > > - const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(code); > > - if (!bayerFormat.isValid()) > > - continue; > > - > > - /* Make sure the format is supported by the pipeline handler. */ > > - auto it = std::find_if(ISICameraConfiguration::formatsMap_.begin(), > > - ISICameraConfiguration::formatsMap_.end(), > > - [code](auto &isiFormat) { > > - auto &pipe = isiFormat.second; > > - return pipe.sensorCode == code; > > - }); > > - if (it == ISICameraConfiguration::formatsMap_.end()) > > - continue; > > - > > - if (bayerFormat.bitDepth > maxDepth) { > > - maxDepth = bayerFormat.bitDepth; > > - rawPipeFormat = &(*it); > > - } > > - } > > - > > - if (!rawPipeFormat) { > > - LOG(ISI, Error) > > - << "Cannot generate a configuration for RAW stream"; > > - return nullptr; > > + cfg = generateYUVConfiguration(camera, > > + PipelineHandlerISI::kPreviewSize); > > + if (!cfg.pixelFormat.isValid()) { > > + /* > > + * Fallback to use a Bayer format if that's what > > + * the sensor supports. > > + */ > > + cfg = generateRawConfiguration(camera); > > } > > > > - size = data->sensor_->resolution(); > > - pixelFormat = rawPipeFormat->first; > > - > > - streamFormats[pixelFormat] = { { kMinISISize, size } }; > > - isRaw = true; > > + break; > > > > + case StreamRole::Raw: { > > + cfg = generateRawConfiguration(camera); > > break; > > } > > > > Would this be clearer ? > > switch (role) { > case StreamRole::StillCapture: > case StreamRole::Viewfinder: > case StreamRole::VideoRecording: > Size size = role == StreamRole::StillCapture > ? data->sensor_->resolution() > : PipelineHandlerISI::kPreviewSize; > cfg = generateYUVConfiguration(camera, size); > if (cfg.pixelFormat.isValid()) > break; > > /* > * Fallback to use a Bayer format if that's what the > * sensor supports. > */ > [[fallthrough]] > > case StreamRole::Raw: { > cfg = generateRawConfiguration(camera); > break; > } > > Up to you. > > > @@ -803,26 +896,12 @@ PipelineHandlerISI::generateConfiguration(Camera *camera, > > return nullptr; > > } > > > > - /* > > - * For non-RAW configurations the ISI can perform colorspace > > - * conversion. List all the supported output formats here. > > - */ > > - if (!isRaw) { > > - for (const auto &[pixFmt, pipeFmt] : ISICameraConfiguration::formatsMap_) { > > - const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt); > > - if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) > > - continue; > > - > > - streamFormats[pixFmt] = { { kMinISISize, size } }; > > - } > > + if (!cfg.pixelFormat.isValid()) { > > + LOG(ISI, Error) > > + << "Cannot generate configuration for role: " << role; > > + return nullptr; > > } > > > > - StreamFormats formats(streamFormats); > > - > > - StreamConfiguration cfg(formats); > > - cfg.pixelFormat = pixelFormat; > > - cfg.size = size; > > - cfg.bufferCount = 4; > > config->addConfiguration(cfg); > > } > > > > -- > Regards, > > Laurent Pinchart
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp index 146ba7465012..a4f437f55b26 100644 --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp @@ -145,6 +145,10 @@ private: Pipe *pipeFromStream(Camera *camera, const Stream *stream); + StreamConfiguration generateYUVConfiguration(Camera *camera, + const Size &size); + StreamConfiguration generateRawConfiguration(Camera *camera); + void bufferReady(FrameBuffer *buffer); MediaDevice *isiDev_; @@ -705,6 +709,129 @@ PipelineHandlerISI::PipelineHandlerISI(CameraManager *manager) { } +/* + * Generate a StreamConfiguration for YUV/RGB use case. + * + * Verify it the sensor can produce a YUV/RGB media bus format and collect + * all the processed pixel formats the ISI can generate as supported stream + * configurations. + */ +StreamConfiguration PipelineHandlerISI::generateYUVConfiguration(Camera *camera, + const Size &size) +{ + ISICameraData *data = cameraData(camera); + PixelFormat pixelFormat = formats::YUYV; + unsigned int mbusCode; + + mbusCode = data->getYuvMediaBusFormat(&pixelFormat); + if (!mbusCode) + return {}; + + /* Adjust the requested size to the sensor's capabilities. */ + const CameraSensor *sensor = data->sensor_.get(); + + V4L2SubdeviceFormat sensorFmt; + sensorFmt.mbus_code = mbusCode; + sensorFmt.size = size; + + int ret = sensor->tryFormat(&sensorFmt); + if (ret) { + LOG(ISI, Error) << "Failed to try sensor format."; + return {}; + } + + Size sensorSize = sensorFmt.size; + + /* + * Populate the StreamConfiguration. + * + * As the sensor supports at least one YUV/RGB media bus format all the + * processed ones in formatsMap_ can be generated from it. + */ + std::map<PixelFormat, std::vector<SizeRange>> streamFormats; + + for (const auto &[pixFmt, pipeFmt] : ISICameraConfiguration::formatsMap_) { + const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt); + if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) + continue; + + streamFormats[pixFmt] = { { kMinISISize, sensorSize } }; + } + + StreamFormats formats(streamFormats); + + StreamConfiguration cfg(formats); + cfg.pixelFormat = pixelFormat; + cfg.size = sensorSize; + cfg.bufferCount = 4; + + return cfg; +} + +/* + * Generate a StreamConfiguration for Raw Bayer use case. Verify if the sensor + * can produce the requested RAW bayer format and eventually adjust it to + * the one with the largest bit-depth the sensor can produce. + */ +StreamConfiguration PipelineHandlerISI::generateRawConfiguration(Camera *camera) +{ + static const std::map<unsigned int, PixelFormat> rawFormats = { + { MEDIA_BUS_FMT_SBGGR8_1X8, formats::SBGGR8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, formats::SGBRG8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, formats::SGRBG8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, formats::SRGGB8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, formats::SBGGR10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, formats::SGBRG10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, formats::SGRBG10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, formats::SRGGB10 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, formats::SBGGR12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, formats::SGBRG12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, formats::SGRBG12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, formats::SRGGB12 }, + }; + + ISICameraData *data = cameraData(camera); + PixelFormat pixelFormat = formats::SBGGR10; + unsigned int mbusCode; + + /* pixelFormat will be adjusted, if the sensor can produce RAW. */ + mbusCode = data->getRawMediaBusFormat(&pixelFormat); + if (!mbusCode) + return {}; + + /* + * Populate the StreamConfiguration with all the supported Bayer + * formats the sensor can produce. + */ + std::map<PixelFormat, std::vector<SizeRange>> streamFormats; + const CameraSensor *sensor = data->sensor_.get(); + + for (unsigned int code : sensor->mbusCodes()) { + /* Find a Bayer media bus code from the sensor. */ + const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(code); + if (!bayerFormat.isValid()) + continue; + + auto it = rawFormats.find(code); + if (it == rawFormats.end()) { + LOG(ISI, Warning) << bayerFormat + << " not supported in ISI formats map."; + continue; + } + + streamFormats[it->second] = { { sensor->resolution(), sensor->resolution() } }; + } + + StreamFormats formats(streamFormats); + + StreamConfiguration cfg(formats); + cfg.size = sensor->resolution(); + cfg.pixelFormat = pixelFormat; + cfg.bufferCount = 4; + + return cfg; +} + std::unique_ptr<CameraConfiguration> PipelineHandlerISI::generateConfiguration(Camera *camera, const StreamRoles &roles) @@ -722,79 +849,45 @@ PipelineHandlerISI::generateConfiguration(Camera *camera, return nullptr; } - bool isRaw = false; for (const auto &role : roles) { /* - * Prefer the following formats + * Prefer the following formats: * - Still Capture: Full resolution YUYV * - ViewFinder/VideoRecording: 1080p YUYV - * - RAW: sensor's native format and resolution + * - RAW: Full resolution Bayer */ - std::map<PixelFormat, std::vector<SizeRange>> streamFormats; - PixelFormat pixelFormat; - Size size; + StreamConfiguration cfg; switch (role) { case StreamRole::StillCapture: - /* - * \todo Make sure the sensor can produce non-RAW formats - * compatible with the ones supported by the pipeline. - */ - size = data->sensor_->resolution(); - pixelFormat = formats::YUYV; + cfg = generateYUVConfiguration(camera, + data->sensor_->resolution()); + if (!cfg.pixelFormat.isValid()) { + /* + * Fallback to use a Bayer format if that's what + * the sensor supports. + */ + cfg = generateRawConfiguration(camera); + } + break; case StreamRole::Viewfinder: case StreamRole::VideoRecording: - /* - * \todo Make sure the sensor can produce non-RAW formats - * compatible with the ones supported by the pipeline. - */ - size = PipelineHandlerISI::kPreviewSize; - pixelFormat = formats::YUYV; - break; - - case StreamRole::Raw: { - /* - * Make sure the sensor can generate a RAW format and - * prefer the ones with a larger bitdepth. - */ - const ISICameraConfiguration::FormatMap::value_type *rawPipeFormat = nullptr; - unsigned int maxDepth = 0; - - for (unsigned int code : data->sensor_->mbusCodes()) { - const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(code); - if (!bayerFormat.isValid()) - continue; - - /* Make sure the format is supported by the pipeline handler. */ - auto it = std::find_if(ISICameraConfiguration::formatsMap_.begin(), - ISICameraConfiguration::formatsMap_.end(), - [code](auto &isiFormat) { - auto &pipe = isiFormat.second; - return pipe.sensorCode == code; - }); - if (it == ISICameraConfiguration::formatsMap_.end()) - continue; - - if (bayerFormat.bitDepth > maxDepth) { - maxDepth = bayerFormat.bitDepth; - rawPipeFormat = &(*it); - } - } - - if (!rawPipeFormat) { - LOG(ISI, Error) - << "Cannot generate a configuration for RAW stream"; - return nullptr; + cfg = generateYUVConfiguration(camera, + PipelineHandlerISI::kPreviewSize); + if (!cfg.pixelFormat.isValid()) { + /* + * Fallback to use a Bayer format if that's what + * the sensor supports. + */ + cfg = generateRawConfiguration(camera); } - size = data->sensor_->resolution(); - pixelFormat = rawPipeFormat->first; - - streamFormats[pixelFormat] = { { kMinISISize, size } }; - isRaw = true; + break; + case StreamRole::Raw: { + cfg = generateRawConfiguration(camera); break; } @@ -803,26 +896,12 @@ PipelineHandlerISI::generateConfiguration(Camera *camera, return nullptr; } - /* - * For non-RAW configurations the ISI can perform colorspace - * conversion. List all the supported output formats here. - */ - if (!isRaw) { - for (const auto &[pixFmt, pipeFmt] : ISICameraConfiguration::formatsMap_) { - const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt); - if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) - continue; - - streamFormats[pixFmt] = { { kMinISISize, size } }; - } + if (!cfg.pixelFormat.isValid()) { + LOG(ISI, Error) + << "Cannot generate configuration for role: " << role; + return nullptr; } - StreamFormats formats(streamFormats); - - StreamConfiguration cfg(formats); - cfg.pixelFormat = pixelFormat; - cfg.size = size; - cfg.bufferCount = 4; config->addConfiguration(cfg); }