/* * jio * * vid -> enc -> dec -> gfx */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* libdm errors */ DMstatus e; const char *e_short; int e_num; char e_long[DM_MAX_ERROR_DETAIL]; #define GE() e_short = dmGetError(&e_num, e_long); #define PR(str) fprintf(stderr, "libdm failed %s %s %d %s\n", str, e_short, e_num, e_long); #define EX(v) exit(v) #define ED(dmfunc, str) if ((e = dmfunc) != DM_SUCCESS) { GE(); PR(str); EX(1); } /* vl errors: sometimes error is 0, sometimes -1... */ #define EV(var, func, str) if (!(var = func)) { vlPerror(str); exit(1); } #define EVN(func, str) if (func == -1) { vlPerror(str); exit(1); } /* X errors */ #define X0(var, func, str) if (!(var = func)) { fprintf(stderr, str); } static int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None }; static Bool WaitForNotify(Display *d, XEvent *e, char *arg) { return (e->type == MapNotify) && (e->xmap.window == (Window)arg); } char *a_prog; int icjpeg(int dir) { int n; DMparams *p; if ((n = dmICGetNum()) <= 0 ) { fprintf(stderr, "no converters? dmICGetNum %d\n", n); exit(1); } while (n--) { dmParamsCreate(&p); if (dmICGetDescription(n, p) == DM_SUCCESS && dmParamsGetInt(p, DM_IC_ID) == 'jpeg' && dmParamsGetEnum(p, DM_IC_SPEED) == DM_IC_SPEED_REALTIME && dmParamsGetEnum(p, DM_IC_CODE_DIRECTION) == dir) { printf("%s: found %s, vers %d, rev %d\n", a_prog, dmParamsGetString(p, DM_IC_ENGINE), dmParamsGetInt(p, DM_IC_VERSION), dmParamsGetInt(p, DM_IC_REVISION)); dmParamsDestroy(p); return n; } dmParamsDestroy(p); } fprintf(stderr, "%s: found no real time JPEG decoder\n", a_prog); exit(1); /* NOTREACHED */ } main(int argc, char **argv) { DMparams *p; DMimageconverter d_ic, e_ic; DMbufferpool inpool, midpool, outpool; DMbuffer buf; size_t imagebytes; int d_icfd, e_icfd; fd_set fdset; int wid, ht; struct timeval to; VLServer svr; VLPath path; VLNode drn, src; VLControlValue val; int xferbytes; int vidfd, vdrop = 0; Display *dpy; XVisualInfo *vi; Colormap cmap; XSetWindowAttributes swa; Window win; GLXContext cx; XEvent event; to.tv_sec = 1; to.tv_usec = 0; a_prog = argv[0]; if (argc != 1) { fprintf(stderr, "usage: %s\n", a_prog); exit(1); } /* * Open video input. */ EV(svr, vlOpenVideo(""), "open video"); EV(drn, vlGetNode(svr, VL_DRN, VL_MEM, VL_ANY), "get drain"); EV(src, vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY), "get src"); EV(path, vlCreatePath(svr, VL_ANY, src, drn), "create path"); EVN(vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE,VL_SHARE),"Setup"); val.intVal = VL_PACKING_YVYU_422_8; EVN(vlSetControl(svr, path, drn, VL_PACKING, &val), "set ycrcb422"); val.intVal = VL_CAPTURE_INTERLEAVED; /* frames */ EVN(vlSetControl(svr, path, drn, VL_CAP_TYPE, &val), "set fields"); EVN(vlGetControl(svr, path, drn, VL_SIZE, &val), "get size"); wid = val.xyVal.x; /* Expected to be 16x */ ht = val.xyVal.y; ht &= ~7; /* Round down to 8x */ xferbytes = vlGetTransferSize(svr, path); printf("wid %d, ht %d, xferbytes %d\n", wid, ht, xferbytes); X0(dpy, XOpenDisplay(0),"XOpenDisplay failed"); X0(vi, glXChooseVisual(dpy, DefaultScreen(dpy), attributeList), "glXChooseVisual failed"); X0(cx, glXCreateContext(dpy, vi, 0, GL_TRUE), "glXCreateContext failed"); cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); swa.colormap = cmap; swa.border_pixel = 0; swa.event_mask = StructureNotifyMask; win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0,0, wid, ht*2, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); XMapWindow(dpy, win); XIfEvent(dpy, &event, WaitForNotify, (char*)win); glXMakeCurrent(dpy, win, cx); glViewport(0, 0, wid, ht*2); glOrtho(0., (GLdouble)wid, 0., (GLdouble)ht*2., -1., 1.); /* video draws top to bottom */ glPixelZoom(1., -1.); ED(dmICCreate(icjpeg(DM_IC_CODE_DIRECTION_DECODE), &d_ic), "d_ic"); ED(dmICCreate(icjpeg(DM_IC_CODE_DIRECTION_ENCODE), &e_ic), "e_ic"); /* * encode "src" and decode "dst" are 422 YCrCb, * encode "dst" and decode "src" is JPEG */ dmParamsCreate(&p); dmSetImageDefaults(p, wid, ht, DM_IMAGE_PACKING_CbYCrY); dmParamsSetString(p, DM_IMAGE_COMPRESSION, DM_IMAGE_UNCOMPRESSED); dmParamsSetEnum(p, DM_IMAGE_ORIENTATION, DM_IMAGE_TOP_TO_BOTTOM); imagebytes = dmImageFrameSize(p); ED(dmICSetSrcParams(e_ic, p), "e src"); ED(dmICSetDstParams(d_ic, p), "d dst"); dmParamsSetString(p, DM_IMAGE_COMPRESSION, DM_IMAGE_JPEG); ED(dmICSetDstParams(e_ic, p), "e dst"); ED(dmICSetSrcParams(d_ic, p), "d src"); dmParamsDestroy(p); /* * Encode conversion params */ dmParamsCreate(&p); dmParamsSetFloat(p, DM_IMAGE_QUALITY_SPATIAL, .9); ED(dmICSetConvParams(e_ic, p), "dmICSetConvParams"); dmParamsDestroy(p); /* * A pool for input video */ dmParamsCreate(&p); #define NOTCACHED DM_FALSE #define NOTMAPPED DM_FALSE #define IBUFS 8 dmBufferSetPoolDefaults(p, IBUFS, imagebytes, NOTCACHED, NOTMAPPED); ED(dmICGetSrcPoolParams(e_ic, p), "dmICGetSrcPoolParams"); EVN(vlDMPoolGetParams(svr, path, drn, p), "vl requirements"); ED(dmBufferCreatePool(p, &inpool), "dmBufferCreatePool inpool"); dmParamsDestroy(p); EVN(vlDMPoolRegister(svr, path, drn, inpool), "vlDMPoolRegister"); /* * A pool for encode -> decode (dst for encoder) */ dmParamsCreate(&p); dmBufferSetPoolDefaults(p, IBUFS, imagebytes, NOTCACHED, NOTMAPPED); ED(dmICGetDstPoolParams(e_ic, p), "e dst pool"); ED(dmICGetSrcPoolParams(d_ic, p), "d src pool"); ED(dmBufferCreatePool(p, &midpool), "dmBufferCreatePool midpool"); ED(dmICSetDstPool(e_ic, midpool), "d set dst pool"); dmParamsDestroy(p); /* * A pool for output images (dst for decoder) */ dmParamsCreate(&p); #define OBUFS 10 dmBufferSetPoolDefaults(p, OBUFS, imagebytes, NOTCACHED, DM_TRUE); ED(dmICGetDstPoolParams(d_ic, p), "dmICGetDstPoolParams"); ED(dmBufferCreatePool(p, &outpool), "dmBufferCreatePool outpool"); dmParamsDestroy(p); ED(dmICSetDstPool(d_ic, outpool), "dmICSetDstPool"); /* * Start video */ #define MASK (VLTransferCompleteMask|VLTransferFailedMask|VLSequenceLostMask) EVN(vlSelectEvents(svr, path, MASK),"vlSelectEvents"); EVN(vlBeginTransfer(svr, path, 0, 0), "begin transfer"); /* * Configure select(2) */ ED(dmBufferSetPoolSelectSize(inpool, imagebytes), "select size"); EVN(vlPathGetFD(svr, path, &vidfd), "get fd"); d_icfd = dmICGetDstQueueFD(d_ic); e_icfd = dmICGetDstQueueFD(e_ic); while (1) { int n, max; FD_ZERO(&fdset); FD_SET(vidfd, &fdset); FD_SET(d_icfd, &fdset); FD_SET(e_icfd, &fdset); max = (vidfd > d_icfd ? vidfd : d_icfd) + 1; max = (max > e_icfd ? max : e_icfd) + 1; n = select(max, &fdset, 0, 0, 0); if (n < 0) { perror("select"); exit(1); } /* Receive JPEG image from encoder, send to decoder */ if (FD_ISSET(e_icfd, &fdset)) { if (dmICReceive(e_ic, &buf) == DM_SUCCESS) { dmICSend(d_ic, buf, 0, 0); } dmBufferFree(buf); } /* Receive YCrCb image from decoder, display on gfx */ if (FD_ISSET(d_icfd, &fdset)) { if (dmICReceive(d_ic, &buf) == DM_SUCCESS) { glRasterPos2i(0, ht); glDrawPixels(wid, ht, GL_YCRCB_422_SGIX, GL_UNSIGNED_BYTE, dmBufferMapData(buf)); } dmBufferFree(buf); } /* Receive video input, send to encoder */ if (FD_ISSET(vidfd, &fdset)) { VLEvent vlevent; if (vlEventRecv(svr, path, &vlevent) == DM_SUCCESS) { if (vlevent.reason == VLSequenceLost) { vdrop++; if (vdrop % 10 == 0) printf("vdrop %d\n", vdrop); continue; } if (vlevent.reason != VLTransferComplete) { fprintf(stderr, "vlevent %d\n", vlevent.reason); exit(1); } EVN(vlEventToDMBuffer(&vlevent, &buf), "vldmbuffer"); glRasterPos2i(0, ht*2); glDrawPixels(wid, ht, GL_YCRCB_422_SGIX, GL_UNSIGNED_BYTE, dmBufferMapData(buf)); dmICSend(e_ic, buf, 0, 0); dmBufferFree(buf); } } } /* NOTREACHED */ }