Message ID | 20200306202637.525587-3-nicolas@ndufresne.ca |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Nicolas, Thank you for the patch. On Fri, Mar 06, 2020 at 03:26:12PM -0500, Nicolas Dufresne wrote: > From: Nicolas Dufresne <nicolas.dufresne@collabora.com> > > 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> > --- > src/gstreamer/gstlibcamera-utils.cpp | 105 +++++++++++++++++++++++++++ > src/gstreamer/gstlibcamera-utils.h | 19 +++++ > src/gstreamer/meson.build | 1 + > 3 files changed, 125 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..386ec36 > --- /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; > +} > diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h > new file mode 100644 > index 0000000..2e4e304 > --- /dev/null > +++ b/src/gstreamer/gstlibcamera-utils.h > @@ -0,0 +1,19 @@ > +/* 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__ > +#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__ */ > diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build > index 25350f2..1539d9e 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', > ]
diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp new file mode 100644 index 0000000..386ec36 --- /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; +} diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h new file mode 100644 index 0000000..2e4e304 --- /dev/null +++ b/src/gstreamer/gstlibcamera-utils.h @@ -0,0 +1,19 @@ +/* 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__ +#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__ */ diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build index 25350f2..1539d9e 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', ]