[libcamera-devel,v2,02/27] gst: Add utility to convert StreamFormats to GstCaps

Message ID 20200227200407.490616-3-nicolas.dufresne@collabora.com
State Accepted
Headers show
Series
  • GStreamer Element for libcamera
Related show

Commit Message

Nicolas Dufresne Feb. 27, 2020, 8:03 p.m. UTC
This transforms the basic information found in StreamFormats to GstCaps.
This can be handy to reply to early caps query or inside a device
provider. Note that we ignored generated range as they are harmful to
caps negotiation. We also don't simplify the caps for readability
reasons, so some of the discrete value may be included in a range.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
 src/gstreamer/gstlibcamera-utils.cpp | 98 ++++++++++++++++++++++++++++
 src/gstreamer/gstlibcamera-utils.h   | 18 +++++
 src/gstreamer/meson.build            |  1 +
 3 files changed, 117 insertions(+)
 create mode 100644 src/gstreamer/gstlibcamera-utils.cpp
 create mode 100644 src/gstreamer/gstlibcamera-utils.h

Comments

Laurent Pinchart Feb. 29, 2020, 1:17 p.m. UTC | #1
Hi Nicolas,

Thank you for the patch.

On Thu, Feb 27, 2020 at 03:03:42PM -0500, Nicolas Dufresne wrote:
> This transforms the basic information found in StreamFormats to GstCaps.
> This can be handy to reply to early caps query or inside a device
> provider. Note that we ignored generated range as they are harmful to
> caps negotiation. We also don't simplify the caps for readability
> reasons, so some of the discrete value may be included in a range.
> 
> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> ---
>  src/gstreamer/gstlibcamera-utils.cpp | 98 ++++++++++++++++++++++++++++
>  src/gstreamer/gstlibcamera-utils.h   | 18 +++++
>  src/gstreamer/meson.build            |  1 +
>  3 files changed, 117 insertions(+)
>  create mode 100644 src/gstreamer/gstlibcamera-utils.cpp
>  create mode 100644 src/gstreamer/gstlibcamera-utils.h
> 
> diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
> new file mode 100644
> index 0000000..dc129c3
> --- /dev/null
> +++ b/src/gstreamer/gstlibcamera-utils.cpp
> @@ -0,0 +1,98 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Collabora Ltd.
> + *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> + *
> + * gstlibcamera-utils.c - GStreamer libcamera Utility Function
> + */
> +
> +#include "gstlibcamera-utils.h"

Missing blank line here.

