[libcamera-devel,v3,23/27] gst: libcamerasrc: Implement timestamp support

Message ID 20200306202637.525587-24-nicolas@ndufresne.ca
State Accepted
Headers show
Series
  • GStreamer Element for libcamera
Related show

Commit Message

Nicolas Dufresne March 6, 2020, 8:26 p.m. UTC
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>

This is an experimental patch adding timestamp support to the libcamerasrc
element. This patch currently assume that the driver timestamp are relative to
the system monotonic clock. Without a reference clock source, the timestamp are
otherwise unusable, and without timestamp only minor use case can be achieved.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/gstreamer/gstlibcamerapad.cpp | 23 +++++++++++++++++++++++
 src/gstreamer/gstlibcamerapad.h   |  2 ++
 src/gstreamer/gstlibcamerasrc.cpp | 20 ++++++++++++++++++++
 3 files changed, 45 insertions(+)

Patch

diff --git a/src/gstreamer/gstlibcamerapad.cpp b/src/gstreamer/gstlibcamerapad.cpp
index 840f391..e184495 100644
--- a/src/gstreamer/gstlibcamerapad.cpp
+++ b/src/gstreamer/gstlibcamerapad.cpp
@@ -63,9 +63,24 @@  gst_libcamera_pad_get_property(GObject *object, guint prop_id, GValue *value,
 	}
 }
 
+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
@@ -173,3 +188,11 @@  gst_libcamera_pad_has_pending(GstPad *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;
+}
diff --git a/src/gstreamer/gstlibcamerapad.h b/src/gstreamer/gstlibcamerapad.h
index 9d43129..779f2d1 100644
--- a/src/gstreamer/gstlibcamerapad.h
+++ b/src/gstreamer/gstlibcamerapad.h
@@ -32,4 +32,6 @@  GstFlowReturn gst_libcamera_pad_push_pending(GstPad *pad);
 
 bool gst_libcamera_pad_has_pending(GstPad *pad);
 
+void gst_libcamera_pad_set_latency(GstPad *pad, GstClockTime latency);
+
 #endif /* __GST_LIBCAMERA_PAD_H__ */
diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index e3718db..b04e9f1 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -154,6 +154,26 @@  GstLibcameraSrcState::requestCompleted(Request *request)
 	for (GstPad *srcpad : srcpads_) {
 		Stream *stream = gst_libcamera_pad_get_stream(srcpad);
 		buffer = wrap->detachBuffer(stream);
+
+		FrameBuffer *fb = gst_libcamera_buffer_get_frame_buffer(buffer);
+
+		if (GST_ELEMENT_CLOCK(src_)) {
+			GstClockTime gst_base_time = GST_ELEMENT(src_)->base_time;
+			GstClockTime gst_now = gst_clock_get_time(GST_ELEMENT_CLOCK(src_));
+			/* \todo Need to expose which reference clock the timestamp relates to. */
+			GstClockTime sys_now = g_get_monotonic_time() * 1000;
+
+			/* Deduced from: sys_now - sys_base_time == gst_now - gst_base_time */
+			GstClockTime sys_base_time = sys_now - (gst_now - gst_base_time);
+			GST_BUFFER_PTS(buffer) = fb->metadata().timestamp - sys_base_time;
+			gst_libcamera_pad_set_latency(srcpad, sys_now - fb->metadata().timestamp);
+		} else {
+			GST_BUFFER_PTS(buffer) = 0;
+		}
+
+		GST_BUFFER_OFFSET(buffer) = fb->metadata().sequence;
+		GST_BUFFER_OFFSET_END(buffer) = fb->metadata().sequence;
+
 		gst_libcamera_pad_queue_buffer(srcpad, buffer);
 	}