/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Collabora Ltd. * Author: Nicolas Dufresne * * gstlibcamerapad.cpp - GStreamer Capture Pad */ #include "gstlibcamerapad.h" #include #include "gstlibcamera-utils.h" using namespace libcamera; struct _GstLibcameraPad { GstPad parent; StreamRole role; GstLibcameraPool *pool; GQueue pending_buffers; GstClockTime latency; }; enum { PROP_0, PROP_STREAM_ROLE }; G_DEFINE_TYPE(GstLibcameraPad, gst_libcamera_pad, GST_TYPE_PAD) static void gst_libcamera_pad_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { auto *self = GST_LIBCAMERA_PAD(object); GLibLocker lock(GST_OBJECT(self)); switch (prop_id) { case PROP_STREAM_ROLE: self->role = (StreamRole)g_value_get_enum(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_libcamera_pad_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { auto *self = GST_LIBCAMERA_PAD(object); GLibLocker lock(GST_OBJECT(self)); switch (prop_id) { case PROP_STREAM_ROLE: g_value_set_enum(value, self->role); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static gboolean gst_libcamera_pad_query(GstPad *pad, GstObject *parent, GstQuery *query) { auto *self = GST_LIBCAMERA_PAD(pad); if (query->type != GST_QUERY_LATENCY) return gst_pad_query_default(pad, parent, query); /* TRUE here means live, we assumes that max latency is the same as min * as we have no idea that duration of frames. */ gst_query_set_latency(query, TRUE, self->latency, self->latency); return TRUE; } static void gst_libcamera_pad_init(GstLibcameraPad *self) { GST_PAD_QUERYFUNC(self) = gst_libcamera_pad_query; } static GType gst_libcamera_stream_role_get_type() { static GType type = 0; static const GEnumValue values[] = { { StillCapture, "libcamera::StillCapture", "still-capture" }, { VideoRecording, "libcamera::VideoRecording", "video-recording" }, { Viewfinder, "libcamera::Viewfinder", "view-finder" }, { 0, NULL, NULL } }; if (!type) type = g_enum_register_static("GstLibcameraStreamRole", values); return type; } static void gst_libcamera_pad_class_init(GstLibcameraPadClass *klass) { auto *object_class = G_OBJECT_CLASS(klass); object_class->set_property = gst_libcamera_pad_set_property; object_class->get_property = gst_libcamera_pad_get_property; auto *spec = g_param_spec_enum("stream-role", "Stream Role", "The selected stream role", gst_libcamera_stream_role_get_type(), VideoRecording, (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_STREAM_ROLE, spec); } StreamRole gst_libcamera_pad_get_role(GstPad *pad) { auto *self = GST_LIBCAMERA_PAD(pad); GLibLocker lock(GST_OBJECT(self)); return self->role; } GstLibcameraPool * gst_libcamera_pad_get_pool(GstPad *pad) { auto *self = GST_LIBCAMERA_PAD(pad); return self->pool; } void gst_libcamera_pad_set_pool(GstPad *pad, GstLibcameraPool *pool) { auto *self = GST_LIBCAMERA_PAD(pad); if (self->pool) g_object_unref(self->pool); self->pool = pool; } Stream * gst_libcamera_pad_get_stream(GstPad *pad) { auto *self = GST_LIBCAMERA_PAD(pad); if (self->pool) return gst_libcamera_pool_get_stream(self->pool); return nullptr; } void gst_libcamera_pad_queue_buffer(GstPad *pad, GstBuffer *buffer) { auto *self = GST_LIBCAMERA_PAD(pad); GLibLocker lock(GST_OBJECT(self)); g_queue_push_head(&self->pending_buffers, buffer); } GstFlowReturn gst_libcamera_pad_push_pending(GstPad *pad) { auto *self = GST_LIBCAMERA_PAD(pad); GstBuffer *buffer; { GLibLocker lock(GST_OBJECT(self)); buffer = GST_BUFFER(g_queue_pop_tail(&self->pending_buffers)); } if (!buffer) return GST_FLOW_OK; return gst_pad_push(pad, buffer); } bool gst_libcamera_pad_has_pending(GstPad *pad) { auto *self = GST_LIBCAMERA_PAD(pad); GLibLocker lock(GST_OBJECT(self)); return self->pending_buffers.length > 0; } void gst_libcamera_pad_set_latency(GstPad *pad, GstClockTime latency) { auto *self = GST_LIBCAMERA_PAD(pad); GLibLocker lock(GST_OBJECT(self)); self->latency = latency; }