[libcamera-devel,05/13] gstreamer: Move timestamp calculation out of pad loop
diff mbox series

Message ID 20220623232210.18742-6-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • gstreamer: Queue multiple requests
Related show

Commit Message

Laurent Pinchart June 23, 2022, 11:22 p.m. UTC
The buffer pts and the pad latency are computed from the framebuffer
timestamp, separately for each pad. Use the sensor timestamp provided
through the request metadata instead, to compute the values once outside
of the pads loop.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/gstreamer/gstlibcamerasrc.cpp | 34 ++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 10 deletions(-)

Comments

Nicolas Dufresne June 27, 2022, 9 p.m. UTC | #1
Hi Laurent,

Le vendredi 24 juin 2022 à 02:22 +0300, Laurent Pinchart a écrit :
> The buffer pts and the pad latency are computed from the framebuffer
> timestamp, separately for each pad. Use the sensor timestamp provided
> through the request metadata instead, to compute the values once outside
> of the pads loop.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/gstreamer/gstlibcamerasrc.cpp | 34 ++++++++++++++++++++++---------
>  1 file changed, 24 insertions(+), 10 deletions(-)
> 
> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
> index 700bee2bf877..a1fab71d4f09 100644
> --- a/src/gstreamer/gstlibcamerasrc.cpp
> +++ b/src/gstreamer/gstlibcamerasrc.cpp
> @@ -34,6 +34,7 @@
>  
>  #include <libcamera/camera.h>
>  #include <libcamera/camera_manager.h>
> +#include <libcamera/control_ids.h>
>  
>  #include <gst/base/base.h>
>  
> @@ -164,22 +165,35 @@ GstLibcameraSrcState::requestCompleted(Request *request)
>  		return;
>  	}
>  
> +	GstClockTime latency;
> +	GstClockTime pts;
> +
> +	if (GST_ELEMENT_CLOCK(src_)) {
> +		int64_t timestamp = request->metadata().get(controls::SensorTimestamp);
> +
> +		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);
> +		pts = timestamp - sys_base_time;
> +		latency = sys_now - timestamp;
> +	} else {
> +		latency = 0;
> +		pts = 0;

I would like to suggest: 

                pts = GST_CLOCK_TIME_NONE;

> +	}
> +
>  	for (GstPad *srcpad : srcpads_) {
>  		Stream *stream = gst_libcamera_pad_get_stream(srcpad);
>  		GstBuffer *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);
> +		if (pts) {

And then:
                if (GST_CLOCK_TIME_IS_VALID(pts)) {

Conceptually, pts can be 0 even if it will never happen in practice. I'm fine
with the change otherwise. This entire block seems complex enough that it could
be its own helper function if you feel like it. In long term, when we start
supporting "desync" streams, we'll be requesting some pads independently, and
then we'd start having per pad latency that do differ. Not sure why, but it
looks like I prepared the field for bunch of future use cases, and I fail to add
all the todos.

> +			GST_BUFFER_PTS(buffer) = pts;
> +			gst_libcamera_pad_set_latency(srcpad, latency);
>  		} else {
>  			GST_BUFFER_PTS(buffer) = 0;
>  		}
Laurent Pinchart June 27, 2022, 10:22 p.m. UTC | #2
Hi Nicolas,

On Mon, Jun 27, 2022 at 05:00:19PM -0400, Nicolas Dufresne wrote:
> Le vendredi 24 juin 2022 à 02:22 +0300, Laurent Pinchart a écrit :
> > The buffer pts and the pad latency are computed from the framebuffer
> > timestamp, separately for each pad. Use the sensor timestamp provided
> > through the request metadata instead, to compute the values once outside
> > of the pads loop.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/gstreamer/gstlibcamerasrc.cpp | 34 ++++++++++++++++++++++---------
> >  1 file changed, 24 insertions(+), 10 deletions(-)
> > 
> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
> > index 700bee2bf877..a1fab71d4f09 100644
> > --- a/src/gstreamer/gstlibcamerasrc.cpp
> > +++ b/src/gstreamer/gstlibcamerasrc.cpp
> > @@ -34,6 +34,7 @@
> >  
> >  #include <libcamera/camera.h>
> >  #include <libcamera/camera_manager.h>
> > +#include <libcamera/control_ids.h>
> >  
> >  #include <gst/base/base.h>
> >  
> > @@ -164,22 +165,35 @@ GstLibcameraSrcState::requestCompleted(Request *request)
> >  		return;
> >  	}
> >  
> > +	GstClockTime latency;
> > +	GstClockTime pts;
> > +
> > +	if (GST_ELEMENT_CLOCK(src_)) {
> > +		int64_t timestamp = request->metadata().get(controls::SensorTimestamp);
> > +
> > +		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);
> > +		pts = timestamp - sys_base_time;
> > +		latency = sys_now - timestamp;
> > +	} else {
> > +		latency = 0;
> > +		pts = 0;
> 
> I would like to suggest: 
> 
>                 pts = GST_CLOCK_TIME_NONE;
> 
> > +	}
> > +
> >  	for (GstPad *srcpad : srcpads_) {
> >  		Stream *stream = gst_libcamera_pad_get_stream(srcpad);
> >  		GstBuffer *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);
> > +		if (pts) {
> 
> And then:
>                 if (GST_CLOCK_TIME_IS_VALID(pts)) {
> 
> Conceptually, pts can be 0 even if it will never happen in practice.

That was my reasoning too :-) I didn't know about GST_CLOCK_TIME_NONE
and GST_CLOCK_TIME_IS_VALID, I'll use those.

> I'm fine
> with the change otherwise. This entire block seems complex enough that it could
> be its own helper function if you feel like it. In long term, when we start
> supporting "desync" streams, we'll be requesting some pads independently, and
> then we'd start having per pad latency that do differ. Not sure why, but it
> looks like I prepared the field for bunch of future use cases, and I fail to add
> all the todos.

That will be interesting to implement.

> > +			GST_BUFFER_PTS(buffer) = pts;
> > +			gst_libcamera_pad_set_latency(srcpad, latency);
> >  		} else {
> >  			GST_BUFFER_PTS(buffer) = 0;
> >  		}
Umang Jain June 29, 2022, 2:39 p.m. UTC | #3
Hi Laurent,

