/* X Window Videum Tool * gcc -o xvideum -L/usr/X11R6/lib/ -lXt -lXaw -Wall xvideum.c * * For testing the Video for Linux Two Videum driver * * This program was written by Bill Dirks. * This program is in the public domain. */ /* Set these according to your set-up */ #define MY_DEVICE "/dev/video0" #define MY_INPUT 0 /*-> 0=MXC, 1=COMPOSITE, 2=SVIDEO */ #define MY_STD "PAL" /*-> "PAL" or "NTSC" */ #define MY_WIDTH 320 #define MY_HEIGHT 240 #define MY_PIXELFORMAT PIX_FMT_RGB565 #define MY_CHROMACOLOR 0xff00ff /* magenta */ /* if you are running 8 bit color or 24 bit color, you will have to modify the following const; I suppose the RIGHT way to do it is through X calls, but I don_t know X well enough yet patb */ #define MY_CHROMACOLOR16 0xf81f /* in rgb 5-6-5 format */ /* PIX_FMT_YUYV */ /* PIX_FMT_GREY */ /* PIX_FMT_YUV420 */ /* PIX_FMT_RGB555 */ /* PIX_FMT_RGB565 */ /* PIX_FMT_RGB24 */ /* PIX_FMT_RGB32 */ /* Uncomment the following to test stuff */ //#define TEST_SELECT /* test the driver select() handling */ //#define TEST_STREAMING /* test streaming capture */ //#define TEST_FRAMERATE 400000 /* 10million / frames-per-second */ #define TEST_INPUTS #define TEST_FORMATS #define TEST_CONTROLS //#define TEST_PREVIEW #define STREAMBUFS 4 #include #include #include #include #include #include #include #include #include #include /* These are needed to use the Videum driver */ #include #include //#include /* Video for Linux Two */ #include "videodev.h" #include #include #include #include #include #include #include int bShowReads = 1; void MoveVidcapWindow(int vid, int x, int y) { struct video_window vw = { x, y, MY_WIDTH, MY_HEIGHT, MY_CHROMACOLOR, 0, 0}; ioctl(vid, VIDIOC_S_WIN, &vw); } typedef struct tag_vimage { struct video_buffer vidbuf; char *data; XImage *shmimage; XShmSegmentInfo *shminfo; int shmsize; } VIMAGE; //void quit(Widget w, XtPointer client, XtPointer call) //{ // exit(0); //} void printctrl(struct video_queryctrl *qc) { printf(" %-12s %-6s %8d %8d %7d %8d\n", qc->name, (qc->step == -1) ? "(enum)" : (qc->step == 0) ? "(bool)" : "(int)", qc->minimum, qc->maximum, qc->step, qc->default_value); } int main(int argc, char *argv[]) { XtAppContext app; Widget toplevel; Widget read_copy_viewport; int vid; int err; int i; struct video_requestbuffers req; struct video_format fmt; struct video_parm parm; struct video_standard std; #ifdef TEST_CONTROLS struct video_queryctrl qc; #endif #ifdef TEST_SELECT fd_set rdset; struct timeval timeout; int n; #endif VIMAGE vimage[STREAMBUFS]; struct video_buffer tempbuf; GC imagegc; /*-> Put in the device node name */ vid = open(MY_DEVICE, O_RDONLY | O_NONBLOCK);//O_NONCAP); if (vid < 0) { printf("No video device\n"); return 1; } #ifdef TEST_INPUTS printf("Video inputs on this device:\n"); for (i = 0, err = 0; err == 0; ++i) { struct video_input inp; inp.index = i; err = ioctl(vid, VIDIOC_ENUMINPUT, &inp); if (!err) printf(" %d: \"%s\" is a%s, %s audio\n", i, inp.name, (inp.type == INPUT_TYPE_TUNER) ? " TV tuner" : "n analog input", (inp.capability & INPUT_CAP_AUDIO) ? "has" : "no" ); } #endif printf("Video standards supported:"); for (i = 0, err = 0; err == 0; ++i) { struct video_enumstd estd; estd.index = i; err = ioctl(vid, VIDIOC_ENUMSTD, &estd); if (!err) { printf("%c %s", i?',':' ', estd.std.name); if (strcmp(MY_STD, estd.std.name) == 0) std = estd.std; } } printf("\n"); #ifdef TEST_FORMATS printf("Video capture image formats supported:\n"); for (i = 0, err = 0; err == 0; ++i) { struct video_fmtdesc fmtd; fmtd.index = i; err = ioctl(vid, VIDIOC_G_CAPFMT, &fmtd); if (!err) printf(" %d: %s (%s)\n", i, fmtd.description, (fmtd.flags & FMT_FLAG_COMPRESSED) ? "compressed" : "uncompressed"); } #endif #ifdef TEST_CONTROLS printf("Controls supported:\n"); printf(" Label type Minimum Maximum Step Default\n"); qc.id = CID_BRIGHTNESS; if (ioctl(vid, VIDIOC_QUERYCTRL, &qc) == 0) printctrl(&qc); qc.id = CID_CONTRAST; if (ioctl(vid, VIDIOC_QUERYCTRL, &qc) == 0) printctrl(&qc); qc.id = CID_SATURATION; if (ioctl(vid, VIDIOC_QUERYCTRL, &qc) == 0) printctrl(&qc); qc.id = CID_HUE; if (ioctl(vid, VIDIOC_QUERYCTRL, &qc) == 0) printctrl(&qc); #endif /*-> 0=MXC, 1=COMPOSITE, 2=SVIDEO */ ioctl(vid, VIDIOC_G_PARM, &parm); parm.input = MY_INPUT; #ifdef TEST_FRAMERATE parm.capturemode |= CAP_TIMEPERFRAME; parm.timeperframe = TEST_FRAMERATE; #endif err = ioctl(vid, VIDIOC_S_PARM, &parm); if (err) printf("S_PARM returned error %d\n",errno); /*-> VIDEO_STD_PAL or VIDEO_STD_NTSC */ err = ioctl(vid, VIDIOC_S_STD, &std); if (err) printf("S_STD returned error %d\n",errno); /*-> Image width, height, pixel format */ ioctl(vid, VIDIOC_G_FMT, &fmt); fmt.width = MY_WIDTH; fmt.height = MY_HEIGHT; fmt.pixelformat = MY_PIXELFORMAT; err = ioctl(vid, VIDIOC_S_FMT, &fmt); if (err) { printf("S_FMT returned error %d\n",errno); return 1; } printf("S_FMT worked; we're at w/h %d/%d totalbytes %d\n", fmt.width, fmt.height, fmt.sizeimage); #ifdef TEST_PREVIEW { struct video_framebuffer vf; ioctl(vid, VIDIOC_G_FBUF, &vf); vf.flags = FBUF_FLAG_CHROMAKEY | FBUF_FLAG_OVERLAY; printf("chromakey set; video capture buffer at %p\n",vf.base[0]); ioctl(vid, VIDIOC_S_FBUF, &vf); ioctl(vid, VIDIOC_PREVIEW, 1); } #endif // TEST_PREVIEW req.count = 1; #ifdef TEST_STREAMING req.count = STREAMBUFS; req.type = BUF_TYPE_CAPTURE; err = ioctl(vid, VIDIOC_REQBUFS, &req); if (err < 0 || req.count < 1) { printf("REQBUFS returned error %d, count %d\n", errno,req.count); return 1; } for (i = 0; i < req.count; ++i) { vimage[i].vidbuf.index = i; vimage[i].vidbuf.type = BUF_TYPE_CAPTURE; err = ioctl(vid, VIDIOC_QUERYBUF, &vimage[i].vidbuf); if (err < 0) { printf("QUERYBUF returned error %d\n",errno); return 1; } vimage[i].data = mmap(0, vimage[i].vidbuf.length, PROT_READ, MAP_PRIVATE, vid, vimage[i].vidbuf.offset); if ((int)vimage[i].data == -1) { printf("mmap() returned error %d\n", errno); return 1; } } #else vimage[0].data = malloc(fmt.sizeimage); if (vimage[0].data == NULL) { printf("malloc(%d) failed\n", fmt.sizeimage); return 1; } #endif toplevel = XtAppInitialize(&app, "xvideum", NULL, 0, &argc, argv, NULL, NULL, 0); /* I create a window that is twice as wide as we need; the read() data goes into the left hand size; the live image will be mapped into the right hand side */ { XColor xc = {MY_CHROMACOLOR, 0x8000, 0x8000, 0x8000, 255}; read_copy_viewport = XtVaCreateManagedWidget("port", portholeWidgetClass, toplevel, XtNwidth, fmt.width, XtNheight, fmt.height, XtNbackground, MY_CHROMACOLOR16, NULL); } XtRealizeWidget(toplevel); imagegc = XCreateGC(XtDisplay(read_copy_viewport), DefaultRootWindow(XtDisplay(read_copy_viewport)), 0, NULL); for (i = 0; i < req.count; ++i) { vimage[i].shminfo = (XShmSegmentInfo*) malloc (sizeof(XShmSegmentInfo)); /* allocate shared image memory for the sub perview window */ vimage[i].shmimage = XShmCreateImage( XtDisplay(read_copy_viewport), DefaultVisual(XtDisplay(read_copy_viewport), 0), fmt.depth, ZPixmap, NULL,vimage[i].shminfo, fmt.width, fmt.height); vimage[i].shmsize = vimage[i].shmimage->bytes_per_line * vimage[i].shmimage->height; if ((err = (vimage[i].shminfo->shmid = shmget(IPC_PRIVATE, vimage[i].shmsize, IPC_CREAT | 0777))) == -1) { fprintf(stderr,"Shared memory error (shmget) - shmget returned %d",err); return(1); } if ((vimage[i].shminfo->shmaddr = (char *) shmat(vimage[i].shminfo->shmid, (void *)0, 0)) == (char *)(-1)) { fprintf(stderr,"Shared memory error (shmget) no data"); return(1); } vimage[i].shminfo->readOnly=False; vimage[tempbuf.index].shmimage->data = vimage[i].shminfo->shmaddr; if(XShmAttach(XtDisplay(read_copy_viewport), vimage[i].shminfo) ==0) { printf("XShm Attach failed, aborting\n"); return 1; }; /* if (vimage[i].ximage == NULL) { printf("No XImage\n"); return 1; } */ } #ifdef TEST_STREAMING for (i = 0; i < req.count; ++i) if ((err = ioctl(vid, VIDIOC_QBUF, vimage[i].vidbuf.type))) { printf("QBUF returned error %d\n",errno); return 1; } err = ioctl(vid, VIDIOC_STREAMON, vimage[0].vidbuf.type); if (err) printf("STREAMON returned error %d\n",errno); tempbuf.type = vimage[0].vidbuf.type; #endif for (;;) { XEvent event; err = 0; if (XtIsRealized(read_copy_viewport)) { #ifdef TEST_SELECT FD_ZERO(&rdset); FD_SET(vid, &rdset); timeout.tv_sec = 1; timeout.tv_usec = 0; n = select(vid + 1, &rdset, NULL, NULL, &timeout) err = -1; if (n == -1) fprintf(stderr, "select error.\n"); else if (n == 0) fprintf(stderr, "select timeout\n"); else if (FD_ISSET(vid, &rdset)) err = 0; #else #ifdef TEST_STREAMING err = ioctl(vid, VIDIOC_NEXTBUF, 0); if (err) printf("NEXTBUF returned error %d\n",errno); #endif #endif if (err == 0) { #ifdef TEST_STREAMING tempbuf.type = vimage[0].vidbuf.type; err = ioctl(vid, VIDIOC_DQBUF, &tempbuf); if (err) printf("DQBUF returned error %d\n", errno); #else if (bShowReads) read(vid, vimage[tempbuf.index].shmimage->data, fmt.sizeimage); #endif XShmPutImage(XtDisplay(read_copy_viewport), XtWindow(read_copy_viewport), imagegc, vimage[tempbuf.index].shmimage, 0, 0, 0, 0, fmt.width, fmt.height,1); XSync(XtDisplay(read_copy_viewport), 0); #ifdef TEST_STREAMING err = ioctl(vid, VIDIOC_QBUF, vimage[0].vidbuf.type); if (err) printf("QBUF returned error %d\n", errno); #endif } } while (XtAppPending(app)) { XtAppNextEvent(app, &event); switch (event.type) { #ifdef TEST_PREVIEW case ConfigureNotify: { XConfigureEvent *ce = (XConfigureEvent*)&event; MoveVidcapWindow(vid,ce->x+MY_WIDTH,ce->y); } break; #endif // TEST_PREVIEW case FocusIn: bShowReads = 1; break; case FocusOut: bShowReads = 0; break; default: break; } XtDispatchEvent(&event); } } close(vid); return 0; }