Add YuvSnapshot support

Stream with YCbCr_420_888 format may be treated as different
usage type on different platforms.

Add YuvSnapshot support. Then pipeline handler can decide
the detail pipe to run.

Treat YCbCr_420_888 as STILL for usage GRALLOC_USAGE_PRIVATE_1.

Signed-off-by: Qingwu Zhang <qingwu.zhang@intel.corp-partner.google.com>
Merged-In: Iadc7aad854242a0879f9be14475b96e026828a33
Change-Id: Iadc7aad854242a0879f9be14475b96e026828a33
diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h
index 2bb3cd9..7927e46 100644
--- a/include/libcamera/stream.h
+++ b/include/libcamera/stream.h
@@ -69,6 +69,7 @@
 	StillCapture,
 	VideoRecording,
 	Viewfinder,
+	YuvSnapshot,
 };
 
 std::ostream &operator<<(std::ostream &out, StreamRole role);
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index 8111d53..d4697db 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -214,6 +214,13 @@
 	return (GRALLOC_USAGE_HW_VIDEO_ENCODER & stream->usage);
 }
 
+// Vendor extended buffer usage bit for the HAL to identify the still capture YUV stream
+#define IS_STILL_USAGE(usage) (((usage)&GRALLOC_USAGE_PRIVATE_1) == GRALLOC_USAGE_PRIVATE_1)
+bool hasStillCaptureFlag(camera3_stream_t *stream)
+{
+	return (IS_STILL_USAGE(stream->usage));
+}
+
 bool isYuvSnapshotStream(camera3_stream_t *stream)
 {
 	return (!isVideoStream(stream) && !isPreviewStream(stream) &&
@@ -374,9 +381,12 @@
 
 		if (isJpegStream(stream)) {
 			continue;
-		} else if (isYuvSnapshotStream(stream)) {
+		} else if (hasStillCaptureFlag(stream)) {
 			streamConfig.streams = { { stream, CameraStream::Type::Direct } };
 			streamConfig.config.role = StreamRole::StillCapture;
+		} else if (isYuvSnapshotStream(stream)) {
+			streamConfig.streams = { { stream, CameraStream::Type::Direct } };
+			streamConfig.config.role = StreamRole::YuvSnapshot;
 		} else if (isPreviewStream(stream)) {
 			streamConfig.streams = { { stream, CameraStream::Type::Direct } };
 			streamConfig.config.role = StreamRole::Viewfinder;
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
index 9bdfff0..f6e87f8 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -765,6 +765,7 @@
 
                 switch (role) {
                 case StreamRole::StillCapture:
+		case StreamRole::YuvSnapshot:
                 case StreamRole::Viewfinder:
                 case StreamRole::VideoRecording: {
                         Size size = role == StreamRole::StillCapture
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index a81c817..3ed3be0 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -407,6 +407,7 @@
 		Size size;
 
 		switch (role) {
+		case StreamRole::YuvSnapshot:
 		case StreamRole::StillCapture:
 			/*
 			 * Use as default full-frame configuration a value
diff --git a/src/libcamera/pipeline/mtkisp7/mtkisp7.cpp b/src/libcamera/pipeline/mtkisp7/mtkisp7.cpp
index 6f25d8f..720affa 100644
--- a/src/libcamera/pipeline/mtkisp7/mtkisp7.cpp
+++ b/src/libcamera/pipeline/mtkisp7/mtkisp7.cpp
@@ -484,6 +484,7 @@
 			}
 			cfg.setStream(const_cast<Stream *>(vidStreams[videoCnt++]));
 			break;
+		case StreamRole::YuvSnapshot:
 		case StreamRole::StillCapture:
 			if (stillCnt >= 2) {
 				LOG(MtkISP7, Error)
@@ -562,6 +563,7 @@
 
 		switch (role) {
 		case StreamRole::StillCapture:
+		case StreamRole::YuvSnapshot:
 			cfg.setStream(&data->still1Stream_);
 			cfg.role = StreamRole::StillCapture;
 			break;
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 6efa79f..89b3b6f 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -638,6 +638,7 @@
 		Size size;
 
 		switch (role) {
+		case StreamRole::YuvSnapshot:
 		case StreamRole::StillCapture:
 			/* JPEG encoders typically expect sYCC. */
 			if (!colorSpace)
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
index fad710a..a6bfce2 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -398,6 +398,7 @@
 			bufferCount = 2;
 			break;
 
+		case StreamRole::YuvSnapshot:
 		case StreamRole::StillCapture:
 			fmts = data->ispFormats();
 			pixelFormat = formats::YUV420;
diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp
index 33d8ce4..087af60 100644
--- a/src/libcamera/pipeline/virtual/virtual.cpp
+++ b/src/libcamera/pipeline/virtual/virtual.cpp
@@ -221,6 +221,7 @@
 	for (const StreamRole role : roles) {
 		switch (role) {
 		case StreamRole::StillCapture:
+		case StreamRole::YuvSnapshot:
 		case StreamRole::VideoRecording:
 		case StreamRole::Viewfinder:
 			break;
diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp
index 1981655..c415813 100644
--- a/src/libcamera/stream.cpp
+++ b/src/libcamera/stream.cpp
@@ -416,6 +416,9 @@
  * The stream is intended to capture video for the purpose of display on the
  * local screen. Trade-offs between quality and usage of system resources are
  * acceptable.
+ * \var YuvSnapshot
+ * The stream is intended to capture high-resolution, high-quality YUV images
+ * with low frame rate.
  */
 
 /**
@@ -426,11 +429,12 @@
  */
 std::ostream &operator<<(std::ostream &out, StreamRole role)
 {
-	static constexpr std::array<const char *, 4> names{
+	static constexpr std::array<const char *, 5> names{
 		"Raw",
 		"StillCapture",
 		"VideoRecording",
 		"Viewfinder",
+		"YuvSnapshot",
 	};
 
 	out << names[static_cast<std::underlying_type_t<StreamRole>>(role)];