On Monday 07 May 2001 01:17, Dmitri wrote:
> Quoting Stefan Nilsen <[EMAIL PROTECTED]>:
> > The camera separates images using one or more 0 length frames. It doesn't
> > have any "magic" number that indicates the start of a new image. Can
> > usbvideo handle that case?
> usbvideo, as it is now, has only one ring queue for the collected data,
> and it has no attributes attached to any place of that queue (which
> could tell that a new transfer starts here or something.) To correctly
> implement what you need requires a message queue instead of ring queue.
>
> However this is irrelevant to your problem because (for now) you just
> need to insert your own "magic" marker (which is unlikely to appear
> on its own in the valid data stream). Then the decoding routine will
> be looking for that marker (as ibmcam does), and you know where each
> transfer (or frame) starts. Make change in usbvideo_IsocIrq() to do that.
It looked more logical (easier) to put a change in
usbvideo_CompressIsochronous to add a marker in the ringqueue. I have a patch
here that adds support for drivers to add a marker sequence. I hope it doesnt
make the other drivers stop working. I now have CVS access so if it looks ok
to you i can submit the changes.
Btw: I also found the reason that my processing callbacks where not called.
Stupid me added the FLAGS_NO_DECODING when initializing the camera... :-(
/Stefan
Index: usbvideo.c
===================================================================
RCS file: /cvsroot/linux-usb/usbvideo/usbvideo.c,v
retrieving revision 1.12
diff -u -r1.12 usbvideo.c
--- usbvideo.c 2001/02/13 12:21:36 1.12
+++ usbvideo.c 2001/05/08 00:16:32
@@ -933,6 +933,21 @@
proc, i, up, up->user_data);
kfree(up->user_data);
}
+ if (up->empty_marker != NULL) {
+ if (up->empty_marker_size <= 0)
+ ++warning;
+ } else {
+ if (up->empty_marker_size > 0)
+ ++warning;
+ }
+ if (warning) {
+ err("%s: Warning: empty_marker=$%p empty_marker_size=%d.",
+ proc, up->empty_marker, up->empty_marker_size);
+ } else {
+ dbg("%s: Freeing %d. $%p->empty_marker=$%p",
+ proc, i, up, up->empty_marker);
+ kfree(up->empty_marker);
+ }
}
/* Whole array was allocated in one chunk */
dbg("%s: Freed %d uvd_t structures",
@@ -1813,6 +1828,13 @@
/* Detect and ignore empty packets */
if (n <= 0) {
uvd->stats.iso_skip_count++;
+ if (uvd->empty_marker_size > 0) {
+ assert(uvd->empty_marker);
+ if (uvd->debug >= 1) {
+ info("Inserting empty marker: size = %d",
+uvd->empty_marker_size);
+ }
+ RingQueue_Enqueue(&uvd->dp, uvd->empty_marker,
+uvd->empty_marker_size);
+ }
continue;
}
totlen += n; /* Little local accounting */
Index: usbvideo.h
===================================================================
RCS file: /cvsroot/linux-usb/usbvideo/usbvideo.h,v
retrieving revision 1.10
diff -u -r1.10 usbvideo.h
--- usbvideo.h 2001/04/12 07:19:46 1.10
+++ usbvideo.h 2001/05/08 00:16:32
@@ -212,6 +212,12 @@
struct s_usbvideo_t *handle; /* Points back to the usbvideo_t */
void *user_data; /* Camera-dependent data */
int user_size; /* Size of that camera-dependent data */
+ void *empty_marker; /* Optional empty marker for empty frames in an
iso-stream
+
+ The empty marker is inserted in ringbuffer when a 0 length
+
+ frame is recieved in the iso stream and the
+
+ empty_marker_size > 0
+
+ Needed for webcamgo driver */
+ int empty_marker_size; /* Size of the empty marker */
int debug; /* Debug level for usbvideo */
unsigned char iface; /* Video interface number */
unsigned char video_endp;
Index: webcamgo.c
===================================================================
RCS file: /cvsroot/linux-usb/usbvideo/webcamgo.c,v
retrieving revision 1.1
diff -u -r1.1 webcamgo.c
--- webcamgo.c 2001/05/07 20:13:16 1.1
+++ webcamgo.c 2001/05/08 00:16:33
@@ -31,7 +31,9 @@
#define MAX_CAMERAS 4 /* How many devices we allow to connect */
-// #define JPEG_COMPRESSED 1
+#define EMPTY_MARKER "[Frame break]"
+
+#define JPEG_COMPRESSED 1
#define PLANAR 1
// #define YUV420 1
@@ -50,7 +52,7 @@
static int debug = 0;
-static int flags = 0; /* FLAGS_NO_DECODING; */ /* FLAGS_DISPLAY_HINTS |
FLAGS_OVERLAY_STATS; */
+static int flags = /* 0; */ /* FLAGS_NO_DECODING; */ FLAGS_RETRY_VIDIOCSYNC;
/* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
static const int min_canvasWidth = 8;
static const int min_canvasHeight = 4;
@@ -134,10 +136,9 @@
assert(uvd != NULL);
assert(frame != NULL);
-#if 1
- info("in webcamgo_ProcessIsocData");
- err("in webcamgo_ProcessIsocData");
-#endif
+ if (uvd->debug >= 1) {
+ info("in webcamgo_ProcessIsocData");
+ }
/* Try to move data from queue into frame buffer */
n = RingQueue_GetLength(&uvd->dp);
@@ -416,7 +417,6 @@
if (!WEBCAMGO_T(uvd)->initialized) {
webcamgo = WEBCAMGO_T(uvd);
- uvd->flags = uvd->flags | FLAGS_NO_DECODING;
webcamgo_alternateSetting(uvd, 0x00); /* Maybe don't need this */
webcamgo_veio(uvd, 0x01, 0x0000, 0x00, 0); /* Read the control reg.
Dont
know why...
@@ -1221,6 +1221,8 @@
static void webcamgo_configure_video(uvd_t *uvd)
{
+ int marker_size;
+
if (uvd == NULL)
return;
@@ -1257,6 +1259,12 @@
uvd->vchan.channel = 0;
uvd->vchan.type = VIDEO_TYPE_CAMERA;
strcpy(uvd->vchan.name, "Camera");
+
+ marker_size = strlen(EMPTY_MARKER);
+ uvd->empty_marker = kmalloc(marker_size, GFP_KERNEL);
+ assert(uvd->empty_marker);
+ memcpy(uvd->empty_marker, EMPTY_MARKER, marker_size);
+ uvd->empty_marker_size = marker_size;
}
/*
@@ -1399,6 +1407,7 @@
int len;
/* Stay under PAGE_SIZE or else */
+ /* TODO: Show the latest reading of button status in CR02 here */
out += sprintf(out, "Chapter MMCMLXXX: Hello World! the hard way...\n");
len = out - page;
len -= off;
@@ -1412,6 +1421,127 @@
return len;
}
+int webcamgo_GetFrame(uvd_t *uvd, int frameNum)
+{
+ static const char proc[] = "usbvideo_GetFrame";
+ usbvideo_frame_t *frame = &uvd->frame[frameNum];
+
+ if (uvd->debug >= 2)
+ info("%s($%p,%d.)", proc, uvd, frameNum);
+
+ switch (frame->frameState) {
+ case FrameState_Unused:
+ if (uvd->debug >= 2)
+ info("%s: FrameState_Unused", proc);
+ return -EINVAL;
+ case FrameState_Ready:
+ case FrameState_Grabbing:
+ case FrameState_Error:
+ {
+ int ntries, signalPending;
+ redo:
+ info("label redo:");
+ if (!CAMERA_IS_OPERATIONAL(uvd)) {
+ if (uvd->debug >= 2)
+ info("%s: Camera is not operational (1)",
+proc);
+ return -EIO;
+ }
+ ntries = 0;
+ do {
+ RingQueue_InterruptibleSleepOn(&uvd->dp);
+ signalPending = signal_pending(current);
+ if (!CAMERA_IS_OPERATIONAL(uvd)) {
+ if (uvd->debug >= 2)
+ info("%s: Camera is not operational
+(2)", proc);
+ return -EIO;
+ }
+ assert(uvd->fbuf != NULL);
+ if (signalPending) {
+ if (uvd->debug >= 2)
+ info("%s: Signal=$%08x", proc,
+signalPending);
+ if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
+ usbvideo_TestPattern(uvd, 1, 0);
+ uvd->curframe = -1;
+ uvd->stats.frame_num++;
+ if (uvd->debug >= 2)
+ info("%s: Forced test pattern
+screen", proc);
+ return 0;
+ } else {
+ /* Standard answer: Interrupted! */
+ if (uvd->debug >= 2)
+ info("%s: Interrupted!", proc);
+ return -EINTR;
+ }
+ } else {
+ /* No signals - we just got new data in dp
+queue */
+ if (uvd->flags & FLAGS_NO_DECODING)
+ usbvideo_CollectRawData(uvd, frame);
+ else if (VALID_CALLBACK(uvd, processData)) {
+ GET_CALLBACK(uvd, processData)(uvd,
+frame);
+ } else
+ err("%s: processData not set", proc);
+ }
+ } while (frame->frameState == FrameState_Grabbing);
+ if (uvd->debug >= 2) {
+ info("%s: Grabbing done; state=%d. (%lu. bytes)",
+ proc, frame->frameState,
+frame->seqRead_Length);
+ }
+ if (frame->frameState == FrameState_Error) {
+ int ret = usbvideo_NewFrame(uvd, frameNum);
+ if (ret < 0) {
+ err("%s: usbvideo_NewFrame() failed (%d.)",
+proc, ret);
+ return ret;
+ }
+ goto redo;
+ }
+ /* Note that we fall through to meet our destiny below */
+ }
+ case FrameState_Done:
+ /*
+ * Do all necessary postprocessing of data prepared in
+ * "interrupt" code and the collecting code above. The
+ * frame gets marked as FrameState_Done by queue parsing code.
+ * This status means that we collected enough data and
+ * most likely processed it as we went through. However
+ * the data may need postprocessing, such as deinterlacing
+ * or picture adjustments implemented in software (horror!)
+ *
+ * As soon as the frame becomes "final" it gets promoted to
+ * FrameState_Done_Hold status where it will remain until the
+ * caller consumed all the video data from the frame. Then
+ * the empty shell of ex-frame is thrown out for dogs to eat.
+ * But we, worried about pets, will recycle the frame!
+ */
+ uvd->stats.frame_num++;
+ if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
+ if (VALID_CALLBACK(uvd, postProcess))
+ GET_CALLBACK(uvd, postProcess)(uvd, frame);
+ if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
+ usbvideo_SoftwareContrastAdjustment(uvd, frame);
+ }
+ frame->frameState = FrameState_Done_Hold;
+ if (uvd->debug >= 2)
+ info("%s: Entered FrameState_Done_Hold state.", proc);
+ return 0;
+
+ case FrameState_Done_Hold:
+ /*
+ * We stay in this state indefinitely until someone external,
+ * like ioctl() or read() call finishes digesting the frame
+ * data. Then it will mark the frame as FrameState_Unused and
+ * it will be released back into the wild to roam freely.
+ */
+ if (uvd->debug >= 2)
+ info("%s: FrameState_Done_Hold state.", proc);
+ return 0;
+ }
+
+ /* Catch-all for other cases. We shall not be here. */
+ err("%s: Invalid state %d.", proc, frame->frameState);
+ frame->frameState = FrameState_Unused;
+ return 0;
+}
+
/*
* webcamgo_init()
*
@@ -1430,6 +1560,7 @@
cbTbl.adjustPicture = webcamgo_adjust_picture;
cbTbl.getFPS = webcamgo_calculate_fps;
cbTbl.procfs_read = webcamgo_procfs_read_proc;
+ cbTbl.getFrame = webcamgo_GetFrame;
return usbvideo_register(
&cams,
MAX_CAMERAS,
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
http://lists.sourceforge.net/lists/listinfo/linux-usb-devel