|  | /* | 
|  | * Very simple AVIPLAYER | 
|  | * | 
|  | * Copyright 1999 Marcus Meissner | 
|  | * | 
|  | * Status: | 
|  | * 	- plays .avi streams, video only | 
|  | *	- requires MicroSoft avifil32.dll and builtin msvfw32.dll. | 
|  | * | 
|  | * Todo: | 
|  | *	- audio support (including synchronization etc) | 
|  | *	- replace DirectDraw by a 'normal' window, including dithering, controls | 
|  | *	  etc. | 
|  | * | 
|  | * Bugs: | 
|  | *	- no time scheduling, video plays too fast using DirectDraw/XF86DGA | 
|  | *	- requires DirectDraw with all disadvantages. | 
|  | */ | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <time.h> | 
|  | #include <assert.h> | 
|  | #include <string.h> | 
|  | #include "windows.h" | 
|  | #include "wingdi.h" | 
|  | #include "mmsystem.h" | 
|  | #include "ddraw.h" | 
|  | #include "vfw.h" | 
|  |  | 
|  |  | 
|  | int PASCAL WinMain (HANDLE hInstance, HANDLE prev, LPSTR cmdline, int show) | 
|  | { | 
|  | int			bytesline,i,n,pos; | 
|  | time_t		tstart,tend; | 
|  | LONG		cnt; | 
|  | BITMAPINFOHEADER	*bmi; | 
|  | HRESULT		hres; | 
|  | HMODULE		avifil32 = LoadLibrary("avifil32.dll"); | 
|  | PAVIFILE		avif; | 
|  | PAVISTREAM		vids=NULL,auds=NULL; | 
|  | AVIFILEINFO		afi; | 
|  | AVISTREAMINFO	asi; | 
|  | PGETFRAME		vidgetframe=NULL; | 
|  | LPDIRECTDRAW	ddraw; | 
|  | DDSURFACEDESC	dsdesc; | 
|  | LPDIRECTDRAWSURFACE dsurf; | 
|  | LPDIRECTDRAWPALETTE dpal; | 
|  | PALETTEENTRY	palent[256]; | 
|  |  | 
|  |  | 
|  | void	(WINAPI *fnAVIFileInit)(void); | 
|  | void	(WINAPI *fnAVIFileExit)(void); | 
|  | ULONG	(WINAPI *fnAVIFileRelease)(PAVIFILE); | 
|  | ULONG	(WINAPI *fnAVIStreamRelease)(PAVISTREAM); | 
|  | HRESULT (WINAPI *fnAVIFileOpen)(PAVIFILE * ppfile,LPCTSTR szFile,UINT uMode,LPCLSID lpHandler); | 
|  | HRESULT (WINAPI *fnAVIFileInfo)(PAVIFILE ppfile,AVIFILEINFO *afi,LONG size); | 
|  | HRESULT (WINAPI *fnAVIFileGetStream)(PAVIFILE ppfile,PAVISTREAM *afi,DWORD fccType,LONG lParam); | 
|  | HRESULT (WINAPI *fnAVIStreamInfo)(PAVISTREAM iface,AVISTREAMINFO *afi,LONG size); | 
|  | HRESULT (WINAPI *fnAVIStreamReadFormat)(PAVISTREAM iface,LONG pos,LPVOID format,LPLONG size); | 
|  | PGETFRAME (WINAPI *fnAVIStreamGetFrameOpen)(PAVISTREAM iface,LPBITMAPINFOHEADER wanted); | 
|  | LPVOID (WINAPI *fnAVIStreamGetFrame)(PGETFRAME pg,LONG pos); | 
|  | HRESULT (WINAPI *fnAVIStreamGetFrameClose)(PGETFRAME pg); | 
|  |  | 
|  | #define XX(x) fn##x = (void*)GetProcAddress(avifil32,#x);assert(fn##x); | 
|  | #ifdef UNICODE | 
|  | # define XXT(x) fn##x = (void*)GetProcAddress(avifil32,#x##"W");assert(fn##x); | 
|  | #else | 
|  | # define XXT(x) fn##x = (void*)GetProcAddress(avifil32,#x##"A");assert(fn##x); | 
|  | #endif | 
|  | /* non character dependend routines: */ | 
|  | XX (AVIFileInit); | 
|  | XX (AVIFileExit); | 
|  | XX (AVIFileRelease); | 
|  | XX (AVIFileGetStream); | 
|  | XX (AVIStreamRelease); | 
|  | XX (AVIStreamReadFormat); | 
|  | XX (AVIStreamGetFrameOpen); | 
|  | XX (AVIStreamGetFrame); | 
|  | XX (AVIStreamGetFrameClose); | 
|  | /* A/W routines: */ | 
|  | XXT(AVIFileOpen); | 
|  | XXT(AVIFileInfo); | 
|  | XXT(AVIStreamInfo); | 
|  | #undef XX | 
|  | #undef XXT | 
|  |  | 
|  |  | 
|  | fnAVIFileInit(); | 
|  | if (-1==GetFileAttributes(cmdline)) { | 
|  | fprintf(stderr,"Usage: aviplay <avifilename>\n"); | 
|  | exit(1); | 
|  | } | 
|  | hres = fnAVIFileOpen(&avif,cmdline,OF_READ,NULL); | 
|  | if (hres) { | 
|  | fprintf(stderr,"AVIFileOpen: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | hres = fnAVIFileInfo(avif,&afi,sizeof(afi)); | 
|  | if (hres) { | 
|  | fprintf(stderr,"AVIFileInfo: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | for (n=0;n<afi.dwStreams;n++) { | 
|  | char buf[5]; | 
|  | PAVISTREAM	ast; | 
|  |  | 
|  | hres = fnAVIFileGetStream(avif,&ast,0,n); | 
|  | if (hres) { | 
|  | fprintf(stderr,"AVIFileGetStream %d: 0x%08lx\n",n,hres); | 
|  | exit(1); | 
|  | } | 
|  | hres = fnAVIStreamInfo(ast,&asi,sizeof(asi)); | 
|  | if (hres) { | 
|  | fprintf(stderr,"AVIStreamInfo %d: 0x%08lx\n",n,hres); | 
|  | exit(1); | 
|  | } | 
|  | fprintf(stderr,"[Stream %d: ",n); | 
|  | buf[4]='\0';memcpy(buf,&(asi.fccType),4); | 
|  | fprintf(stderr,"%s.",buf); | 
|  | buf[4]='\0';memcpy(buf,&(asi.fccHandler),4); | 
|  | fprintf(stderr,"%s, %s]\n",buf,asi.szName); | 
|  | switch (asi.fccType) { | 
|  | case streamtypeVIDEO: | 
|  | vids = ast; | 
|  | break; | 
|  | case streamtypeAUDIO: | 
|  | auds = ast; | 
|  | break; | 
|  | default:  { | 
|  | char type[5]; | 
|  | type[4]='\0';memcpy(type,&(asi.fccType),4); | 
|  |  | 
|  | fprintf(stderr,"Unhandled streamtype %s\n",type); | 
|  | fnAVIStreamRelease(ast); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | /********************* begin video setup ***********************************/ | 
|  | if (!vids) { | 
|  | fprintf(stderr,"No video stream found. Good Bye.\n"); | 
|  | exit(0); | 
|  | } | 
|  | cnt = sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD); | 
|  | bmi = HeapAlloc(GetProcessHeap(),0,cnt); | 
|  | hres = fnAVIStreamReadFormat(vids,0,bmi,&cnt); | 
|  | if (hres) { | 
|  | fprintf(stderr,"AVIStreamReadFormat vids: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | vidgetframe = NULL; | 
|  | bmi->biCompression = 0; /* we want it in raw form, uncompressed */ | 
|  | /* recalculate the image size */ | 
|  | bmi->biSizeImage = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes*bmi->biHeight/8; | 
|  | bytesline = ((bmi->biWidth*bmi->biBitCount+31)&~0x1f)*bmi->biPlanes/8; | 
|  | vidgetframe = fnAVIStreamGetFrameOpen(vids,bmi); | 
|  | if (!vidgetframe) { | 
|  | fprintf(stderr,"AVIStreamGetFrameOpen: failed\n"); | 
|  | exit(1); | 
|  | } | 
|  | /********************* end video setup ***********************************/ | 
|  |  | 
|  | /********************* begin display setup *******************************/ | 
|  | hres = DirectDrawCreate(NULL,&ddraw,NULL); | 
|  | if (hres) { | 
|  | fprintf(stderr,"DirectDrawCreate: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | hres = IDirectDraw_SetDisplayMode(ddraw,bmi->biWidth,bmi->biHeight,bmi->biBitCount); | 
|  | if (hres) { | 
|  | fprintf(stderr,"ddraw.SetDisplayMode: 0x%08lx (change resolution!)\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | dsdesc.dwSize=sizeof(dsdesc); | 
|  | dsdesc.dwFlags = DDSD_CAPS; | 
|  | dsdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; | 
|  | hres = IDirectDraw_CreateSurface(ddraw,&dsdesc,&dsurf,NULL); | 
|  | if (hres) { | 
|  | fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | if (bmi->biBitCount==8) { | 
|  | RGBQUAD		*rgb = (RGBQUAD*)(bmi+1); | 
|  | int		i; | 
|  |  | 
|  | hres = IDirectDraw_CreatePalette(ddraw,DDPCAPS_8BIT,NULL,&dpal,NULL); | 
|  | if (hres) { | 
|  | fprintf(stderr,"ddraw.CreateSurface: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | IDirectDrawSurface_SetPalette(dsurf,dpal); | 
|  | for (i=0;i<bmi->biClrUsed;i++) { | 
|  | palent[i].peRed = rgb[i].rgbRed; | 
|  | palent[i].peBlue = rgb[i].rgbBlue; | 
|  | palent[i].peGreen = rgb[i].rgbGreen; | 
|  | } | 
|  | IDirectDrawPalette_SetEntries(dpal,0,0,bmi->biClrUsed,palent); | 
|  | } else | 
|  | dpal = NULL; | 
|  | /********************* end display setup *******************************/ | 
|  |  | 
|  | tstart = time(NULL); | 
|  | pos = 0; | 
|  | while (1) { | 
|  | LPVOID		decodedframe; | 
|  | LPBITMAPINFOHEADER lpbmi; | 
|  | LPVOID		decodedbits; | 
|  |  | 
|  | /* video stuff */ | 
|  | if (!(decodedframe=fnAVIStreamGetFrame(vidgetframe,pos++))) | 
|  | break; | 
|  | lpbmi = (LPBITMAPINFOHEADER)decodedframe; | 
|  | decodedbits = (LPVOID)(((DWORD)decodedframe)+lpbmi->biSize); | 
|  | if (lpbmi->biBitCount == 8) { | 
|  | /* cant detect palette change that way I think */ | 
|  | RGBQUAD	*rgb = (RGBQUAD*)(lpbmi+1); | 
|  | int		i,palchanged; | 
|  |  | 
|  | /* skip used colorentries. */ | 
|  | decodedbits=(char*)decodedbits+bmi->biClrUsed*sizeof(RGBQUAD); | 
|  | palchanged = 0; | 
|  | for (i=0;i<bmi->biClrUsed;i++) { | 
|  | if (	(palent[i].peRed != rgb[i].rgbRed) || | 
|  | (palent[i].peBlue != rgb[i].rgbBlue) || | 
|  | (palent[i].peGreen != rgb[i].rgbGreen) | 
|  | ) { | 
|  | palchanged = 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (palchanged) { | 
|  | for (i=0;i<bmi->biClrUsed;i++) { | 
|  | palent[i].peRed = rgb[i].rgbRed; | 
|  | palent[i].peBlue = rgb[i].rgbBlue; | 
|  | palent[i].peGreen = rgb[i].rgbGreen; | 
|  | } | 
|  | IDirectDrawPalette_SetEntries(dpal,0,0,bmi->biClrUsed,palent); | 
|  | } | 
|  | } | 
|  | dsdesc.dwSize = sizeof(dsdesc); | 
|  | hres = IDirectDrawSurface_Lock(dsurf,NULL,&dsdesc,DDLOCK_WRITEONLY,0); | 
|  | if (hres) { | 
|  | fprintf(stderr,"dsurf.Lock: 0x%08lx\n",hres); | 
|  | exit(1); | 
|  | } | 
|  | /* Argh. AVIs are upside down. */ | 
|  | for (i=0;i<dsdesc.dwHeight;i++) { | 
|  | memcpy( (char *)dsdesc.u1.lpSurface+(i*dsdesc.lPitch), | 
|  | (char *)decodedbits+bytesline*(dsdesc.dwHeight-i-1), | 
|  | bytesline | 
|  | ); | 
|  | } | 
|  | IDirectDrawSurface_Unlock(dsurf,dsdesc.u1.lpSurface); | 
|  | } | 
|  | tend = time(NULL); | 
|  | fnAVIStreamGetFrameClose(vidgetframe); | 
|  |  | 
|  | IDirectDrawSurface_Release(dsurf); | 
|  | IDirectDraw_RestoreDisplayMode(ddraw); | 
|  | IDirectDraw_Release(ddraw); | 
|  | if (vids) fnAVIStreamRelease(vids); | 
|  | if (auds) fnAVIStreamRelease(auds); | 
|  | fprintf(stderr,"%d frames at %g frames/s\n",pos,pos*1.0/(tend-tstart)); | 
|  | fnAVIFileRelease(avif); | 
|  | fnAVIFileExit(); | 
|  | return 0; | 
|  | } |