libcamera: pipeline: raspberrypi: Support color spaces

The Raspberry Pi pipeline handler now sets color spaces correctly.

In generateConfiguration() it sets them to reasonable default values
based on the stream role.

validate() now calls validateColorSpaces() to ensure that the
requested color spaces are sensible, before proceeding to check what
the hardware can deliver.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
David Plowman 2021-12-10 14:44:24 +00:00 committed by Laurent Pinchart
parent 5e5eadabd8
commit 13fdf9d0dc

View file

@ -96,6 +96,7 @@ V4L2DeviceFormat toV4L2DeviceFormat(const V4L2SubdeviceFormat &format,
deviceFormat.fourcc = V4L2PixelFormat::fromPixelFormat(pix); deviceFormat.fourcc = V4L2PixelFormat::fromPixelFormat(pix);
deviceFormat.size = format.size; deviceFormat.size = format.size;
deviceFormat.colorSpace = format.colorSpace;
return deviceFormat; return deviceFormat;
} }
@ -132,6 +133,7 @@ V4L2SubdeviceFormat findBestFormat(const SensorFormats &formatsMap, const Size &
{ {
double bestScore = std::numeric_limits<double>::max(), score; double bestScore = std::numeric_limits<double>::max(), score;
V4L2SubdeviceFormat bestFormat; V4L2SubdeviceFormat bestFormat;
bestFormat.colorSpace = ColorSpace::Raw;
constexpr float penaltyAr = 1500.0; constexpr float penaltyAr = 1500.0;
constexpr float penaltyBitDepth = 500.0; constexpr float penaltyBitDepth = 500.0;
@ -329,6 +331,8 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
if (config_.empty()) if (config_.empty())
return Invalid; return Invalid;
status = validateColorSpaces(ColorSpaceFlag::StreamsShareColorSpace);
/* /*
* What if the platform has a non-90 degree rotation? We can't even * What if the platform has a non-90 degree rotation? We can't even
* "adjust" the configuration and carry on. Alternatively, raising an * "adjust" the configuration and carry on. Alternatively, raising an
@ -496,11 +500,25 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
format.colorSpace = cfg.colorSpace;
LOG(RPI, Debug)
<< "Try color space " << ColorSpace::toString(cfg.colorSpace);
int ret = dev->tryFormat(&format); int ret = dev->tryFormat(&format);
if (ret) if (ret)
return Invalid; return Invalid;
if (cfg.colorSpace != format.colorSpace) {
status = Adjusted;
LOG(RPI, Debug)
<< "Color space changed from "
<< ColorSpace::toString(cfg.colorSpace) << " to "
<< ColorSpace::toString(format.colorSpace);
}
cfg.colorSpace = format.colorSpace;
cfg.stride = format.planes[0].bpl; cfg.stride = format.planes[0].bpl;
cfg.frameSize = format.planes[0].size; cfg.frameSize = format.planes[0].size;
@ -524,6 +542,7 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
PixelFormat pixelFormat; PixelFormat pixelFormat;
V4L2VideoDevice::Formats fmts; V4L2VideoDevice::Formats fmts;
Size size; Size size;
std::optional<ColorSpace> colorSpace;
if (roles.empty()) if (roles.empty())
return config; return config;
@ -539,6 +558,7 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
pixelFormat = mbusCodeToPixelFormat(sensorFormat.mbus_code, pixelFormat = mbusCodeToPixelFormat(sensorFormat.mbus_code,
BayerFormat::Packing::CSI2); BayerFormat::Packing::CSI2);
ASSERT(pixelFormat.isValid()); ASSERT(pixelFormat.isValid());
colorSpace = ColorSpace::Raw;
bufferCount = 2; bufferCount = 2;
rawCount++; rawCount++;
break; break;
@ -546,6 +566,12 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
case StreamRole::StillCapture: case StreamRole::StillCapture:
fmts = data->isp_[Isp::Output0].dev()->formats(); fmts = data->isp_[Isp::Output0].dev()->formats();
pixelFormat = formats::NV12; pixelFormat = formats::NV12;
/*
* Still image codecs usually expect the JPEG color space.
* Even RGB codecs will be fine as the RGB we get with the
* JPEG color space is the same as sRGB.
*/
colorSpace = ColorSpace::Jpeg;
/* Return the largest sensor resolution. */ /* Return the largest sensor resolution. */
size = sensorSize; size = sensorSize;
bufferCount = 1; bufferCount = 1;
@ -563,6 +589,11 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
*/ */
fmts = data->isp_[Isp::Output0].dev()->formats(); fmts = data->isp_[Isp::Output0].dev()->formats();
pixelFormat = formats::YUV420; pixelFormat = formats::YUV420;
/*
* Choose a color space appropriate for video recording.
* Rec.709 will be a good default for HD resolutions.
*/
colorSpace = ColorSpace::Rec709;
size = { 1920, 1080 }; size = { 1920, 1080 };
bufferCount = 4; bufferCount = 4;
outCount++; outCount++;
@ -571,6 +602,7 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
case StreamRole::Viewfinder: case StreamRole::Viewfinder:
fmts = data->isp_[Isp::Output0].dev()->formats(); fmts = data->isp_[Isp::Output0].dev()->formats();
pixelFormat = formats::ARGB8888; pixelFormat = formats::ARGB8888;
colorSpace = ColorSpace::Jpeg;
size = { 800, 600 }; size = { 800, 600 };
bufferCount = 4; bufferCount = 4;
outCount++; outCount++;
@ -617,6 +649,7 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
StreamConfiguration cfg(formats); StreamConfiguration cfg(formats);
cfg.size = size; cfg.size = size;
cfg.pixelFormat = pixelFormat; cfg.pixelFormat = pixelFormat;
cfg.colorSpace = colorSpace;
cfg.bufferCount = bufferCount; cfg.bufferCount = bufferCount;
config->addConfiguration(cfg); config->addConfiguration(cfg);
} }
@ -724,6 +757,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
V4L2PixelFormat fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); V4L2PixelFormat fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
format.fourcc = fourcc; format.fourcc = fourcc;
format.colorSpace = cfg.colorSpace;
LOG(RPI, Debug) << "Setting " << stream->name() << " to " LOG(RPI, Debug) << "Setting " << stream->name() << " to "
<< format.toString(); << format.toString();
@ -739,6 +773,10 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
return -EINVAL; return -EINVAL;
} }
LOG(RPI, Debug)
<< "Stream " << stream->name() << " has color space "
<< ColorSpace::toString(cfg.colorSpace);
cfg.setStream(stream); cfg.setStream(stream);
stream->setExternal(true); stream->setExternal(true);
@ -763,6 +801,8 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
format = {}; format = {};
format.size = maxSize; format.size = maxSize;
format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420); format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420);
/* No one asked for output, so the color space doesn't matter. */
format.colorSpace = ColorSpace::Jpeg;
ret = data->isp_[Isp::Output0].dev()->setFormat(&format); ret = data->isp_[Isp::Output0].dev()->setFormat(&format);
if (ret) { if (ret) {
LOG(RPI, Error) LOG(RPI, Error)