[libcamera-devel,3/3] pipeline: raspberrypi: Fix colour spaces by handling missing YCbCr information
diff mbox series

Message ID 20221216143344.8177-4-david.plowman@raspberrypi.com
State Superseded
Headers show
Series
  • Fix colour spaces on Raspberry Pi
Related show

Commit Message

David Plowman Dec. 16, 2022, 2:33 p.m. UTC
In this patch we fix up colour spaces by adding the YCbCr information
that is now not present for streams with an RGB output format. We need
this information so that colour spaces are translated into the V4L2
ones that the Raspberry Pi hardware drivers will interpret correctly.

Related to this, the YCbCr information is once again removed before
the actual colour space is returned to us, so we have to be more
careful about how we check that we got what we expected.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
---
 .../pipeline/raspberrypi/raspberrypi.cpp      | 56 ++++++++++++++++++-
 1 file changed, 54 insertions(+), 2 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index 8569df17..f2d10d2a 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -357,6 +357,39 @@  RPiCameraConfiguration::RPiCameraConfiguration(const RPiCameraData *data)
 {
 }
 
+static const std::vector<ColorSpace> validColorSpaces = {
+	ColorSpace::Sycc,
+	ColorSpace::Smpte170m,
+	ColorSpace::Rec709
+};
+
+static std::optional<ColorSpace> fixColorSpace(const std::optional<ColorSpace> &colorSpace,
+					       CameraConfiguration::Status &status)
+{
+	if (!colorSpace)
+		return std::nullopt;
+
+	/*
+	 * We prefer to restore any YCbCr encoding and range information that may have been
+	 * removed from RGB streams. This ensures the colour spaces will be converted correctly
+	 * into the colour spaces that the drivers handle, namely V4L2_COLORSPACE_JPEG,
+	 * V4L2_COLORSPACE_SMPTE170M and V4L2_COLORSPACE_REC709.
+	 *
+	 * Luckily, the primaries and transfer function are enough for us to deduce exactly which
+	 * ColorSpace was originally intended.
+	 */
+	for (const auto &cs : validColorSpaces) {
+		if (colorSpace->primaries == cs.primaries &&
+		    colorSpace->transferFunction == cs.transferFunction)
+			return cs;
+	}
+
+	/* If nothing was matched, ask for sYCC. */
+	LOG(RPI, Debug) << "No match for colour space " << colorSpace->toString();
+	status = CameraConfiguration::Adjusted;
+	return ColorSpace::Sycc;
+}
+
 CameraConfiguration::Status RPiCameraConfiguration::validate()
 {
 	Status status = Valid;
@@ -533,7 +566,26 @@  CameraConfiguration::Status RPiCameraConfiguration::validate()
 		V4L2DeviceFormat format;
 		format.fourcc = dev->toV4L2PixelFormat(cfg.pixelFormat);
 		format.size = cfg.size;
-		format.colorSpace = cfg.colorSpace;
+		/*
+		 * Make sure the colour space is the one we want converted for our drivers, with
+		 * the YCbCr information restored. status will be set to Adjusted if we didn't
+		 * like the input colour space.
+		 */
+		format.colorSpace = fixColorSpace(cfg.colorSpace, status);
+
+		/*
+		 * When it comes back, RGB streams will have had the YCbCr information
+		 * overwritten again, so let's figure out what we really expect to be
+		 * returned.
+		 */
+		auto checkColorSpace = format.colorSpace;
+		if (checkColorSpace) {
+			const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+			if (info.colourEncoding == PixelFormatInfo::ColourEncodingRGB) {
+				checkColorSpace->ycbcrEncoding = ColorSpace::YcbcrEncoding::None;
+				checkColorSpace->range = ColorSpace::Range::Full;
+			}
+		}
 
 		LOG(RPI, Debug)
 			<< "Try color space " << ColorSpace::toString(cfg.colorSpace);
@@ -542,7 +594,7 @@  CameraConfiguration::Status RPiCameraConfiguration::validate()
 		if (ret)
 			return Invalid;
 
-		if (cfg.colorSpace != format.colorSpace) {
+		if (checkColorSpace != format.colorSpace) {
 			status = Adjusted;
 			LOG(RPI, Debug)
 				<< "Color space changed from "