[libcamera-devel] [PATCH v2 23/27] gst: libcamerasrc: Implement timestamp support
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Mon Mar 2 12:01:52 CET 2020
Hi Nicolas,
On Sat, Feb 29, 2020 at 10:32:52AM -0500, Nicolas Dufresne wrote:
> Le samedi 29 février 2020 à 16:59 +0200, Laurent Pinchart a écrit :
> > On Thu, Feb 27, 2020 at 03:04:03PM -0500, Nicolas Dufresne wrote:
> > > 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 at collabora.com>
> > > ---
> > > src/gstreamer/gstlibcamerapad.cpp | 23 +++++++++++++++++++++++
> > > src/gstreamer/gstlibcamerapad.h | 2 ++
> > > src/gstreamer/gstlibcamerasrc.cpp | 20 ++++++++++++++++++++
> > > 3 files changed, 45 insertions(+)
> > >
> > > diff --git a/src/gstreamer/gstlibcamerapad.cpp b/src/gstreamer/gstlibcamerapad.cpp
> > > index 2cf1630..31d3edd 100644
> > > --- a/src/gstreamer/gstlibcamerapad.cpp
> > > +++ b/src/gstreamer/gstlibcamerapad.cpp
> > > @@ -62,9 +62,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
> > > @@ -172,3 +187,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 eb24000..a3291e8 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 70f2048..73a1360 100644
> > > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > > @@ -151,6 +151,26 @@ GstLibcameraSrcState::requestCompleted(Request *request)
> > > for (GstPad *srcpad : this->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(this->src)) {
> > > + GstClockTime gst_base_time = GST_ELEMENT(this->src)->base_time;
> > > + GstClockTime gst_now = gst_clock_get_time(GST_ELEMENT_CLOCK(this->src));
> > > + /* \todo Need to expose which reference clock the timestamp relates to. */
> >
> > Something we need to do indeed. We're considering standardizing on
> > CLOCK_BOOTTIME, would that be good for gstreamer ?
>
> Can we do like DRM and just pass back the clock ID ? I've followed a
> little bit the discussion and haven't found enough rationale to show
> that BOOTTIME is the right approach. It felt very usecase specific and
> to make things worst, drivers will have to support both for backward
> compatibility reason.
>
> As you can see, this code path is a userland translation from one clock
> to another. This the type of thing you want to avoid like the peste in
> fact, since it's really error prone due to scheduling latency. So
> forcing BOOTIME would imply that we'd have two of these translation
> going on per frame for V4L2 devices (at least in current state of v4l2
> drivers).
I was thinking of getting V4L2 to produce BOOTTIME timestamps :-)
My question was whether the BOOTTIME clock would be appropriate for
GStreamer, or if there would be a clock that would be more suitable.
> That being said, I'll add a \todo if someone want to do future
> enhancement, since we could try to use GstClock derivation mechanism.
> It's a mechanism to which you pass samples of the match, and GstClock
> will average and smooth a slope for derivation. Last time I tried, it
> was a bit inconvenient to use and the result tend to be historic, hence
> the reason I went for a KISS implementation. I would need to dig into
> this 15 years old piece of code in GStreamer and find out what I'm
> doing wrong, or what its doing wrong.
There are so many ways to get clock conversion wrong that I think it
should always be implemented in helpers, regardless of whether they're
KISS or very complex.
> > > + GstClockTime sys_now = g_get_monotonic_time() * 1000;
> > > +
> > > + /* Deduced from: sys_now - sys_base_time == gst_now - gst_bae_time */
> >
> > s/gst_bae_time/gst_base_time/
> >
> > Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> >
> > > + 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);
> > > }
> > >
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list