| /* |
| * Very simple AVIPLAYER |
| * |
| * Copyright 1999 Marcus Meissner |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * 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> |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| #include "windows.h" |
| #include "wingdi.h" |
| #include "mmsystem.h" |
| #include "ddraw.h" |
| #include "vfw.h" |
| |
| |
| int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE 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.lpSurface+(i*dsdesc.u1.lPitch), |
| (char *)decodedbits+bytesline*(dsdesc.dwHeight-i-1), |
| bytesline |
| ); |
| } |
| IDirectDrawSurface_Unlock(dsurf,dsdesc.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; |
| } |