[v2] gstreamer: Add CSI-2 packed Bayer format mappings
diff mbox series

Message ID 20260219173423.1028522-1-dev@fredfunk.tech
State New
Headers show
Series
  • [v2] gstreamer: Add CSI-2 packed Bayer format mappings
Related show

Commit Message

Frederic Laing Feb. 19, 2026, 5:34 p.m. UTC
Add SRGGB/SBGGR/SGBRG/SGRBG 10/12/14-bit CSI-2 packed (CSI2P) format
entries to both format_map and bayer_map in gstlibcamera-utils.cpp.

Many camera sensors (e.g., IMX371, IMX376) natively output
CSI-2 packed Bayer formats like SRGGB10_CSI2P. Without mappings for
these formats, GStreamer's libcamerasrc cannot negotiate raw Bayer
output (video/x-bayer caps) when the sensor only supports CSI2P
variants, causing caps negotiation to fail with empty caps.

This is particularly important for dual-stream (ViewFinder + Raw)
capture where the Raw stream needs to use the sensor's native CSI2P
format. The Software ISP processes only the ViewFinder stream while
the Raw stream bypasses it entirely, but GStreamer needs to be able
to represent the Raw stream's format in caps.

The CSI2P formats are mapped to distinct GStreamer Bayer format names
using a "p" suffix (e.g., SRGGB10_CSI2P -> "rggb10p") to distinguish
them from their unpacked counterparts (e.g., SRGGB10 -> "rggb10le").

This patch depends on the corresponding GStreamer merge request that
adds CSI-2 packed Bayer format support to the V4L2 plugin:
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10852

Tested on OnePlus 6T (Qualcomm SDM845) with IMX371 front camera:
- Single raw stream: 4656x3496 SRGGB10_CSI2P
- Dual stream: 640x480 ABGR8888 (ViewFinder) + 4656x3496 SRGGB10_CSI2P

Signed-off-by: Frederic Laing <dev@fredfunk.tech>
---
 src/gstreamer/gstlibcamera-utils.cpp | 31 +++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

Comments

Laurent Pinchart Feb. 20, 2026, 4:26 p.m. UTC | #1
Hi Frederic,

Thank you for the patch.

On Thu, Feb 19, 2026 at 05:34:34PM +0000, Frederic Laing wrote:
> Add SRGGB/SBGGR/SGBRG/SGRBG 10/12/14-bit CSI-2 packed (CSI2P) format
> entries to both format_map and bayer_map in gstlibcamera-utils.cpp.
> 
> Many camera sensors (e.g., IMX371, IMX376) natively output
> CSI-2 packed Bayer formats like SRGGB10_CSI2P.

It's not a property of the sensor, but of the CSI-2 receiver (or more
precisely the DMA engine on the output of the CSI-2 receievr). Same
CSI-2 receivers will write the packed data to memory, some will unpack
the data, and others will even repack them in a different format. I'd
write

Many CSI-2 receivers write raw data in the packed format defined in the
CSI-2 specification, like SRGGB10_CSI2P.

> Without mappings for
> these formats, GStreamer's libcamerasrc cannot negotiate raw Bayer
> output (video/x-bayer caps) when the sensor only supports CSI2P
> variants, causing caps negotiation to fail with empty caps.
> 
> This is particularly important for dual-stream (ViewFinder + Raw)
> capture where the Raw stream needs to use the sensor's native CSI2P

s/sensor's native //

> format. The Software ISP processes only the ViewFinder stream while
> the Raw stream bypasses it entirely, but GStreamer needs to be able
> to represent the Raw stream's format in caps.
> 
> The CSI2P formats are mapped to distinct GStreamer Bayer format names
> using a "p" suffix (e.g., SRGGB10_CSI2P -> "rggb10p") to distinguish
> them from their unpacked counterparts (e.g., SRGGB10 -> "rggb10le").
> 
> This patch depends on the corresponding GStreamer merge request that
> adds CSI-2 packed Bayer format support to the V4L2 plugin:
> https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10852

The code looks fine. Once the merge request gets appreoved, we can merge
this in libcamera.

