[libcamera-devel,2/3] libcamera: camera: Fix validateColorSpaces not to loose YCbCr encodings
diff mbox series

Message ID 20221216143344.8177-3-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
When sharing the same colour spaces across streams, the "main" stream
might be an RGB stream so we must stop its YCbCr information (encoding
and range) from overwriting other YUV streams.

Instead we also make a note of the largest stream with YCbCr
information. We take the primaries and transfer function from the
original "main" stream, but the YCbCr encoding and range from this
second stream.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
---
 src/libcamera/camera.cpp | 47 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 5 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index 0da167a7..e0a5d03d 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -358,10 +358,13 @@  CameraConfiguration::Status CameraConfiguration::validateColorSpaces(ColorSpaceF
 
 	/*
 	 * Set all raw streams to the Raw color space, and make a note of the
-	 * largest non-raw stream with a defined color space (if there is one).
+	 * largest non-raw stream with a defined color space (if there is one), and
+	 * also the largest stream with YCbCr encoding information.
 	 */
 	std::optional<ColorSpace> colorSpace;
+	std::optional<ColorSpace> ycbcrColorSpace;
 	Size size;
+	Size ycbcrSize;
 
 	for (auto [i, cfg] : utils::enumerate(config_)) {
 		if (!cfg.colorSpace)
@@ -370,22 +373,56 @@  CameraConfiguration::Status CameraConfiguration::validateColorSpaces(ColorSpaceF
 		if (cfg.colorSpace->adjust(cfg.pixelFormat))
 			status = Adjusted;
 
-		if (cfg.colorSpace != ColorSpace::Raw && cfg.size > size) {
+		if (cfg.colorSpace == ColorSpace::Raw)
+			continue;
+
+		if (cfg.size > size) {
 			colorSpace = cfg.colorSpace;
 			size = cfg.size;
 		}
+
+		if (cfg.colorSpace->ycbcrEncoding != ColorSpace::YcbcrEncoding::None &&
+		    cfg.size > ycbcrSize) {
+			ycbcrColorSpace = cfg.colorSpace;
+			ycbcrSize = cfg.size;
+		}
 	}
 
 	if (!colorSpace || !(flags & ColorSpaceFlag::StreamsShareColorSpace))
 		return status;
 
-	/* Make all output color spaces the same, if requested. */
+	/*
+	 * Make all output color spaces the same, if requested. Note that when sharing like
+	 * this, we copy the primaries and transfer function from the principal stream
+	 * (the variable "colorSpace") but we mustn't use its ycbcrEncoding or range because
+	 * it may be an RGB stream. So we take these fields instead from the "ycbcrColorSpace".
+	 */
 	for (auto &cfg : config_) {
-		if (cfg.colorSpace != ColorSpace::Raw &&
-		    cfg.colorSpace != colorSpace) {
+		if (!cfg.colorSpace) {
 			cfg.colorSpace = colorSpace;
 			status = Adjusted;
 		}
+
+		if (cfg.colorSpace == ColorSpace::Raw)
+			continue;
+
+		/* Ensure the primaries and transferFunction match the "main" stream. */
+		if (cfg.colorSpace->primaries != colorSpace->primaries ||
+		    cfg.colorSpace->transferFunction != colorSpace->transferFunction) {
+			cfg.colorSpace->primaries = colorSpace->primaries;
+			cfg.colorSpace->transferFunction = colorSpace->transferFunction;
+			status = Adjusted;
+		}
+
+		if (cfg.colorSpace->ycbcrEncoding != ColorSpace::YcbcrEncoding::None) {
+			/* Set these from the ycbcrColorSpace (which we note must exist). */
+			if (ycbcrColorSpace->ycbcrEncoding != cfg.colorSpace->ycbcrEncoding ||
+			    ycbcrColorSpace->range != cfg.colorSpace->range) {
+				cfg.colorSpace->ycbcrEncoding = ycbcrColorSpace->ycbcrEncoding;
+				cfg.colorSpace->range = ycbcrColorSpace->range;
+				status = Adjusted;
+			}
+		}
 	}
 
 	return status;