Re: UVC Gadget Driver shows glitched frames with a Linux host

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, May 6, 2023 at 5:53 AM Laurent Pinchart
<laurent.pinchart@xxxxxxxxxxxxxxxx> wrote:

> > The first thing I tried was to split one video frame over 266 frames, without
> > changing the number of requests allocated. And it works! However, as Laurent
> > mentioned, it does add a fair amount of bookkeeping to split a video frame into
> > the required number of requests. I also hardcoded the number 266 from our
> > discussion, but I am not sure how to figure out that number dynamically. 266
> > also didn't work if the host started sending frames at more than 30fps :/, so
> > our dynamic calculation would need to take camera's real output fps into
> > account, which as far as I can tell is not known to the UVC driver.
>
> It would probably need to monitor how full the request queue is, and
> adapt the number of bytes it queues in each request accordingly. That's
> indeed quite a bit of work, for little gain compared to the option you
> describe below.
>
Agreed, especially if the hosts already handle 0 length packets.
As long as the usb controllers can keep up, the burst approach seems
more reasonable.

> > With those issues I tried what Laurent called the "burst" approach
> > (attached below), i.e. send the video frames in as few packets as possible,
> > and then queue up 0 length packets to keep the ISOC queue happy. This approach
> > works perfectly as far as I can tell. Locally I tried with a Linux, Window,
> > and MacOS host with no frame drops or ISOC failures on any of them!
> >
> > In the current patch, UVC gadget driver keeps the ISOC cadence by effectively
> > maintaining a back-pressure on the USB controller (at least to the best of its
> > capabilities). Any usb_request available to the UVC gadget gets immediately
> > queued back to the USB controller. If a video frame is available, the frame is
> > encoded, if not, the length is set to 0. The idea being that the host's polling
> > and the controller's 'complete' callback will result in a somewhat consistent
> > cadence for the uvc driver after the initial burst of packets.
> >
> > However this does mean that at worst, the new video frames are up to 63
> > usb_requests behind, but assuming a 125us per usb_request, that amounts to ~8ms
> > latency at the worst, which seems acceptable?
>
> There's a trade off between latency and the risk of underruns. We could
> decrease the number of queued requests to lower the latency, as long as
> we ensure the margin is high enough to avoid underruns in higher load
> conditions. We could also do so only when queuing 0-size requests, and
> queue the data in burst mode with a higher number of requests.

Would 8ms of latency be considered significant? Unless the host asks
for >125fps,
that amounts to less than a frame of latency, so frames should not be dropped
by the host for being "late". Admittedly, I don't know enough about UVC usage to
say if 8ms (at worst) will be problematic for certain usages. The
hosts don't seem to
have any issues when streaming at <=60fps.

> > Another concern I had was about how the back-pressure might affect other USB
> > controllers. DWC3 doesn't seem to be sweating and in local testing I saw no
> > EXDEVs or frame drops other than when the stream was being transitioned from
> > one configuration to another, but I don't know how this interaction might go for
> > other USB controllers. Would you have any insights into non-DWC3 controllers,
> > and if they might be negatively affected by having up to 64 requests queued at
> > once?
>
> Dan, do I recall correctly you have tested uvc-gadget with dwc2 too ?
> Could you test the patch below ? Testing with musb would be nice too.
>
> > Here's the patch, it doesn't currently handle bulk transfers, but I can upload a
> > formal patch with it if this approach seems acceptable!
> >
> > ---
> >  drivers/usb/gadget/function/uvc_video.c | 24 ++++++++++++++++--------
> >  1 file changed, 16 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
> > index dd1c6b2ca7c6..d7ad278709d4 100644
> > --- a/drivers/usb/gadget/function/uvc_video.c
> > +++ b/drivers/usb/gadget/function/uvc_video.c
> > @@ -386,6 +386,7 @@ static void uvcg_video_pump(struct work_struct *work)
> >       struct uvc_buffer *buf;
> >       unsigned long flags;
> >       int ret;
> > +     bool buf_int;
> >
> >       while (video->ep->enabled) {
> >               /*
> > @@ -408,20 +409,29 @@ static void uvcg_video_pump(struct work_struct *work)
> >                */
> >               spin_lock_irqsave(&queue->irqlock, flags);
> >               buf = uvcg_queue_head(queue);
> > -             if (buf == NULL) {
> > +
> > +             if (buf != NULL) {
> > +                     // Encode video frame if we have one.
>
> C-style comments please.
>
Addressed this comment and uploaded a formal patch:
https://lore.kernel.org/20230508231103.1621375-1-arakesh@xxxxxxxxxx/
It is basically this patch with an extra flag to ensure that we don't
spam a bulk endpoint with 0-length requests.

I wrote a script to detect abrupt size changes in uvc frames on the
host. In my two hours of testing with the above patch, I've recorded
only one "short" frame.
```
[616677.453290] usb 1-6: frame 1 stats: 0/31/31 packets, 0/0/0 pts
(!early !initial), 30/31 scr, last pts/stc/sof 0/4055830784/1298
[617701.585256] usb 1-6: frame 30594 stats: 0/1/1 packets, 0/0/0 pts
(!early !initial), 0/1 scr, last pts/stc/sof 0/1677462368/2636
[617701.621240] usb 1-6: frame 30596 stats: 0/32/32 packets, 0/0/0 pts
(!early !initial), 31/32 scr, last pts/stc/sof 0/1679244656/2933
```
First log is when streaming starts (abrupt change from 0 to 31).
Frame 30594 had only 1 packet for some reason  (I couldn't capture
gadget logs at the time :/), but the stream recovered after one
skipped frame.

Will leave the script running overnight, and report back if there's
anything significant there.

- Avi.




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux