[libcamera-devel] [PATCH 2/2] gstreamer: src: Add transform property
Nicolas Dufresne
nicolas at ndufresne.ca
Tue Jun 13 16:39:33 CEST 2023
Le mardi 13 juin 2023 à 12:34 +0200, Robert Mader via libcamera-devel a écrit :
> This allows users to request a transform using the Gstreamer
> equivalent. If the combined transform of the requested one and a
> possible rotation from the camera properties is not fully supported by
> the sensor, the remaining transform will be passed down to downstream
> elements as tag.
>
> The later is common for 90/270 degree rotations. Thus, a side effect of
> this feature is that libcamerasrc now behaves similar to pipewiresrc in
> regards to rotated cameras in e.g. phones, allowing apps to compensate
> accordingly.
>
> Signed-off-by: Robert Mader <robert.mader at collabora.com>
> ---
> src/gstreamer/gstlibcamera-utils.cpp | 72 ++++++++++++++++++++++++++++
> src/gstreamer/gstlibcamera-utils.h | 5 ++
> src/gstreamer/gstlibcamerasrc.cpp | 41 +++++++++++++++-
> 3 files changed, 117 insertions(+), 1 deletion(-)
>
> diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
> index 750ec351..43ce75cb 100644
> --- a/src/gstreamer/gstlibcamera-utils.cpp
> +++ b/src/gstreamer/gstlibcamera-utils.cpp
> @@ -553,3 +553,75 @@ gst_libcamera_get_camera_manager(int &ret)
>
> return cm;
> }
> +
> +libcamera::Transform
> +gst_libcamera_orientation_to_transform(GstVideoOrientationMethod orientation)
> +{
> + switch (orientation) {
> + case GST_VIDEO_ORIENTATION_90R:
> + return Transform::Rot90;
> + case GST_VIDEO_ORIENTATION_180:
> + return Transform::Rot180;
> + case GST_VIDEO_ORIENTATION_90L:
> + return Transform::Rot270;
> + case GST_VIDEO_ORIENTATION_HORIZ:
> + return Transform::HFlip;
> + case GST_VIDEO_ORIENTATION_VERT:
> + return Transform::VFlip;
> + case GST_VIDEO_ORIENTATION_UL_LR:
> + return Transform::Transpose;
> + case GST_VIDEO_ORIENTATION_UR_LL:
> + return Transform::Rot180Transpose;
> + case GST_VIDEO_ORIENTATION_IDENTITY:
> + default:
> + return Transform::Identity;
> + }
> +}
> +
> +GstVideoOrientationMethod
> +gst_libcamera_transform_to_orientation(libcamera::Transform transform)
> +{
> + switch (transform) {
> + case Transform::Rot90:
> + return GST_VIDEO_ORIENTATION_90R;
> + case Transform::Rot180:
> + return GST_VIDEO_ORIENTATION_180;
> + case Transform::Rot270:
> + return GST_VIDEO_ORIENTATION_90L;
> + case Transform::HFlip:
> + return GST_VIDEO_ORIENTATION_HORIZ;
> + case Transform::VFlip:
> + return GST_VIDEO_ORIENTATION_VERT;
> + case Transform::Transpose:
> + return GST_VIDEO_ORIENTATION_UL_LR;
> + case Transform::Rot180Transpose:
> + return GST_VIDEO_ORIENTATION_UR_LL;
> + case Transform::Identity:
> + default:
> + return GST_VIDEO_ORIENTATION_IDENTITY;
> + }
> +}
> +
> +const char *
> +gst_libcamera_transform_to_tag_string(libcamera::Transform transform)
> +{
> + switch (transform) {
> + case Transform::Rot90:
> + return "rotate-90";
> + case Transform::Rot180:
> + return "rotate-180";
> + case Transform::Rot270:
> + return "rotate-270";
> + case Transform::HFlip:
> + return "flip-rotate-0";
> + case Transform::VFlip:
> + return "flip-rotate-180";
> + case Transform::Transpose:
> + return "flip-rotate-270";
> + case Transform::Rot180Transpose:
> + return "flip-rotate-90";
> + case Transform::Identity:
> + default:
> + return "rotate-0";
> + }
> +}
> diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h
> index fd304a8b..84d26c47 100644
> --- a/src/gstreamer/gstlibcamera-utils.h
> +++ b/src/gstreamer/gstlibcamera-utils.h
> @@ -11,6 +11,7 @@
> #include <libcamera/camera_manager.h>
> #include <libcamera/controls.h>
> #include <libcamera/stream.h>
> +#include <libcamera/transform.h>
>
> #include <gst/gst.h>
> #include <gst/video/video.h>
> @@ -30,6 +31,10 @@ gboolean gst_task_resume(GstTask *task);
> #endif
> std::shared_ptr<libcamera::CameraManager> gst_libcamera_get_camera_manager(int &ret);
>
> +libcamera::Transform gst_libcamera_orientation_to_transform(GstVideoOrientationMethod orientation);
> +GstVideoOrientationMethod gst_libcamera_transform_to_orientation(libcamera::Transform transform);
> +const char *gst_libcamera_transform_to_tag_string(libcamera::Transform transform);
nit: Just to follow the style, I'd been adding empty line between each
declaration to ease the readability. The style checker didn't allow to indent it
further though.
> +
> /**
> * \class GLibLocker
> * \brief A simple scoped mutex locker for GMutex
> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
> index 721b35c2..9d9437d0 100644
> --- a/src/gstreamer/gstlibcamerasrc.cpp
> +++ b/src/gstreamer/gstlibcamerasrc.cpp
> @@ -147,6 +147,8 @@ struct _GstLibcameraSrc {
>
> gchar *camera_name;
>
> + GstVideoOrientationMethod transform;
> +
> GstLibcameraSrcState *state;
> GstLibcameraAllocator *allocator;
> GstFlowCombiner *flow_combiner;
> @@ -154,7 +156,9 @@ struct _GstLibcameraSrc {
>
> enum {
> PROP_0,
> - PROP_CAMERA_NAME
> + PROP_CAMERA_NAME,
> + PROP_TRANSFORM,
> + PROP_LAST
> };
>
> G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
> @@ -461,6 +465,8 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
> GLibRecLocker lock(&self->stream_lock);
> GstLibcameraSrcState *state = self->state;
> GstFlowReturn flow_ret = GST_FLOW_OK;
> + libcamera::Transform tag_transform;
> + const char* tag_string;
> gint ret;
>
> g_autoptr(GstStructure) element_caps = gst_structure_new_empty("caps");
> @@ -513,12 +519,27 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
> if (flow_ret != GST_FLOW_OK)
> goto done;
>
> + state->config_->transform =
> + gst_libcamera_orientation_to_transform (self->transform);
> +
> /* Validate the configuration. */
> if (state->config_->validate() == CameraConfiguration::Invalid) {
> flow_ret = GST_FLOW_NOT_NEGOTIATED;
> goto done;
> }
>
> + tag_transform = (gst_libcamera_orientation_to_transform (self->transform) ^
> + state->config_->transform);
> + tag_string = gst_libcamera_transform_to_tag_string(tag_transform);
> + for (gsize i = 0; i < state->srcpads_.size(); i++) {
> + GstPad *srcpad = state->srcpads_[i];
> + GstEvent *tag_event;
> +
> + tag_event = gst_event_new_tag(gst_tag_list_new(GST_TAG_IMAGE_ORIENTATION,
> + tag_string, NULL));
> + gst_pad_push_event (srcpad, tag_event);
> + }
> +
> ret = state->cam_->configure(state->config_.get());
> if (ret) {
> GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
> @@ -659,6 +680,11 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,
> g_free(self->camera_name);
> self->camera_name = g_value_dup_string(value);
> break;
> + case PROP_TRANSFORM:
> + self->transform =
> + static_cast<GstVideoOrientationMethod>(
> + g_value_get_enum(value));
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> break;
> @@ -676,6 +702,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,
> case PROP_CAMERA_NAME:
> g_value_set_string(value, self->camera_name);
> break;
> + case PROP_TRANSFORM:
> + g_value_set_enum(value, self->transform);
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> break;
> @@ -845,4 +874,14 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
> | G_PARAM_CONSTRUCT
> | G_PARAM_READWRITE
> | G_PARAM_STATIC_STRINGS)));
> +
> + g_object_class_install_property (object_class, PROP_TRANSFORM,
> + g_param_spec_enum ("transform", "Transform",
Shouldn't this be "video-direction" and this patch should implement the
GstVideoDirection interface ? Every other element in gstreamer do that.
> + "Request a transform (rotation and/or flip).",
> + GST_TYPE_VIDEO_ORIENTATION_METHOD,
> + GST_VIDEO_ORIENTATION_IDENTITY,
> + (GParamFlags)(GST_PARAM_MUTABLE_READY
> + | G_PARAM_CONSTRUCT
> + | G_PARAM_READWRITE
> + | G_PARAM_STATIC_STRINGS)));
> }
More information about the libcamera-devel
mailing list