/* * Copyright (c) 1994 by * PARALLAX GRAPHICS, INCORPORATED, Santa Clara, California. * All rights reserved * * This software is furnished on an as-is basis, and may be used and copied * only with the inclusion of the above copyright notice. * * The information in this software is subject to change without notice. * No committment is made as to the usability or reliability of this * software. * * Parallax Graphics, Inc. * 2500 Condensa Street * Santa Clara, California 95051 * Author: Paul Lovvik */ /* $Log: playmovie.c,v $ * Revision 0.93 1995/12/12 17:37:57 lovvik * Made 2 changes: * 1. Changed the timing logic. playmovie would sometimes take 12 * seconds to play a 10 second movie because of the way the timing * was done. * 2. Added a command line argument that plays the movie repeatedly. * (Now, the default is to play the movie once and exit). * * Revision 0.92 1995/09/19 23:13:45 drapeau * Used the new utility functions XPlxGetVideoVisual() and XPlxSleep() * now part of the XPlx library. * * Revision 0.91 1994/10/22 04:40:23 drapeau * Made the code more ANSI-compatible. * * Revision 0.90 1994/08/10 17:42:22 lovvik * Synchronization added. * Window Title added. * XFlush removed. * */ /* $Header: /plx/source/Xclients/generic/RCS/playmovie.c,v 0.93 1995/12/12 17:37:57 lovvik Exp $ */ static char rscid[] = "$Header: /plx/source/Xclients/generic/RCS/playmovie.c,v 0.93 1995/12/12 17:37:57 lovvik Exp $"; /* Program: playback Usage: playback jpeg_movie_file Description: This demo illustrates the usage of XPlxPutCImage() to display JPEG movie images. Parallax JPEG movie file has the following format: --------------------------------------------- | jpheader + filler = sizeof(jpheader) | jpheader defined in movie.h |-------------------------------------------| | frame #1 starts at offset[0] | |-------------------------------------------| | frame #2 starts at offset[1] | |-------------------------------------------| : : : : : : |-------------------------------------------| | frame #N starts at offset[N-1] | |-------------------------------------------| | offset[0 to (N-1)] = N * sizeof(int) | | starts at jpheader.indexbuf | --------------------------------------------- Each frame can be of video only or video+audio: AUDIO: -------------------------------------------- | LOAD_AUDIO instr | audio data | -------------------------------------------- 1 byte size defined in jpheader.audioslice VIDEO: --------------------------------------------------------- | LOAD_JPEG instr | frame data size | XPlxCImage data | --------------------------------------------------------- 1 byte sizeof(int) frame data size Instructions (instr) are defined in movie.h. */ #include #include #include #include #include #include #include #include /* required for gettimeofday */ #include #include #include #include /*#include /* required for movie.h */ #include "movie.h" long ElapsedTime(); void main(argc, argv) int argc; char **argv; { Window win; /* movie playback window */ Display *disp; char *window_name = "playmovie"; XTextProperty windowname; /* used to set up the window name */ int scr, winMask; /* scr= screen, winMask= valuemask of window attributes */ GC gc; XEvent event; FILE *jpegFile; /* JPEG movie file to play back */ int width, height, depth; /* movie window width, height, and depth */ jpheader header; /* JPEG movie header sturcture */ char instruction; /* movie file instruction byte */ int *indexBuffer; /* frame offset index buffer */ int currentFrame; /* current movie frame */ int qTableSize; /* Q table size */ unsigned char* qTable; /* decompression Q table */ int cImageSize, maximumSize; /* compressed image size & maximum image size */ XPlxCImage *cImage; /* compressed image sturcture */ char *cImageData; /* compressed image data */ XVisualInfo *visualInfo; /* visual info of movie window */ XSetWindowAttributes winAttributes; /* window attrubutes of movie window */ char *audioslice=NULL; int devaudio; int first=1; /* flag to keep track of first XPlxPutCImage */ int FramesPerSecond; /* number of frames per second */ long int mSecondsPerFrame; /* number of milliseconds per frame */ struct timeval starttime, now; /* variable to calculate event-loop time */ int nextFrameTime; int repeat = False; if (argc<2) /* requires movie filename as argument */ { printf("usage: playmovie <-repeat> moviefile\n"); exit(1); } if(argc > 2 && strcmp(argv[1], "-repeat") == 0) { repeat = True; } jpegFile=fopen(argv[argc-1],"r"); if (jpegFile==NULL) { printf("Can't open input file\n"); exit(1); } fread((char*)&header,sizeof(jpheader),1,jpegFile); /* read in jpheader info of movie */ FramesPerSecond = header.fps; /* Get frames per second */ mSecondsPerFrame = (long int)(1000 / (float)(FramesPerSecond)); if (header.tracks>0) /* check whether there's audio recorded in movie */ { audioslice=(char*)malloc(header.audioslice); /* initialize audio device */ devaudio=open("/dev/audio",O_WRONLY,0); if (devaudio<0) printf("Can't open /dev/audio\n"); } width=header.width; /* set window width to that of movie */ height=header.height; /* set window height to that of movie */ fseek(jpegFile,header.indexbuf,0); /* skip file to read frame offset locations */ indexBuffer=(int*)malloc(header.frames*sizeof(int)); /* create index buffer according to number of movie frames */ fread((char*)indexBuffer,sizeof(int),header.frames,jpegFile); /* Read in frame offsets to buffer */ currentFrame=0; /* frame index starts at 0 */ disp=XOpenDisplay(""); scr=(int)XDefaultScreen(disp); visualInfo = XPlxGetVideoVisual(scr, disp); /* Get a proper Visual for using 24-bit video in a window */ depth = visualInfo->depth; printf("depth %d\n",depth); winMask=CWBackPixel|CWColormap|CWBorderPixel; winAttributes.colormap=XCreateColormap(disp, XRootWindow(disp, scr), visualInfo->visual,AllocNone); winAttributes.background_pixel=BlackPixel(disp,scr); winAttributes.border_pixel=WhitePixel(disp,scr); win=XCreateWindow(disp,XRootWindow(disp,scr), 0,0,width,height, /* x, y, width and height */ 0, /* border width */ depth, /* window depth */ InputOutput,visualInfo->visual, winMask,&winAttributes); XStringListToTextProperty(&window_name, 1, &windowname); /* Set up the window title */ XSetWMProperties(disp, win, &windowname, &windowname, argv, argc, NULL, NULL, NULL); gc=XCreateGC(disp,win,0,0); /* create GC for movie window */ XSelectInput(disp,win,ExposureMask | ButtonPressMask); XMapWindow(disp,win); qTableSize=MakeQTables(header.qfactor,&qTable); /* generate Q table according to Q factor from header */ XPlxPutTable(disp,win,gc,qTable,qTableSize,1); /* load Q table to CCube chip for decompression */ maximumSize=width*height*3/5; /* calculate maximum compressed image data size, for one frame of movie */ /* assume minimum compression of 5:1 */ cImageData=malloc(maximumSize); /* allocate data area in memory */ cImage=(XPlxCImage*)XPlxCreateCImage(disp,cImageData, maximumSize,width,height); /* assign allocated memory for XPlxCImage */ XPlxVideoTag(disp,win,gc,PLX_VIDEO); /* video tag remains PLX_VIDEO until ready for playback */ gettimeofday(&starttime, NULL); while (1) { if (XPending(disp)) { XNextEvent(disp,&event); first=1; } gettimeofday(&now, NULL); nextFrameTime = (int)((unsigned int)(mSecondsPerFrame * (currentFrame+1)) - (unsigned int)(ElapsedTime(starttime, now))); if(nextFrameTime >= 0) /* Are we late for this frame? */ { XPlxSleep(nextFrameTime * 1000); /* No, display a new image. */ fseek(jpegFile,indexBuffer[currentFrame],0); /* skip to start of frame pointed to by index offset */ fread(&instruction,1,1,jpegFile); /* this is to skip the opcode instruction */ if ((instruction&0x00ff)==LOAD_AUDIO_0) /* if instruction is to load audio */ { int i; if (audioslice==NULL) abort(); i=fread(audioslice,1,header.audioslice,jpegFile); /* read audio data from file */ write(devaudio,audioslice,header.audioslice); /* send data to device */ fread(&instruction,1,1,jpegFile); /* read the opcode instruction. */ } if ((instruction&0x00ff)==LOAD_JPEG) /* if instruction is to load jpeg data */ { fread(&cImageSize,4,1,jpegFile); /* read in the frame data size */ fread(cImageData,cImageSize,1,jpegFile); /* read in the jpeg data of the frame */ cImage->size=cImageSize; XPlxPutCImage(disp,win,gc,cImage, 0,0,width,height, 0,0,width,height, 0); /* set to crop image if necessary */ if (first) { XPlxVideoTag(disp,win,gc,PLX_VIDEO_OVR); /* set tag to PLX_VIDEO_OVR so window doesn't get */ first=0; /* refresh with background color before drawing */ } /* the next image */ } } else { /* frame was late, skip it. */ } if (++currentFrame>=header.frames-1) /* allows loopback when it's end of movie */ { if(repeat == False) { XFreeGC(disp, gc); XCloseDisplay(disp); exit(1); } else { currentFrame=0; gettimeofday(&starttime, NULL); } } if (event.type == ButtonPress) { XFreeGC(disp, gc); XCloseDisplay(disp); exit(1); } } } long ElapsedTime(before, after) struct timeval* before; struct timeval* after; { return(((after->tv_sec - before->tv_sec) * 1000) + /* Convert the seconds part to milliseconds */ ((after->tv_usec - before->tv_usec) /1000)); /* Convert the microseconds part to milliseconds */ } /* end function ElapsedTime */