summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-09-28 02:18:37 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-09-30 22:00:13 +0300
commit0cd715c4ded3b945e7281421552d185018f96a0c (patch)
treec0be90e5d1646c31c09a7a86925b1cd99ade5c1d
parent1d54f8d0a268b5053db8d30aebdff0adf6d748a2 (diff)
cam: kms_sink: Add color space support
KMS defines YCbCr encoding and quantization properties for planes. When supported by the device, set them to match the color space of the stream to render colors accurately. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Eric Curtin <ecurtin@redhat.com>
-rw-r--r--src/cam/kms_sink.cpp80
-rw-r--r--src/cam/kms_sink.h3
2 files changed, 83 insertions, 0 deletions
diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp
index 17e2fa69..754b061e 100644
--- a/src/cam/kms_sink.cpp
+++ b/src/cam/kms_sink.cpp
@@ -149,6 +149,81 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)
size_ = cfg.size;
stride_ = cfg.stride;
+ /* Configure color space. */
+ colorEncoding_ = std::nullopt;
+ colorRange_ = std::nullopt;
+
+ if (cfg.colorSpace->ycbcrEncoding == libcamera::ColorSpace::YcbcrEncoding::None)
+ return 0;
+
+ /*
+ * The encoding and range enums are defined in the kernel but not
+ * exposed in public headers.
+ */
+ enum drm_color_encoding {
+ DRM_COLOR_YCBCR_BT601,
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_BT2020,
+ };
+
+ enum drm_color_range {
+ DRM_COLOR_YCBCR_LIMITED_RANGE,
+ DRM_COLOR_YCBCR_FULL_RANGE,
+ };
+
+ const DRM::Property *colorEncoding = plane_->property("COLOR_ENCODING");
+ const DRM::Property *colorRange = plane_->property("COLOR_RANGE");
+
+ if (colorEncoding) {
+ drm_color_encoding encoding;
+
+ switch (cfg.colorSpace->ycbcrEncoding) {
+ case libcamera::ColorSpace::YcbcrEncoding::Rec601:
+ default:
+ encoding = DRM_COLOR_YCBCR_BT601;
+ break;
+ case libcamera::ColorSpace::YcbcrEncoding::Rec709:
+ encoding = DRM_COLOR_YCBCR_BT709;
+ break;
+ case libcamera::ColorSpace::YcbcrEncoding::Rec2020:
+ encoding = DRM_COLOR_YCBCR_BT2020;
+ break;
+ }
+
+ for (const auto &[id, name] : colorEncoding->enums()) {
+ if (id == encoding) {
+ colorEncoding_ = encoding;
+ break;
+ }
+ }
+ }
+
+ if (colorRange) {
+ drm_color_range range;
+
+ switch (cfg.colorSpace->range) {
+ case libcamera::ColorSpace::Range::Limited:
+ default:
+ range = DRM_COLOR_YCBCR_LIMITED_RANGE;
+ break;
+ case libcamera::ColorSpace::Range::Full:
+ range = DRM_COLOR_YCBCR_FULL_RANGE;
+ break;
+ }
+
+ for (const auto &[id, name] : colorRange->enums()) {
+ if (id == range) {
+ colorRange_ = range;
+ break;
+ }
+ }
+ }
+
+ if (!colorEncoding_ || !colorRange_)
+ std::cerr << "Color space " << cfg.colorSpace->toString()
+ << " not supported by the display device."
+ << " Colors may be wrong." << std::endl;
+
return 0;
}
@@ -415,6 +490,11 @@ bool KMSSink::processRequest(libcamera::Request *camRequest)
drmRequest->addProperty(plane_, "CRTC_W", dst_.width);
drmRequest->addProperty(plane_, "CRTC_H", dst_.height);
+ if (colorEncoding_)
+ drmRequest->addProperty(plane_, "COLOR_ENCODING", *colorEncoding_);
+ if (colorRange_)
+ drmRequest->addProperty(plane_, "COLOR_RANGE", *colorRange_);
+
flags |= DRM::AtomicRequest::FlagAllowModeset;
}
diff --git a/src/cam/kms_sink.h b/src/cam/kms_sink.h
index 76c4e611..e2c618a1 100644
--- a/src/cam/kms_sink.h
+++ b/src/cam/kms_sink.h
@@ -10,6 +10,7 @@
#include <list>
#include <memory>
#include <mutex>
+#include <optional>
#include <string>
#include <utility>
@@ -67,6 +68,8 @@ private:
libcamera::PixelFormat format_;
libcamera::Size size_;
unsigned int stride_;
+ std::optional<unsigned int> colorEncoding_;
+ std::optional<unsigned int> colorRange_;
libcamera::Rectangle src_;
libcamera::Rectangle dst_;