> 
> Tested on OnePlus 6T (Qualcomm SDM845) with IMX371 front camera:
> - Single raw stream: 4656x3496 SRGGB10_CSI2P
> - Dual stream: 640x480 ABGR8888 (ViewFinder) + 4656x3496 SRGGB10_CSI2P
> 
> Signed-off-by: Frederic Laing <dev@fredfunk.tech>
> ---
>  src/gstreamer/gstlibcamera-utils.cpp | 31 +++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
> index bfb094c9..467e4f71 100644
> --- a/src/gstreamer/gstlibcamera-utils.cpp
> +++ b/src/gstreamer/gstlibcamera-utils.cpp
> @@ -22,7 +22,7 @@ static const struct {
>  	/* Compressed */
>  	{ GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },
>  
> -	/* Bayer formats */
> +	/* Bayer formats - unpacked */
>  	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },
>  	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },
>  	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },
> @@ -44,6 +44,20 @@ static const struct {
>  	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG16 },
>  	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB16 },
>  
> +	/* Bayer formats - CSI-2 packed */
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR10_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG10_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG10_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB10_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR12_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG12_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG12_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB12_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR14_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG14_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG14_CSI2P },
> +	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB14_CSI2P },
> +
>  	/* Monochrome */
>  	{ GST_VIDEO_FORMAT_GRAY8, formats::R8 },
>  	{ GST_VIDEO_FORMAT_GRAY16_LE, formats::R16 },
> @@ -265,6 +279,7 @@ static const struct {
>  	PixelFormat format;
>  	const gchar *name;
>  } bayer_map[]{
> +	/* Unpacked */
>  	{ formats::SBGGR8, "bggr" },
>  	{ formats::SGBRG8, "gbrg" },
>  	{ formats::SGRBG8, "grbg" },
> @@ -285,6 +300,20 @@ static const struct {
>  	{ formats::SGBRG16, "gbrg16le" },
>  	{ formats::SGRBG16, "grbg16le" },
>  	{ formats::SRGGB16, "rggb16le" },
> +
> +	/* CSI-2 packed */
> +	{ formats::SBGGR10_CSI2P, "bggr10p" },
> +	{ formats::SGBRG10_CSI2P, "gbrg10p" },
> +	{ formats::SGRBG10_CSI2P, "grbg10p" },
> +	{ formats::SRGGB10_CSI2P, "rggb10p" },
> +	{ formats::SBGGR12_CSI2P, "bggr12p" },
> +	{ formats::SGBRG12_CSI2P, "gbrg12p" },
> +	{ formats::SGRBG12_CSI2P, "grbg12p" },
> +	{ formats::SRGGB12_CSI2P, "rggb12p" },
> +	{ formats::SBGGR14_CSI2P, "bggr14p" },
> +	{ formats::SGBRG14_CSI2P, "gbrg14p" },
> +	{ formats::SGRBG14_CSI2P, "grbg14p" },
> +	{ formats::SRGGB14_CSI2P, "rggb14p" },
>  };
>  
>  static const gchar *

Patch
diff mbox series

diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
index bfb094c9..467e4f71 100644
--- a/src/gstreamer/gstlibcamera-utils.cpp
+++ b/src/gstreamer/gstlibcamera-utils.cpp
@@ -22,7 +22,7 @@  static const struct {
 	/* Compressed */
 	{ GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },
 
-	/* Bayer formats */
+	/* Bayer formats - unpacked */
 	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },
 	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },
 	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },
@@ -44,6 +44,20 @@  static const struct {
 	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG16 },
 	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB16 },
 
+	/* Bayer formats - CSI-2 packed */
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR10_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG10_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG10_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB10_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR12_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG12_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG12_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB12_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR14_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG14_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG14_CSI2P },
+	{ GST_VIDEO_FORMAT_ENCODED, formats::SRGGB14_CSI2P },
+
 	/* Monochrome */
 	{ GST_VIDEO_FORMAT_GRAY8, formats::R8 },
 	{ GST_VIDEO_FORMAT_GRAY16_LE, formats::R16 },
@@ -265,6 +279,7 @@  static const struct {
 	PixelFormat format;
 	const gchar *name;
 } bayer_map[]{
+	/* Unpacked */
 	{ formats::SBGGR8, "bggr" },
 	{ formats::SGBRG8, "gbrg" },
 	{ formats::SGRBG8, "grbg" },
@@ -285,6 +300,20 @@  static const struct {
 	{ formats::SGBRG16, "gbrg16le" },
 	{ formats::SGRBG16, "grbg16le" },
 	{ formats::SRGGB16, "rggb16le" },
+
+	/* CSI-2 packed */
+	{ formats::SBGGR10_CSI2P, "bggr10p" },
+	{ formats::SGBRG10_CSI2P, "gbrg10p" },
+	{ formats::SGRBG10_CSI2P, "grbg10p" },
+	{ formats::SRGGB10_CSI2P, "rggb10p" },
+	{ formats::SBGGR12_CSI2P, "bggr12p" },
+	{ formats::SGBRG12_CSI2P, "gbrg12p" },
+	{ formats::SGRBG12_CSI2P, "grbg12p" },
+	{ formats::SRGGB12_CSI2P, "rggb12p" },
+	{ formats::SBGGR14_CSI2P, "bggr14p" },
+	{ formats::SGBRG14_CSI2P, "gbrg14p" },
+	{ formats::SGRBG14_CSI2P, "grbg14p" },
+	{ formats::SRGGB14_CSI2P, "rggb14p" },
 };
 
 static const gchar *