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

Jaslo Ziska jaslo at ziska.de
Mon Nov 6 17:52:57 CET 2023


---
Hi,

I recently implemented basic EOS handling for the libcamerasrc gstreamer element.

I basically looked at how GstBaseSrc does it and tried to do it similarly.

I have no idea whether the locking is correct or if this is thread safe but so far it worked without any issues for my purposes.

You can also now run the following command and receive a working video file:

gst-launch-1.0 -e libcamerasrc ! videoconvert ! x264enc ! h264parse ! mp4mux ! filesink location=test.mp4

Looking forward for feedback!

Cheers,

Jaslo

 src/gstreamer/gstlibcamerasrc.cpp | 47 +++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 63d99571..a4681e1e 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -144,6 +144,9 @@ struct _GstLibcameraSrc {
 	gchar *camera_name;
 	controls::AfModeEnum auto_focus_mode = controls::AfModeManual;

+	GstEvent *pending_eos;
+	int has_pending_eos;
+
 	GstLibcameraSrcState *state;
 	GstLibcameraAllocator *allocator;
 	GstFlowCombiner *flow_combiner;
@@ -397,6 +400,21 @@ gst_libcamera_src_task_run(gpointer user_data)

 	bool doResume = false;

+	if (g_atomic_int_get(&self->has_pending_eos)) {
+		g_atomic_int_set(&self->has_pending_eos, FALSE);
+
+		GST_OBJECT_LOCK(self);
+		GstEvent *event = self->pending_eos;
+		self->pending_eos = NULL;
+		GST_OBJECT_UNLOCK(self);
+
+		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 +765,32 @@ 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: {
+		GST_OBJECT_LOCK(self);
+		g_atomic_int_set(&self->has_pending_eos, TRUE);
+		if (self->pending_eos)
+			gst_event_unref(self->pending_eos);
+		self->pending_eos = event;
+		GST_OBJECT_UNLOCK(self);
+
+		ret = TRUE;
+		break;
+	}
+	default:
+		gst_event_unref(event);
+		break;
+	}
+
+	return ret;
+}
+
 static void
 gst_libcamera_src_finalize(GObject *object)
 {
@@ -779,6 +823,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 +890,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