Hi Bruce,
On Friday 05 June 2009 22:36:55 bruce m beach wrote:
> Hello Laurent
>
> I replied to your last email but it 'mailman' is holding it because it is
> far too big.
Mailman was holding it but I've manually accepted the mail, so it made it
through to the list.
> Just to give you an update on something that I realized:
> > What bothers me in the trace is
> >
> > May 28 10:53:28 lapsystemx kernel: uvcvideo: Dropping payload (out of
> > sync). May 28 10:53:59 lapsystemx last message repeated 30784 times
> > May 28 10:55:00 lapsystemx last message repeated 60992 times
> > May 28 10:55:24 lapsystemx last message repeated 24351 times
> >
> > The "out of sync" message means that the device didn't toggle the FID
> > bit. Quirk 0x10 is supposed to work around that by ignoring the FID bit.
>
> in the following bit of code from
>
> static void uvc_video_decode_end(...
>
> if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0)
> -------------
> {
> uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
> if (data[0] == len)
> uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
> buf->state = UVC_BUF_STATE_DONE;
> if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
> video->last_fid ^= UVC_STREAM_FID;
> }
>
> last_fid is toggled ->only<- if the appropriate bit of data[1] is
> set (UVC_STREAM_EOF) which will never happen since UVC_STREAM_EOF
> is always zero (on the crystal eye webcam).
last_fid is also set in uvc_video_decode_start().
Here's what's supposed to happen with a UVC compliant device.
- The EOH bit is set in every packet.
- The SCR and PTS bits are usually set in every packets as well.
- The ERR, STI and RES bits should not be set.
- The EOF bit should be set for the last packet of a video frame.
- The FID bit should be toggled in the first packet of every video frame.
Your device always sets EOH, SCR and PTS. It never sets ERR, STI and RES. So
good so far.
>From the logs you sent me, the EOF bit is never set. This is wrong, but the
driver tries to work around that by checking when the FID bit toggles in
uvc_video_decode_start():
/* Mark the buffer as done if we're at the beginning of a new frame.
* End of frame detection is better implemented by checking the EOF
* bit (FID bit toggling is delayed by one frame compared to the EOF
* bit), but some devices don't set the bit at end of frame (and the
* last payload can be lost anyway). We thus must check if the FID has
* been toggled.
*
* stream->last_fid is initialized to -1, so the first isochronous
* frame will never trigger an end of frame detection.
*
* Empty buffers (bytesused == 0) don't trigger end of frame detection
* as it doesn't make sense to return an empty buffer. This also
* avoids detecting end of frame conditions at FID toggling if the
* previous payload had the EOF bit set.
*/
if (fid != stream->last_fid && buf->buf.bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n");
buf->state = UVC_BUF_STATE_DONE;
return -EAGAIN;
}
(the code might be slightly different from the one you're using, I'm reworking
part of the driver).
If the current FID bit is different from the last one, and if the current
video buffer is not empty, the buffer is marked as done and the function
returns -EAGAIN. The caller will move the buffer to the output queue, get a
new buffer from the input queue and call uvc_video_decode_start() again. At
that point, the following code should be triggered:
/* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
* stream->last_fid is initialized to -1, so the first isochronous
* frame will always be in sync.
*
* If the device doesn't toggle the FID bit, invert stream->last_fid
* when the EOF bit is set to force synchronisation on the next
* packet.
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n");
if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
(data[1] & UVC_STREAM_EOF))
stream->last_fid ^= UVC_STREAM_FID;
return -ENODATA;
}
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
}
The buffer being freshly dequeued, it's state will not be
UVC_BUF_STATE_ACTIVE. The FID bit being different than the last stored value
(otherwise the first call to uvc_video_decode_start() wouldn't have returned -
EAGAIN in the first place), the buffer state is set to UVC_BUF_STATE_ACTIVE
and the function continues with
stream->last_fid = fid;
which effectively toggles the stored FID value.
If the buffer gets filled with video data before the FID bit is toggled,
uvc_video_decode_data() will mark the buffer as done and the caller will
process a new buffer. The next call to uvc_video_decode_start() will then drop
all packets with "Dropping payload (out of sync)." until the FID bit set by
the device is toggled. This seems to never happen in your case.
If the camera doesn't set the EOF bit and doesn't toggle the FID bit there's
very little I can do. Without any frame boundary information the driver can't
synchronize itself to the video stream. I'm really puzzled by how this camera
can work at all. Your last e-mail showed that it toggled the FID bit once from
0 to 1 and left it at 1 forever after. Is my understanding correct ?
Best regards,
Laurent Pinchart
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel