#include "disp.h" /* frames are 0 - 224 */ const int numFiles = 225; int pktsInFile; /* Number of packets in tracefile */ const int pixelsPerPacket = 38400; /* 48 for an ATM cell */ const int width = 320; const int height = 240; const float timeScaleFactor = 0.0025; int packetsPerFrame; int packetNumber, frameNumber, packetCounter, frameCounter; /* the indexes keep increasing, the frame and pkt numbers are modulo the number of frames and pkts */ u_char *imageData; char filename[80]; FILE *fp; char magic[80]; int maxval; Display *disp; int screen; float currDesiredDispTime, prevDesiredDispTime; /* target image */ XImage *image; struct Trace *videoTrace; struct wininfo capinfo; Window win; struct timeval sysTime, sysTime; char frameDir[80]; void readTraceFile() { int i; fp = fopen("video.trace", "r"); if (fp == (FILE*) NULL) { printf("Error: could not open input file.\n"); return; } fscanf(fp, "%d\n", &pktsInFile); videoTrace = (struct Trace *) calloc(pktsInFile+1, sizeof(struct Trace)); for (i = 0; i < pktsInFile; i++) { fscanf(fp, "%d %f\n", &videoTrace[i].pktReceived, &videoTrace[i].recTime); printf("time stamp is %f\n", videoTrace[i].recTime); } } void readFrame() { int W, H; fp = fopen(filename, "r"); if (fp == (FILE*) NULL) { printf("Error: could not open input file.\n"); exit(-1); } fscanf(fp, "%s %d %d %d%*c", magic, &W, &H, &maxval); if ((W != width) || (H != height)) { printf("Mismatched size:\n"); printf("W = %d, H = %d", W, H); exit(-1); } if (strcmp(magic, "P5")) { /* P5 is PGM magic number */ printf("Error in PGM magic number.\n"); exit(-1); } if (maxval > 255) printf("Error in maxval."); fread(imageData, sizeof(unsigned char), width*height, fp); fclose(fp); /* printf("Read file ok.\n"); */ } void editFrame() { /* Currently, this routine blacks out pixels that were not received (or that were received late). Another approach is to leave the pixels from the previous frame buffer. */ int i, j, packetIndex, startPixel, endPixel; for (i = 1; i <= packetsPerFrame; i++) { packetIndex = packetCounter % pktsInFile; if (videoTrace[packetIndex].pktReceived != 1) { /* black out pixelsPerPacket pixels for the dropped packet */ startPixel = (packetIndex % packetsPerFrame) * pixelsPerPacket; endPixel = (((packetIndex % packetsPerFrame) + 1) * pixelsPerPacket) - 1; for (j = startPixel; j <= endPixel; j++) { imageData[j] = 0; /* or Oxff to white out */ } } packetCounter++; currDesiredDispTime = videoTrace[packetIndex].recTime; } } Window createXwindow(int w, int h, char *wname, char *iname, struct wininfo *info) { XVisualInfo *vList; int visualsMatched; XSizeHints size_hints; int screen; u_int border_width = 2; Window win, root; XSetWindowAttributes attr; /* Get screen size from display structure macro */ info->vinfo.screen = screen = DefaultScreen(disp); if (info->visual == 0) { vList = XGetVisualInfo(disp, VisualScreenMask|VisualDepthMask | VisualClassMask, &info->vinfo, &visualsMatched); if (visualsMatched == 0) { fprintf(stderr, "cannot find suitable visual\n"); exit(-1); } info->visual = vList[0].visual; /* store info about Visual */ info->vinfo = vList[0]; /* each visual requires a different colormap */ root = DefaultRootWindow(disp); info->cmap = XCreateColormap(disp, root, info->visual, AllocNone); } attr.colormap = info->cmap; attr.event_mask = ExposureMask | VisibilityChangeMask; attr.backing_store = Always; attr.border_pixel = BlackPixel(disp, screen); attr.background_pixel = BlackPixel(disp, screen); attr.override_redirect = True; win = XCreateWindow(disp, root, info->x, info->y, w, h, border_width, info->vinfo.depth, InputOutput, info->visual, CWColormap | CWBorderPixel | CWBackPixel | CWBackingStore, &attr); /* Initialize size hint property for window manager */ size_hints.flags = PSize; size_hints.width = w; size_hints.height = h; if (info->x >= 0) size_hints.x = info->x; if (info->y >= 0) size_hints.y = info->y; size_hints.flags |= USPosition; /* Set properties for window manager (always before mapping) */ XSetStandardProperties(disp, win, wname, iname, None, (char **) 0, 0, &size_hints); /* Select event types wanted */ XSelectInput(disp, win, ExposureMask | ButtonPressMask); if (info->gc == 0) info->gc = XCreateGC(disp, win, (u_long)0, (XGCValues *)0); XMapWindow(disp, win); /* * override window manager if it doesn't follow hints * the standard says we're not supposed to do this! */ XResizeWindow(disp, win, w, h); XFlush(disp); info->win = win; return (win); } Drawable createpixmap(int w, int h, int depth, struct wininfo *info) { int visualsMatched; XVisualInfo *vList; int mask = VisualScreenMask|VisualDepthMask|VisualClassMask; vList = XGetVisualInfo(disp, mask, &info->vinfo, &visualsMatched); if (visualsMatched == 0) { fprintf(stderr, "cannot find suitable visual\n"); exit(-1); } info->visual = vList[0].visual; /* store info about Visual */ info->vinfo = vList[0]; /* each visual requires a different colormap */ info->cmap = XCreateColormap(disp, DefaultRootWindow(disp), info->visual, AllocNone); info->win = XCreatePixmap(disp, DefaultRootWindow(disp), w, h, depth); info->gc = XCreateGC(disp, info->win, (u_long)0, (XGCValues *)0); /* XXX */ return (info->win); } void capture(struct wininfo *capinfo) { u_char *sp; u_char *ep; u_char *dp; int delta; static int offset = -1; XPutImage(disp, capinfo->win, capinfo->gc, image, 0, 0, 0, 0, width, height); XSync(disp, False); } allocimage(const struct wininfo *p) { image = XCreateImage(disp, p->visual, p->vinfo.depth, ZPixmap, 0, imageData, width, height, 0, width); } void displayFrame() { capture(&capinfo); /* display frame */ frameCounter++; frameNumber = frameCounter % numFiles; } void initFunctions() { /* Connect to X server */ prevDesiredDispTime = 0.0; packetNumber = 0; packetCounter = 0; frameNumber = 0; frameCounter = 0; sprintf(frameDir,"frames/frame_"); disp = XOpenDisplay(0); if (disp == 0) { fprintf(stderr, "cannot connect to X server\n"); exit(-1); } imageData = (unsigned char *) calloc(width*height, sizeof(int)); XFlush(disp); bzero(&capinfo, sizeof(capinfo)); capinfo.vinfo.depth = 8; capinfo.vinfo.class = StaticGray; capinfo.x = width + 5; capinfo.y = 0; } main(int argc, char *argv[]) { float desiredScaledFrameTime; double timeSinceLastFrame; double prevActualDispTime, currActualDispTime, currActualFrameTime; struct itimerval vt_val; packetsPerFrame = ceil (width * height / pixelsPerPacket); readTraceFile(); initFunctions(); win = createXwindow(width, height, "grab", "grab", &capinfo); XSync(disp, False); /* get gray scale image */ allocimage(&capinfo); gettimeofday(&sysTime, 0); prevActualDispTime = (double) sysTime.tv_sec + ((double) sysTime.tv_usec / 1e6); while(1) { /* use the system clock to show the effects of delay jitter */ sprintf(filename,"%s%04d", frameDir, frameNumber); /* printf("frame file %s\n", filename); */ readFrame(); editFrame(); /* to degrade the frame b/c of lost pkts */ desiredScaledFrameTime = timeScaleFactor * (currDesiredDispTime - prevDesiredDispTime); printf("desired (scaled) frame time is %f\n", desiredScaledFrameTime); gettimeofday(&sysTime, 0); timeSinceLastFrame = ((double) sysTime.tv_sec + ((double) sysTime.tv_usec / 1e6)) - prevActualDispTime; /* Loop until it is time to display frame */ while ( timeSinceLastFrame < desiredScaledFrameTime) { gettimeofday(&sysTime, 0); timeSinceLastFrame = (double) sysTime.tv_sec + ((double) sysTime.tv_usec / 1e6) - prevActualDispTime; } displayFrame(); gettimeofday(&sysTime, 0); currActualDispTime = sysTime.tv_sec + (sysTime.tv_usec / 1e6); currActualFrameTime = currActualDispTime - prevActualDispTime; printf("actual interframe time is %f\n", currActualFrameTime); prevDesiredDispTime = currDesiredDispTime; prevActualDispTime = currActualDispTime; } }