/* * record off-screen graphics * * gfx (pbuffer/dmbuffer) -> dmic (jpeg) -> Movie File */ #include #include #include #include #include #include #include #include /* frame */ #define WID 1024 #define HT 480 #define RATE 24. static int attrs_rgba_sb[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None, }; #define E0(ret,func,str) if ((ret = func) == NULL) { fprintf(stderr, str); } /* 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);} /* moviefile errors */ #define MVPR(s) fprintf(stderr, "%s: %s\n", s, mvGetErrorStr(mvGetErrno())) #define EMV(func, s) if (func == DM_FAILURE) { MVPR(s); exit(1); } static int attrs_pbuffer[] = {None}; int findrealtimejpeg(void); int findrealtimejpeg(void) { 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) == DM_IC_CODE_DIRECTION_ENCODE) { printf("found %s, vers %d, rev %d\n", dmParamsGetString(p, DM_IC_ENGINE), dmParamsGetInt(p, DM_IC_VERSION), dmParamsGetInt(p, DM_IC_REVISION)); dmParamsDestroy(p); return n; } dmParamsDestroy(p); } fprintf(stderr, "found no real time JPEG decoder\n"); exit(1); /* NOTREACHED */ } void render(int x) { static int frame; glClearColor((double)(256 - x)/256., 0., (double)x/256., 0.); glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glTranslatef((double)WID/2.,(double)HT/2.,0.); #define CLOCK (360./RATE) glRotatef(CLOCK*(double)frame, 0., 0., 1.); glColor3f(1.,1.,1.); /* white */ glBegin(GL_TRIANGLES); glVertex2i(-10,0); glVertex2i(0,50); glVertex2i(10,0); glEnd(); glPopMatrix(); if (frame++ == (int)RATE) { frame = 0; } } main(int argc, char **argv) { int x = 240; Display *dpy; XVisualInfo *vi; GLXFBConfigSGIX conf; GLXContext ctx; GLXPbufferSGIX pbuffer; DMparams *p; DMbufferpool gpool, cpool; DMbuffer gbuf, cbuf; DMimageconverter ic; int icfd, poolfd, maxfd; size_t nbytes; fd_set fdr, fdw; char *mvfile = argv[1]; MVid movie, track; MVtimescale tscale; MVtime dur, time = 0; double rate = RATE; if (argc != 2) { fprintf(stderr, "usage: %s file.mv\n", argv[0]); exit(1); } /* * Create off-screen graphics context (pbuffer). */ E0(dpy, XOpenDisplay(0), "XOpenDisplay"); E0(vi, glXChooseVisual(dpy, DefaultScreen(dpy), attrs_rgba_sb), "glXChooseVisual"); E0(conf, glXGetFBConfigFromVisualSGIX(dpy, vi), "get fb config"); E0(ctx, glXCreateContextWithConfigSGIX(dpy, conf, GLX_RGBA_TYPE_SGIX, NULL, GL_TRUE), "create context"); /* XXX if vice jpeg could talke LAYOUT_GRAPHICS we'd make a dmbuffer */ E0(pbuffer, glXCreateGLXPbufferSGIX(dpy, conf, WID, HT, attrs_pbuffer), "create pbuffer"); glXMakeCurrent(dpy, pbuffer, ctx); glViewport(0, 0, WID, HT); glOrtho((GLdouble)0, (GLdouble)WID, (GLdouble)0, (GLdouble)HT, -1., 1.); /* * Create and configure JPEG image converter. */ ED(dmICCreate(findrealtimejpeg(), &ic), "dmICCreate"); dmParamsCreate(&p); dmSetImageDefaults(p, WID, HT, DM_IMAGE_PACKING_ABGR); nbytes = dmImageFrameSize(p); printf("frame bytes %d\n", nbytes); dmParamsSetEnum(p, DM_IMAGE_ORIENTATION, DM_IMAGE_TOP_TO_BOTTOM); dmParamsSetString(p, DM_IMAGE_COMPRESSION, DM_IMAGE_UNCOMPRESSED); ED(dmICSetSrcParams(ic, p), "dmICSetSrcParams"); dmParamsSetEnum(p, DM_IMAGE_PACKING, DM_IMAGE_PACKING_CbYCrY); dmParamsSetString(p, DM_IMAGE_COMPRESSION, DM_IMAGE_JPEG); ED(dmICSetDstParams(ic, p), "dmICSetDstParams"); dmParamsDestroy(p); dmParamsCreate(&p); dmParamsSetFloat(p, DM_IMAGE_QUALITY_SPATIAL, .95); ED(dmICSetConvParams(ic, p), "dmICSetConvParams"); dmParamsDestroy(p); /* * Create buffer pool for gfx -> dmic. */ dmParamsCreate(&p); ED(dmBufferSetPoolDefaults(p, 2, nbytes, DM_FALSE, DM_FALSE), "i defaults"); ED(dmICGetSrcPoolParams(ic, p), "dmICGetSrcPoolParams"); ED(dmBufferCreatePool(p, &gpool), "create gpool"); dmParamsDestroy(p); poolfd = dmBufferGetPoolFD(gpool); /* * Create pool for dmic output. */ dmParamsCreate(&p); ED(dmBufferSetPoolDefaults(p, 2, nbytes, DM_FALSE, DM_FALSE), "o defaults"); ED(dmICGetDstPoolParams(ic, p), "dmICGetDstPoolParams"); ED(dmBufferCreatePool(p, &cpool), "create cpool"); dmParamsDestroy(p); ED(dmICSetDstPool(ic, cpool), "dmICSetDstPool"); icfd = dmICGetDstQueueFD(ic); /* * Create a Movie File with an image track. */ dmParamsCreate(&p); EMV(mvSetMovieDefaults(p, MV_FORMAT_QT), "movie defaults"); EMV(mvCreateFile(mvfile, p, NULL, &movie), "mv create"); dmParamsDestroy(p); dmParamsCreate(&p); ED(dmSetImageDefaults(p, WID, HT, DM_PACKING_RGBX), "img def"); ED(dmParamsSetString(p, DM_IMAGE_COMPRESSION, DM_IMAGE_JPEG), "jpeg"); ED(dmParamsSetFloat(p, DM_IMAGE_RATE, rate), "rate"); ED(dmParamsSetEnum(p, DM_IMAGE_ORIENTATION, DM_TOP_TO_BOTTOM), "ttob"); ED(dmParamsSetEnum(p, DM_IMAGE_INTERLACING, DM_IMAGE_NONINTERLACED), "not interlaced"); EMV(mvAddTrack(movie, DM_IMAGE, p, NULL, &track), "add track"); dmParamsDestroy(p); tscale = mvGetTrackTimeScale(track); dur = (long long)((double)tscale/rate); maxfd = (icfd > poolfd ? icfd : poolfd) + 1; while (x--) { FD_ZERO(&fdr); FD_ZERO(&fdw); FD_SET(icfd, &fdr); FD_SET(poolfd, &fdw); if (select(maxfd, &fdr, &fdw, 0, 0) < 0) { perror("select"); exit(1); } printf("%d\n", x); if (FD_ISSET(icfd, &fdr)) { ED(dmICReceive(ic, &cbuf), "recv"); EMV(mvInsertTrackData(track, 1, time, dur, tscale, dmBufferGetSize(cbuf), dmBufferMapData(cbuf), MV_FRAMETYPE_KEY, 0), "mvinsert"); dmBufferFree(cbuf); time += dur; } if (FD_ISSET(poolfd, &fdw)) { render(x); ED(dmBufferAllocate(gpool, &gbuf), "alloc gbuf"); glReadPixels(0, 0, WID, HT, GL_ABGR_EXT, GL_UNSIGNED_BYTE, dmBufferMapData(gbuf)); ED(dmICSend(ic, gbuf, 0, 0), "send"); dmBufferFree(gbuf); } } mvClose(movie); }