dcoppa@ noticed that his camera still didn't work with ffmpeg after
the latest uvideo changes. the problem was that the device reported
a ridiculously large maximum frame size, and then malloc(9) failed
because there wasn't enough free memory to allocate the frame buffer.
this is similar to a problem with other cameras, and is why uvideo(4)
has the UVIDEO_FLAG_FIX_MAX_VIDEO_FRAME_SIZE quirk.
however, these problems and the quirk only affect/fix uncompressed
video formats. uncompressed video formats have a fixed bit-depth
per pixel. that means that if you know how many pixels are in
a frame, you can figure out how many bytes are needed to store the
frame. we always know the frame size and bit depth, so we can
always figure out the needed buffer size for uncompressed frames.
so, that's what the following diff does. it calculates the frame
buffer size neeed for uncompressed frames and ignores values given
by the device.
I also noticed that one of my cameras will produce a "short" frame
almost every time capture is started, and occasionally during
capture. this breaks ffmpeg. also, the v4l2 spec says that
the read() method should never give out partial frames. the spec
isn't so clear about mmap'd frames, but ffmpeg doesn't like them,
and I imagine other applications won't like them either. so I
also extended the check that skips over-sized frames to skip
under-sized frames for uncompressed formats.
and finally, I moved the check of the data returned from a probe
request from the function that does the probe request to the
function that does the parameter negotiation. also added a check
that we actually got the parameters we wanted. without that check,
the driver could think one format is being used, but the device
is using a different one ...
please test with all uvideo(4) devices, especially these that were
using a quirk to fix the frame size:
USB_PRODUCT_CHENSOURCE_CM12402: "Eagle IR Cam"
USB_PRODUCT_MICRODIA_CAM_1: "CAM_1" (Sonix web cam)
USB_PRODUCT_MICROSOFT_LIFECAM: "Microsoft LifeCam"
--
jake...@sdf.lonestar.org
SDF Public Access UNIX System - http://sdf.lonestar.org
Index: uvideo.c
===
RCS file: /cvs/src/sys/dev/usb/uvideo.c,v
retrieving revision 1.158
diff -u -p uvideo.c
--- uvideo.c26 Mar 2011 19:50:52 - 1.158
+++ uvideo.c27 Mar 2011 19:04:00 -
@@ -249,7 +249,6 @@ struct video_hw_if uvideo_hw_if = {
#define UVIDEO_FLAG_ISIGHT_STREAM_HEADER 0x1
#define UVIDEO_FLAG_REATTACH 0x2
#define UVIDEO_FLAG_VENDOR_CLASS 0x4
-#define UVIDEO_FLAG_FIX_MAX_VIDEO_FRAME_SIZE 0x8
struct uvideo_devs {
struct usb_devno uv_dev;
char*ucode_name;
@@ -325,27 +324,6 @@ struct uvideo_devs {
NULL,
UVIDEO_FLAG_VENDOR_CLASS
},
- {
- /* Needs to fix dwMaxVideoFrameSize */
- { USB_VENDOR_CHENSOURCE, USB_PRODUCT_CHENSOURCE_CM12402 },
- NULL,
- NULL,
- UVIDEO_FLAG_FIX_MAX_VIDEO_FRAME_SIZE
- },
- {
- /* Needs to fix dwMaxVideoFrameSize */
- { USB_VENDOR_MICRODIA, USB_PRODUCT_MICRODIA_CAM_1 },
- NULL,
- NULL,
- UVIDEO_FLAG_FIX_MAX_VIDEO_FRAME_SIZE
- },
- {
- /* Needs to fix dwMaxVideoFrameSize */
- { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_LIFECAM },
- NULL,
- NULL,
- UVIDEO_FLAG_FIX_MAX_VIDEO_FRAME_SIZE
- },
};
#define uvideo_lookup(v, p) \
((struct uvideo_devs *)usb_lookup(uvideo_devs, v, p))
@@ -1077,15 +1055,20 @@ uvideo_vs_parse_desc_frame_sub(struct uvideo_softc *sc
sc->sc_fmtgrp[fmtidx].frame_cur = fd;
/*
-* On some broken device, dwMaxVideoFrameBufferSize is not correct.
-* So fix it by frame width/height (XXX YUV2 format only).
+* On some devices, dwMaxVideoFrameBufferSize is not correct.
+* Version 1.1 of the UVC spec says this field is deprecated.
+* For uncompressed pixel formats, the frame buffer size can
+* be determined by multiplying width, height, and bytes per pixel.
+* Uncompressed formats have a fixed number of bytes per pixel.
+* Bytes per pixel can vary with compressed formats.
*/
- if (sc->sc_quirk &&
- sc->sc_quirk->flags & UVIDEO_FLAG_FIX_MAX_VIDEO_FRAME_SIZE &&
- sc->sc_fmtgrp[fmtidx].pixelformat == V4L2_PIX_FMT_YUYV) {
- fbuf_size = UGETW(fd->wWidth) * UGETW(fd->wHeight) * 4;
- DPRINTF(1, "wWidth = %d, wHeight = %d\n",
- UGETW(fd->wWidth), UGETW(fd->wHeight));
+ if (desc->bDescriptorSubtype == UDESCSUB_VS_FRAME_UNCOMPRESSED) {
+ fbuf_size = UGETW(fd->wWidth) * UGETW(fd->wHeight) *
+ sc->sc_fmtgrp[fmtidx].format->u.uc.bBitsPerPixel / NBBY;
+ DPRINTF(10, "%s: %s: frame b