Message ID | 20240610-hwtimestamp-followup-v1-1-f9eaed7be7f0@chromium.org |
---|---|
State | New |
Headers | show |
Series | media: uvcvideo: Followup hwtimestamp patches | expand |
Hi Ricardo, Thank you for the patch. On Mon, Jun 10, 2024 at 07:17:48PM +0000, Ricardo Ribalda wrote: > In UVC 1.5 we get a single clock value per frame. With the current > buffer size of 32, FPS slowers than 32 might roll-over twice. > > The current code cannot handle two roll-over and provide invalid > timestamps. > > Revome all the samples from the circular buffer that are more than two > rollovers old, so the algorithm always provides good timestamps. > > Note that we are removing values that are more than one second old, > which means that there is enough distance between the two points that > we use for the interpolation to provide good values. > > Tested-by: HungNien Chen <hn.chen@sunplusit.com> > Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org> > Reviewed-by: Tomasz Figa <tfiga@chromium.org> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > --- > drivers/media/usb/uvc/uvc_video.c | 23 +++++++++++++++++++++++ > drivers/media/usb/uvc/uvcvideo.h | 1 + > 2 files changed, 24 insertions(+) > > diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c > index 76a375fe47dc..869876afdcce 100644 > --- a/drivers/media/usb/uvc/uvc_video.c > +++ b/drivers/media/usb/uvc/uvc_video.c > @@ -471,8 +471,30 @@ static void uvc_video_clock_add_sample(struct uvc_clock *clock, > { > unsigned long flags; > > + /* > + * If we write new data on the position where we had the last > + * overflow, remove the overflow pointer. There is no SOF overflow > + * in the whole circular buffer. > + */ > + if (clock->head == clock->last_sof_overflow) > + clock->last_sof_overflow = -1; > + > spin_lock_irqsave(&clock->lock, flags); > > + /* Handle SOF overflows. */ > + if (clock->count > 0 && clock->last_sof > sample->dev_sof) { > + /* > + * Remove data from the circular buffer that is older than the > + * last SOF overflow. We only support one SOF overflow per > + * circular buffer. > + */ > + if (clock->last_sof_overflow != -1) > + clock->count = (clock->head - clock->last_sof_overflow > + + clock->size) % clock->size; > + clock->last_sof_overflow = clock->head; > + } > + > + /* Add sample. */ > memcpy(&clock->samples[clock->head], sample, sizeof(*sample)); > clock->head = (clock->head + 1) % clock->size; > clock->count = min(clock->count + 1, clock->size); > @@ -605,6 +627,7 @@ static void uvc_video_clock_reset(struct uvc_clock *clock) > clock->head = 0; > clock->count = 0; > clock->last_sof = -1; > + clock->last_sof_overflow = -1; > clock->sof_offset = -1; > } > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h > index e5b12717016f..f21207debd54 100644 > --- a/drivers/media/usb/uvc/uvcvideo.h > +++ b/drivers/media/usb/uvc/uvcvideo.h > @@ -501,6 +501,7 @@ struct uvc_streaming { > unsigned int head; > unsigned int count; > unsigned int size; > + unsigned int last_sof_overflow; > > u16 last_sof; > u16 sof_offset; >
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 76a375fe47dc..869876afdcce 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -471,8 +471,30 @@ static void uvc_video_clock_add_sample(struct uvc_clock *clock, { unsigned long flags; + /* + * If we write new data on the position where we had the last + * overflow, remove the overflow pointer. There is no SOF overflow + * in the whole circular buffer. + */ + if (clock->head == clock->last_sof_overflow) + clock->last_sof_overflow = -1; + spin_lock_irqsave(&clock->lock, flags); + /* Handle SOF overflows. */ + if (clock->count > 0 && clock->last_sof > sample->dev_sof) { + /* + * Remove data from the circular buffer that is older than the + * last SOF overflow. We only support one SOF overflow per + * circular buffer. + */ + if (clock->last_sof_overflow != -1) + clock->count = (clock->head - clock->last_sof_overflow + + clock->size) % clock->size; + clock->last_sof_overflow = clock->head; + } + + /* Add sample. */ memcpy(&clock->samples[clock->head], sample, sizeof(*sample)); clock->head = (clock->head + 1) % clock->size; clock->count = min(clock->count + 1, clock->size); @@ -605,6 +627,7 @@ static void uvc_video_clock_reset(struct uvc_clock *clock) clock->head = 0; clock->count = 0; clock->last_sof = -1; + clock->last_sof_overflow = -1; clock->sof_offset = -1; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index e5b12717016f..f21207debd54 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -501,6 +501,7 @@ struct uvc_streaming { unsigned int head; unsigned int count; unsigned int size; + unsigned int last_sof_overflow; u16 last_sof; u16 sof_offset;