> +#include <linux/drm_fourcc.h>
> +
> +using namespace libcamera;
> +
> +static struct {
> +	GstVideoFormat gst_format;
> +	guint drm_fourcc;
> +} format_map[] = {
> +	{ GST_VIDEO_FORMAT_ENCODED, DRM_FORMAT_MJPEG },
> +	{ GST_VIDEO_FORMAT_RGB, DRM_FORMAT_BGR888 },
> +	{ GST_VIDEO_FORMAT_BGR, DRM_FORMAT_RGB888 },
> +	{ GST_VIDEO_FORMAT_ARGB, DRM_FORMAT_BGRA8888 },
> +	{ GST_VIDEO_FORMAT_NV12, DRM_FORMAT_NV12 },
> +	{ GST_VIDEO_FORMAT_NV21, DRM_FORMAT_NV21 },
> +	{ GST_VIDEO_FORMAT_NV16, DRM_FORMAT_NV16 },
> +	{ GST_VIDEO_FORMAT_NV61, DRM_FORMAT_NV61 },
> +	{ GST_VIDEO_FORMAT_NV24, DRM_FORMAT_NV24 },
> +	{ GST_VIDEO_FORMAT_UYVY, DRM_FORMAT_UYVY },
> +	{ GST_VIDEO_FORMAT_VYUY, DRM_FORMAT_VYUY },
> +	{ GST_VIDEO_FORMAT_YUY2, DRM_FORMAT_YUYV },
> +	{ GST_VIDEO_FORMAT_YVYU, DRM_FORMAT_YVYU },
> +	/* \todo NV42 is used in libcamera but is not mapped in GStreamer yet. */
> +};
> +
> +static inline GstVideoFormat
> +drm_to_gst_format(guint drm_fourcc)
> +{
> +	for (const auto &item : format_map)

	for (const auto &item : format_map) {
> +		if (item.drm_fourcc == drm_fourcc)
> +			return item.gst_format;
	}

Sweet, I didn't know C++ allowed range loops on plain C arrays :-)

> +	return GST_VIDEO_FORMAT_UNKNOWN;
> +}
> +
> +static GstStructure *
> +bare_structure_from_fourcc(guint fourcc)
> +{
> +	GstVideoFormat gst_format = drm_to_gst_format(fourcc);
> +
> +	if (gst_format == GST_VIDEO_FORMAT_UNKNOWN)
> +		return nullptr;
> +
> +	if (gst_format != GST_VIDEO_FORMAT_ENCODED)
> +		return gst_structure_new("video/x-raw", "format", G_TYPE_STRING,
> +					 gst_video_format_to_string(gst_format), nullptr);
> +
> +	switch (fourcc) {
> +	case DRM_FORMAT_MJPEG:
> +		return gst_structure_new_empty("image/jpeg");
> +	default:
> +		return nullptr;
> +	}
> +}
> +
> +GstCaps *
> +gst_libcamera_stream_formats_to_caps(const StreamFormats &formats)
> +{
> +	GstCaps *caps = gst_caps_new_empty();
> +
> +	for (unsigned int fourcc : formats.pixelformats()) {
> +		g_autoptr(GstStructure) bare_s = bare_structure_from_fourcc(fourcc);
> +
> +		if (!bare_s) {
> +			GST_WARNING("Unsupported DRM format %" GST_FOURCC_FORMAT,
> +				    GST_FOURCC_ARGS(fourcc));
> +			continue;
> +		}
> +
> +		for (const Size &size : formats.sizes(fourcc)) {
> +			GstStructure *s = gst_structure_copy(bare_s);
> +			gst_structure_set(s,
> +					  "width", G_TYPE_INT, size.width,
> +					  "height", G_TYPE_INT, size.height,
> +					  nullptr);
> +			gst_caps_append_structure(caps, s);
> +		}
> +
> +		const SizeRange &range = formats.range(fourcc);
> +		if (range.hStep && range.vStep) {
> +			GstStructure *s = gst_structure_copy(bare_s);
> +			gst_structure_set(s,
> +					  "width", GST_TYPE_INT_RANGE, range.min.width, range.max.width, range.hStep,
> +					  "height", GST_TYPE_INT_RANGE, range.min.height, range.max.height, range.vStep,
> +					  nullptr);
> +			gst_caps_append_structure(caps, s);
> +		}
> +	}
> +
> +	return caps;
> +}
> diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h
> new file mode 100644
> index 0000000..33160b8
> --- /dev/null
> +++ b/src/gstreamer/gstlibcamera-utils.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Collabora Ltd.
> + *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> + *
> + * gstlibcamera-utils.h - GStreamer libcamera Utility Functions
> + */
> +
> +#ifndef __GST_LIBCAMERA_UTILS_H_

s/__GST_LIBCAMERA_UTILS_H_/__GST_LIBCAMERA_UTILS_H__/

Missing

#define __GST_LIBCAMERA_UTILS_H__

> +
> +#include <gst/gst.h>
> +#include <gst/video/video.h>
> +
> +#include <libcamera/stream.h>
> +
> +GstCaps *gst_libcamera_stream_formats_to_caps(const libcamera::StreamFormats &formats);
> +
> +#endif /* __GST_LIBCAMERA_UTILS_H_ */

__GST_LIBCAMERA_UTILS_H__ here too.

> diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build
> index 832b8a5..f409107 100644
> --- a/src/gstreamer/meson.build
> +++ b/src/gstreamer/meson.build
> @@ -1,4 +1,5 @@
>  libcamera_gst_sources = [
> +    'gstlibcamera-utils.cpp',
>      'gstlibcamera.c',
>      'gstlibcamerasrc.cpp',
>  ]
Nicolas Dufresne March 6, 2020, 4:38 p.m. UTC | #2
Le samedi 29 février 2020 à 15:17 +0200, Laurent Pinchart a écrit :
> Hi Nicolas,
> 
> Thank you for the patch.
> 
> On Thu, Feb 27, 2020 at 03:03:42PM -0500, Nicolas Dufresne wrote:
> > This transforms the basic information found in StreamFormats to GstCaps.
> > This can be handy to reply to early caps query or inside a device
> > provider. Note that we ignored generated range as they are harmful to
> > caps negotiation. We also don't simplify the caps for readability
> > reasons, so some of the discrete value may be included in a range.
> > 
> > Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> > ---
> >  src/gstreamer/gstlibcamera-utils.cpp | 98 ++++++++++++++++++++++++++++
> >  src/gstreamer/gstlibcamera-utils.h   | 18 +++++
> >  src/gstreamer/meson.build            |  1 +
> >  3 files changed, 117 insertions(+)
> >  create mode 100644 src/gstreamer/gstlibcamera-utils.cpp
> >  create mode 100644 src/gstreamer/gstlibcamera-utils.h
> > 
> > diff --git a/src/gstreamer/gstlibcamera-utils.cpp
> > b/src/gstreamer/gstlibcamera-utils.cpp
> > new file mode 100644
> > index 0000000..dc129c3
> > --- /dev/null
> > +++ b/src/gstreamer/gstlibcamera-utils.cpp
> > @@ -0,0 +1,98 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2020, Collabora Ltd.
> > + *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> > + *
> > + * gstlibcamera-utils.c - GStreamer libcamera Utility Function
> > + */
> > +
> > +#include "gstlibcamera-utils.h"
> 
> Missing blank line here.
> 
> > +#include <linux/drm_fourcc.h>
> > +
> > +using namespace libcamera;
> > +
> > +static struct {
> > +	GstVideoFormat gst_format;
> > +	guint drm_fourcc;
> > +} format_map[] = {
> > +	{ GST_VIDEO_FORMAT_ENCODED, DRM_FORMAT_MJPEG },
> > +	{ GST_VIDEO_FORMAT_RGB, DRM_FORMAT_BGR888 },
> > +	{ GST_VIDEO_FORMAT_BGR, DRM_FORMAT_RGB888 },
> > +	{ GST_VIDEO_FORMAT_ARGB, DRM_FORMAT_BGRA8888 },
> > +	{ GST_VIDEO_FORMAT_NV12, DRM_FORMAT_NV12 },
> > +	{ GST_VIDEO_FORMAT_NV21, DRM_FORMAT_NV21 },
> > +	{ GST_VIDEO_FORMAT_NV16, DRM_FORMAT_NV16 },
> > +	{ GST_VIDEO_FORMAT_NV61, DRM_FORMAT_NV61 },
> > +	{ GST_VIDEO_FORMAT_NV24, DRM_FORMAT_NV24 },
> > +	{ GST_VIDEO_FORMAT_UYVY, DRM_FORMAT_UYVY },
> > +	{ GST_VIDEO_FORMAT_VYUY, DRM_FORMAT_VYUY },
> > +	{ GST_VIDEO_FORMAT_YUY2, DRM_FORMAT_YUYV },
> > +	{ GST_VIDEO_FORMAT_YVYU, DRM_FORMAT_YVYU },
> > +	/* \todo NV42 is used in libcamera but is not mapped in GStreamer yet.
> > */
> > +};
> > +
> > +static inline GstVideoFormat

I'm also dropping the inline here, which you asked and I missed in v2.

> > +drm_to_gst_format(guint drm_fourcc)
> > +{
> > +	for (const auto &item : format_map)
> 
> 	for (const auto &item : format_map) {
> > +		if (item.drm_fourcc == drm_fourcc)
> > +			return item.gst_format;
> 	}
> 
> Sweet, I didn't know C++ allowed range loops on plain C arrays :-)
> 
> > +	return GST_VIDEO_FORMAT_UNKNOWN;
> > +}
> > +
> > +static GstStructure *
> > +bare_structure_from_fourcc(guint fourcc)
> > +{
> > +	GstVideoFormat gst_format = drm_to_gst_format(fourcc);
> > +
> > +	if (gst_format == GST_VIDEO_FORMAT_UNKNOWN)
> > +		return nullptr;
> > +
> > +	if (gst_format != GST_VIDEO_FORMAT_ENCODED)
> > +		return gst_structure_new("video/x-raw", "format", G_TYPE_STRING,
> > +					 gst_video_format_to_string(gst_format),
> > nullptr);
> > +
> > +	switch (fourcc) {
> > +	case DRM_FORMAT_MJPEG:
> > +		return gst_structure_new_empty("image/jpeg");
> > +	default:
> > +		return nullptr;
> > +	}
> > +}
> > +
> > +GstCaps *
> > +gst_libcamera_stream_formats_to_caps(const StreamFormats &formats)
> > +{
> > +	GstCaps *caps = gst_caps_new_empty();
> > +
> > +	for (unsigned int fourcc : formats.pixelformats()) {
> > +		g_autoptr(GstStructure) bare_s =
> > bare_structure_from_fourcc(fourcc);
> > +
> > +		if (!bare_s) {
> > +			GST_WARNING("Unsupported DRM format %"
> > GST_FOURCC_FORMAT,
> > +				    GST_FOURCC_ARGS(fourcc));
> > +			continue;
> > +		}
> > +
> > +		for (const Size &size : formats.sizes(fourcc)) {
> > +			GstStructure *s = gst_structure_copy(bare_s);
> > +			gst_structure_set(s,
> > +					  "width", G_TYPE_INT, size.width,
> > +					  "height", G_TYPE_INT, size.height,
> > +					  nullptr);
> > +			gst_caps_append_structure(caps, s);
> > +		}
> > +
> > +		const SizeRange &range = formats.range(fourcc);
> > +		if (range.hStep && range.vStep) {
> > +			GstStructure *s = gst_structure_copy(bare_s);
> > +			gst_structure_set(s,
> > +					  "width", GST_TYPE_INT_RANGE,
> > range.min.width, range.max.width, range.hStep,
> > +					  "height", GST_TYPE_INT_RANGE,
> > range.min.height, range.max.height, range.vStep,
> > +					  nullptr);
> > +			gst_caps_append_structure(caps, s);
> > +		}
> > +	}
> > +
> > +	return caps;
> > +}
> > diff --git a/src/gstreamer/gstlibcamera-utils.h
> > b/src/gstreamer/gstlibcamera-utils.h
> > new file mode 100644
> > index 0000000..33160b8
> > --- /dev/null
> > +++ b/src/gstreamer/gstlibcamera-utils.h
> > @@ -0,0 +1,18 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2020, Collabora Ltd.
> > + *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> > + *
> > + * gstlibcamera-utils.h - GStreamer libcamera Utility Functions
> > + */
> > +
> > +#ifndef __GST_LIBCAMERA_UTILS_H_
> 
> s/__GST_LIBCAMERA_UTILS_H_/__GST_LIBCAMERA_UTILS_H__/
> 
> Missing
> 
> #define __GST_LIBCAMERA_UTILS_H__
> 
> > +
> > +#include <gst/gst.h>
> > +#include <gst/video/video.h>
> > +
> > +#include <libcamera/stream.h>
> > +
> > +GstCaps *gst_libcamera_stream_formats_to_caps(const
> > libcamera::StreamFormats &formats);
> > +
> > +#endif /* __GST_LIBCAMERA_UTILS_H_ */
> 
> __GST_LIBCAMERA_UTILS_H__ here too.
> 
> > diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build
> > index 832b8a5..f409107 100644
> > --- a/src/gstreamer/meson.build
> > +++ b/src/gstreamer/meson.build
> > @@ -1,4 +1,5 @@
> >  libcamera_gst_sources = [
> > +    'gstlibcamera-utils.cpp',
> >      'gstlibcamera.c',
> >      'gstlibcamerasrc.cpp',
> >  ]

Patch

diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
new file mode 100644
index 0000000..dc129c3
--- /dev/null
+++ b/src/gstreamer/gstlibcamera-utils.cpp
@@ -0,0 +1,98 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * gstlibcamera-utils.c - GStreamer libcamera Utility Function
+ */
+
+#include "gstlibcamera-utils.h"
+#include <linux/drm_fourcc.h>
+
+using namespace libcamera;
+
+static struct {
+	GstVideoFormat gst_format;
+	guint drm_fourcc;
+} format_map[] = {
+	{ GST_VIDEO_FORMAT_ENCODED, DRM_FORMAT_MJPEG },
+	{ GST_VIDEO_FORMAT_RGB, DRM_FORMAT_BGR888 },
+	{ GST_VIDEO_FORMAT_BGR, DRM_FORMAT_RGB888 },
+	{ GST_VIDEO_FORMAT_ARGB, DRM_FORMAT_BGRA8888 },
+	{ GST_VIDEO_FORMAT_NV12, DRM_FORMAT_NV12 },
+	{ GST_VIDEO_FORMAT_NV21, DRM_FORMAT_NV21 },
+	{ GST_VIDEO_FORMAT_NV16, DRM_FORMAT_NV16 },
+	{ GST_VIDEO_FORMAT_NV61, DRM_FORMAT_NV61 },
+	{ GST_VIDEO_FORMAT_NV24, DRM_FORMAT_NV24 },
+	{ GST_VIDEO_FORMAT_UYVY, DRM_FORMAT_UYVY },
+	{ GST_VIDEO_FORMAT_VYUY, DRM_FORMAT_VYUY },
+	{ GST_VIDEO_FORMAT_YUY2, DRM_FORMAT_YUYV },
+	{ GST_VIDEO_FORMAT_YVYU, DRM_FORMAT_YVYU },
+	/* \todo NV42 is used in libcamera but is not mapped in GStreamer yet. */
+};
+
+static inline GstVideoFormat
+drm_to_gst_format(guint drm_fourcc)
+{
+	for (const auto &item : format_map)
+		if (item.drm_fourcc == drm_fourcc)
+			return item.gst_format;
+	return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+static GstStructure *
+bare_structure_from_fourcc(guint fourcc)
+{
+	GstVideoFormat gst_format = drm_to_gst_format(fourcc);
+
+	if (gst_format == GST_VIDEO_FORMAT_UNKNOWN)
+		return nullptr;
+
+	if (gst_format != GST_VIDEO_FORMAT_ENCODED)
+		return gst_structure_new("video/x-raw", "format", G_TYPE_STRING,
+					 gst_video_format_to_string(gst_format), nullptr);
+
+	switch (fourcc) {
+	case DRM_FORMAT_MJPEG:
+		return gst_structure_new_empty("image/jpeg");
+	default:
+		return nullptr;
+	}
+}
+
+GstCaps *
+gst_libcamera_stream_formats_to_caps(const StreamFormats &formats)
+{
+	GstCaps *caps = gst_caps_new_empty();
+
+	for (unsigned int fourcc : formats.pixelformats()) {
+		g_autoptr(GstStructure) bare_s = bare_structure_from_fourcc(fourcc);
+
+		if (!bare_s) {
+			GST_WARNING("Unsupported DRM format %" GST_FOURCC_FORMAT,
+				    GST_FOURCC_ARGS(fourcc));
+			continue;
+		}
+
+		for (const Size &size : formats.sizes(fourcc)) {
+			GstStructure *s = gst_structure_copy(bare_s);
+			gst_structure_set(s,
+					  "width", G_TYPE_INT, size.width,
+					  "height", G_TYPE_INT, size.height,
+					  nullptr);
+			gst_caps_append_structure(caps, s);
+		}
+
+		const SizeRange &range = formats.range(fourcc);
+		if (range.hStep && range.vStep) {
+			GstStructure *s = gst_structure_copy(bare_s);
+			gst_structure_set(s,
+					  "width", GST_TYPE_INT_RANGE, range.min.width, range.max.width, range.hStep,
+					  "height", GST_TYPE_INT_RANGE, range.min.height, range.max.height, range.vStep,
+					  nullptr);
+			gst_caps_append_structure(caps, s);
+		}
+	}
+
+	return caps;
+}
diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h
new file mode 100644
index 0000000..33160b8
--- /dev/null
+++ b/src/gstreamer/gstlibcamera-utils.h
@@ -0,0 +1,18 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * gstlibcamera-utils.h - GStreamer libcamera Utility Functions
+ */
+
+#ifndef __GST_LIBCAMERA_UTILS_H_
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <libcamera/stream.h>
+
+GstCaps *gst_libcamera_stream_formats_to_caps(const libcamera::StreamFormats &formats);
+
+#endif /* __GST_LIBCAMERA_UTILS_H_ */
diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build
index 832b8a5..f409107 100644
--- a/src/gstreamer/meson.build
+++ b/src/gstreamer/meson.build
@@ -1,4 +1,5 @@ 
 libcamera_gst_sources = [
+    'gstlibcamera-utils.cpp',
     'gstlibcamera.c',
     'gstlibcamerasrc.cpp',
 ]