/* * Copyright 1999 Marcus Meissner */ #include #include #include #include "vfw.h" #include "winbase.h" #include "wine/winestring.h" #include "driver.h" #include "mmsystem.h" #include "winerror.h" #include "debugstr.h" #include "debug.h" DECLARE_DEBUG_CHANNEL(avifile) DECLARE_DEBUG_CHANNEL(msvideo) DECLARE_DEBUG_CHANNEL(relay) typedef struct IAVIStreamImpl { /* IUnknown stuff */ ICOM_VTABLE(IAVIStream)* lpvtbl; DWORD ref; /* IAVIStream stuff */ LPVOID lpInputFormat; DWORD inputformatsize; BOOL iscompressing; DWORD curframe; /* Compressor stuff */ HIC hic; LPVOID lpCompressFormat; ICINFO icinfo; DWORD compbufsize; LPVOID compbuffer; DWORD decompbufsize; LPVOID decompbuffer; LPVOID decompformat; AVICOMPRESSOPTIONS aco; LPVOID lpPrev; /* pointer to decompressed frame later */ LPVOID lpPrevFormat; /* pointer to decompressed info later */ } IAVIStreamImpl; void WINAPI AVIFileInit(void) { FIXME(avifile,"(),stub!\n"); } typedef struct IAVIFileImpl { /* IUnknown stuff */ ICOM_VTABLE(IAVIFile)* lpvtbl; DWORD ref; /* IAVIFile stuff... */ } IAVIFileImpl; struct ICOM_VTABLE(IAVIStream) iavist; static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj) { ICOM_THIS(IAVIFileImpl,iface); char xrefiid[50]; WINE_StringFromCLSID((LPCLSID)refiid,xrefiid); TRACE(relay,"(%p)->QueryInterface(%s,%p)\n",This,xrefiid,obj); if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) || !memcmp(&IID_IAVIFile,refiid,sizeof(IID_IAVIFile)) ) { *obj = iface; return S_OK; } return OLE_E_ENUM_NOMORE; } static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface) { ICOM_THIS(IAVIFileImpl,iface); FIXME(relay,"(%p)->AddRef()\n",iface); return ++(This->ref); } static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface) { ICOM_THIS(IAVIFileImpl,iface); FIXME(relay,"(%p)->Release()\n",iface); if (!--(This->ref)) { HeapFree(GetProcessHeap(),0,iface); return 0; } return This->ref; } static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size) { FIXME(avifile,"(%p)->Info(%p,%ld)\n",iface,afi,size); /* FIXME: fill out struct? */ return E_FAIL; } static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam) { FIXME(avifile,"(%p)->GetStream(%p,0x%08lx,%ld)\n",iface,avis,fccType,lParam); /* FIXME: create interface etc. */ return E_FAIL; } static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi) { ICOM_THIS(IAVIStreamImpl,iface); char fcc[5]; IAVIStreamImpl *istream; FIXME(avifile,"(%p,%p,%p)\n",This,avis,asi); istream = (IAVIStreamImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IAVIStreamImpl)); istream->ref = 1; istream->lpvtbl = &iavist; fcc[4]='\0'; memcpy(fcc,(char*)&(asi->fccType),4); FIXME(avifile,"\tfccType '%s'\n",fcc); memcpy(fcc,(char*)&(asi->fccHandler),4); FIXME(avifile,"\tfccHandler '%s'\n",fcc); FIXME(avifile,"\tdwFlags 0x%08lx\n",asi->dwFlags); FIXME(avifile,"\tdwCaps 0x%08lx\n",asi->dwCaps); FIXME(avifile,"\tname '%s'\n",debugstr_w(asi->szName)); istream->curframe = 0; *avis = (PAVISTREAM)istream; return S_OK; } static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size) { FIXME(avifile,"(%p)->WriteData(0x%08lx,%p,%ld)\n",iface,ckid,lpData,size); /* FIXME: write data to file */ return E_FAIL; } static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size) { FIXME(avifile,"(%p)->ReadData(0x%08lx,%p,%p)\n",iface,ckid,lpData,size); /* FIXME: read at most size bytes from file */ return E_FAIL; } static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface) { FIXME(avifile,"(%p)->EndRecord()\n",iface); /* FIXME: end record? */ return E_FAIL; } static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam) { FIXME(avifile,"(%p)->DeleteStream(0x%08lx,%ld)\n",iface,fccType,lParam); /* FIXME: delete stream? */ return E_FAIL; } struct ICOM_VTABLE(IAVIFile) iavift = { IAVIFile_fnQueryInterface, IAVIFile_fnAddRef, IAVIFile_fnRelease, IAVIFile_fnInfo, IAVIFile_fnGetStream, IAVIFile_fnCreateStream, IAVIFile_fnWriteData, IAVIFile_fnReadData, IAVIFile_fnEndRecord, IAVIFile_fnDeleteStream }; HRESULT WINAPI AVIFileOpenA( PAVIFILE * ppfile,LPCSTR szFile,UINT uMode,LPCLSID lpHandler ) { char buf[80]; IAVIFileImpl *iavi; if (HIWORD(lpHandler)) WINE_StringFromCLSID(lpHandler,buf); else sprintf(buf,"",(DWORD)lpHandler); FIXME(avifile,"(%p,%s,0x%08lx,%s),stub!\n",ppfile,szFile,(DWORD)uMode,buf); iavi = (IAVIFileImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IAVIFileImpl)); iavi->ref = 1; iavi->lpvtbl = &iavift; *ppfile = (LPVOID)iavi; return S_OK; } static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj) { ICOM_THIS(IAVIStreamImpl,iface); char xrefiid[50]; WINE_StringFromCLSID((LPCLSID)refiid,xrefiid); TRACE(relay,"(%p)->QueryInterface(%s,%p)\n",This,xrefiid,obj); if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) || !memcmp(&IID_IAVIStream,refiid,sizeof(IID_IAVIStream)) ) { *obj = This; return S_OK; } /* can return IGetFrame interface too */ return OLE_E_ENUM_NOMORE; } static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface) { ICOM_THIS(IAVIStreamImpl,iface); FIXME(relay,"(%p)->AddRef()\n",iface); return ++(This->ref); } static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface) { ICOM_THIS(IAVIStreamImpl,iface); FIXME(relay,"(%p)->Release()\n",iface); if (!--(This->ref)) { HeapFree(GetProcessHeap(),0,This); return 0; } return This->ref; } HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2) { FIXME(avifile,"(%p)->Create(0x%08lx,0x%08lx)\n",iface,lParam1,lParam2); return E_FAIL; } HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size) { FIXME(avifile,"(%p)->Info(%p,%ld)\n",iface,psi,size); return E_FAIL; } LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags) { FIXME(avifile,"(%p)->FindSample(%ld,0x%08lx)\n",iface,pos,flags); return E_FAIL; } HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize) { FIXME(avifile,"(%p)->ReadFormat(%ld,%p,%p)\n",iface,pos,format,formatsize); return E_FAIL; } /***************************************************************************** * [IAVIStream::SetFormat] */ HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize) { IAVIStreamImpl *as = (IAVIStreamImpl*)iface; FIXME(avifile,"(%p)->SetFormat(%ld,%p,%ld)\n",iface,pos,format,formatsize); if (as->lpInputFormat) HeapFree(GetProcessHeap(),0,as->lpInputFormat); as->inputformatsize = formatsize; as->lpInputFormat = HeapAlloc(GetProcessHeap(),0,formatsize); memcpy(as->lpInputFormat,format,formatsize); if (as->iscompressing) { int xsize; /* Set up the Compressor part */ xsize = ICCompressGetFormatSize(as->hic,as->lpInputFormat); as->lpCompressFormat = HeapAlloc(GetProcessHeap(),0,xsize); ICCompressGetFormat(as->hic,as->lpInputFormat,as->lpCompressFormat); ICCompressBegin(as->hic,as->lpInputFormat,as->lpCompressFormat); as->compbufsize = ICCompressGetSize(as->hic,as->lpInputFormat,as->lpCompressFormat); as->compbuffer = HeapAlloc(GetProcessHeap(),0,as->compbufsize); /* Set up the Decompressor part (for prev frames?) */ xsize=ICDecompressGetFormatSize(as->hic,as->lpCompressFormat); as->decompformat = HeapAlloc(GetProcessHeap(),0,xsize); ICDecompressGetFormat(as->hic,as->lpCompressFormat,as->decompformat); as->decompbufsize=((LPBITMAPINFOHEADER)as->decompbuffer)->biSizeImage; as->decompbuffer = HeapReAlloc(GetProcessHeap(),0,as->decompbuffer,as->decompbufsize); memset(as->decompbuffer,0xff,as->decompbufsize); assert(HeapValidate(GetProcessHeap(),0,NULL)); ICDecompressGetFormat(as->hic,as->lpCompressFormat,as->decompformat); ICDecompressBegin(as->hic,as->lpCompressFormat,as->decompformat); as->lpPrev = as->lpPrevFormat = NULL; } return S_OK; } HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { FIXME(avifile,"(%p)->Read(%ld,%ld,%p,%ld,%p,%p)\n",iface,start,samples,buffer,buffersize,bytesread,samplesread); return E_FAIL; } HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { IAVIStreamImpl *as = (IAVIStreamImpl*)iface; DWORD ckid,xflags; FIXME(avifile,"(%p)->Write(%ld,%ld,%p,%ld,0x%08lx,%p,%p)\n",iface,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); ICCompress( as->hic,flags, as->lpCompressFormat, as->compbuffer, as->lpInputFormat,buffer, &ckid,&xflags, as->curframe,0xffffff/*framesize*/,as->aco.dwQuality, as->lpPrevFormat,as->lpPrev ); ICDecompress( as->hic, flags, /* FIXME: check */ as->lpCompressFormat, as->compbuffer, as->decompformat, as->decompbuffer ); /* We now have a prev format for the next compress ... */ as->lpPrevFormat = as->decompformat; as->lpPrev = as->decompbuffer; return S_OK; } HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples) { FIXME(avifile,"(%p)->Delete(%ld,%ld)\n",iface,start,samples); return E_FAIL; } HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread) { FIXME(avifile,"(%p)->ReadData(0x%08lx,%p,%p)\n",iface,fcc,lp,lpread); return E_FAIL; } HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size) { FIXME(avifile,"(%p)->WriteData(0x%08lx,%p,%ld)\n",iface,fcc,lp,size); return E_FAIL; } HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen) { FIXME(avifile,"(%p)->SetInfo(%p,%ld)\n",iface,info,infolen); return E_FAIL; } struct ICOM_VTABLE(IAVIStream) iavist = { IAVIStream_fnQueryInterface, IAVIStream_fnAddRef, IAVIStream_fnRelease, IAVIStream_fnCreate, IAVIStream_fnInfo, IAVIStream_fnFindSample, IAVIStream_fnReadFormat, IAVIStream_fnSetFormat, IAVIStream_fnRead, IAVIStream_fnWrite, IAVIStream_fnDelete, IAVIStream_fnReadData, IAVIStream_fnWriteData, IAVIStream_fnSetInfo }; HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE iface,PAVISTREAM *ppavi,AVISTREAMINFOA * psi) { AVISTREAMINFOW psiw; /* Only the szName at the end is different */ memcpy(&psiw,psi,sizeof(*psi)-sizeof(psi->szName)); lstrcpynAtoW(psiw.szName,psi->szName,sizeof(psi->szName)); return iface->lpvtbl->fnCreateStream(iface,ppavi,&psiw); } HRESULT WINAPI AVIFileCreateStreamW(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi) { return iface->lpvtbl->fnCreateStream(iface,avis,asi); } HRESULT WINAPI AVIFileGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam) { return iface->lpvtbl->fnGetStream(iface,avis,fccType,lParam); } HRESULT WINAPI AVIFileInfoA(PAVIFILE iface,LPAVIFILEINFOA afi,LONG size) { AVIFILEINFOW afiw; HRESULT hres; if (size < sizeof(AVIFILEINFOA)) return AVIERR_BADSIZE; hres = iface->lpvtbl->fnInfo(iface,&afiw,sizeof(afiw)); memcpy(afi,&afiw,sizeof(*afi)-sizeof(afi->szFileType)); lstrcpynWtoA(afi->szFileType,afiw.szFileType,sizeof(afi->szFileType)); return hres; } HRESULT WINAPI AVIStreamInfoW(PAVISTREAM iface,AVISTREAMINFOW *asi,LONG size) { return iface->lpvtbl->fnInfo(iface,asi,size); } HRESULT WINAPI AVIStreamInfoA(PAVISTREAM iface,AVISTREAMINFOA *asi,LONG size) { AVISTREAMINFOW asiw; HRESULT hres; if (sizelpvtbl->fnInfo(iface,&asiw,sizeof(asiw)); memcpy(asi,&asiw,sizeof(asiw)-sizeof(asiw.szName)); lstrcpynWtoA(asi->szName,asiw.szName,sizeof(asi->szName)); return hres; } HRESULT WINAPI AVIFileInfoW(PAVIFILE iface,LPAVIFILEINFOW afi,LONG size) { return iface->lpvtbl->fnInfo(iface,afi,size); } HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,PAVISTREAM ppsSource,AVICOMPRESSOPTIONS *aco,CLSID *pclsidHandler) { char fcc[5]; IAVIStreamImpl *as; FIXME(avifile,"(%p,%p,%p,%p)\n",ppsCompressed,ppsSource,aco,pclsidHandler); fcc[4]='\0'; memcpy(fcc,&(aco->fccType),4); FIXME(avifile,"\tfccType: '%s'\n",fcc); memcpy(fcc,&(aco->fccHandler),4); FIXME(avifile,"\tfccHandler: '%s'\n",fcc); FIXME(avifile,"\tdwFlags: 0x%08lx\n",aco->dwFlags); /* we just create a duplicate for now */ ((IUnknown*)ppsSource)->lpvtbl->fnAddRef((IUnknown*)ppsSource); *ppsCompressed = ppsSource; as = (IAVIStreamImpl*)ppsSource; /* this is where the fun begins. Open a compressor and prepare it. */ as->hic = ICOpen(aco->fccType,aco->fccHandler,ICMODE_COMPRESS); /* May happen. for instance if the codec is not able to compress */ if (!as->hic) return AVIERR_UNSUPPORTED; ICGetInfo(as->hic,&(as->icinfo),sizeof(ICINFO)); FIXME(avifile,"Opened compressor: '%s' '%s'\n",debugstr_w(as->icinfo.szName),debugstr_w(as->icinfo.szDescription)); as->iscompressing = TRUE; memcpy(&(as->aco),aco,sizeof(*aco)); if (as->icinfo.dwFlags & VIDCF_COMPRESSFRAMES) { ICCOMPRESSFRAMES icf; /* now what to fill in there ... Hmm */ memset(&icf,0,sizeof(icf)); icf.lDataRate = aco->dwBytesPerSecond; icf.lQuality = aco->dwQuality; icf.lKeyRate = aco->dwKeyFrameEvery; icf.GetData = (LONG (*)(LPARAM,LONG,LPVOID,LONG)) 0xdead4242; icf.PutData = (LONG (*)(LPARAM,LONG,LPVOID,LONG)) 0xdead4243; ICSendMessage(as->hic,ICM_COMPRESS_FRAMES_INFO,(LPARAM)&icf,sizeof(icf)); } return S_OK; } HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM iface,LONG pos,LPVOID format,LONG formatsize) { return iface->lpvtbl->fnSetFormat(iface,pos,format,formatsize); } HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM iface,LONG pos,LPVOID format,LONG *formatsize) { return iface->lpvtbl->fnReadFormat(iface,pos,format,formatsize); } HRESULT WINAPI AVIStreamWrite(PAVISTREAM iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { return iface->lpvtbl->fnWrite(iface,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); } HRESULT WINAPI AVIStreamRead(PAVISTREAM iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { return iface->lpvtbl->fnRead(iface,start,samples,buffer,buffersize,bytesread,samplesread); } HRESULT WINAPI AVIStreamWriteData(PAVISTREAM iface,DWORD fcc,LPVOID lp,LONG size) { return iface->lpvtbl->fnWriteData(iface,fcc,lp,size); } HRESULT WINAPI AVIStreamReadData(PAVISTREAM iface,DWORD fcc,LPVOID lp,LONG *lpread) { return iface->lpvtbl->fnReadData(iface,fcc,lp,lpread); } LONG WINAPI AVIStreamStart(PAVISTREAM iface) { AVISTREAMINFOW si; iface->lpvtbl->fnInfo(iface,&si,sizeof(si)); return si.dwStart; } LONG WINAPI AVIStreamLength(PAVISTREAM iface) { AVISTREAMINFOW si; HRESULT ret; ret = iface->lpvtbl->fnInfo(iface,&si,sizeof(si)); if (ret) /* error */ return 1; return si.dwLength; } ULONG WINAPI AVIStreamRelease(PAVISTREAM iface) { return ((LPUNKNOWN)iface)->lpvtbl->fnRelease((LPUNKNOWN)iface); } PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM iface,LPBITMAPINFOHEADER bmi) { FIXME(msvideo,"(%p)->(%p),stub!\n",iface,bmi); return NULL; } LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg,LONG pos) { return pg->lpvtbl->fnGetFrame(pg,pos); } HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg) { if (pg) ((LPUNKNOWN)pg)->lpvtbl->fnRelease((LPUNKNOWN)pg); return 0; } ULONG WINAPI AVIFileRelease(PAVIFILE iface) { return ((LPUNKNOWN)iface)->lpvtbl->fnRelease((LPUNKNOWN)iface); } void WINAPI AVIFileExit(void) { FIXME(avifile,"(), stub.\n"); }