[libcamera-devel] [PATCH v2] gstreamer: Implement element EOS handling

Jaslo Ziska jaslo at ziska.de
Fri Nov 10 13:07:29 CET 2023


Add a function for the send_event method which handles the GST_EVENT_EOS
event. This function will set an atomic to the received event and push
this EOS event to all source pads in the running task.

Also set the GST_ELEMENT_FLAG_SOURCE flag to identify libcamerasrc as a
source element which enables it to receive EOS events sent to the
(pipeline) bin containing it.
This in turn enables libcamerasrc to for example receive EOS events from
gst-launch-1.0 when using the -e flag.

Signed-off-by: Jaslo Ziska <jaslo at ziska.de>
Acked-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
---
Use std::atomic<GstEvent *> instead of glib_atomic_int_* plus a seperate GstEvent pointer and add a commit message.

 src/gstreamer/gstlibcamerasrc.cpp | 37 ++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 63d99571..8e197956 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -9,7 +9,6 @@
 /**
  * \todo The following is a list of items that needs implementation in the GStreamer plugin
  *  - Implement GstElement::send_event
- *    + Allowing application to send EOS
  *    + Allowing application to use FLUSH/FLUSH_STOP
  *    + Prevent the main thread from accessing streaming thread
  *  - Implement renegotiation (even if slow)
@@ -29,6 +28,7 @@

 #include "gstlibcamerasrc.h"

+#include <atomic>
 #include <queue>
 #include <vector>

@@ -144,6 +144,8 @@ struct _GstLibcameraSrc {
 	gchar *camera_name;
 	controls::AfModeEnum auto_focus_mode = controls::AfModeManual;

+	std::atomic<GstEvent *> pending_eos;
+
 	GstLibcameraSrcState *state;
 	GstLibcameraAllocator *allocator;
 	GstFlowCombiner *flow_combiner;
@@ -397,6 +399,14 @@ gst_libcamera_src_task_run(gpointer user_data)

 	bool doResume = false;

+	if (GstEvent *event = self->pending_eos.exchange(nullptr)) {
+		for (GstPad *srcpad : state->srcpads_)
+			gst_pad_push_event(srcpad, gst_event_ref(event));
+		gst_event_unref(event);
+
+		return;
+	}
+
 	/*
 	 * Create and queue one request. If no buffers are available the
 	 * function returns -ENOBUFS, which we ignore here as that's not a
@@ -747,6 +757,28 @@ gst_libcamera_src_change_state(GstElement *element, GstStateChange transition)
 	return ret;
 }

+static gboolean
+gst_libcamera_src_send_event(GstElement *element, GstEvent *event)
+{
+	GstLibcameraSrc *self = GST_LIBCAMERA_SRC(element);
+	gboolean ret = FALSE;
+
+	switch (GST_EVENT_TYPE(event)) {
+	case GST_EVENT_EOS: {
+		if (GstEvent *old_event = self->pending_eos.exchange(event))
+			gst_event_unref(old_event);
+
+		ret = TRUE;
+		break;
+	}
+	default:
+		gst_event_unref(event);
+		break;
+	}
+
+	return ret;
+}
+
 static void
 gst_libcamera_src_finalize(GObject *object)
 {
@@ -779,6 +811,8 @@ gst_libcamera_src_init(GstLibcameraSrc *self)
 	state->srcpads_.push_back(gst_pad_new_from_template(templ, "src"));
 	gst_element_add_pad(GST_ELEMENT(self), state->srcpads_.back());

+	GST_OBJECT_FLAG_SET(self, GST_ELEMENT_FLAG_SOURCE);
+
 	/* C-style friend. */
 	state->src_ = self;
 	self->state = state;
@@ -844,6 +878,7 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
 	element_class->request_new_pad = gst_libcamera_src_request_new_pad;
 	element_class->release_pad = gst_libcamera_src_release_pad;
 	element_class->change_state = gst_libcamera_src_change_state;
+	element_class->send_event = gst_libcamera_src_send_event;

 	gst_element_class_set_metadata(element_class,
 				       "libcamera Source", "Source/Video",
--
2.42.1


More information about the libcamera-devel mailing list