summaryrefslogtreecommitdiff
path: root/src/gstreamer/gstlibcamera-utils.cpp
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.com>2020-01-14 10:55:01 -0500
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-03-07 01:57:45 +0200
commiteee8f56f0a7f34574752948027843bf6a1912e90 (patch)
tree1f3f61bf2ac1d9acb0fd242436cade5111582a43 /src/gstreamer/gstlibcamera-utils.cpp
parent17cccc68a88ffaaeb06fb2383ad27b5ccb627c24 (diff)
gst: Add utility to convert StreamFormats to GstCaps
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> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src/gstreamer/gstlibcamera-utils.cpp')
-rw-r--r--src/gstreamer/gstlibcamera-utils.cpp105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
new file mode 100644
index 00000000..386ec364
--- /dev/null
+++ b/src/gstreamer/gstlibcamera-utils.cpp
@@ -0,0 +1,105 @@
+/* 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 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);
+ GValue val = G_VALUE_INIT;
+
+ g_value_init(&val, GST_TYPE_INT_RANGE);
+ gst_value_set_int_range_step(&val, range.min.width, range.max.width, range.hStep);
+ gst_structure_set_value(s, "width", &val);
+ gst_value_set_int_range_step(&val, range.min.height, range.max.height, range.vStep);
+ gst_structure_set_value(s, "height", &val);
+ g_value_unset(&val);
+
+ gst_caps_append_structure(caps, s);
+ }
+ }
+
+ return caps;
+}