On 6/28/22 03:52, Laurent Pinchart via libcamera-devel wrote:
> Hi Nicolas,
>
> On Mon, Jun 27, 2022 at 05:00:19PM -0400, Nicolas Dufresne wrote:
>> Le vendredi 24 juin 2022 à 02:22 +0300, Laurent Pinchart a écrit :
>>> The buffer pts and the pad latency are computed from the framebuffer
>>> timestamp, separately for each pad. Use the sensor timestamp provided
>>> through the request metadata instead, to compute the values once outside
>>> of the pads loop.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> ---
>>>   src/gstreamer/gstlibcamerasrc.cpp | 34 ++++++++++++++++++++++---------
>>>   1 file changed, 24 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
>>> index 700bee2bf877..a1fab71d4f09 100644
>>> --- a/src/gstreamer/gstlibcamerasrc.cpp
>>> +++ b/src/gstreamer/gstlibcamerasrc.cpp
>>> @@ -34,6 +34,7 @@
>>>   
>>>   #include <libcamera/camera.h>
>>>   #include <libcamera/camera_manager.h>
>>> +#include <libcamera/control_ids.h>
>>>   
>>>   #include <gst/base/base.h>
>>>   
>>> @@ -164,22 +165,35 @@ GstLibcameraSrcState::requestCompleted(Request *request)
>>>   		return;
>>>   	}
>>>   
>>> +	GstClockTime latency;
>>> +	GstClockTime pts;
>>> +
>>> +	if (GST_ELEMENT_CLOCK(src_)) {
>>> +		int64_t timestamp = request->metadata().get(controls::SensorTimestamp);
>>> +
>>> +		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);
>>> +		pts = timestamp - sys_base_time;
>>> +		latency = sys_now - timestamp;
>>> +	} else {
>>> +		latency = 0;
>>> +		pts = 0;
>> I would like to suggest:
>>
>>                  pts = GST_CLOCK_TIME_NONE;
>>
>>> +	}
>>> +
>>>   	for (GstPad *srcpad : srcpads_) {
>>>   		Stream *stream = gst_libcamera_pad_get_stream(srcpad);
>>>   		GstBuffer *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);
>>> +		if (pts) {
>> And then:
>>                  if (GST_CLOCK_TIME_IS_VALID(pts)) {
>>
>> Conceptually, pts can be 0 even if it will never happen in practice.
> That was my reasoning too :-) I didn't know about GST_CLOCK_TIME_NONE
> and GST_CLOCK_TIME_IS_VALID, I'll use those.
>
>> I'm fine
>> with the change otherwise. This entire block seems complex enough that it could
>> be its own helper function if you feel like it. In long term, when we start


Agreed. Can be done on top as well.

Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>

>> supporting "desync" streams, we'll be requesting some pads independently, and
>> then we'd start having per pad latency that do differ. Not sure why, but it
>> looks like I prepared the field for bunch of future use cases, and I fail to add
>> all the todos.
> That will be interesting to implement.
>
>>> +			GST_BUFFER_PTS(buffer) = pts;
>>> +			gst_libcamera_pad_set_latency(srcpad, latency);
>>>   		} else {
>>>   			GST_BUFFER_PTS(buffer) = 0;
>>>   		}

Patch
diff mbox series

diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 700bee2bf877..a1fab71d4f09 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -34,6 +34,7 @@ 
 
 #include <libcamera/camera.h>
 #include <libcamera/camera_manager.h>
+#include <libcamera/control_ids.h>
 
 #include <gst/base/base.h>
 
@@ -164,22 +165,35 @@  GstLibcameraSrcState::requestCompleted(Request *request)
 		return;
 	}
 
+	GstClockTime latency;
+	GstClockTime pts;
+
+	if (GST_ELEMENT_CLOCK(src_)) {
+		int64_t timestamp = request->metadata().get(controls::SensorTimestamp);
+
+		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);
+		pts = timestamp - sys_base_time;
+		latency = sys_now - timestamp;
+	} else {
+		latency = 0;
+		pts = 0;
+	}
+
 	for (GstPad *srcpad : srcpads_) {
 		Stream *stream = gst_libcamera_pad_get_stream(srcpad);
 		GstBuffer *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);
+		if (pts) {
+			GST_BUFFER_PTS(buffer) = pts;
+			gst_libcamera_pad_set_latency(srcpad, latency);
 		} else {
 			GST_BUFFER_PTS(buffer) = 0;
 		}