dlls/avifil32: many implemented functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hallo.

This patch is a replacement of the one from

Fri Oct 11 2002 - 16:49:14 CDT

License: X11

What this patch does:

winedefault.reg:
- add the neccessary avifile.dll and avifil32.dll registry entries

include/vfw.h:
- add FIND_* constants
- add AVISAVECALLBACK declaration
- add declaration for some AVI functions
- add some AVI macros

dlls/avifil32:
- add wavefile handler to avifil32
- add implementation for IGetFrame to avifil32.dll
- implemented loading and writing of AVIs.
- add some more stubs for some API functions.
- add resources to avifil32.dll
- implemented AVISaveOptionsFree
- declared IID_* as extern in avifil32.spec (avoids linker problem).

programs/avitools/aviinfo.c:
- fixed memory leak (release AVI stream)

Index: winedefault.reg
===================================================================
RCS file: /home/wine/wine/winedefault.reg,v
retrieving revision 1.55
diff -u -r1.55 winedefault.reg
--- winedefault.reg	13 Oct 2002 17:56:34 -0000	1.55
+++ winedefault.reg	13 Oct 2002 20:21:20 -0000
@@ -1057,3 +1057,60 @@
 "Times New Roman Greek,161"="Times New Roman,161"
 "Times New Roman TUR,162"="Times New Roman,162"
 "Tms Rmn"="Times New Roman"
+
+[HKEY_CLASSES_ROOT\AVIFile\Compressors\auds]
+@="{0002000F-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\AVIFile\Compressors\vids]
+@="{00020001-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\AVIFile\Extensions\AU]
+@="{00020003-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\AVIFile\Extensions\AVI]
+@="{00020000-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\AVIFile\Extensions\WAV]
+@="{00020003-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\AVIFile\RIFFHandlers\AVI]
+@="{00020000-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\AVIFile\RIFFHandlers\WAVE]
+@="{00020003-0000-0000-C000-000000000046}"
+
+[HKEY_CLASSES_ROOT\CLSID\{00020000-0000-0000-C000-000000000046}\InProcServer]
+@="avifile.dll"
+
+[HKEY_CLASSES_ROOT\CLSID\{00020000-0000-0000-C000-000000000046}\InProcServer32]
+@="avifil32.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\CLSID\{00020001-0000-0000-C000-000000000046}\InProcServer]
+@="avifile.dll"
+
+[HKEY_CLASSES_ROOT\CLSID\{00020001-0000-0000-C000-000000000046}\InProcServer32]
+@="avifil32.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\CLSID\{00020003-0000-0000-C000-000000000046}\InProcServer]
+@="avifile.dll"
+
+[HKEY_CLASSES_ROOT\CLSID\{00020003-0000-0000-C000-000000000046}\InProcServer32]
+@="avifil32.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\CLSID\{0002000D-0000-0000-C000-000000000046}\InProcServer]
+@="avifile.dll"
+
+[HKEY_CLASSES_ROOT\CLSID\{0002000D-0000-0000-C000-000000000046}\InProcServer32]
+@="avifil32.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\CLSID\{0002000F-0000-0000-C000-000000000046}\InProcServer]
+@="avifile.dll"
+
+[HKEY_CLASSES_ROOT\CLSID\{0002000F-0000-0000-C000-000000000046}\InProcServer32]
+@="avifil32.dll"
+"ThreadingModel"="Apartment"
+
Index: dlls/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/Makefile.in,v
retrieving revision 1.156
diff -u -r1.156 Makefile.in
--- dlls/Makefile.in	10 Oct 2002 23:36:52 -0000	1.156
+++ dlls/Makefile.in	13 Oct 2002 20:21:20 -0000
@@ -764,7 +764,7 @@
 advapi32: kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT)
 avicap32: ntdll.dll$(DLLEXT)
 avifil32: msvfw32.dll$(DLLEXT) shell32.dll$(DLLEXT) user32.dll$(DLLEXT) advapi32.dll$(DLLEXT) \
-          kernel32.dll$(DLLEXT)
+          winmm.dll$(DLLEXT) kernel32.dll$(DLLEXT)
 comcat:   ole32.dll$(DLLEXT) user32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT)
 comctl32: user32.dll$(DLLEXT) gdi32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) \
           winmm.dll$(DLLEXT)
Index: dlls/avifil32/.cvsignore
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/.cvsignore,v
retrieving revision 1.9
diff -u -r1.9 .cvsignore
--- dlls/avifil32/.cvsignore	14 May 2002 20:54:58 -0000	1.9
+++ dlls/avifil32/.cvsignore	13 Oct 2002 20:21:20 -0000
@@ -2,3 +2,4 @@
 avifil32.dll.dbg.c
 avifil32.spec.c
 avifile.spec.c
+rsrc.res
Index: dlls/avifil32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/Makefile.in,v
retrieving revision 1.21
diff -u -r1.21 Makefile.in
--- dlls/avifil32/Makefile.in	10 Oct 2002 23:31:13 -0000	1.21
+++ dlls/avifil32/Makefile.in	13 Oct 2002 20:21:20 -0000
@@ -3,7 +3,7 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = avifil32.dll
-IMPORTS   = msvfw32 shell32 user32 advapi32 kernel32
+IMPORTS   = msvfw32 advapi32 shell32 winmm user32 kernel32
 ALTNAMES  = avifile.dll
 EXTRALIBS = $(LIBUUID)
 
@@ -13,7 +13,13 @@
 C_SRCS = \
 	api.c \
 	avifile.c \
+	getframe.c \
+	wavfile.c \
+	extrachunk.c \
 	factory.c
+
+RC_SRCS = \
+	rsrc.rc
 
 @MAKE_DLL_RULES@
 
Index: dlls/avifil32/api.c
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/api.c,v
retrieving revision 1.6
diff -u -r1.6 api.c
--- dlls/avifil32/api.c	10 Oct 2002 23:31:13 -0000	1.6
+++ dlls/avifil32/api.c	13 Oct 2002 20:21:21 -0000
@@ -24,11 +24,14 @@
 #include "winuser.h"
 #include "winreg.h"
 #include "winerror.h"
+#include "windowsx.h"
 
 #include "ole2.h"
 #include "shellapi.h"
 #include "vfw.h"
 
+#include "avifile_private.h"
+
 #include "wine/debug.h"
 #include "wine/unicode.h"
 
@@ -125,6 +128,25 @@
   return S_OK;
 }
 
+static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
+{
+  CHAR   szRegKey[25];
+  CHAR   szValue[100];
+  LPWSTR szExt = strrchrW(szFile, '.');
+  LONG   len = sizeof(szValue) / sizeof(szValue[0]);
+
+  if (szExt == NULL)
+    return FALSE;
+
+  szExt++;
+
+  wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
+  if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
+    return FALSE;
+
+  return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
+}
+
 /***********************************************************************
  *		AVIFileInit		(AVIFIL32.@)
  *		AVIFileInit		(AVIFILE.100)
@@ -190,7 +212,7 @@
   CLSID         clsidHandler;
   HRESULT       hr;
 
-  FIXME("(%p,%s,0x%X,%s): stub!\n", ppfile, debugstr_w(szFile), uMode,
+  TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
 	debugstr_guid(lpHandler));
 
   /* check parameters */
@@ -201,7 +223,8 @@
 
   /* if no handler then try guessing it by extension */
   if (lpHandler == NULL) {
-    FIXME(": must read HKEY_CLASSES_ROOT\\AVIFile\\Extensions\\%s\n", debugstr_w(strrchrW(szFile, L'.')));
+    if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
+      return AVIERR_UNSUPPORTED;
   } else
     memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
 
@@ -599,8 +622,9 @@
 
   if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
       pg == NULL) {
-    FIXME(": need internal class for IGetFrame!\n");
-    return NULL;
+    pg = AVIFILE_CreateGetFrame(pstream);
+    if (pg == NULL)
+      return NULL;
   }
 
   if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
@@ -760,7 +784,7 @@
   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
     return 0;
 
-  return asiw.dwLength;
+  return asiw.dwStart;
 }
 
 /***********************************************************************
@@ -819,4 +843,84 @@
     return -1;
 
   return (LONG)(((float)lTime * asiw.dwRate) / asiw.dwScale / 1000.0);
+}
+
+/***********************************************************************
+ *		AVIBuildFilterA		(AVIFIL32.@)
+ */
+HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
+{
+  FIXME("(%p,%ld,%d): stub\n", szFilter, cbFilter, fSaving);
+
+  /* check parameters */
+  if (szFilter == NULL)
+    return AVIERR_BADPARAM;
+  if (cbFilter < 2)
+    return AVIERR_BADSIZE;
+
+  szFilter[0] = 0;
+  szFilter[1] = 0;
+
+  return AVIERR_UNSUPPORTED;
+}
+
+/***********************************************************************
+ *		AVIBuildFilterW		(AVIFIL32.@)
+ */
+HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
+{
+  FIXME("(%p,%ld,%d): stub\n", szFilter, cbFilter, fSaving);
+
+  /* check parameters */
+  if (szFilter == NULL)
+    return AVIERR_BADPARAM;
+  if (cbFilter < 2)
+    return AVIERR_BADSIZE;
+
+  szFilter[0] = 0;
+  szFilter[1] = 0;
+
+  return AVIERR_UNSUPPORTED;
+}
+
+/***********************************************************************
+ *		AVISaveOptions		(AVIFIL32.@)
+ */
+BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStream,
+			   PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
+{
+  FIXME("(0x%X,0x%X,%d,%p,%p): stub\n", hWnd, uFlags, nStream,
+	ppavi, ppOptions);
+
+  return FALSE;
+}
+
+/***********************************************************************
+ *		AVISaveOptionsFree	(AVIFIL32.@)
+ */
+HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
+{
+  TRACE("(%d,%p)\n", nStreams, ppOptions);
+
+  if (nStreams < 0 || ppOptions == NULL)
+    return AVIERR_BADPARAM;
+
+  for (; nStreams > 0; nStreams--) {
+    if (ppOptions[nStreams] != NULL) {
+      ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
+
+      if (ppOptions[nStreams]->lpParms != NULL) {
+	GlobalFreePtr(ppOptions[nStreams]->lpParms);
+	ppOptions[nStreams]->lpParms = NULL;
+	ppOptions[nStreams]->cbParms = 0;
+      }
+      if (ppOptions[nStreams]->lpFormat != NULL) {
+	GlobalFreePtr(ppOptions[nStreams]->lpFormat);
+	ppOptions[nStreams]->lpFormat = NULL;
+	ppOptions[nStreams]->cbFormat = 0;
+      }
+    }
+  }
+
+  return AVIERR_OK;
 }
Index: dlls/avifil32/avifil32.spec
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/avifil32.spec,v
retrieving revision 1.13
diff -u -r1.13 avifil32.spec
--- dlls/avifil32/avifil32.spec	10 Oct 2002 23:31:13 -0000	1.13
+++ dlls/avifil32/avifil32.spec	13 Oct 2002 20:21:21 -0000
@@ -1,6 +1,8 @@
+init AVIFILE_DllMain
+
 @ stub    AVIBuildFilter
-@ stub    AVIBuildFilterA
-@ stub    AVIBuildFilterW
+@ stdcall AVIBuildFilterA(str long long) AVIBuildFilterA
+@ stdcall AVIBuildFilterW(wstr long long) AVIBuildFilterW
 @ stub    AVIClearClipboard
 @ stdcall AVIFileAddRef(ptr) AVIFileAddRef
 @ stub    AVIFileCreateStream
@@ -26,8 +28,8 @@
 @ stub    AVIPutFileOnClipboard
 @ stub    AVISave
 @ stub    AVISaveA
-@ stub    AVISaveOptions
-@ stub    AVISaveOptionsFree
+@ stdcall AVISaveOptions(long long long ptr ptr) AVISaveOptions
+@ stdcall AVISaveOptionsFree(long ptr) AVISaveOptionsFree
 @ stub    AVISaveV
 @ stub    AVISaveVA
 @ stub    AVISaveVW
@@ -59,8 +61,8 @@
 @ stdcall AVIStreamWriteData(ptr long ptr long) AVIStreamWriteData
 @ stub    CLSID_AVISimpleUnMarshal
 @ stub    CreateEditableStream
-@ stub    DllCanUnloadNow
-@ stub    DllGetClassObject
+@ stdcall DllCanUnloadNow() AVIFILE_DllCanUnloadNow
+@ stdcall DllGetClassObject(ptr ptr ptr) AVIFILE_DllGetClassObject
 @ stub    EditStreamClone
 @ stub    EditStreamCopy
 @ stub    EditStreamCut
@@ -71,7 +73,7 @@
 @ stub    EditStreamSetName
 @ stub    EditStreamSetNameA
 @ stub    EditStreamSetNameW
-@ stub    IID_IAVIEditStream
-@ stub    IID_IAVIFile
-@ stub    IID_IAVIStream
-@ stub    IID_IGetFrame
+@ extern  IID_IAVIEditStream IID_IAVIEditStream
+@ extern  IID_IAVIFile IID_IAVIFile
+@ extern  IID_IAVIStream IID_IAVIStream
+@ extern  IID_IGetFrame IID_IGetFrame
Index: dlls/avifil32/avifile.c
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/avifile.c,v
retrieving revision 1.26
diff -u -r1.26 avifile.c
--- dlls/avifil32/avifile.c	10 Oct 2002 23:31:13 -0000	1.26
+++ dlls/avifil32/avifile.c	13 Oct 2002 20:21:24 -0000
@@ -17,9 +17,19 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* TODO:
+ *  - IAVIFile_fnEndRecord: a stub -- needed for creating interleaved AVIs.
+ *  - IAVIStreaming interface is missing for the IAVIStreamImpl
+ *  - IAVIStream_fnFindSample: FIND_INDEX isn't supported.
+ *  - IAVIStream_fnReadFormat: formatchanges aren't read in.
+ *  - IAVIStream_fnDelete: a stub.
+ *  - IAVIStream_fnSetInfo: a stub.
+ */
+
 #include <assert.h>
 
 #include "winbase.h"
+#include "winuser.h"
 #include "winnls.h"
 #include "winerror.h"
 #include "windowsx.h"
@@ -27,11 +37,16 @@
 #include "vfw.h"
 
 #include "avifile_private.h"
+#include "extrachunk.h"
 
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
 
+#ifndef IDX_PER_BLOCK
+#define IDX_PER_BLOCK 2730
+#endif
+
 /***********************************************************************/
 
 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
@@ -132,7 +147,26 @@
 
   /* IAVIStream stuff */
   IAVIFileImpl     *paf;
+  DWORD             nStream;       /* the n-th stream in file */
   AVISTREAMINFOW    sInfo;
+
+  LPVOID            lpFormat;
+  DWORD             cbFormat;
+
+  LPVOID            lpHandlerData;
+  DWORD             cbHandlerData;
+
+  EXTRACHUNKS       extra;
+
+  LPDWORD           lpBuffer;
+  DWORD             cbBuffer;       /* size of lpBuffer */
+  DWORD             dwCurrentFrame; /* frame/block currently in lpBuffer */
+
+  DWORD             dwLastFrame;    /* last correct index in idxFrames */
+  AVIINDEXENTRY    *idxFrames;
+  DWORD             nIdxFrames;     /* upper index limit of idxFrames */
+  AVIINDEXENTRY    *idxFmtChanges;
+  DWORD             nIdxFmtChanges; /* upper index limit of idxFmtChanges */
 } IAVIStreamImpl;
 
 struct _IAVIFileImpl {
@@ -146,6 +180,15 @@
   AVIFILEINFOW      fInfo;
   IAVIStreamImpl   *ppStreams[MAX_AVISTREAMS];
 
+  EXTRACHUNKS       fileextra;
+
+  DWORD             dwMoviChunkPos;  /* some stuff for saving ... */
+  DWORD             dwIdxChunkPos;
+  DWORD             dwNextFramePos;
+
+  AVIINDEXENTRY    *idxRecords;      /* won't be updated while loading */
+  DWORD             nIdxRecords;
+
   /* IPersistFile stuff ... */
   HMMIO             hmmio;
   LPWSTR            szFileName;
@@ -155,6 +198,29 @@
 
 /***********************************************************************/
 
+static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size,
+				DWORD offset, DWORD flags);
+static DWORD   AVIFILE_ComputeMoviStart(IAVIFileImpl *This);
+static void    AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr,
+					  LPAVISTREAMINFOW asi);
+static void    AVIFILE_DestructAVIStream(IAVIStreamImpl *This);
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset);
+static HRESULT AVIFILE_ParseIndex(IAVIFileImpl *This, AVIINDEXENTRY *lp,
+				  LONG count, DWORD pos, BOOL *bAbsolute);
+static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD start,
+				 LPVOID buffer, LONG size);
+static void    AVIFILE_SamplesToBlock(IAVIStreamImpl *This, LPLONG pos,
+				      LPLONG offset);
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This);
+static ULONG   AVIFILE_SearchStream(IAVIFileImpl *This, DWORD fccType,
+				    LONG lSkip);
+static void    AVIFILE_UpdateInfo(IAVIFileImpl *This);
+static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block,
+				  FOURCC ckid, DWORD flags, LPVOID buffer,
+				  LONG size);
+
 HRESULT AVIFILE_CreateAVIFile(REFIID riid, LPVOID *ppv)
 {
   IAVIFileImpl *pfile;
@@ -190,9 +256,13 @@
   if (IsEqualGUID(&IID_IUnknown, refiid) ||
       IsEqualGUID(&IID_IAVIFile, refiid)) {
     *obj = iface;
+    IAVIFile_AddRef(iface);
+
     return S_OK;
   } else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
     *obj = &This->iPersistFile;
+    IAVIFile_AddRef(iface);
+
     return S_OK;
   }
 
@@ -203,21 +273,57 @@
 {
   ICOM_THIS(IAVIFileImpl,iface);
 
-  TRACE("(%p)\n",iface);
+  TRACE("(%p) -> %ld\n", iface, This->ref + 1);
   return ++(This->ref);
 }
 
 static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
 {
   ICOM_THIS(IAVIFileImpl,iface);
+  UINT i;
+
+  TRACE("(%p) -> %ld\n", iface, This->ref - 1);
 
-  FIXME("(%p): partial stub!\n",iface);
   if (!--(This->ref)) {
     if (This->fDirty) {
-      /* FIXME: write headers to disk */
+      /* need to write headers to file */
+      AVIFILE_SaveFile(This);
+    }
+
+    for (i = 0; i < This->fInfo.dwStreams; i++) {
+      if (This->ppStreams[i] != NULL) {
+	if (This->ppStreams[i]->ref != 0) {
+	  ERR(": someone has still a reference to stream %u (%p)!\n",
+	       i, This->ppStreams[i]);
+	}
+	AVIFILE_DestructAVIStream(This->ppStreams[i]);
+	LocalFree((HLOCAL)This->ppStreams[i]);
+	This->ppStreams[i] = NULL;
+      }
     }
 
-    HeapFree(GetProcessHeap(),0,iface);
+    if (This->idxRecords != NULL) {
+      GlobalFreePtr(This->idxRecords);
+      This->idxRecords  = NULL;
+      This->nIdxRecords = 0;
+    }
+
+    if (This->fileextra.lp != NULL) {
+      GlobalFreePtr(This->fileextra.lp);
+      This->fileextra.lp = NULL;
+      This->fileextra.cb = 0;
+    }
+
+    if (This->szFileName != NULL) {
+      LocalFree((HLOCAL)This->szFileName);
+      This->szFileName = NULL;
+    }
+    if (This->hmmio != (HMMIO)NULL) {
+      mmioClose(This->hmmio, 0);
+      This->hmmio = (HMMIO)NULL;
+    }
+
+    LocalFree((HLOCAL)This);
     return 0;
   }
   return This->ref;
@@ -235,6 +341,8 @@
   if (size < 0)
     return AVIERR_BADSIZE;
 
+  AVIFILE_UpdateInfo(This);
+
   memcpy(afi, &This->fInfo, min(size, sizeof(This->fInfo)));
 
   if (size < sizeof(This->fInfo))
@@ -245,50 +353,163 @@
 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
 					   DWORD fccType, LONG lParam)
 {
-  FIXME("(%p,%p,0x%08lX,%ld): stub\n", iface, avis, fccType, lParam);
-  /* FIXME: create interface etc. */
-  return E_FAIL;
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  ULONG nStream;
+
+  TRACE("(%p,%p,0x%08lX,%ld)\n", iface, avis, fccType, lParam);
+
+  if (avis == NULL || lParam < 0)
+    return AVIERR_BADPARAM;
+
+  nStream = AVIFILE_SearchStream(This, fccType, lParam);
+
+  /* Does the requested stream exist? */
+  if (nStream < This->fInfo.dwStreams &&
+      This->ppStreams[nStream] != NULL) {
+    *avis = (PAVISTREAM)This->ppStreams[nStream];
+    IAVIStream_AddRef(*avis);
+
+    return AVIERR_OK;
+  }
+
+  /* Sorry, but the specified stream doesn't exist */
+  return AVIERR_NODATA;
 }
 
 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
 					      LPAVISTREAMINFOW asi)
 {
-/*  ICOM_THIS(IAVIStreamImpl,iface); */
+  ICOM_THIS(IAVIFileImpl,iface);
 
-  FIXME("(%p,%p,%p): stub\n", iface, avis, asi);
+  DWORD n;
 
-  return AVIERR_UNSUPPORTED;
+  TRACE("(%p,%p,%p)\n", iface, avis, asi);
+
+  /* check parameters */
+  if (avis == NULL || asi == NULL)
+    return AVIERR_BADPARAM;
+
+  /* Does the user have write permission? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  /* Can we add another stream? */
+  n = This->fInfo.dwStreams;
+  if (n >= MAX_AVISTREAMS || This->dwMoviChunkPos != 0) {
+    /* already reached max nr of streams
+     * or have already written frames to disk */
+    return AVIERR_UNSUPPORTED;
+  }
+
+  /* check AVISTREAMINFO for some really needed things */
+  if (asi->fccType == 0 || asi->dwScale == 0 || asi->dwRate == 0)
+    return AVIERR_BADFORMAT;
+
+  /* now it seems to be save to add the stream */
+  assert(This->ppStreams[n] == NULL);
+  This->ppStreams[n] = (IAVIStreamImpl*)LocalAlloc(LPTR,
+						   sizeof(IAVIStreamImpl));
+  if (This->ppStreams[n] == NULL)
+    return AVIERR_MEMORY;
+
+  /* initialize the new allocated stream */
+  AVIFILE_ConstructAVIStream(This, n, asi);
+
+  This->fInfo.dwStreams++;
+  This->fDirty = TRUE;
+
+  /* update our AVIFILEINFO structure */
+  AVIFILE_UpdateInfo(This);
+
+  return AVIERR_OK;
 }
 
 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid,
 					   LPVOID lpData, LONG size)
 {
-  FIXME("(%p,0x%08lX,%p,%ld): stub\n", iface, ckid, lpData, size);
-  /* FIXME: write data to file */
-  return E_FAIL;
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,0x%08lX,%p,%ld)\n", iface, ckid, lpData, size);
+
+  /* check parameters */
+  if (lpData == NULL)
+    return AVIERR_BADPARAM;
+  if (size < 0)
+    return AVIERR_BADSIZE;
+
+  /* Do we have write permission? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  This->fDirty = TRUE;
+
+  return WriteExtraChunk(&This->fileextra, ckid, lpData, size);
 }
 
 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid,
 					  LPVOID lpData, LONG *size)
 {
-  FIXME("(%p,0x%08lX,%p,%p): stub\n", iface, ckid, lpData, size);
-  /* FIXME: read at most size bytes from file */
-  return E_FAIL;
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,0x%08lX,%p,%p)\n", iface, ckid, lpData, size);
+
+  return ReadExtraChunk(&This->fileextra, ckid, lpData, size);
 }
 
 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
 {
+  ICOM_THIS(IAVIFileImpl,iface);
+
   FIXME("(%p): stub\n",iface);
+
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  This->fDirty = TRUE;
+
   /* FIXME: end record -- for interleaved files */
+
   return E_FAIL;
 }
 
 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
 					      LONG lParam)
 {
-  FIXME("(%p,0x%08lX,%ld): stub\n", iface, fccType, lParam);
-  /* FIXME: delete stream */
-  return E_FAIL;
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  ULONG nStream;
+
+  TRACE("(%p,0x%08lX,%ld)\n", iface, fccType, lParam);
+
+  /* check parameter */
+  if (lParam < 0)
+    return AVIERR_BADPARAM;
+
+  /* Habe user write permissions? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  nStream = AVIFILE_SearchStream(This, fccType, lParam);
+
+  /* Does the requested stream exist? */
+  if (nStream < This->fInfo.dwStreams &&
+      This->ppStreams[nStream] != NULL) {
+    /* ... so delete it now */
+    LocalFree((HLOCAL)This->ppStreams[nStream]);
+
+    if (This->fInfo.dwStreams - nStream > 0)
+      memcpy(This->ppStreams + nStream, This->ppStreams + nStream + 1,
+	     (This->fInfo.dwStreams - nStream) * sizeof(IAVIStreamImpl*));
+
+    This->ppStreams[This->fInfo.dwStreams] = NULL;
+    This->fInfo.dwStreams--;
+    This->fDirty = TRUE;
+
+    /* This->fInfo will be updated further when asked for */
+    return AVIERR_OK;
+  } else
+    return AVIERR_NODATA;
 }
 
 /***********************************************************************/
@@ -350,11 +571,41 @@
 {
   ICOM_THIS(IPersistFileImpl,iface);
 
-  FIXME("(%p,%s,0x%08lX): stub\n", iface, debugstr_w(pszFileName), dwMode);
+  int len;
+
+  TRACE("(%p,%s,0x%08lX)\n", iface, debugstr_w(pszFileName), dwMode);
+
+  /* check parameter */
+  if (pszFileName == NULL)
+    return AVIERR_BADPARAM;
 
   assert(This->paf != NULL);
+  if (This->paf->hmmio != (HMMIO)NULL)
+    return AVIERR_ERROR; /* No reuse of this object for another file! */
+
+  /* remeber mode and name */
+  This->paf->uMode = dwMode;
 
-  return AVIERR_ERROR;
+  len = lstrlenW(pszFileName) + 1;
+  This->paf->szFileName = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
+  if (This->paf->szFileName == NULL)
+    return AVIERR_MEMORY;
+  lstrcpyW(This->paf->szFileName, pszFileName);
+
+  /* try to open the file */
+  This->paf->hmmio = mmioOpenW(This->paf->szFileName, NULL,
+			       MMIO_ALLOCBUF | dwMode);
+  if (This->paf->hmmio == (HMMIO)NULL)
+    return AVIERR_FILEOPEN;
+
+  /* should we create a new file? */
+  if (dwMode & OF_CREATE) {
+    memset(& This->paf->fInfo, 0, sizeof(This->paf->fInfo));
+    This->paf->fInfo.dwFlags = AVIFILEINFO_HASINDEX | AVIFILEINFO_TRUSTCKTYPE;
+
+    return AVIERR_OK;
+  } else
+    return AVIFILE_LoadFile(This->paf);
 }
 
 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
@@ -416,6 +667,8 @@
   if (IsEqualGUID(&IID_IUnknown, refiid) ||
       IsEqualGUID(&IID_IAVIStream, refiid)) {
     *obj = This;
+    IAVIStream_AddRef(iface);
+
     return S_OK;
   }
   /* FIXME: IAVIStreaming interface */
@@ -427,7 +680,12 @@
 {
   ICOM_THIS(IAVIStreamImpl,iface);
 
-  TRACE("(%p)\n",iface);
+  TRACE("(%p) -> %ld\n", iface, This->ref + 1);
+
+  /* also add ref to parent, so that it doesn't kill us */
+  if (This->paf != NULL)
+    IAVIFile_AddRef((PAVIFILE)This->paf);
+
   return ++(This->ref);
 }
 
@@ -435,7 +693,7 @@
 {
   ICOM_THIS(IAVIStreamImpl,iface);
 
-  TRACE("(%p)\n",iface);
+  TRACE("(%p) -> %ld\n", iface, This->ref - 1);
 
   /* we belong to the AVIFile, which must free us! */
   if (This->ref == 0) {
@@ -443,6 +701,9 @@
     return 0;
   }
 
+  if (This->paf != NULL)
+    IAVIFile_Release((PAVIFILE)This->paf);
+
   return --This->ref;
 }
 
@@ -477,7 +738,89 @@
 static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos,
 					   LONG flags)
 {
-  FIXME("(%p,%ld,0x%08lX): stub\n",iface,pos,flags);
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  LONG offset = 0;
+
+  TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+  if (flags & FIND_FROM_START) {
+    pos = This->sInfo.dwStart;
+    flags &= ~(FIND_FROM_START|FIND_PREV);
+    flags |= FIND_NEXT;
+  }
+
+  if (This->sInfo.dwSampleSize != 0) {
+    /* convert samples into block number with offset */
+    AVIFILE_SamplesToBlock(This, &pos, &offset);
+  }
+
+  if (flags & FIND_TYPE) {
+    if (flags & FIND_KEY) {
+      while (0 <= pos && pos <= This->dwLastFrame) {
+	if (This->idxFrames[pos].dwFlags & AVIIF_KEYFRAME)
+	  goto RETURN_FOUND;
+
+	if (flags & FIND_NEXT)
+	  pos++;
+	else
+	  pos--;
+      };
+    } else if (flags & FIND_ANY) {
+      while (0 <= pos && pos <= This->dwLastFrame) {
+	if (This->idxFrames[pos].dwChunkLength > 0)
+	  goto RETURN_FOUND;
+
+	if (flags & FIND_NEXT)
+	  pos++;
+	else
+	  pos--;
+
+      };
+    } else if ((flags & FIND_FORMAT) && This->idxFmtChanges != NULL &&
+	       This->sInfo.fccType == streamtypeVIDEO) {
+      UINT n;
+
+      if (flags & FIND_NEXT) {
+	for (n = 0; n < This->sInfo.dwFormatChangeCount; n++)
+	  if (This->idxFmtChanges[n].ckid >= pos)
+	    goto RETURN_FOUND;
+      } else {
+	for (n = This->sInfo.dwFormatChangeCount; n >= 0; n--) {
+	  if (This->idxFmtChanges[n].ckid <= pos)
+	    goto RETURN_FOUND;
+	}
+
+	if (pos > This->sInfo.dwStart)
+	  return 0; /* format changes always for first frame */
+      }
+    }
+
+    return -1;
+  }
+
+  if (flags & FIND_RET) {
+  RETURN_FOUND:
+    if (flags & FIND_LENGTH) {
+      /* logical size */
+      if (This->sInfo.dwSampleSize)
+	pos = This->sInfo.dwSampleSize;
+      else
+	pos = 1;
+    } else if (flags & FIND_OFFSET) {
+      /* physical position */
+      pos = This->idxFrames[pos].dwChunkOffset + offset * This->sInfo.dwSampleSize;
+    } else if (flags & FIND_SIZE) {
+      /* physical size */
+      pos = This->idxFrames[pos].dwChunkLength;
+    } else if (flags & FIND_INDEX) {
+      FIXME(": FIND_INDEX flag is not supported!");
+
+      pos = This->paf->dwIdxChunkPos;
+    } /* else logical position */
+
+    return pos;
+  }
 
   return -1;
 }
@@ -485,19 +828,149 @@
 static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
 					      LPVOID format, LONG *formatsize)
 {
-  FIXME("(%p,%ld,%p,%p): stub\n", iface, pos, format, formatsize);
+  ICOM_THIS(IAVIStreamImpl,iface);
 
-  return E_FAIL;
+  TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
+
+  if (formatsize == NULL)
+    return AVIERR_BADPARAM;
+
+  /* only interested in needed buffersize? */
+  if (format == NULL || *formatsize <= 0) {
+    *formatsize = This->cbFormat;
+
+    return AVIERR_OK;
+  }
+
+  /* copy initial format (only as much as will fit) */
+  memcpy(format, This->lpFormat, min(*formatsize, This->cbFormat));
+  if (*formatsize < This->cbFormat) {
+    *formatsize = This->cbFormat;
+    return AVIERR_BUFFERTOOSMALL;
+  }
+
+  /* Could format change? When yes will it change? */
+  if ((This->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
+      pos > This->sInfo.dwStart) {
+    LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)This->lpFormat;
+    LONG lLastFmt;
+
+    lLastFmt = IAVIStream_fnFindSample(iface, pos, FIND_FORMAT|FIND_PREV);
+    if (lLastFmt > 0) {
+      FIXME(": need to read formatchange for %ld -- unimplemented!\n",lLastFmt);
+    }
+  }
+
+  *formatsize = This->cbFormat;
+  return AVIERR_OK;
 }
 
 static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
 					     LPVOID format, LONG formatsize)
 {
-/*  ICOM_THIS(IAVIStreamImpl,iface); */
+  ICOM_THIS(IAVIStreamImpl,iface);
 
-  FIXME("(%p,%ld,%p,%ld): stub\n", iface, pos, format, formatsize);
+  LPBITMAPINFOHEADER lpbiNew = (LPBITMAPINFOHEADER)format;
 
-  return E_FAIL;
+  TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
+
+  /* check parameters */
+  if (format == NULL || formatsize <= 0)
+    return AVIERR_BADPARAM;
+
+  /* Do we have write permission? */
+  if ((This->paf->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  /* can only set format before frame is written! */
+  if (This->dwLastFrame > pos)
+    return AVIERR_UNSUPPORTED;
+
+  /* initial format or a formatchange? */
+  if (This->lpFormat != NULL) {
+    /* initial format */
+    if (This->paf->dwMoviChunkPos != 0)
+      return AVIERR_ERROR; /* user has used API in wrong sequnece! */
+
+    This->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, formatsize);
+    if (This->lpFormat == NULL)
+      return AVIERR_MEMORY;
+    This->cbFormat = formatsize;
+
+    memcpy(This->lpFormat, format, formatsize);
+
+    /* update some infos about stream */
+    if (This->sInfo.fccType == streamtypeVIDEO) {
+      LONG lDim;
+
+      lDim = This->sInfo.rcFrame.right - This->sInfo.rcFrame.left;
+      if (lDim < lpbiNew->biWidth)
+	This->sInfo.rcFrame.right = This->sInfo.rcFrame.left + lpbiNew->biWidth;
+      lDim = This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top;
+      if (lDim < lpbiNew->biHeight)
+	This->sInfo.rcFrame.bottom = This->sInfo.rcFrame.top + lpbiNew->biHeight;
+    } else if (This->sInfo.fccType == streamtypeAUDIO)
+      This->sInfo.dwSampleSize = ((LPWAVEFORMATEX)This->lpFormat)->nBlockAlign;
+
+    return AVIERR_OK;
+  } else {
+    MMCKINFO           ck;
+    LPBITMAPINFOHEADER lpbiOld = (LPBITMAPINFOHEADER)This->lpFormat;
+    RGBQUAD           *rgbNew  = (RGBQUAD*)((LPBYTE)lpbiNew + lpbiNew->biSize);
+    AVIPALCHANGE      *lppc = NULL;
+    INT                n;
+
+    /* pherhaps formatchange, check it ... */
+    if (This->cbFormat != formatsize)
+      return AVIERR_UNSUPPORTED;
+
+    /* no formatchange, only the initial one */
+    if (memcmp(This->lpFormat, format, formatsize) == 0)
+      return AVIERR_OK;
+
+    /* check that's only the palette, which changes */
+    if (lpbiOld->biSize        != lpbiNew->biSize ||
+	lpbiOld->biWidth       != lpbiNew->biWidth ||
+	lpbiOld->biHeight      != lpbiNew->biHeight ||
+	lpbiOld->biPlanes      != lpbiNew->biPlanes ||
+	lpbiOld->biBitCount    != lpbiNew->biBitCount ||
+	lpbiOld->biCompression != lpbiNew->biCompression ||
+	lpbiOld->biClrUsed     != lpbiNew->biClrUsed)
+      return AVIERR_UNSUPPORTED;
+
+    This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
+
+    /* simply say all colors have changed */
+    ck.ckid   = MAKEAVICKID(cktypePALchange, This->nStream);
+    ck.cksize = 2 * sizeof(WORD) + lpbiOld->biClrUsed * sizeof(PALETTEENTRY);
+    lppc = (AVIPALCHANGE*)GlobalAllocPtr(GMEM_MOVEABLE, ck.cksize);
+    if (lppc == NULL)
+      return AVIERR_MEMORY;
+
+    lppc->bFirstEntry = 0;
+    lppc->bNumEntries = (lpbiOld->biClrUsed < 256 ? lpbiOld->biClrUsed : 0);
+    lppc->wFlags      = 0;
+    for (n = 0; n < lpbiOld->biClrUsed; n++) {
+      lppc->peNew[n].peRed   = rgbNew[n].rgbRed;
+      lppc->peNew[n].peGreen = rgbNew[n].rgbGreen;
+      lppc->peNew[n].peBlue  = rgbNew[n].rgbBlue;
+      lppc->peNew[n].peFlags = 0;
+    }
+
+    if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1)
+      return AVIERR_FILEWRITE;
+    if (mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+    if (mmioWrite(This->paf->hmmio, (HPSTR)lppc, ck.cksize) != ck.cksize)
+      return AVIERR_FILEWRITE;
+    if (mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+    This->paf->dwNextFramePos += ck.cksize + 2 * sizeof(DWORD);
+
+    GlobalFreePtr(lppc);
+
+    return AVIFILE_AddFrame(This, cktypePALchange, n, ck.dwDataOffset, 0);
+  }
 }
 
 static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,
@@ -505,17 +978,109 @@
 					LONG buffersize, LPLONG bytesread,
 					LPLONG samplesread)
 {
-/*  ICOM_THIS(IAVIStreamImpl,iface); */
+  ICOM_THIS(IAVIStreamImpl,iface);
 
-  FIXME("(%p,%ld,%ld,%p,%ld,%p,%p): stub\n", iface, start, samples, buffer,
-	buffersize, bytesread, samplesread);
+  DWORD    size;
+  HRESULT  hr;
 
+  TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
+ 	buffersize, bytesread, samplesread);
+
+  /* clear return parameters if given */
   if (bytesread != NULL)
     *bytesread = 0;
   if (samplesread != NULL)
     *samplesread = 0;
 
-  return E_FAIL;
+  /* check parameters */
+  if (This->sInfo.dwStart > start)
+    return AVIERR_NODATA; /* couldn't read before start of stream */
+  if (This->sInfo.dwStart + This->sInfo.dwLength < start)
+    return AVIERR_NODATA; /* start is past end of stream */
+
+  /* should we read as much as possible? */
+  if (samples == -1) {
+    /* User should know how much we have read */
+    if (bytesread == NULL && samplesread == NULL)
+      return AVIERR_BADPARAM;
+
+    if (This->sInfo.dwSampleSize != 0)
+      samples = buffersize / This->sInfo.dwSampleSize;
+    else
+      samples = 1;
+  }
+
+  /* limit to end of stream */
+  if (This->sInfo.dwLength < samples)
+    samples = This->sInfo.dwLength;
+  if ((start - This->sInfo.dwStart) > (This->sInfo.dwLength - samples))
+    samples = This->sInfo.dwLength - (start - This->sInfo.dwStart);
+
+  /* nothing to read? Then leave ... */
+  if (samples == 0)
+    return AVIERR_OK;
+
+  if (This->sInfo.dwSampleSize != 0) {
+    /* fixed samplesize -- we can read over frame/block boundaries */
+    LONG block  = start;
+    LONG offset = 0;
+
+    /* convert start sample to block,offset pair */
+    AVIFILE_SamplesToBlock(This, &block, &offset);
+
+    /* convert samples to bytes */
+    samples *= This->sInfo.dwSampleSize;
+
+    while (samples > 0 && buffersize > 0) {
+      if (block != This->dwCurrentFrame) {
+	hr = AVIFILE_ReadBlock(This, block, NULL, 0);
+	if (FAILED(hr))
+	  return hr;
+      }
+
+      size = min((DWORD)samples, (DWORD)buffersize);
+      size = min(size, This->cbBuffer - offset);
+      memcpy(buffer, ((BYTE*)&This->lpBuffer[2]) + offset, size);
+
+      block++;
+      offset = 0;
+      ((BYTE*)buffer) += size;
+      samples    -= size;
+      buffersize -= size;
+
+      /* fill out return parameters if given */
+      if (bytesread != NULL)
+	*bytesread   += size;
+      if (samplesread != NULL)
+	*samplesread += size / This->sInfo.dwSampleSize;
+    }
+
+    if (samples == 0)
+      return AVIERR_OK;
+    else
+      return AVIERR_BUFFERTOOSMALL;
+  } else {
+    /* variable samplesize -- we can only read one full frame/block */
+    if (samples > 1)
+      samples = 1;
+
+    assert(start <= This->dwLastFrame);
+    size = This->idxFrames[start].dwChunkLength;
+    if (buffer != NULL && buffersize >= size) {
+      hr = AVIFILE_ReadBlock(This, start, buffer, size);
+      if (FAILED(hr))
+	return hr;
+    } else if (buffer != NULL)
+      return AVIERR_BUFFERTOOSMALL;
+
+    /* fill out return parameters if given */
+    if (bytesread != NULL)
+      *bytesread = size;
+    if (samplesread != NULL)
+      *samplesread = samples;
+
+    return AVIERR_OK;
+  }
 }
 
 static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start,
@@ -524,44 +1089,202 @@
 					 LPLONG sampwritten,
 					 LPLONG byteswritten)
 {
-/*  ICOM_THIS(IAVIStreamImpl,iface); */
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  FOURCC  ckid;
+  HRESULT hr;
 
-  FIXME("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p): stub\n", iface, start, samples,
+  TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
 	buffer, buffersize, flags, sampwritten, byteswritten);
 
+  /* clear return parameters if given */
   if (sampwritten != NULL)
     *sampwritten = 0;
   if (byteswritten != NULL)
     *byteswritten = 0;
 
-  if (buffer == NULL && buffersize > 0)
+  /* check parameters */
+  if (buffer == NULL && (buffersize > 0 || samples > 0))
     return AVIERR_BADPARAM;
 
-  return E_FAIL;
+  /* Have we write permission? */
+  if ((This->paf->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  switch (This->sInfo.fccType) {
+  case streamtypeAUDIO:
+    ckid = MAKEAVICKID(cktypeWAVEbytes, This->nStream);
+    break;
+  default:
+    if ((flags & AVIIF_KEYFRAME) && buffersize != 0)
+      ckid = MAKEAVICKID(cktypeDIBbits, This->nStream);
+    else
+      ckid = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
+    break;
+  };
+
+  /* append to end of stream? */
+  if (start == -1) {
+    if (This->dwLastFrame == -1)
+      start = This->sInfo.dwStart;
+    else
+      start = This->sInfo.dwLength;
+  }
+
+  if (This->sInfo.dwSampleSize != 0) {
+    /* fixed sample size -- audio like */
+    if (samples * This->sInfo.dwSampleSize != buffersize)
+      return AVIERR_BADPARAM;
+
+    /* Couldn't skip audio-like data -- User must supply appropriate silence */
+    if (This->sInfo.dwLength != start)
+      return AVIERR_UNSUPPORTED;
+
+    /* Convert position to frame/block */
+    start = This->dwLastFrame + 1;
+
+    if ((This->paf->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) == 0) {
+      FIXME(": not interleaved, could collect audio data!\n");
+    }
+  } else {
+    /* variable sample size -- video like */
+    if (samples > 1)
+      return AVIERR_UNSUPPORTED;
+
+    /* must we fill up with empty frames? */
+    if (This->dwLastFrame != -1) {
+      FOURCC ckid2 = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
+
+      while (start > This->dwLastFrame + 1) {
+	hr = AVIFILE_WriteBlock(This, This->dwLastFrame + 1, ckid2, 0, NULL, 0);
+	if (FAILED(hr))
+	  return hr;
+      }
+    }
+  }
+
+  /* write the block now */
+  hr = AVIFILE_WriteBlock(This, start, ckid, flags, buffer, buffersize);
+  if (SUCCEEDED(hr)) {
+    /* fill out return parameters if given */
+    if (sampwritten != NULL)
+      *sampwritten = samples;
+    if (byteswritten != NULL)
+      *byteswritten = buffersize;
+  }
+
+  return hr;
 }
 
 static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start,
 					  LONG samples)
 {
+  ICOM_THIS(IAVIStreamImpl,iface);
+
   FIXME("(%p,%ld,%ld): stub\n", iface, start, samples);
 
-  return E_FAIL;
+  /* check parameters */
+  if (start < 0 || samples < 0)
+    return AVIERR_BADPARAM;
+
+  /* Delete before start of stream? */
+  if (start + samples < This->sInfo.dwStart)
+    return AVIERR_OK;
+
+  /* Delete after end of stream? */
+  if (start > This->sInfo.dwLength)
+    return AVIERR_OK;
+
+  /* For the rest we need write permissions */
+  if ((This->paf->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  /* 1. overwrite the data with JUNK
+   *
+   * if ISINTERLEAVED {
+   *   2. concat all neighboured JUNK-blocks in this record to one
+   *   3. if this record only contains JUNK and is at end set dwNextFramePos
+   *      to start of this record, repeat this.
+   * } else {
+   *   2. concat all neighboured JUNK-blocks.
+   *   3. if the JUNK block is at the end, then set dwNextFramePos to
+   *      start of this block.
+   * }
+   */
+
+  return AVIERR_UNSUPPORTED;
 }
 
 static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc,
 					    LPVOID lp, LPLONG lpread)
 {
-  FIXME("(%p,0x%08lX,%p,%p): stub\n", iface, fcc, lp, lpread);
+  ICOM_THIS(IAVIStreamImpl,iface);
 
-  return E_FAIL;
+  TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
+
+  if (fcc == ckidSTREAMHANDLERDATA) {
+    if (This->lpHandlerData != NULL && This->cbHandlerData > 0) {
+      if (lp == NULL || *lpread <= 0) {
+	*lpread = This->cbHandlerData;
+	return AVIERR_OK;
+      }
+
+      memcpy(lp, This->lpHandlerData, min(This->cbHandlerData, *lpread));
+      if (*lpread < This->cbHandlerData)
+	return AVIERR_BUFFERTOOSMALL;
+      return AVIERR_OK;
+    } else
+      return AVIERR_NODATA;
+  } else
+    return ReadExtraChunk(&This->extra, fcc, lp, lpread);
 }
 
 static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
 					     LPVOID lp, LONG size)
 {
-  FIXME("(%p,0x%08lx,%p,%ld): stub\n", iface, fcc, lp, size);
+  ICOM_THIS(IAVIStreamImpl,iface);
 
-  return E_FAIL;
+  TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
+
+  /* check parameters */
+  if (lp == NULL)
+    return AVIERR_BADPARAM;
+  if (size <= 0)
+    return AVIERR_BADSIZE;
+
+  /* need write permission */
+  if ((This->paf->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  /* already written something to this file? */
+  if (This->paf->dwMoviChunkPos != 0) {
+    /* the data will be inserted before the 'movi' chunk, so check for
+     * enough space */
+    DWORD dwPos = AVIFILE_ComputeMoviStart(This->paf);
+
+    /* ckid,size => 2 * sizeof(DWORD) */
+    dwPos += 2 * sizeof(DWORD) + size;
+    if (size >= This->paf->dwMoviChunkPos)
+      return AVIERR_UNSUPPORTED; /* not enough space left */
+  }
+
+  This->paf->fDirty = TRUE;
+
+  if (fcc == ckidSTREAMHANDLERDATA) {
+    if (This->lpHandlerData != NULL) {
+      FIXME(": handler data already set -- overwirte?\n");
+      return AVIERR_UNSUPPORTED;
+    }
+
+    This->lpHandlerData = GlobalAllocPtr(GMEM_MOVEABLE, size);
+    if (This->lpHandlerData == NULL)
+      return AVIERR_MEMORY;
+    This->cbHandlerData = size;
+    memcpy(This->lpHandlerData, lp, size);
+
+    return AVIERR_OK;
+  } else
+    return WriteExtraChunk(&This->extra, fcc, lp, size);
 }
 
 static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
@@ -570,4 +1293,1146 @@
   FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
 
   return E_FAIL;
+}
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DWORD offset, DWORD flags)
+{
+  switch (TWOCCFromFOURCC(ckid)) {
+  case cktypeDIBbits:
+    if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
+      flags |= AVIIF_KEYFRAME;
+    break;
+  case cktypeDIBcompressed:
+    if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
+      flags &= ~AVIIF_KEYFRAME;
+    break;
+  case cktypePALchange:
+    if (This->sInfo.fccType != streamtypeVIDEO) {
+      ERR(": found palette change in non-video stream!\n");
+      return AVIERR_BADFORMAT;
+    }
+    This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
+    This->sInfo.dwFormatChangeCount++;
+
+    if (This->idxFmtChanges == NULL || This->sInfo.dwFormatChangeCount < This->nIdxFmtChanges) {
+      UINT n = This->sInfo.dwFormatChangeCount;
+
+      This->nIdxFmtChanges += 16;
+      This->idxFmtChanges = GlobalReAllocPtr(This->idxFmtChanges, This->nIdxFmtChanges * sizeof(AVIINDEXENTRY), GHND);
+      if (This->idxFmtChanges == NULL)
+	return AVIERR_MEMORY;
+
+      This->idxFmtChanges[n].ckid          = This->dwLastFrame;
+      This->idxFmtChanges[n].dwFlags       = 0;
+      This->idxFmtChanges[n].dwChunkOffset = offset;
+      This->idxFmtChanges[n].dwChunkLength = size;
+
+      return AVIERR_OK;
+    }
+    break;
+  case cktypeWAVEbytes:
+    if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
+      flags |= AVIIF_KEYFRAME;
+    break;
+  default:
+    WARN(": unknown TWOCC 0x%04X found\n", TWOCCFromFOURCC(ckid));
+    break;
+  };
+
+  /* first frame is alwasy a keyframe */
+  if (This->dwLastFrame == -1)
+    flags |= AVIIF_KEYFRAME;
+
+  if (This->sInfo.dwSuggestedBufferSize < size)
+    This->sInfo.dwSuggestedBufferSize = size;
+
+  /* get memory for index */
+  if (This->idxFrames == NULL || This->dwLastFrame + 1 < This->nIdxFrames) {
+    This->nIdxFrames += 512;
+    This->idxFrames = GlobalReAllocPtr(This->idxFrames, This->nIdxFrames * sizeof(AVIINDEXENTRY), GHND);
+    if (This->idxFrames == NULL)
+      return AVIERR_MEMORY;
+  }
+
+  This->dwLastFrame++;
+  This->idxFrames[This->dwLastFrame].ckid          = ckid;
+  This->idxFrames[This->dwLastFrame].dwFlags       = flags;
+  This->idxFrames[This->dwLastFrame].dwChunkOffset = offset;
+  This->idxFrames[This->dwLastFrame].dwChunkLength = size;
+
+  return AVIERR_OK;
+}
+
+static DWORD   AVIFILE_ComputeMoviStart(IAVIFileImpl *This)
+{
+  DWORD dwPos;
+  DWORD nStream;
+
+  /* RIFF,hdrl,movi,avih => (3 * 3 + 2) * sizeof(DWORD) = 11 * sizeof(DWORD) */
+  dwPos = 11 * sizeof(DWORD) + sizeof(MainAVIHeader);
+
+  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+    IAVIStreamImpl *pStream = This->ppStreams[nStream];
+
+    /* strl,strh,strf => (3 + 2 * 2) * sizeof(DWORD) = 7 * sizeof(DWORD) */
+    dwPos += 7 * sizeof(DWORD) + sizeof(AVIStreamHeader);
+    dwPos += ((pStream->cbFormat + 1) & ~1);
+    if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0)
+      dwPos += 2 * sizeof(DWORD) + ((pStream->cbHandlerData + 1) & ~1);
+    if (lstrlenW(pStream->sInfo.szName) > 0)
+      dwPos += 2 * sizeof(DWORD) + ((lstrlenW(pStream->sInfo.szName) + 1) & ~1);
+  }
+
+  if (This->dwMoviChunkPos == 0) {
+    This->dwNextFramePos = dwPos;
+
+    /* pad to multiple of AVI_HEADERSIZE only if we are more than 8 bytes away from it */
+    if (((dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1)) - dwPos > 2 * sizeof(DWORD))
+      This->dwNextFramePos = (dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1);
+
+    This->dwMoviChunkPos = This->dwNextFramePos - sizeof(DWORD);
+  }
+
+  return dwPos;
+}
+
+static void    AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr, LPAVISTREAMINFOW asi)
+{
+  IAVIStreamImpl *pstream;
+
+  /* pre-conditions */
+  assert(paf != NULL);
+  assert(nr < MAX_AVISTREAMS);
+  assert(paf->ppStreams[nr] != NULL);
+
+  pstream = paf->ppStreams[nr];
+
+  ICOM_VTBL(pstream)      = &iavist;
+  pstream->ref            = 0;
+  pstream->paf            = paf;
+  pstream->nStream        = nr;
+  pstream->dwCurrentFrame = -1;
+  pstream->dwLastFrame    = -1;
+
+  if (asi != NULL) {
+    memcpy(&pstream->sInfo, asi, sizeof(pstream->sInfo));
+
+    if (asi->dwLength > 0) {
+      /* pre-allocate mem for frame-index structure */
+      pstream->idxFrames =
+	(AVIINDEXENTRY*)GlobalAllocPtr(GHND, asi->dwLength * sizeof(AVIINDEXENTRY));
+      if (pstream->idxFrames != NULL)
+	pstream->nIdxFrames = asi->dwLength;
+    }
+    if (asi->dwFormatChangeCount > 0) {
+      /* pre-allocate mem for formatchange-index structure */
+      pstream->idxFmtChanges =
+	(AVIINDEXENTRY*)GlobalAllocPtr(GHND, asi->dwFormatChangeCount * sizeof(AVIINDEXENTRY));
+      if (pstream->idxFmtChanges != NULL)
+	pstream->nIdxFmtChanges = asi->dwFormatChangeCount;
+    }
+
+    /* These values will be computed */
+    pstream->sInfo.dwLength              = 0;
+    pstream->sInfo.dwSuggestedBufferSize = 0;
+    pstream->sInfo.dwFormatChangeCount   = 0;
+    pstream->sInfo.dwEditCount           = 1;
+    if (pstream->sInfo.dwSampleSize > 0)
+      SetRectEmpty(&pstream->sInfo.rcFrame);
+  }
+
+  pstream->sInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+}
+
+static void    AVIFILE_DestructAVIStream(IAVIStreamImpl *This)
+{
+  /* pre-conditions */
+  assert(This != NULL);
+
+  This->dwCurrentFrame = -1;
+  This->dwLastFrame    = -1;
+  This->paf = NULL;
+  if (This->idxFrames != NULL) {
+    GlobalFreePtr(This->idxFrames);
+    This->idxFrames  = NULL;
+    This->nIdxFrames = 0;
+  }
+  if (This->idxFmtChanges != NULL) {
+    GlobalFreePtr(This->idxFmtChanges);
+    This->idxFmtChanges = NULL;
+  }
+  if (This->lpBuffer != NULL) {
+    GlobalFreePtr(This->lpBuffer);
+    This->lpBuffer = NULL;
+    This->cbBuffer = 0;
+  }
+  if (This->lpHandlerData != NULL) {
+    GlobalFreePtr(This->lpHandlerData);
+    This->lpHandlerData = NULL;
+    This->cbHandlerData = 0;
+  }
+  if (This->extra.lp != NULL) {
+    GlobalFreePtr(This->extra.lp);
+    This->extra.lp = NULL;
+    This->extra.cb = 0;
+  }
+  if (This->lpFormat != NULL) {
+    GlobalFreePtr(This->lpFormat);
+    This->lpFormat = NULL;
+    This->cbFormat = 0;
+  }
+}
+
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
+{
+  MainAVIHeader   MainAVIHdr;
+  MMCKINFO        ckRIFF;
+  MMCKINFO        ckLIST1;
+  MMCKINFO        ckLIST2;
+  MMCKINFO        ck;
+  IAVIStreamImpl *pStream;
+  DWORD           nStream;
+  HRESULT         hr;
+
+  if (This->hmmio == (HMMIO)NULL)
+    return AVIERR_FILEOPEN;
+
+  /* initialize stream ptr's */
+  memset(This->ppStreams, 0, sizeof(This->ppStreams));
+
+  /* try to get "RIFF" chunk -- must not be at beginning of file! */
+  ckRIFF.fccType = formtypeAVI;
+  if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
+    ERR(": not an AVI!\n");
+    return AVIERR_FILEREAD;
+  }
+
+  /* get "LIST" "hdrl" */
+  ckLIST1.fccType = listtypeAVIHEADER;
+  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF, MMIO_FINDLIST);
+  if (FAILED(hr))
+    return hr;
+
+  /* get "avih" chunk */
+  ck.ckid = ckidAVIMAINHDR;
+  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, MMIO_FINDCHUNK);
+  if (FAILED(hr))
+    return hr;
+
+  if (ck.cksize != sizeof(MainAVIHdr)) {
+    ERR(": invalid size of %ld for MainAVIHeader!\n", ck.cksize);
+    return AVIERR_BADFORMAT;
+  }
+  if (mmioRead(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
+    return AVIERR_FILEREAD;
+
+  /* adjust permissions if copyrighted material in file */
+  if (MainAVIHdr.dwFlags & AVIFILEINFO_COPYRIGHTED) {
+    This->uMode &= ~MMIO_RWMODE;
+    This->uMode |= MMIO_READ;
+  }
+
+  /* convert MainAVIHeader into AVIFILINFOW */
+  memset(&This->fInfo, 0, sizeof(This->fInfo));
+  This->fInfo.dwRate                = MainAVIHdr.dwMicroSecPerFrame;
+  This->fInfo.dwScale               = 1000000;
+  This->fInfo.dwMaxBytesPerSec      = MainAVIHdr.dwMaxBytesPerSec;
+  This->fInfo.dwFlags               = MainAVIHdr.dwFlags;
+  This->fInfo.dwCaps                = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+  This->fInfo.dwLength              = MainAVIHdr.dwTotalFrames;
+  This->fInfo.dwStreams             = MainAVIHdr.dwStreams;
+  This->fInfo.dwSuggestedBufferSize = MainAVIHdr.dwSuggestedBufferSize;
+  This->fInfo.dwWidth               = MainAVIHdr.dwWidth;
+  This->fInfo.dwHeight              = MainAVIHdr.dwHeight;
+  LoadStringW(AVIFILE_hModule, IDS_AVIFILETYPE, This->fInfo.szFileType,
+	      sizeof(This->fInfo.szFileType));
+
+  /* go back to into header list */
+  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEREAD;
+
+  /* foreach stream exists a "LIST","strl" chunk */
+  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+    /* get next nested chunk in this "LIST","strl" */
+    if (mmioDescend(This->hmmio, &ckLIST2, &ckLIST1, 0) != S_OK)
+      return AVIERR_FILEREAD;
+
+    /* nested chunk must be of type "LIST","strl" -- when not normally JUNK */
+    if (ckLIST2.ckid == FOURCC_LIST &&
+	ckLIST2.fccType == listtypeSTREAMHEADER) {
+      pStream = This->ppStreams[nStream] =
+	(IAVIStreamImpl*)LocalAlloc(LPTR, sizeof(IAVIStreamImpl));
+      if (pStream == NULL)
+	return AVIERR_MEMORY;
+      AVIFILE_ConstructAVIStream(This, nStream, NULL);
+
+      ck.ckid = 0;
+      while (mmioDescend(This->hmmio, &ck, &ckLIST2, 0) == S_OK) {
+	switch (ck.ckid) {
+	case ckidSTREAMHANDLERDATA:
+	  if (pStream->lpHandlerData != NULL)
+	    return AVIERR_BADFORMAT;
+	  pStream->lpHandlerData = GlobalAllocPtr(GMEM_DDESHARE|GMEM_MOVEABLE,
+						  ck.cksize);
+	  if (pStream->lpHandlerData == NULL)
+	    return AVIERR_MEMORY;
+	  pStream->cbHandlerData = ck.cksize;
+
+	  if (mmioRead(This->hmmio, (HPSTR)pStream->lpHandlerData, ck.cksize) != ck.cksize)
+	    return AVIERR_FILEREAD;
+	  break;
+	case ckidSTREAMFORMAT:
+	  if (pStream->lpFormat != NULL)
+	    return AVIERR_BADFORMAT;
+	  pStream->lpFormat = GlobalAllocPtr(GMEM_DDESHARE|GMEM_MOVEABLE,
+					     ck.cksize);
+	  if (pStream->lpFormat == NULL)
+	    return AVIERR_MEMORY;
+	  pStream->cbFormat = ck.cksize;
+
+	  if (mmioRead(This->hmmio, (HPSTR)pStream->lpFormat, ck.cksize) != ck.cksize)
+	    return AVIERR_FILEREAD;
+
+	  if (pStream->sInfo.fccType == streamtypeVIDEO) {
+	    LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)pStream->lpFormat;
+
+	    /* some corrections to the video format */
+	    if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
+	      lpbi->biClrUsed = 1u << lpbi->biBitCount;
+	    if (lpbi->biCompression == BI_RGB && lpbi->biSizeImage == 0)
+	      lpbi->biSizeImage = DIBWIDTHBYTES(*lpbi) * lpbi->biHeight;
+	    if (lpbi->biCompression != BI_RGB && lpbi->biBitCount == 8) {
+	      if (pStream->sInfo.fccHandler == mmioFOURCC('R','L','E','0') ||
+		  pStream->sInfo.fccHandler == mmioFOURCC('R','L','E',' '))
+		lpbi->biCompression = BI_RLE8;
+	    }
+	    if (lpbi->biCompression == BI_RGB &&
+		(pStream->sInfo.fccHandler == 0 ||
+		 pStream->sInfo.fccHandler == mmioFOURCC('N','O','N','E')))
+	      pStream->sInfo.fccHandler = comptypeDIB;
+
+	    /* init rcFrame if it's empty */
+	    if (IsRectEmpty(&pStream->sInfo.rcFrame))
+	      SetRect(&pStream->sInfo.rcFrame, 0, 0, lpbi->biWidth, lpbi->biHeight);
+	  }
+	  break;
+	case ckidSTREAMHEADER:
+	  {
+	    static WCHAR streamTypeFmt[] = {'%','4','.','4','h','s'};
+
+	    AVIStreamHeader streamHdr;
+	    WCHAR           szType[25];
+	    WCHAR           streamNameFmt[25];
+	    UINT            count;
+	    LONG            n = ck.cksize;
+
+	    if (ck.cksize > sizeof(streamHdr))
+	      n = sizeof(streamHdr);
+
+	    if (mmioRead(This->hmmio, (HPSTR)&streamHdr, n) != n)
+	      return AVIERR_FILEREAD;
+
+	    pStream->sInfo.fccType               = streamHdr.fccType;
+	    pStream->sInfo.fccHandler            = streamHdr.fccHandler;
+	    pStream->sInfo.dwFlags               = streamHdr.dwFlags;
+	    pStream->sInfo.wPriority             = streamHdr.wPriority;
+	    pStream->sInfo.wLanguage             = streamHdr.wLanguage;
+	    pStream->sInfo.dwInitialFrames       = streamHdr.dwInitialFrames;
+	    pStream->sInfo.dwScale               = streamHdr.dwScale;
+	    pStream->sInfo.dwRate                = streamHdr.dwRate;
+	    pStream->sInfo.dwStart               = streamHdr.dwStart;
+	    pStream->sInfo.dwLength              = streamHdr.dwLength;
+	    pStream->sInfo.dwSuggestedBufferSize =
+	      streamHdr.dwSuggestedBufferSize;
+	    pStream->sInfo.dwQuality             = streamHdr.dwQuality;
+	    pStream->sInfo.dwSampleSize          = streamHdr.dwSampleSize;
+	    pStream->sInfo.rcFrame.left          = streamHdr.rcFrame.left;
+	    pStream->sInfo.rcFrame.top           = streamHdr.rcFrame.top;
+	    pStream->sInfo.rcFrame.right         = streamHdr.rcFrame.right;
+	    pStream->sInfo.rcFrame.bottom        = streamHdr.rcFrame.bottom;
+	    pStream->sInfo.dwEditCount           = 0;
+	    pStream->sInfo.dwFormatChangeCount   = 0;
+
+	    /* generate description for stream like "filename.avi Type #n" */
+	    if (streamHdr.fccType == streamtypeVIDEO)
+	      LoadStringW(AVIFILE_hModule, IDS_VIDEO, szType, sizeof(szType));
+	    else if (streamHdr.fccType == streamtypeAUDIO)
+	      LoadStringW(AVIFILE_hModule, IDS_AUDIO, szType, sizeof(szType));
+	    else
+	      wsprintfW(szType, streamTypeFmt, (char*)&streamHdr.fccType);
+
+	    /* get count of this streamtype up to this stream */
+	    count = 0;
+	    for (n = nStream; 0 <= n; n--) {
+	      if (This->ppStreams[n]->sInfo.fccHandler == streamHdr.fccType)
+		count++;
+	    }
+
+	    memset(pStream->sInfo.szName, 0, sizeof(pStream->sInfo.szName));
+
+	    LoadStringW(AVIFILE_hModule, IDS_AVISTREAMFORMAT, streamNameFmt, sizeof(streamNameFmt));
+
+	    /* FIXME: avoid overflow -- better use wsnprintfW, which doesn't exists ! */
+	    wsprintfW(pStream->sInfo.szName, streamNameFmt,
+		      AVIFILE_BasenameW(This->szFileName), szType, count);
+	  }
+	  break;
+	case ckidSTREAMNAME:
+	  { /* streamname will be saved as ASCII string */
+	    LPSTR str = (LPSTR)LocalAlloc(LMEM_FIXED, ck.cksize);
+	    if (str == NULL)
+	      return AVIERR_MEMORY;
+
+	    if (mmioRead(This->hmmio, (HPSTR)str, ck.cksize) != ck.cksize)
+	      return AVIERR_FILEREAD;
+
+	    MultiByteToWideChar(CP_ACP, 0, str, -1, pStream->sInfo.szName,
+				sizeof(pStream->sInfo.szName)/sizeof(pStream->sInfo.szName[0]));
+
+	    LocalFree((HLOCAL)str);
+	  }
+	  break;
+	case ckidAVIPADDING:
+	case mmioFOURCC('p','a','d','d'):
+	  break;
+	default:
+	  WARN(": found extra chunk 0x%08lX\n", ck.ckid);
+	  hr = ReadChunkIntoExtra(&pStream->extra, This->hmmio, &ck);
+	  if (FAILED(hr))
+	    return hr;
+	};
+
+	if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+	  return AVIERR_FILEREAD;
+      }
+    } else {
+      /* nested chunks in "LIST","hdrl" which are not of type "LIST","strl" */
+      hr = ReadChunkIntoExtra(&This->fileextra, This->hmmio, &ckLIST2);
+      if (FAILED(hr))
+	return hr;
+      if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
+	return AVIERR_FILEREAD;
+    }
+  }
+
+  /* read any extra headers in "LIST","hdrl" */
+  FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, 0);
+  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+    return AVIERR_FILEREAD;
+
+  /* search "LIST","movi" chunk in "RIFF","AVI " */
+  ckLIST1.fccType = listtypeAVIMOVIE;
+  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF,
+			      MMIO_FINDLIST);
+  if (FAILED(hr))
+    return hr;
+
+  This->dwMoviChunkPos = ckLIST1.dwDataOffset - 2 * sizeof(DWORD);
+  This->dwIdxChunkPos  = ckLIST1.cksize + ckLIST1.dwDataOffset;
+  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+    return AVIERR_FILEREAD;
+
+  /* try to find an index */
+  ck.ckid = ckidAVINEWINDEX;
+  hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio,
+			      &ck, &ckRIFF, MMIO_FINDCHUNK);
+  if (SUCCEEDED(hr) && ck.cksize > 0) {
+    if (FAILED(AVIFILE_LoadIndex(This, ck.cksize, ckLIST1.dwDataOffset)))
+      This->fInfo.dwFlags &= ~AVIFILEINFO_HASINDEX;
+  }
+
+  /* when we haven't found an index or it's bad, then build one
+   * by parsing 'movi' chunk */
+  if ((This->fInfo.dwFlags & AVIFILEINFO_HASINDEX) == 0) {
+    for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++)
+      This->ppStreams[nStream]->dwLastFrame = -1;
+
+    if (mmioSeek(This->hmmio, ckLIST1.dwDataOffset + sizeof(DWORD), SEEK_SET) == -1) {
+      ERR(": Oops, can't seek back to 'movi' chunk!\n");
+      return AVIERR_FILEREAD;
+    }
+
+    /* seek through the 'movi' list until end */
+    while (mmioDescend(This->hmmio, &ck, &ckLIST1, 0) == S_OK) {
+      if (ck.ckid != FOURCC_LIST) {
+	if (mmioAscend(This->hmmio, &ck, 0) == S_OK) {
+	  nStream = StreamFromFOURCC(ck.ckid);
+
+	  AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
+			   ck.dwDataOffset - 2 * sizeof(DWORD), 0);
+	} else {
+	  nStream = StreamFromFOURCC(ck.ckid);
+	  WARN(": file seems to be truncated!\n");
+	  if (nStream <= This->fInfo.dwStreams &&
+	      This->ppStreams[nStream]->sInfo.dwSampleSize > 0) {
+	    ck.cksize = mmioSeek(This->hmmio, 0, SEEK_END);
+	    if (ck.cksize != -1) {
+	      ck.cksize -= ck.dwDataOffset;
+	      ck.cksize &= ~(This->ppStreams[nStream]->sInfo.dwSampleSize - 1);
+
+	      AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
+			       ck.dwDataOffset - 2 * sizeof(DWORD), 0);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  /* find other chunks */
+  FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckRIFF, 0);
+
+  return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset)
+{
+  AVIINDEXENTRY *lp;
+  DWORD          pos, n;
+  HRESULT        hr = AVIERR_OK;
+  BOOL           bAbsolute = TRUE;
+
+  lp = (AVIINDEXENTRY*)GlobalAllocPtr(GMEM_MOVEABLE,
+				      IDX_PER_BLOCK * sizeof(AVIINDEXENTRY));
+  if (lp == NULL)
+    return AVIERR_MEMORY;
+
+  /* adjust limits for index tables, so that inserting will be faster */
+  for (n = 0; n < This->fInfo.dwStreams; n++) {
+    IAVIStreamImpl *pStream = This->ppStreams[n];
+
+    pStream->dwLastFrame = -1;
+
+    if (pStream->idxFrames != NULL) {
+      GlobalFreePtr(pStream->idxFrames);
+      pStream->idxFrames  = NULL;
+      pStream->nIdxFrames = 0;
+    }
+
+    if (pStream->sInfo.dwSampleSize != 0) {
+      if (n > 0 && This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
+	pStream->nIdxFrames = pStream->nIdxFrames;
+      } else if (pStream->sInfo.dwSuggestedBufferSize) {
+	pStream->nIdxFrames =
+	  pStream->sInfo.dwLength / pStream->sInfo.dwSuggestedBufferSize;
+      }
+    } else
+      pStream->nIdxFrames = pStream->sInfo.dwLength;
+
+    pStream->idxFrames =
+      (AVIINDEXENTRY*)GlobalAllocPtr(GHND, pStream->nIdxFrames * sizeof(AVIINDEXENTRY));
+    if (pStream->idxFrames == NULL) {
+      pStream->nIdxFrames = 0;
+      return AVIERR_MEMORY;
+    }
+  }
+
+  pos = (DWORD)-1;
+  while (size != 0) {
+    LONG read = min(IDX_PER_BLOCK * sizeof(AVIINDEXENTRY), size);
+
+    if (mmioRead(This->hmmio, (HPSTR)lp, read) != read) {
+      hr = AVIERR_FILEREAD;
+      break;
+    }
+    size -= read;
+
+    if (pos == (DWORD)-1)
+      pos = offset - lp->dwChunkOffset + sizeof(DWORD);
+
+    AVIFILE_ParseIndex(This, lp, read / sizeof(AVIINDEXENTRY),
+		       pos, &bAbsolute);
+  }
+
+  if (lp != NULL)
+    GlobalFreePtr(lp);
+
+  return hr;
+}
+
+static HRESULT AVIFILE_ParseIndex(IAVIFileImpl *This, AVIINDEXENTRY *lp,
+				  LONG count, DWORD pos, BOOL *bAbsolute)
+{
+  if (lp == NULL)
+    return AVIERR_BADPARAM;
+
+  for (; count > 0; count--, lp++) {
+    WORD nStream = StreamFromFOURCC(lp->ckid);
+
+    if (lp->ckid == listtypeAVIRECORD || nStream == 0x7F)
+      continue; /* skip these */
+
+    if (nStream > This->fInfo.dwStreams)
+      return AVIERR_BADFORMAT;
+
+    if (*bAbsolute == TRUE && lp->dwChunkOffset < This->dwMoviChunkPos)
+      *bAbsolute = FALSE;
+
+    if (*bAbsolute)
+      lp->dwChunkOffset += sizeof(DWORD);
+    else
+      lp->dwChunkOffset += pos;
+
+    if (FAILED(AVIFILE_AddFrame(This->ppStreams[nStream], lp->ckid, lp->dwChunkLength, lp->dwChunkOffset, lp->dwFlags)))
+      return AVIERR_MEMORY;
+  }
+
+  return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD pos,
+				 LPVOID buffer, LONG size)
+{
+  /* pre-conditions */
+  assert(This != NULL);
+  assert(This->paf != NULL);
+  assert(This->paf->hmmio != (HMMIO)NULL);
+  assert(This->sInfo.dwStart <= pos && pos < This->sInfo.dwLength);
+  assert(pos <= This->dwLastFrame);
+
+  /* should we read as much as block gives us? */
+  if (size == 0 || size > This->idxFrames[pos].dwChunkLength)
+    size = This->idxFrames[pos].dwChunkLength;
+
+  /* read into out own buffer or given one? */
+  if (buffer == NULL) {
+    /* we also read the chunk */
+    size += 2 * sizeof(DWORD);
+
+    /* check that buffer is big enough -- don't trust dwSuggestedBufferSize */
+    if (This->lpBuffer == NULL || size < This->cbBuffer) {
+      This->lpBuffer =
+	(LPDWORD)GlobalReAllocPtr(This->lpBuffer, max(size, This->sInfo.dwSuggestedBufferSize), GMEM_MOVEABLE);
+      if (This->lpBuffer == NULL)
+	return AVIERR_MEMORY;
+      This->cbBuffer = max(size, This->sInfo.dwSuggestedBufferSize);
+    }
+
+    /* now read the complete chunk into our buffer */
+    if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset, SEEK_SET) == -1)
+      return AVIERR_FILEREAD;
+    if (mmioRead(This->paf->hmmio, (HPSTR)This->lpBuffer, size) != size)
+      return AVIERR_FILEREAD;
+
+    /* check if it was the correct block which we have read */
+    if (This->lpBuffer[0] != This->idxFrames[pos].ckid ||
+	This->lpBuffer[1] != This->idxFrames[pos].dwChunkLength) {
+      ERR(": block %ld not found at 0x%08lX\n", pos, This->idxFrames[pos].dwChunkOffset);
+      ERR(": Index says: '%4.4s'(0x%08lX) size 0x%08lX\n",
+	  (char*)&This->idxFrames[pos].ckid, This->idxFrames[pos].ckid,
+	  This->idxFrames[pos].dwChunkLength);
+      ERR(": Data  says: '%4.4s'(0x%08lX) size 0x%08lX\n",
+	  (char*)&This->lpBuffer[0], This->lpBuffer[0], This->lpBuffer[1]);
+      return AVIERR_FILEREAD;
+    }
+  } else {
+    if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset + 2 * sizeof(DWORD), SEEK_SET) == -1)
+      return AVIERR_FILEREAD;
+    if (mmioRead(This->paf->hmmio, (HPSTR)buffer, size) != size)
+      return AVIERR_FILEREAD;
+  }
+
+  return AVIERR_OK;
+}
+
+static void    AVIFILE_SamplesToBlock(IAVIStreamImpl *This, LPLONG pos,
+				      LPLONG offset)
+{
+  DWORD block;
+
+  /* pre-conditions */
+  assert(This != NULL);
+  assert(pos != NULL);
+  assert(offset != NULL);
+  assert(This->sInfo.dwSampleSize != 0);
+  assert(*pos >= This->sInfo.dwStart);
+
+  /* convert start sample to start bytes */
+  (*offset)  = (*pos) - This->sInfo.dwStart;
+  (*offset) *= This->sInfo.dwSampleSize;
+
+  /* convert bytes to block number */
+  for (block = 0; block <= This->dwLastFrame; block++) {
+    if (This->idxFrames[block].dwChunkLength <= *offset)
+      (*offset) -= This->idxFrames[block].dwChunkLength;
+    else
+      break;
+  }
+
+  *pos = block;
+}
+
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
+{
+  MainAVIHeader   MainAVIHdr;
+  IAVIStreamImpl* pStream;
+  MMCKINFO        ckRIFF;
+  MMCKINFO        ckLIST1;
+  MMCKINFO        ckLIST2;
+  MMCKINFO        ck;
+  DWORD           nStream;
+  DWORD           dwPos;
+  HRESULT         hr;
+
+  /* initialize some things */
+  if (This->dwMoviChunkPos == 0)
+    AVIFILE_ComputeMoviStart(This);
+
+  AVIFILE_UpdateInfo(This);
+
+  assert(This->fInfo.dwScale != 0);
+
+  memset(&MainAVIHdr, 0, sizeof(MainAVIHdr));
+  MainAVIHdr.dwMicroSecPerFrame    = MulDiv(This->fInfo.dwRate, 1000000,
+					    This->fInfo.dwScale);
+  MainAVIHdr.dwMaxBytesPerSec      = This->fInfo.dwMaxBytesPerSec;
+  MainAVIHdr.dwPaddingGranularity  = AVI_HEADERSIZE;
+  MainAVIHdr.dwFlags               = This->fInfo.dwFlags;
+  MainAVIHdr.dwTotalFrames         = This->fInfo.dwLength;
+  MainAVIHdr.dwInitialFrames       = 0;
+  MainAVIHdr.dwStreams             = This->fInfo.dwStreams;
+  MainAVIHdr.dwSuggestedBufferSize = This->fInfo.dwSuggestedBufferSize;
+  MainAVIHdr.dwWidth               = This->fInfo.dwWidth;
+  MainAVIHdr.dwHeight              = This->fInfo.dwHeight;
+  for (nStream = 0; nStream < MainAVIHdr.dwStreams; nStream++) {
+    pStream = This->ppStreams[nStream];
+
+    if (MainAVIHdr.dwInitialFrames < pStream->sInfo.dwInitialFrames)
+      MainAVIHdr.dwInitialFrames = pStream->sInfo.dwInitialFrames;
+  }
+
+  /* now begin writing ... */
+  mmioSeek(This->hmmio, 0, SEEK_SET);
+
+  /* RIFF chunk */
+  ckRIFF.cksize  = 0;
+  ckRIFF.fccType = formtypeAVI;
+  if (mmioCreateChunk(This->hmmio, &ckRIFF, MMIO_CREATERIFF) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  /* AVI headerlist */
+  ckLIST1.cksize  = 0;
+  ckLIST1.fccType = listtypeAVIHEADER;
+  if (mmioCreateChunk(This->hmmio, &ckLIST1, MMIO_CREATELIST) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  /* MainAVIHeader */
+  ck.ckid    = ckidAVIMAINHDR;
+  ck.cksize  = sizeof(MainAVIHdr);
+  ck.fccType = 0;
+  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+  if (mmioWrite(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
+    return AVIERR_FILEWRITE;
+  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  /* write the headers of each stream into a seperate streamheader list */
+  for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+    AVIStreamHeader strHdr;
+
+    pStream = This->ppStreams[nStream];
+
+    /* begin the new streamheader list */
+    ckLIST2.cksize  = 0;
+    ckLIST2.fccType = listtypeSTREAMHEADER;
+    if (mmioCreateChunk(This->hmmio, &ckLIST2, MMIO_CREATELIST) != S_OK)
+      return AVIERR_FILEWRITE;
+
+    /* create an AVIStreamHeader from the AVSTREAMINFO */
+    strHdr.fccType               = pStream->sInfo.fccType;
+    strHdr.fccHandler            = pStream->sInfo.fccHandler;
+    strHdr.dwFlags               = pStream->sInfo.dwFlags;
+    strHdr.wPriority             = pStream->sInfo.wPriority;
+    strHdr.wLanguage             = pStream->sInfo.wLanguage;
+    strHdr.dwInitialFrames       = pStream->sInfo.dwInitialFrames;
+    strHdr.dwScale               = pStream->sInfo.dwScale;
+    strHdr.dwRate                = pStream->sInfo.dwRate;
+    strHdr.dwLength              = pStream->sInfo.dwLength;
+    strHdr.dwSuggestedBufferSize = pStream->sInfo.dwSuggestedBufferSize;
+    strHdr.dwQuality             = pStream->sInfo.dwQuality;
+    strHdr.dwSampleSize          = pStream->sInfo.dwSampleSize;
+    strHdr.rcFrame.left          = pStream->sInfo.rcFrame.left;
+    strHdr.rcFrame.top           = pStream->sInfo.rcFrame.top;
+    strHdr.rcFrame.right         = pStream->sInfo.rcFrame.right;
+    strHdr.rcFrame.bottom        = pStream->sInfo.rcFrame.bottom;
+
+    /* now write the AVIStreamHeader */
+    ck.ckid   = ckidSTREAMHEADER;
+    ck.cksize = sizeof(strHdr);
+    if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+    if (mmioWrite(This->hmmio, (HPSTR)&strHdr, ck.cksize) != ck.cksize)
+      return AVIERR_FILEWRITE;
+    if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+
+    /* ... the hopefull ever present streamformat ... */
+    ck.ckid   = ckidSTREAMFORMAT;
+    ck.cksize = pStream->cbFormat;
+    if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+    if (pStream->lpFormat != NULL && ck.cksize > 0) {
+      if (mmioWrite(This->hmmio, (HPSTR)pStream->lpFormat, ck.cksize) != ck.cksize)
+	return AVIERR_FILEWRITE;
+    }
+    if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+
+    /* ... some optional existing handler data ... */
+    if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0) {
+      ck.ckid   = ckidSTREAMHANDLERDATA;
+      ck.cksize = pStream->cbHandlerData;
+      if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+	return AVIERR_FILEWRITE;
+      if (mmioWrite(This->hmmio, (HPSTR)pStream->lpHandlerData, ck.cksize) != ck.cksize)
+	return AVIERR_FILEWRITE;
+      if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+	return AVIERR_FILEWRITE;
+    }
+
+    /* ... some optional additional extra chunk for this stream ... */
+    if (pStream->extra.lp != NULL && pStream->extra.cb > 0) {
+      /* the chunk header(s) are already in the strucuture */
+      if (mmioWrite(This->hmmio, (HPSTR)pStream->extra.lp, pStream->extra.cb) != pStream->extra.cb)
+	return AVIERR_FILEWRITE;
+    }
+
+    /* ... an optional name for this stream ... */
+    if (lstrlenW(pStream->sInfo.szName) > 0) {
+      LPSTR str;
+
+      ck.ckid   = ckidSTREAMNAME;
+      ck.cksize = lstrlenW(pStream->sInfo.szName) + 1;
+      if (ck.cksize & 1) /* align */
+	ck.cksize++;
+      if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+	return AVIERR_FILEWRITE;
+
+      /* the streamname must be saved in ASCII not Unicode */
+      str = (LPSTR)LocalAlloc(LPTR, ck.cksize);
+      if (str == NULL)
+	return AVIERR_MEMORY;
+      WideCharToMultiByte(CP_ACP, 0, pStream->sInfo.szName, -1, str,
+			  ck.cksize, NULL, NULL);
+
+      if (mmioWrite(This->hmmio, (HPSTR)str, ck.cksize) != ck.cksize) {
+	LocalFree((HLOCAL)str);	
+	return AVIERR_FILEWRITE;
+      }
+
+      LocalFree((HLOCAL)str);
+      if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+	return AVIERR_FILEWRITE;
+    }
+
+    /* close streamheader list for this stream */
+    if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+  } /* for (0 <= nStream < MainAVIHdr.dwStreams) */
+
+  /* close the aviheader list */
+  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  /* check for padding to pre-guessed 'movi'-chunk position */
+  dwPos = ckLIST1.dwDataOffset + ckLIST1.cksize;
+  if (This->dwMoviChunkPos - 2 * sizeof(DWORD) > dwPos) {
+    ck.ckid   = ckidAVIPADDING;
+    ck.cksize = This->dwMoviChunkPos - dwPos - 4 * sizeof(DWORD);
+    assert((LONG)ck.cksize >= 0);
+
+    if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+    if (mmioSeek(This->hmmio, ck.cksize, SEEK_CUR) == -1)
+      return AVIERR_FILEWRITE;
+    if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+      return AVIERR_FILEWRITE;
+  }
+
+  /* now write the 'movi' chunk */
+  mmioSeek(This->hmmio, This->dwMoviChunkPos - 2 * sizeof(DWORD), SEEK_SET);
+  ckLIST1.cksize  = 0;
+  ckLIST1.fccType = listtypeAVIMOVIE;
+  if (mmioCreateChunk(This->hmmio, &ckLIST1, MMIO_CREATELIST) != S_OK)
+    return AVIERR_FILEWRITE;
+  if (mmioSeek(This->hmmio, This->dwNextFramePos, SEEK_SET) == -1)
+    return AVIERR_FILEWRITE;
+  if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  /* write 'idx1' chunk */
+  hr = AVIFILE_SaveIndex(This);
+  if (FAILED(hr))
+    return hr;
+
+  /* write optional extra file chunks */
+  if (This->fileextra.lp != NULL && This->fileextra.cb > 0) {
+    /* as for the streams, are the chunk header(s) in the structure */
+    if (mmioWrite(This->hmmio, (HPSTR)This->fileextra.lp, This->fileextra.cb) != This->fileextra.cb)
+      return AVIERR_FILEWRITE;
+  }
+
+  /* close RIFF chunk */
+  if (mmioAscend(This->hmmio, &ckRIFF, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  /* add some JUNK at end for bad parsers */
+  memset(&ckRIFF, 0, sizeof(ckRIFF));
+  mmioWrite(This->hmmio, (HPSTR)&ckRIFF, sizeof(ckRIFF));
+  mmioFlush(This->hmmio, 0);
+
+  return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
+{
+  IAVIStreamImpl *pStream;
+  AVIINDEXENTRY   idx;
+  MMCKINFO        ck;
+  DWORD           nStream;
+  LONG            n;
+
+  ck.ckid   = ckidAVINEWINDEX;
+  ck.cksize = 0;
+  if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  if (This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
+    /* is interleaved -- write block of coresponding frames */
+    LONG lInitialFrames = 0;
+    LONG stepsize;
+    LONG i;
+
+    if (This->ppStreams[0]->sInfo.dwSampleSize == 0)
+      stepsize = 1;
+    else
+      stepsize = AVIStreamTimeToSample((PAVISTREAM)This->ppStreams[0], 1000000);
+
+    for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+      if (lInitialFrames < This->ppStreams[nStream]->sInfo.dwInitialFrames)
+	lInitialFrames = This->ppStreams[nStream]->sInfo.dwInitialFrames;
+    }
+
+    for (i = -lInitialFrames; i < (LONG)This->fInfo.dwLength - lInitialFrames;
+	 i += stepsize) {
+      DWORD nFrame = lInitialFrames + i;
+
+      assert(nFrame < This->nIdxRecords);
+
+      idx.ckid          = listtypeAVIRECORD;
+      idx.dwFlags       = AVIIF_LIST;
+      idx.dwChunkLength = This->idxRecords[nFrame].dwChunkLength;
+      idx.dwChunkOffset = This->idxRecords[nFrame].dwChunkOffset
+	- This->dwMoviChunkPos;
+      if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+	return AVIERR_FILEWRITE;
+
+      for (nStream = 0; nStream < This->fInfo.dwStreams; n++) {
+	pStream = This->ppStreams[nStream];
+
+	/* heave we reached start of this stream? */
+	if (-(LONG)pStream->sInfo.dwInitialFrames > i)
+	  continue;
+
+	if (pStream->sInfo.dwInitialFrames < lInitialFrames)
+	  nFrame -= (lInitialFrames - pStream->sInfo.dwInitialFrames);
+
+	/* reached end of this stream? */
+	if (pStream->dwLastFrame <= nFrame)
+	  continue;
+
+	if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
+	    pStream->sInfo.dwFormatChangeCount != 0 &&
+	    pStream->idxFmtChanges != NULL) {
+	  DWORD pos;
+
+	  for (pos = 0; pos < pStream->sInfo.dwFormatChangeCount; pos++) {
+	    if (pStream->idxFmtChanges[pos].ckid == nFrame) {
+	      idx.dwFlags = AVIIF_NOTIME;
+	      idx.ckid    = MAKEAVICKID(cktypePALchange, pStream->nStream);
+	      idx.dwChunkLength = pStream->idxFmtChanges[pos].dwChunkLength;
+	      idx.dwChunkOffset = pStream->idxFmtChanges[pos].dwChunkOffset
+		- This->dwMoviChunkPos;
+
+	      if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+		return AVIERR_FILEWRITE;
+	      break;
+	    }
+	  }
+	} /* if have formatchanges */
+
+	idx.ckid          = pStream->idxFrames[nFrame].ckid;
+	idx.dwFlags       = pStream->idxFrames[nFrame].dwFlags;
+	idx.dwChunkLength = pStream->idxFrames[nFrame].dwChunkLength;
+	idx.dwChunkOffset = pStream->idxFrames[nFrame].dwChunkOffset
+	  - This->dwMoviChunkPos;
+	if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+	  return AVIERR_FILEWRITE;
+      }
+    }
+  } else {
+    /* not interleaved -- write index for each stream at once */
+    for (nStream = 0; nStream < This->fInfo.dwStreams; n++) {
+      pStream = This->ppStreams[nStream];
+
+      for (n = 0; n < pStream->dwLastFrame; n++) {
+	if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
+	    (pStream->sInfo.dwFormatChangeCount != 0)) {
+	  DWORD pos;
+
+	  for (pos = 0; pos < pStream->sInfo.dwFormatChangeCount; pos++) {
+	    if (pStream->idxFmtChanges[pos].ckid == n) {
+	      idx.dwFlags = AVIIF_NOTIME;
+	      idx.ckid    = MAKEAVICKID(cktypePALchange, pStream->nStream);
+	      idx.dwChunkLength = pStream->idxFmtChanges[pos].dwChunkLength;
+	      idx.dwChunkOffset =
+		pStream->idxFmtChanges[pos].dwChunkOffset - This->dwMoviChunkPos;
+	      if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+		return AVIERR_FILEWRITE;
+	      break;
+	    }
+	  }
+	} /* if have formatchanges */
+
+	idx.ckid          = pStream->idxFrames[n].ckid;
+	idx.dwFlags       = pStream->idxFrames[n].dwFlags;
+	idx.dwChunkLength = pStream->idxFrames[n].dwChunkLength;
+	idx.dwChunkOffset = pStream->idxFrames[n].dwChunkOffset
+	  - This->dwMoviChunkPos;
+
+	if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+	  return AVIERR_FILEWRITE;
+      }
+    }
+  } /* if not interleaved */
+
+  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  return AVIERR_OK;
+}
+
+static ULONG  AVIFILE_SearchStream(IAVIFileImpl *This, DWORD fcc, LONG lSkip)
+{
+  UINT i;
+  UINT nStream;
+
+  /* pre-condition */
+  assert(lSkip >= 0);
+
+  if (fcc != 0) {
+    /* search the number of the specified stream */
+    nStream = (ULONG)-1;
+    for (i = 0; i < This->fInfo.dwStreams; i++) {
+      assert(This->ppStreams[i] != NULL);
+
+      if (This->ppStreams[i]->sInfo.fccType == fcc) {
+	if (lSkip == 0) {
+	  nStream = i;
+	  break;
+	} else
+	  lSkip--;
+      }
+    }
+  } else
+    nStream = lSkip;
+
+  return nStream;
+}
+
+static void    AVIFILE_UpdateInfo(IAVIFileImpl *This)
+{
+  UINT i;
+
+  /* pre-conditions */
+  assert(This != NULL);
+
+  This->fInfo.dwMaxBytesPerSec      = 0;
+  This->fInfo.dwCaps                = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+  This->fInfo.dwSuggestedBufferSize = 0;
+  This->fInfo.dwWidth               = 0;
+  This->fInfo.dwHeight              = 0;
+  This->fInfo.dwScale               = 0;
+  This->fInfo.dwRate                = 0;
+  This->fInfo.dwLength              = 0;
+
+  for (i = 0; i < This->fInfo.dwStreams; i++) {
+    AVISTREAMINFOW *psi;
+    DWORD           n;
+
+    /* pre-conditions */
+    assert(This->ppStreams[i] != NULL);
+
+    psi = &This->ppStreams[i]->sInfo;
+    assert(psi->dwScale != 0);
+    assert(psi->dwRate != 0);
+
+    if (i == 0) {
+      /* use first stream timings as base */
+      This->fInfo.dwScale  = psi->dwScale;
+      This->fInfo.dwRate   = psi->dwRate;
+      This->fInfo.dwLength = psi->dwLength;
+    } else {
+      n = AVIStreamSampleToSample((PAVISTREAM)This->ppStreams[0],
+				  (PAVISTREAM)This->ppStreams[i],psi->dwLength);
+      if (This->fInfo.dwLength < n)
+	This->fInfo.dwLength = n;
+    }
+
+    if (This->fInfo.dwSuggestedBufferSize < psi->dwSuggestedBufferSize)
+      This->fInfo.dwSuggestedBufferSize = psi->dwSuggestedBufferSize;
+
+    if (psi->dwSampleSize != 0) {
+      /* fixed sample size -- exact computation */
+      This->fInfo.dwMaxBytesPerSec += MulDiv(psi->dwSampleSize, psi->dwRate,
+					     psi->dwScale);
+    } else {
+      /* variable sample size -- only upper limit */
+      This->fInfo.dwMaxBytesPerSec += MulDiv(psi->dwSuggestedBufferSize,
+					     psi->dwRate, psi->dwScale);
+
+      /* update dimensions */
+      n = psi->rcFrame.right - psi->rcFrame.left;
+      if (This->fInfo.dwWidth < n)
+	This->fInfo.dwWidth = n;
+      n = psi->rcFrame.bottom - psi->rcFrame.top;
+      if (This->fInfo.dwHeight < n)
+	This->fInfo.dwHeight = n;
+    }
+  }
+}
+
+static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block,
+				  FOURCC ckid, DWORD flags, LPVOID buffer,
+				  LONG size)
+{
+  MMCKINFO ck;
+
+  ck.ckid    = ckid;
+  ck.cksize  = size;
+  ck.fccType = 0;
+
+  /* if no frame/block is already written, we must compute start of movi chunk */
+  if (This->paf->dwMoviChunkPos == 0)
+    AVIFILE_ComputeMoviStart(This->paf);
+
+  if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1)
+    return AVIERR_FILEWRITE;
+
+  if (mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+  if (buffer != NULL && size > 0) {
+    if (mmioWrite(This->paf->hmmio, (HPSTR)buffer, size) != size)
+      return AVIERR_FILEWRITE;
+  }
+  if (mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEWRITE;
+
+  This->paf->fDirty         = TRUE;
+  This->paf->dwNextFramePos = ck.dwDataOffset + ck.cksize;
+
+  return AVIFILE_AddFrame(This, ckid, size, ck.dwDataOffset, flags);
 }
Index: dlls/avifil32/avifile_private.h
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/avifile_private.h,v
retrieving revision 1.4
diff -u -r1.4 avifile_private.h
--- dlls/avifil32/avifile_private.h	10 Oct 2002 23:31:13 -0000	1.4
+++ dlls/avifil32/avifile_private.h	13 Oct 2002 20:21:24 -0000
@@ -23,6 +23,23 @@
 #define MAX_AVISTREAMS 4
 #endif
 
+#ifndef comptypeDIB
+#define comptypeDIB  mmioFOURCC('D','I','B',' ')
+#endif
+
+#ifndef DIBWIDTHBYTES
+#define WIDTHBYTES(i)     (((i+31)&(~31))/8)
+#define DIBWIDTHBYTES(bi) WIDTHBYTES((bi).biWidth * (bi).biBitCount)
+#endif
+
+#define IDS_WAVESTREAMFORMAT 0x0100
+#define IDS_WAVEFILETYPE     0x0101
+#define IDS_VIDEO            0x0189
+#define IDS_AUDIO            0x0190
+#define IDS_AVISTREAMFORMAT  0x0191
+#define IDS_AVIFILETYPE      0x0192
+#define IDS_UNCOMPRESSED     0x0193
+
 DEFINE_AVIGUID(CLSID_ICMStream, 0x00020001, 0, 0);
 DEFINE_AVIGUID(CLSID_WAVFile,   0x00020003, 0, 0);
 DEFINE_AVIGUID(CLSID_ACMStream, 0x0002000F, 0, 0);
@@ -33,5 +50,8 @@
 extern HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppobj);
 extern HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppobj);
 extern HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppobj);
+extern PGETFRAME AVIFILE_CreateGetFrame(PAVISTREAM pstream);
+
+extern LPCWSTR  AVIFILE_BasenameW(LPCWSTR szFileName);
 
 #endif
Index: dlls/avifil32/factory.c
===================================================================
RCS file: /home/wine/wine/dlls/avifil32/factory.c,v
retrieving revision 1.1
diff -u -r1.1 factory.c
--- dlls/avifil32/factory.c	10 Oct 2002 23:31:13 -0000	1.1
+++ dlls/avifil32/factory.c	13 Oct 2002 20:21:24 -0000
@@ -19,6 +19,7 @@
 #include <assert.h>
 
 #include "winbase.h"
+#include "winnls.h"
 #include "winerror.h"
 
 #include "ole2.h"
@@ -126,7 +127,8 @@
 {
   ICOM_THIS(IClassFactoryImpl,iface);
 
-  FIXME("(%p,%p,%s,%p): stub!\n", iface, pOuter, debugstr_guid(riid), ppobj);
+  FIXME("(%p,%p,%s,%p): partial stub!\n", iface, pOuter, debugstr_guid(riid),
+	ppobj);
 
   if (ppobj == NULL || pOuter != NULL)
     return E_FAIL;
@@ -134,11 +136,11 @@
 
   if (IsEqualGUID(&CLSID_AVIFile, &This->clsid))
     return AVIFILE_CreateAVIFile(riid,ppobj);
-/*   if (IsEqualGUID(&CLSID_ICMStream, This->clsid)) */
+/*   if (IsEqualGUID(&CLSID_ICMStream, &This->clsid)) */
 /*     return AVIFILE_CreateICMStream(riid,ppobj); */
-/*   if (IsEqualGUID(&CLSID_WAVFile, This->clsid)) */
-/*     return AVIFILE_CreateWAVFile(riid,ppobj); */
-/*   if (IsEqualGUID(&CLSID_ACMStream, This->clsid)) */
+  if (IsEqualGUID(&CLSID_WAVFile, &This->clsid))
+    return AVIFILE_CreateWAVFile(riid,ppobj);
+/*   if (IsEqualGUID(&CLSID_ACMStream, &This->clsid)) */
 /*     return AVIFILE_CreateACMStream(riid,ppobj); */
 
   return E_NOINTERFACE;
@@ -153,6 +155,23 @@
   return S_OK;
 }
 
+LPCWSTR AVIFILE_BasenameW(LPCWSTR szPath)
+{
+#define SLASH(w) ((w) == '/' || (w) == '\\')
+
+  LPCWSTR szCur;
+
+  for (szCur = szPath + lstrlenW(szPath);
+       szCur > szPath && !SLASH(*szCur) && *szCur != ':';)
+    szCur--;
+
+  if (szCur == szPath)
+    return szCur;
+  else
+    return szCur + 1;
+
+#undef SLASH
+}
 
 /***********************************************************************
  *		DllGetClassObject (AVIFIL32.@)
@@ -181,7 +200,7 @@
 BOOL WINAPI AVIFILE_DllMain(HINSTANCE hInstDll, DWORD fdwReason,
 			    LPVOID lpvReserved)
 {
-  TRACE("(%d,%lu,%p)\n", hInstDll, fdwReason, lpvReserved);
+  TRACE("(0x%X,%lu,%p)\n", hInstDll, fdwReason, lpvReserved);
 
   switch (fdwReason) {
   case DLL_PROCESS_ATTACH:
Index: include/vfw.h
===================================================================
RCS file: /home/wine/wine/include/vfw.h,v
retrieving revision 1.28
diff -u -r1.28 vfw.h
--- include/vfw.h	10 Oct 2002 23:31:13 -0000	1.28
+++ include/vfw.h	13 Oct 2002 20:21:29 -0000
@@ -793,6 +793,8 @@
 
 #define AVI_HEADERSIZE	2048
 
+typedef BOOL (CALLBACK *AVISAVECALLBACK)(INT);
+
 typedef struct _MainAVIHeader
 {
     DWORD	dwMicroSecPerFrame;
@@ -907,6 +909,7 @@
 #define AVIFILEINFO_HASINDEX		0x00000010
 #define AVIFILEINFO_MUSTUSEINDEX	0x00000020
 #define AVIFILEINFO_ISINTERLEAVED	0x00000100
+#define AVIFILEINFO_TRUSTCKTYPE         0x00000800
 #define AVIFILEINFO_WASCAPTUREFILE	0x00010000
 #define AVIFILEINFO_COPYRIGHTED		0x00020000
 
@@ -968,6 +971,23 @@
     DWORD	dwInterleaveEvery;	/* for non-video streams only */
 } AVICOMPRESSOPTIONS, *LPAVICOMPRESSOPTIONS,*PAVICOMPRESSOPTIONS;
 
+#define FIND_DIR        0x0000000FL     /* direction mask */
+#define FIND_NEXT       0x00000001L     /* search forward */
+#define FIND_PREV       0x00000004L     /* search backward */
+#define FIND_FROM_START 0x00000008L     /* start at the logical beginning */
+
+#define FIND_TYPE       0x000000F0L     /* type mask */
+#define FIND_KEY        0x00000010L     /* find a key frame */
+#define FIND_ANY        0x00000020L     /* find any (non-empty) sample */
+#define FIND_FORMAT     0x00000040L     /* find a formatchange */
+
+#define FIND_RET        0x0000F000L     /* return mask */
+#define FIND_POS        0x00000000L     /* return logical position */
+#define FIND_LENGTH     0x00001000L     /* return logical size */
+#define FIND_OFFSET     0x00002000L     /* return physical position */
+#define FIND_SIZE       0x00003000L     /* return physical size */
+#define FIND_INDEX      0x00004000L     /* return physical index position */
+
 #include "ole2.h"
 
 #define DEFINE_AVIGUID(name, l, w1, w2) \
@@ -1048,13 +1068,33 @@
 				      UINT mode, CLSID *pclsidHandler);
 #define AVIStreamOpenFromFile WINELIB_NAME_AW(AVIStreamOpenFromFile)
 
+HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving);
+HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving);
+#define AVIBuildFilter WINELIB_NAME_AW(AVIBuildFilter)
+
+BOOL WINAPI AVISaveOptions(HWND hWnd,UINT uFlags,INT nStream,
+			   PAVISTREAM *ppavi,LPAVICOMPRESSOPTIONS *ppOptions);
+HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions);
+
 LONG WINAPI AVIStreamStart(PAVISTREAM iface);
 LONG WINAPI AVIStreamLength(PAVISTREAM iface);
 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample);
 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime);
 
+#define AVIStreamEnd(pavi) \
+    (AVIStreamStart(pavi) + AVIStreamLength(pavi))
+#define AVIStreamEndTime(pavi) \
+    AVIStreamSampleToTime(pavi, AVIStreamEnd(pavi))
 #define AVIStreamFormatSize(pavi, lPos, plSize) \
     AVIStreamReadFormat(pavi, lPos, NULL, plSize)
+#define AVIStreamLengthTime(pavi) \
+    AVIStreamSampleToTime(pavi, AVIStreamLength(pavi))
+#define AVIStreamSampleSize(pavi,pos,psize) \
+    AVIStreamRead(pavi,pos,1,NULL,0,psize,NULL)
+#define AVIStreamSampleToSample(pavi1, pavi2, samp2) \
+    AVIStreamTimeToSample(pavi1, AVIStreamSampleToTime(pavi2, samp2))
+#define AVIStreamStartTime(pavi) \
+    AVIStreamSampleToTime(pavi, AVIStreamStart(pavi))
 
 /*****************************************************************************
  * IAVIFile interface
Index: programs/avitools/aviinfo.c
===================================================================
RCS file: /home/wine/wine/programs/avitools/aviinfo.c,v
retrieving revision 1.10
diff -u -r1.10 aviinfo.c
--- programs/avitools/aviinfo.c	31 May 2002 23:40:58 -0000	1.10
+++ programs/avitools/aviinfo.c	13 Oct 2002 20:21:30 -0000
@@ -147,10 +147,10 @@
 		type[4]='\0';memcpy(type,&(asi.fccType),4);
 
 	    	fprintf(stderr,"Unhandled streamtype %s\n",type);
-	    	fnAVIStreamRelease(ast);
 		break;
 	    }
 	    }
+	    fnAVIStreamRelease(ast);
     }
     fnAVIFileRelease(avif);
     fnAVIFileExit();
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/extrachunk.c	Fri Oct 11 23:36:39 2002
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#include <assert.h>
+
+#include "extrachunk.h"
+#include "winbase.h"
+#include "windowsx.h"
+#include "vfw.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/* reads a chunk outof the extrachunk-structure */
+HRESULT ReadExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lpData,
+		       LPLONG size)
+{
+  LPBYTE lp;
+  LONG   cb;
+
+  /* pre-conditions */
+  assert(extra != NULL);
+  assert(size != NULL);
+
+  lp = extra->lp;
+  cb = extra->cb;
+
+  if (lp != NULL) {
+    while (cb > 0) {
+      if (((FOURCC*)lp)[0] == ckid) {
+	/* found correct chunk */
+	if (lpData != NULL && *size > 0)
+	  memcpy(lpData, lp + 2 * sizeof(DWORD), min(((LPDWORD)lp)[1],*size));
+
+	*size = ((LPDWORD)lp)[1];
+
+	return AVIERR_OK;
+      } else {
+	/* skip to next chunk */
+	cb -= ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
+	lp += ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
+      }
+    }
+  }
+
+  /* wanted chunk doesn't exist */
+  *size = 0;
+
+  return AVIERR_NODATA;
+}
+
+/* writes a chunk into the extrachunk-structure */
+HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lpData,
+			LONG size)
+{
+  LPDWORD lp;
+
+  /* pre-conditions */
+  assert(extra != NULL);
+  assert(lpData != NULL);
+  assert(size > 0);
+
+  if (extra->lp)
+    lp = (LPDWORD)GlobalReAllocPtr(extra->lp, extra->cb + size + 2 * sizeof(DWORD), GHND);
+  else
+    lp = (LPDWORD)GlobalAllocPtr(GHND, size + 2 * sizeof(DWORD));
+
+  if (lp == NULL)
+    return AVIERR_MEMORY;
+
+  extra->lp  = lp;
+  ((LPBYTE)lp) += extra->cb;
+  extra->cb += size + 2 * sizeof(DWORD);
+
+  /* insert chunk-header in block */
+  lp[0] = ckid;
+  lp[1] = size;
+
+  if (lpData != NULL && size > 0)
+    memcpy(lp + 2, lpData, size);
+
+  return AVIERR_OK;
+}
+
+/* reads a chunk fomr the HMMIO into the extrachunk-structure */
+HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck)
+{
+  LPDWORD lp;
+  LONG    cb;
+
+  /* pre-conditions */
+  assert(extra != NULL);
+  assert(hmmio != (HMMIO)NULL);
+  assert(lpck  != NULL);
+
+  cb  = lpck->cksize + 2 * sizeof(DWORD);
+  cb += (cb & 1);
+
+  if (extra->lp != NULL) {
+    lp = (LPDWORD)GlobalReAllocPtr(extra->lp, extra->cb + cb, GHND);
+  } else
+    lp = (LPDWORD)GlobalAllocPtr(GHND, cb);
+
+  if (lp == NULL)
+    return AVIERR_MEMORY;
+
+  extra->lp  = lp;
+  ((LPBYTE)lp) += extra->cb;
+  extra->cb += cb;
+
+  /* insert chunk-header in block */
+  lp[0] = lpck->ckid;
+  lp[1] = lpck->cksize;
+
+  if (lpck->cksize > 0) {
+    if (mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET) == -1)
+      return AVIERR_FILEREAD;
+    if (mmioRead(hmmio, (HPSTR)&lp[2], lpck->cksize) != lpck->cksize)
+      return AVIERR_FILEREAD;
+  }
+
+  return AVIERR_OK;
+}
+
+/* reads all non-junk chunks into the extrachunk-structure until it founds
+ * the given chunk or the optional parent-chunk is at the end */
+HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck,
+			       MMCKINFO *lpckParent,UINT flags)
+{
+  FOURCC  ckid;
+  FOURCC  fccType;
+  HRESULT hr;
+
+  /* pre-conditions */
+  assert(extra != NULL);
+  assert(hmmio != (HMMIO)NULL);
+  assert(lpck  != NULL);
+
+  TRACE("({%p,%lu},%d,%p,%p,0x%X)\n", extra->lp, extra->cb, hmmio, lpck,
+	lpckParent, flags);
+
+  /* what chunk id and form/list type shoiuld we search? */
+  if (flags & MMIO_FINDCHUNK) {
+    ckid    = lpck->ckid;
+    fccType = 0;
+  } else if (flags & MMIO_FINDLIST) {
+    ckid    = FOURCC_LIST;
+    fccType = lpck->fccType;
+  } else if (flags & MMIO_FINDRIFF) {
+    ckid    = FOURCC_RIFF;
+    fccType = lpck->fccType;
+  } else
+    ckid = fccType = (FOURCC)-1; /* collect everything into extra! */
+
+  TRACE(": find ckid=0x%08lX fccType=0x%08lX\n", ckid, fccType);
+
+  for (;;) {
+    hr = mmioDescend(hmmio, lpck, lpckParent, 0);
+    if (hr != S_OK) {
+      /* No extra chunks infront of desired chunk? */
+      if (flags == 0 && hr == MMIOERR_CHUNKNOTFOUND)
+	hr = AVIERR_OK;
+      return hr;
+    }
+
+    /* Have we found what we search for? */
+    if ((lpck->ckid == ckid) &&
+	(fccType == (FOURCC)0 || lpck->fccType == fccType))
+      return AVIERR_OK;
+
+    /* Skip padding chunks, the others put into the extrachunk-structure */
+    if (lpck->ckid == ckidAVIPADDING ||
+	lpck->ckid == mmioFOURCC('p','a','d','d'))
+      hr = mmioAscend(hmmio, lpck, 0);
+    else
+      hr = ReadChunkIntoExtra(extra, hmmio, lpck);
+    if (FAILED(hr))
+      return hr;
+  }
+}
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/extrachunk.h	Fri Oct 11 23:36:55 2002
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#ifndef __WINE_EXTRACHUNK_H
+#define __WINE_EXTRACHUNK_H
+
+#include "windef.h"
+#include "mmsystem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _EXTRACHUNKS {
+  LPVOID lp;
+  DWORD  cb;
+} EXTRACHUNKS, *LPEXTRACHUNKS;
+
+/* reads a chunk outof the extrachunk-structure */
+HRESULT ReadExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lp,LPLONG size);
+
+/* writes a chunk into the extrachunk-structure */
+HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lp,LONG size);
+
+/* reads a chunk fomr the HMMIO into the extrachunk-structure */
+HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck);
+
+/* reads all non-junk chunks into the extrachunk-structure until it founds
+ * the given chunk or the optional parent-chunk is at the end */
+HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,
+			       MMCKINFO *lpck,MMCKINFO *lpckParent,UINT flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/getframe.c	Sun Oct 13 21:01:11 2002
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "winbase.h"
+#include "winnls.h"
+#include "windowsx.h"
+#include "vfw.h"
+
+#include "avifile_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+#ifndef DIBPTR
+#define DIBPTR(lp)      ((LPBYTE)(lp) + (lp)->biSize + \
+                         (lp)->biClrUsed * sizeof(RGBQUAD))
+#endif
+
+/***********************************************************************/
+
+static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame *iface,
+						 REFIID refiid, LPVOID *obj);
+static ULONG   WINAPI IGetFrame_fnAddRef(IGetFrame *iface);
+static ULONG   WINAPI IGetFrame_fnRelease(IGetFrame *iface);
+static LPVOID  WINAPI IGetFrame_fnGetFrame(IGetFrame *iface, LONG lPos);
+static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame *iface, LONG lStart,
+					LONG lEnd, LONG lRate);
+static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame *iface);
+static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame *iface,
+					    LPBITMAPINFOHEADER lpbi,
+					    LPVOID lpBits, INT x, INT y,
+					    INT dx, INT dy);
+
+struct ICOM_VTABLE(IGetFrame) igetframeVtbl = {
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  IGetFrame_fnQueryInterface,
+  IGetFrame_fnAddRef,
+  IGetFrame_fnRelease,
+  IGetFrame_fnGetFrame,
+  IGetFrame_fnBegin,
+  IGetFrame_fnEnd,
+  IGetFrame_fnSetFormat
+};
+
+typedef struct _IGetFrameImpl {
+  /* IUnknown stuff */
+  ICOM_VFIELD(IGetFrame);
+  DWORD              ref;
+
+  /* IGetFrame stuff */
+  BOOL               bFixedStream;
+  PAVISTREAM         pStream;
+
+  LPVOID             lpInBuffer;
+  DWORD              cbInBuffer;
+  LPBITMAPINFOHEADER lpInFormat;
+  DWORD              cbInFormat;
+
+  LONG               lCurrentFrame;
+  LPBITMAPINFOHEADER lpOutFormat;
+  LPVOID             lpOutBuffer;
+
+  HIC                hic;
+  BOOL               bResize;
+  DWORD              x;
+  DWORD              y;
+  DWORD              dx;
+  DWORD              dy;
+
+  BOOL               bFormatChanges;
+  DWORD              dwFormatChangeCount;
+  DWORD              dwEditCount;
+} IGetFrameImpl;
+
+/***********************************************************************/
+
+static void AVIFILE_CloseCompressor(IGetFrameImpl *This)
+{
+  if (This->lpOutFormat != NULL && This->lpInFormat != This->lpOutFormat) {
+    GlobalFreePtr(This->lpOutFormat);
+    This->lpOutFormat = NULL;
+  }
+  if (This->lpInFormat != NULL) {
+    GlobalFreePtr(This->lpInFormat);
+    This->lpInFormat = NULL;
+  }
+  if (This->hic != (HIC)NULL) {
+    if (This->bResize)
+      ICDecompressExEnd(This->hic);
+    else
+      ICDecompressEnd(This->hic);
+    ICClose(This->hic);
+    This->hic = (HIC)NULL;
+  }
+}
+
+PGETFRAME AVIFILE_CreateGetFrame(PAVISTREAM pStream)
+{
+  IGetFrameImpl *pg;
+
+  /* check parameter */
+  if (pStream == NULL)
+    return NULL;
+
+  pg = (IGetFrameImpl*)LocalAlloc(LPTR, sizeof(IGetFrameImpl));
+  if (pg != NULL) {
+    ICOM_VTBL(pg)     = &igetframeVtbl;
+    pg->ref           = 1;
+    pg->lCurrentFrame = -1;
+    pg->pStream       = pStream;
+    IAVIStream_AddRef(pStream);
+  }
+
+  return (PGETFRAME)pg;
+}
+
+static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame *iface,
+						 REFIID refiid, LPVOID *obj)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
+
+  if (IsEqualGUID(&IID_IUnknown, refiid) ||
+      IsEqualGUID(&IID_IGetFrame, refiid)) {
+    *obj = iface;
+    return S_OK;
+  }
+
+  return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG   WINAPI IGetFrame_fnAddRef(IGetFrame *iface)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  TRACE("(%p)\n", iface);
+
+  return ++(This->ref);
+}
+
+static ULONG   WINAPI IGetFrame_fnRelease(IGetFrame *iface)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  TRACE("(%p)\n", iface);
+
+  if (!--(This->ref)) {
+    AVIFILE_CloseCompressor(This);
+    if (This->pStream != NULL) {
+      AVIStreamRelease(This->pStream);
+      This->pStream = NULL;
+    }
+
+    LocalFree((HLOCAL)iface);
+    return 0;
+  }
+
+  return This->ref;
+}
+
+static LPVOID  WINAPI IGetFrame_fnGetFrame(IGetFrame *iface, LONG lPos)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  LONG readBytes;
+  LONG readSamples;
+
+  TRACE("(%p,%ld)\n", iface, lPos);
+
+  /* check state */
+  if (This->pStream == NULL)
+    return NULL;
+  if (This->lpInFormat == NULL)
+    return NULL;
+
+  /* Could stream have changed? */
+  if (! This->bFixedStream) {
+    AVISTREAMINFOW sInfo;
+
+    IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo));
+
+    if (sInfo.dwEditCount != This->dwEditCount) {
+      This->dwEditCount   = sInfo.dwEditCount;
+      This->lCurrentFrame = -1;
+    }
+
+    if (sInfo.dwFormatChangeCount != This->dwFormatChangeCount) {
+      /* stream has changed */
+      if (This->lpOutFormat != NULL) {
+	BITMAPINFOHEADER bi;
+
+	memcpy(&bi, This->lpOutFormat, sizeof(bi));
+	AVIFILE_CloseCompressor(This);
+
+	if (FAILED(IGetFrame_SetFormat(iface, &bi, NULL, 0, 0, -1, -1))) {
+	  if (FAILED(IGetFrame_SetFormat(iface, NULL, NULL, 0, 0, -1, -1)))
+	    return NULL;
+	}
+      } else if (FAILED(IGetFrame_SetFormat(iface, NULL, NULL, 0, 0, -1, -1)))
+	return NULL;
+    }
+  }
+
+  if (lPos != This->lCurrentFrame) {
+    LONG lNext = AVIStreamFindSample(This->pStream, lPos, FIND_KEY|FIND_PREV);
+
+    if (lNext == -1)
+      lNext = 0; /* first frame is always a keyframe */
+    if (lNext <= This->lCurrentFrame && This->lCurrentFrame < lPos)
+      lNext++;
+
+    for (; lNext < lPos; lNext++) {
+      /* new format for this frame? */
+      if (This->bFormatChanges) {
+	AVIStreamReadFormat(This->pStream, lNext, This->lpInFormat, &This->cbInFormat);
+	if (This->lpOutFormat != NULL) {
+	  if (This->lpOutFormat->biBitCount <= 8)
+	    ICDecompressGetPalette(This->hic, This->lpInFormat,
+				   This->lpOutFormat);
+	}
+      }
+
+      /* read input frame */
+      while (FAILED(AVIStreamRead(This->pStream, lNext, 1, This->lpInBuffer,
+				  This->cbInBuffer, &readBytes, &readSamples))) {
+	/* not enough memory for input buffer? */
+	readBytes = 0;
+	if (FAILED(AVIStreamSampleSize(This->pStream, lNext, &readBytes)))
+	  return NULL;
+	if (This->cbInBuffer >= readBytes)
+	  break;
+	This->lpInFormat = GlobalReAllocPtr(This->lpInFormat, This->cbInFormat + readBytes, 0);
+	if (This->lpInFormat == NULL)
+	  return NULL;
+	This->lpInBuffer = (BYTE*)This->lpInFormat + This->cbInFormat;
+      }
+
+      if (readSamples != 1)
+	return NULL;
+      if (readBytes != 0) {
+	This->lpInFormat->biSizeImage = readBytes;
+
+	/* nothing to decompress? */
+	if (This->hic == (HIC)NULL) {
+	  This->lCurrentFrame = lPos;
+	  return This->lpInFormat;
+	}
+
+	if (This->bResize) {
+	  ICDecompressEx(This->hic,0,This->lpInFormat,This->lpInBuffer,0,0,
+			 This->lpInFormat->biWidth,This->lpInFormat->biHeight,
+			 This->lpOutFormat,This->lpOutBuffer,This->x,This->y,
+			 This->dx,This->dy);
+	} else {
+	  ICDecompress(This->hic, 0, This->lpInFormat, This->lpInBuffer,
+		       This->lpOutFormat, This->lpOutBuffer);
+	}
+      }
+    } /* for (lNext < lPos) */
+  } /* if (This->lCurrentFrame != lPos) */
+
+  return (This->hic == (HIC)NULL ? This->lpInFormat : This->lpOutFormat);
+}
+
+static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame *iface, LONG lStart,
+					LONG lEnd, LONG lRate)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  TRACE("(%p,%ld,%ld,%ld)\n", iface, lStart, lEnd, lRate);
+
+  This->bFixedStream = TRUE;
+
+  return (IGetFrame_GetFrame(iface, lStart) ? AVIERR_OK : AVIERR_ERROR);
+}
+
+static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame *iface)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  TRACE("(%p)\n", iface);
+
+  This->bFixedStream = FALSE;
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame *iface,
+					    LPBITMAPINFOHEADER lpbiWanted,
+					    LPVOID lpBits, INT x, INT y,
+					    INT dx, INT dy)
+{
+  ICOM_THIS(IGetFrameImpl,iface);
+
+  AVISTREAMINFOW     sInfo;
+  LPBITMAPINFOHEADER lpbi         = lpbiWanted;
+  BOOL               bBestDisplay = FALSE;
+
+  TRACE("(%p,%p,%p,%d,%d,%d,%d)\n", iface, lpbiWanted, lpBits,
+	x, y, dx, dy);
+
+  if (This->pStream == NULL)
+    return AVIERR_ERROR;
+
+  if ((LONG)lpbiWanted == AVIGETFRAMEF_BESTDISPLAYFMT) {
+    lpbi = NULL;
+    bBestDisplay = TRUE;
+  }
+
+  IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo));
+  if (sInfo.fccType != streamtypeVIDEO)
+    return AVIERR_UNSUPPORTED;
+
+  This->bFormatChanges =
+    (sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES ? TRUE : FALSE );
+  This->dwFormatChangeCount = sInfo.dwFormatChangeCount;
+  This->dwEditCount         = sInfo.dwEditCount;
+  This->lCurrentFrame       = -1;
+
+  /* get input format from stream */
+  if (This->lpInFormat == NULL) {
+    This->cbInBuffer = sInfo.dwSuggestedBufferSize;
+    if (This->cbInBuffer == 0)
+      This->cbInBuffer = 1024;
+
+    AVIStreamFormatSize(This->pStream, sInfo.dwStart, &This->cbInFormat);
+
+    This->lpInFormat =
+      (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, This->cbInFormat + This->cbInBuffer);
+    if (This->lpInFormat == NULL) {
+      AVIFILE_CloseCompressor(This);
+      return AVIERR_MEMORY;
+    }
+
+    AVIStreamReadFormat(This->pStream, sInfo.dwStart, This->lpInFormat, &This->cbInFormat);
+
+    This->lpInBuffer = ((LPBYTE)This->lpInFormat) + This->cbInFormat;
+  }
+
+  /* check input format */
+  if (This->lpInFormat->biClrUsed == 0 && This->lpInFormat->biBitCount <= 8)
+    This->lpInFormat->biClrUsed = 1u << This->lpInFormat->biBitCount;
+  if (This->lpInFormat->biSizeImage == 0 &&
+      This->lpInFormat->biCompression == BI_RGB) {
+    This->lpInFormat->biSizeImage =
+      DIBWIDTHBYTES(*This->lpInFormat) * This->lpInFormat->biHeight;
+  }
+
+  /* only to pass through? */
+  if (This->lpInFormat->biCompression == BI_RGB && lpBits == NULL) {
+    if (lpbi == NULL || 
+	(lpbi->biCompression == BI_RGB &&
+	 lpbi->biWidth == This->lpInFormat->biWidth &&
+	 lpbi->biHeight == This->lpInFormat->biHeight &&
+	 lpbi->biBitCount == This->lpInFormat->biBitCount)) {
+      This->lpOutFormat = This->lpInFormat;
+      This->lpOutBuffer = DIBPTR(This->lpInFormat);
+      return AVIERR_OK;
+    }
+  }
+
+  /* need memory for output format? */
+  if (This->lpOutFormat == NULL) {
+    This->lpOutFormat =
+      (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, sizeof(BITMAPINFOHEADER)
+					 + 256 * sizeof(RGBQUAD));
+    if (This->lpOutFormat == NULL) {
+      AVIFILE_CloseCompressor(This);
+      return AVIERR_MEMORY;
+    }
+  }
+
+  /* need handle to video compressor */
+  if (This->hic == (HIC)NULL) {
+    FOURCC fccHandler;
+
+    if (This->lpInFormat->biCompression == BI_RGB)
+      fccHandler = comptypeDIB;
+    else if (This->lpInFormat->biCompression == BI_RLE8)
+      fccHandler = mmioFOURCC('R','L','E',' ');
+    else
+      fccHandler = sInfo.fccHandler;
+
+    if (lpbi != NULL) {
+      if (lpbi->biWidth == 0)
+	lpbi->biWidth = This->lpInFormat->biWidth;
+      if (lpbi->biHeight == 0)
+	lpbi->biHeight = This->lpInFormat->biHeight;
+    }
+
+    This->hic = ICLocate(ICTYPE_VIDEO, fccHandler, This->lpInFormat, lpbi, ICMODE_DECOMPRESS);
+    if (This->hic == (HIC)NULL) {
+      AVIFILE_CloseCompressor(This);
+      return AVIERR_NOCOMPRESSOR;
+    }
+  }
+
+  /* output format given? */
+  if (lpbi != NULL) {
+    /* check the given output format ... */
+    if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
+      lpbi->biClrUsed = 1u << lpbi->biBitCount;
+
+    /* ... and remember it */
+    memcpy(This->lpOutFormat, lpbi,
+	   lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD));
+    if (lpbi->biBitCount <= 8)
+      ICDecompressGetPalette(This->hic, This->lpInFormat, This->lpOutFormat);
+
+    return AVIERR_OK;
+  } else {
+    if (bBestDisplay) {
+      ICGetDisplayFormat(This->hic, This->lpInFormat,
+			 This->lpOutFormat, 0, dx, dy);
+    } else if (ICDecompressGetFormat(This->hic, This->lpInFormat,
+				     This->lpOutFormat) < 0) {
+      AVIFILE_CloseCompressor(This);
+      return AVIERR_NOCOMPRESSOR;
+    }
+
+    /* check output format */
+    if (This->lpOutFormat->biClrUsed == 0 &&
+	This->lpOutFormat->biBitCount <= 8)
+      This->lpOutFormat->biClrUsed = 1u << This->lpOutFormat->biBitCount;
+    if (This->lpOutFormat->biSizeImage == 0 &&
+	This->lpOutFormat->biCompression == BI_RGB) {
+      This->lpOutFormat->biSizeImage =
+	DIBWIDTHBYTES(*This->lpOutFormat) * This->lpOutFormat->biHeight;
+    }
+
+    if (lpBits == NULL) {
+      register DWORD size = This->lpOutFormat->biClrUsed * sizeof(RGBQUAD);
+
+      size += This->lpOutFormat->biSize + This->lpOutFormat->biSizeImage;
+      This->lpOutFormat =
+	(LPBITMAPINFOHEADER)GlobalReAllocPtr(This->lpOutFormat, size, GMEM_MOVEABLE);
+      if (This->lpOutFormat == NULL) {
+	AVIFILE_CloseCompressor(This);
+	return AVIERR_MEMORY;
+      }
+      This->lpOutBuffer = DIBPTR(This->lpOutFormat);
+    } else
+      This->lpOutBuffer = lpBits;
+
+    /* for user size was irrelevant */
+    if (dx == -1)
+      dx = This->lpOutFormat->biWidth;
+    if (dy == -1)
+      dy = This->lpOutFormat->biHeight;
+
+    /* need to resize? */
+    if (x != 0 || y != 0) {
+      if (dy == This->lpOutFormat->biHeight &&
+	  dx == This->lpOutFormat->biWidth)
+	This->bResize = FALSE;
+      else
+	This->bResize = TRUE;
+    }
+
+    if (This->bResize) {
+      This->x  = x;
+      This->y  = y;
+      This->dx = dx;
+      This->dy = dy;
+
+      if (ICDecompressExBegin(This->hic,0,This->lpInFormat,This->lpInBuffer,0,
+			      0,This->lpInFormat->biWidth,
+			      This->lpInFormat->biHeight,This->lpOutFormat,
+			      This->lpOutBuffer, x, y, dx, dy) == ICERR_OK)
+	return AVIERR_OK;
+    } else if (ICDecompressBegin(This->hic, This->lpInFormat,
+				 This->lpOutFormat) == ICERR_OK)
+      return AVIERR_OK;
+
+    AVIFILE_CloseCompressor(This);
+
+    return AVIERR_COMPRESSOR;
+  }
+}
+
+/***********************************************************************/
+
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/wavfile.c	Sun Oct 13 18:41:46 2002
@@ -0,0 +1,1070 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "winbase.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+
+#include "avifile_private.h"
+#include "extrachunk.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/***********************************************************************/
+
+#define formtypeWAVE    mmioFOURCC('W','A','V','E')
+#define ckidWAVEFORMAT  mmioFOURCC('f','m','t',' ')
+#define ckidWAVEFACT    mmioFOURCC('f','a','c','t')
+#define ckidWAVEDATA    mmioFOURCC('d','a','t','a')
+
+/***********************************************************************/
+
+static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
+static ULONG   WINAPI IAVIFile_fnAddRef(IAVIFile* iface);
+static ULONG   WINAPI IAVIFile_fnRelease(IAVIFile* iface);
+static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size);
+static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam);
+static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi);
+static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size);
+static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size);
+static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface);
+static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam);
+
+struct ICOM_VTABLE(IAVIFile) iwavft = {
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  IAVIFile_fnQueryInterface,
+  IAVIFile_fnAddRef,
+  IAVIFile_fnRelease,
+  IAVIFile_fnInfo,
+  IAVIFile_fnGetStream,
+  IAVIFile_fnCreateStream,
+  IAVIFile_fnWriteData,
+  IAVIFile_fnReadData,
+  IAVIFile_fnEndRecord,
+  IAVIFile_fnDeleteStream
+};
+
+static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile*iface,REFIID refiid,LPVOID*obj);
+static ULONG   WINAPI IPersistFile_fnAddRef(IPersistFile*iface);
+static ULONG   WINAPI IPersistFile_fnRelease(IPersistFile*iface);
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile*iface,CLSID*pClassID);
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile*iface);
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile*iface,LPCOLESTR pszFileName,DWORD dwMode);
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile*iface,LPCOLESTR pszFileName,BOOL fRemember);
+static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile*iface,LPCOLESTR pszFileName);
+static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile*iface,LPOLESTR*ppszFileName);
+
+struct ICOM_VTABLE(IPersistFile) iwavpft = {
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  IPersistFile_fnQueryInterface,
+  IPersistFile_fnAddRef,
+  IPersistFile_fnRelease,
+  IPersistFile_fnGetClassID,
+  IPersistFile_fnIsDirty,
+  IPersistFile_fnLoad,
+  IPersistFile_fnSave,
+  IPersistFile_fnSaveCompleted,
+  IPersistFile_fnGetCurFile
+};
+
+static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
+static ULONG   WINAPI IAVIStream_fnAddRef(IAVIStream*iface);
+static ULONG   WINAPI IAVIStream_fnRelease(IAVIStream* iface);
+static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
+static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
+static LONG    WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
+static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
+static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
+static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
+static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
+static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
+static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
+static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
+static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
+
+struct ICOM_VTABLE(IAVIStream) iwavst = {
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  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
+};
+
+typedef struct _IAVIFileImpl IAVIFileImpl;
+
+typedef struct _IPersistFileImpl {
+  /* IUnknown stuff */
+  ICOM_VFIELD(IPersistFile);
+
+  /* IPersistFile stuff */
+  IAVIFileImpl     *paf;
+} IPersistFileImpl;
+
+typedef struct _IAVIStreamImpl {
+  /* IUnknown stuff */
+  ICOM_VFIELD(IAVIStream);
+
+  /* IAVIStream stuff */
+  IAVIFileImpl     *paf;
+} IAVIStreamImpl;
+
+struct _IAVIFileImpl {
+  /* IUnknown stuff */
+  ICOM_VFIELD(IAVIFile);
+  DWORD		    ref;
+
+  /* IAVIFile, IAVIStream stuff... */
+  IPersistFileImpl  iPersistFile;
+  IAVIStreamImpl    iAVIStream;
+
+  AVIFILEINFOW      fInfo;
+  AVISTREAMINFOW    sInfo;
+
+  LPWAVEFORMATEX    lpFormat;
+  LONG              cbFormat;
+
+  MMCKINFO          ckData;
+
+  EXTRACHUNKS       extra;
+
+  /* IPersistFile stuff ... */
+  HMMIO             hmmio;
+  LPWSTR            szFileName;
+  UINT              uMode;
+  BOOL              fDirty;
+};
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This);
+
+HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppv)
+{
+  IAVIFileImpl *pfile;
+  HRESULT       hr;
+
+  assert(riid != NULL && ppv != NULL);
+
+  *ppv = NULL;
+
+  pfile = (IAVIFileImpl*)LocalAlloc(LPTR, sizeof(IAVIFileImpl));
+  if (pfile == NULL)
+    return AVIERR_MEMORY;
+
+  ICOM_VTBL(pfile)                = &iwavft;
+  ICOM_VTBL(&pfile->iPersistFile) = &iwavpft;
+  ICOM_VTBL(&pfile->iAVIStream)   = &iwavst;
+  pfile->ref = 0;
+  pfile->iPersistFile.paf = pfile;
+  pfile->iAVIStream.paf   = pfile;
+
+  hr = IUnknown_QueryInterface((IUnknown*)pfile, riid, ppv);
+  if (FAILED(hr))
+    LocalFree((HLOCAL)pfile);
+
+  return hr;
+}
+
+static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
+						LPVOID *obj)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
+
+  if (IsEqualGUID(&IID_IUnknown, refiid) ||
+      IsEqualGUID(&IID_IAVIFile, refiid)) {
+    *obj = iface;
+    return S_OK;
+  } else if (This->fInfo.dwStreams == 1 &&
+	     IsEqualGUID(&IID_IAVIStream, refiid)) {
+    *obj = &This->iAVIStream;
+    return S_OK;
+  } else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
+    *obj = &This->iPersistFile;
+    return S_OK;
+  }
+
+  return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p)\n",iface);
+
+  return ++(This->ref);
+}
+
+static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p)\n",iface);
+
+  if (!--(This->ref)) {
+    if (This->fDirty) {
+      /* need to write headers to file */
+      AVIFILE_SaveFile(This);
+    }
+
+    if (This->lpFormat != NULL) {
+      GlobalFreePtr(This->lpFormat);
+      This->lpFormat = NULL;
+      This->cbFormat = 0;
+    }
+    if (This->extra.lp != NULL) {
+      GlobalFreePtr(This->extra.lp);
+      This->extra.lp = NULL;
+      This->extra.cb = 0;
+    }
+    if (This->szFileName != NULL) {
+      LocalFree((HLOCAL)This->szFileName);
+      This->szFileName = NULL;
+    }
+    if (This->hmmio != (HMMIO)NULL) {
+      mmioClose(This->hmmio, 0);
+      This->hmmio = (HMMIO)NULL;
+    }
+
+    LocalFree((HLOCAL)This);
+    return 0;
+  }
+  return This->ref;
+}
+
+static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, LPAVIFILEINFOW afi,
+				      LONG size)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,%p,%ld)\n",iface,afi,size);
+
+  if (afi == NULL)
+    return AVIERR_BADPARAM;
+  if (size < 0)
+    return AVIERR_BADSIZE;
+
+  /* update file info */
+  This->fInfo.dwFlags = 0;
+  This->fInfo.dwCaps  = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+  if (This->lpFormat != NULL) {
+    This->fInfo.dwStreams             = 1;
+    This->fInfo.dwScale               = This->sInfo.dwScale;
+    This->fInfo.dwRate                = This->sInfo.dwRate;
+    This->fInfo.dwLength              = This->sInfo.dwLength;
+    This->fInfo.dwSuggestedBufferSize = This->ckData.cksize;
+  }
+
+  memcpy(afi, &This->fInfo, min(size, sizeof(This->fInfo)));
+
+  if (size < sizeof(This->fInfo))
+    return AVIERR_BUFFERTOOSMALL;
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
+					   DWORD fccType, LONG lParam)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,%p,0x%08lX,%ld)\n", iface, avis, fccType, lParam);
+
+  /* check parameter */
+  if (avis == NULL)
+    return AVIERR_BADPARAM;
+
+  *avis = NULL;
+
+  /* Does our stream exists? */
+  if (lParam != 0 || This->fInfo.dwStreams == 0)
+    return AVIERR_NODATA;
+  if (fccType != 0 && fccType != streamtypeAUDIO)
+    return AVIERR_NODATA;
+
+  *avis = (PAVISTREAM)&This->iAVIStream;
+  IAVIFile_AddRef(iface);
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
+					      LPAVISTREAMINFOW asi)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,%p,%p)\n", iface, avis, asi);
+
+  /* check parameters */
+  if (avis == NULL || asi == NULL)
+    return AVIERR_BADPARAM;
+
+  *avis = NULL;
+
+  /* We only support one audio stream */
+  if (This->fInfo.dwStreams != 0 || This->lpFormat != NULL)
+    return AVIERR_UNSUPPORTED;
+  if (asi->fccType != streamtypeAUDIO)
+    return AVIERR_UNSUPPORTED;
+
+  /* Does the user have write permission? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  This->cbFormat = 0;
+  This->lpFormat = NULL;
+
+  memcpy(&This->sInfo, asi, sizeof(This->sInfo));
+
+  /* make sure streaminfo if okay for us */
+  This->sInfo.fccHandler          = 0;
+  This->sInfo.dwFlags             = 0;
+  This->sInfo.dwCaps              = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+  This->sInfo.dwStart             = 0;
+  This->sInfo.dwInitialFrames     = 0;
+  This->sInfo.dwFormatChangeCount = 0;
+  memset(&This->sInfo.rcFrame, 0, sizeof(This->sInfo.rcFrame));
+
+  This->fInfo.dwStreams = 1;
+  This->fInfo.dwScale   = This->sInfo.dwScale;
+  This->fInfo.dwRate    = This->sInfo.dwRate;
+  This->fInfo.dwLength  = This->sInfo.dwLength;
+
+  This->ckData.dwDataOffset = 0;
+  This->ckData.cksize       = 0;
+
+  *avis = (PAVISTREAM)&This->iAVIStream;
+  IAVIFile_AddRef(iface);
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid,
+					   LPVOID lpData, LONG size)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,0x%08lX,%p,%ld)\n", iface, ckid, lpData, size);
+
+  /* check parameters */
+  if (lpData == NULL)
+    return AVIERR_BADPARAM;
+  if (size < 0)
+    return AVIERR_BADSIZE;
+
+  /* Do we have write permission? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  This->fDirty = TRUE;
+
+  return WriteExtraChunk(&This->extra, ckid, lpData, size);
+}
+
+static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid,
+					  LPVOID lpData, LONG *size)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,0x%08lX,%p,%p)\n", iface, ckid, lpData, size);
+
+  return ReadExtraChunk(&This->extra, ckid, lpData, size);
+}
+
+static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
+{
+  TRACE("(%p)\n",iface);
+
+  /* This is only needed for interleaved files.
+   * We have only one stream, which can't be interleaved.
+   */
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
+					      LONG lParam)
+{
+  ICOM_THIS(IAVIFileImpl,iface);
+
+  TRACE("(%p,0x%08lX,%ld)\n", iface, fccType, lParam);
+
+  /* check parameter */
+  if (lParam < 0)
+    return AVIERR_BADPARAM;
+
+  /* Have we our audio stream? */
+  if (lParam != 0 || This->fInfo.dwStreams == 0 ||
+      (fccType != 0 && fccType != streamtypeAUDIO))
+    return AVIERR_NODATA;
+
+  /* Have user write permissions? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  GlobalFreePtr(This->lpFormat);
+  This->lpFormat = NULL;
+  This->cbFormat = 0;
+
+  /* update infos */
+  This->ckData.dwDataOffset = 0;
+  This->ckData.cksize       = 0;
+
+  This->sInfo.dwScale   = 0;
+  This->sInfo.dwRate    = 0;
+  This->sInfo.dwLength  = 0;
+  This->sInfo.dwSuggestedBufferSize = 0;
+
+  This->fInfo.dwStreams = 0;
+  This->fInfo.dwEditCount++;
+
+  This->fDirty = TRUE;
+
+  return AVIERR_OK;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface,
+						    REFIID refiid, LPVOID *obj)
+{
+  ICOM_THIS(IPersistFileImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
+}
+
+static ULONG   WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
+{
+  ICOM_THIS(IPersistFileImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_AddRef((PAVIFILE)This->paf);
+}
+
+static ULONG   WINAPI IPersistFile_fnRelease(IPersistFile *iface)
+{
+  ICOM_THIS(IPersistFileImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_Release((PAVIFILE)This->paf);
+}
+
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface,
+						LPCLSID pClassID)
+{
+  TRACE("(%p,%p)\n", iface, pClassID);
+
+  if (pClassID == NULL)
+    return AVIERR_BADPARAM;
+
+  memcpy(pClassID, &CLSID_WAVFile, sizeof(CLSID_WAVFile));
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
+{
+  ICOM_THIS(IPersistFileImpl,iface);
+
+  TRACE("(%p)\n", iface);
+
+  assert(This->paf != NULL);
+
+  return (This->paf->fDirty ? S_OK : S_FALSE);
+}
+
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface,
+					  LPCOLESTR pszFileName, DWORD dwMode)
+{
+  IAVIFileImpl *This = ((IPersistFileImpl*)iface)->paf;
+
+  WCHAR wszStreamFmt[50];
+  INT   len;
+
+  TRACE("(%p,%s,0x%08lX)\n", iface, debugstr_w(pszFileName), dwMode);
+
+  /* check parameter */
+  if (pszFileName == NULL)
+    return AVIERR_BADPARAM;
+
+  assert(This != NULL);
+  if (This->hmmio != (HMMIO)NULL)
+    return AVIERR_ERROR; /* No reuse of this object for another file! */
+
+  /* remeber mode and name */
+  This->uMode = dwMode;
+
+  len = lstrlenW(pszFileName) + 1;
+  This->szFileName = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
+  if (This->szFileName == NULL)
+    return AVIERR_MEMORY;
+  lstrcpyW(This->szFileName, pszFileName);
+
+  /* try to open the file */
+  This->hmmio = mmioOpenW(This->szFileName, NULL, MMIO_ALLOCBUF | dwMode);
+  if (This->hmmio == (HMMIO)NULL)
+    return AVIERR_FILEOPEN;
+
+  memset(& This->fInfo, 0, sizeof(This->fInfo));
+  memset(& This->sInfo, 0, sizeof(This->sInfo));
+
+  LoadStringW(AVIFILE_hModule, IDS_WAVEFILETYPE, This->fInfo.szFileType,
+	      sizeof(This->fInfo.szFileType));
+  if (LoadStringW(AVIFILE_hModule, IDS_WAVESTREAMFORMAT,
+		  wszStreamFmt, sizeof(wszStreamFmt)) > 0) {
+    wsprintfW(This->sInfo.szName, wszStreamFmt,
+	      AVIFILE_BasenameW(This->szFileName));
+  }
+
+  /* should we create a new file? */
+  if (dwMode & OF_CREATE) {
+    /* nothing more to do */
+    return AVIERR_OK;
+  } else
+    return AVIFILE_LoadFile(This);
+}
+
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
+					  LPCOLESTR pszFileName,BOOL fRemember)
+{
+  TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
+
+  /* We write directly to disk, so nothing to do. */
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface,
+						   LPCOLESTR pszFileName)
+{
+  TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
+
+  /* We write directly to disk, so nothing to do. */
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface,
+						LPOLESTR *ppszFileName)
+{
+  ICOM_THIS(IPersistFileImpl,iface);
+
+  TRACE("(%p,%p)\n", iface, ppszFileName);
+
+  if (ppszFileName == NULL)
+    return AVIERR_BADPARAM;
+
+  *ppszFileName = NULL;
+
+  assert(This->paf != NULL);
+
+  if (This->paf->szFileName != NULL) {
+    int len = lstrlenW(This->paf->szFileName);
+
+    *ppszFileName = (LPOLESTR)GlobalAllocPtr(GHND, len * sizeof(WCHAR));
+    if (*ppszFileName == NULL)
+      return AVIERR_MEMORY;
+
+    memcpy(*ppszFileName, This->paf->szFileName, len * sizeof(WCHAR));
+  }
+
+  return AVIERR_OK;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface,
+						  REFIID refiid, LPVOID *obj)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
+}
+
+static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_AddRef((PAVIFILE)This->paf);
+}
+
+static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_Release((PAVIFILE)This->paf);
+}
+
+static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
+					  LPARAM lParam2)
+{
+  TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
+
+  /* This IAVIStream interface needs an WAVFile */
+  return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
+					LONG size)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  TRACE("(%p,%p,%ld)\n", iface, psi, size);
+
+  if (psi == NULL)
+    return AVIERR_BADPARAM;
+  if (size < 0)
+    return AVIERR_BADSIZE;
+
+  memcpy(psi, &This->paf->sInfo, min(size, sizeof(This->paf->sInfo)));
+
+  if (size < sizeof(This->paf->sInfo))
+    return AVIERR_BUFFERTOOSMALL;
+  return AVIERR_OK;
+}
+
+static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos,
+					   LONG flags)
+{
+  IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+  TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+  /* Do we have data? */
+  if (This->lpFormat == NULL)
+    return -1;
+
+  /* We don't have an index */
+  if (flags & FIND_INDEX)
+    return -1;
+
+  if (flags & FIND_FROM_START) {
+    pos = This->sInfo.dwStart;
+    flags &= ~(FIND_FROM_START|FIND_PREV);
+    flags |= FIND_NEXT;
+  }
+
+  if (flags & FIND_FORMAT) {
+    if ((flags & FIND_NEXT) && pos > 0)
+      pos = -1;
+    else
+      pos = 0;
+  }
+
+  if (flags & (FIND_LENGTH|FIND_SIZE))
+    return This->sInfo.dwSampleSize;
+  if (flags & FIND_OFFSET)
+    return This->ckData.dwDataOffset + pos * This->sInfo.dwSampleSize;
+
+  return pos;
+}
+
+static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
+					      LPVOID format, LONG *formatsize)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
+
+  if (formatsize == NULL)
+    return AVIERR_BADPARAM;
+
+  /* only interested in needed buffersize? */
+  if (format == NULL || *formatsize <= 0) {
+    *formatsize = This->paf->cbFormat;
+
+    return AVIERR_OK;
+  }
+
+  /* copy initial format (only as much as will fit) */
+  memcpy(format, This->paf->lpFormat, min(*formatsize, This->paf->cbFormat));
+  if (*formatsize < This->paf->cbFormat) {
+    *formatsize = This->paf->cbFormat;
+    return AVIERR_BUFFERTOOSMALL;
+  }
+
+  *formatsize = This->paf->cbFormat;
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
+					     LPVOID format, LONG formatsize)
+{
+  IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+  TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
+
+  /* check parameters */
+  if (format == NULL || formatsize <= sizeof(PCMWAVEFORMAT))
+    return AVIERR_BADPARAM;
+
+  /* We can only do this to an empty wave file, but ignore call
+   * if still same format */
+  if (This->lpFormat != NULL) {
+    if (formatsize != This->cbFormat ||
+	memcmp(format, This->lpFormat, formatsize) != 0)
+      return AVIERR_UNSUPPORTED;
+
+    return AVIERR_OK;
+  }
+
+  /* only support start at position 0 */
+  if (pos != 0)
+    return AVIERR_UNSUPPORTED;
+
+  /* Do we have write permission? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  /* get memory for format and copy it */
+  This->lpFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, formatsize);
+  if (This->lpFormat == NULL)
+    return AVIERR_MEMORY;
+
+  This->cbFormat = formatsize;
+  memcpy(This->lpFormat, format, formatsize);
+
+  /* update info's about 'data' chunk */
+  This->ckData.dwDataOffset = formatsize + 7 * sizeof(DWORD);
+  This->ckData.cksize       = 0;
+
+  /* for non-pcm format we need also a 'fact' chunk */
+  if (This->lpFormat->wFormatTag != WAVE_FORMAT_PCM)
+    This->ckData.dwDataOffset += 3 * sizeof(DWORD);
+
+  /* update stream and file info */
+  This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
+  This->sInfo.dwScale      = This->lpFormat->nBlockAlign;
+  This->sInfo.dwRate       = This->lpFormat->nAvgBytesPerSec;
+  This->sInfo.dwLength     = 0;
+  This->sInfo.dwSuggestedBufferSize = 0;
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,
+					LONG samples, LPVOID buffer,
+					LONG buffersize, LPLONG bytesread,
+					LPLONG samplesread)
+{
+  IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+  TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
+	buffersize, bytesread, samplesread);
+
+  /* clear return parameters if given */
+  if (bytesread != NULL)
+    *bytesread = 0;
+  if (samplesread != NULL)
+    *samplesread = 0;
+
+  /* positions without data */
+  if (start < 0 || start > This->sInfo.dwLength)
+    return AVIERR_OK;
+
+  /* check samples */
+  if (samples < 0)
+    samples = 0;
+  if (buffersize > 0) {
+    if (samples > 0)
+      samples = min(samples, buffersize / This->sInfo.dwSampleSize);
+    else
+      samples = buffersize / This->sInfo.dwSampleSize;
+  }
+
+  /* limit to end of stream */
+  if (start + samples > This->sInfo.dwLength)
+    samples = This->sInfo.dwLength - start;
+
+  /* request only the sizes? */
+  if (buffer == NULL || buffersize <= 0) {
+    /* then I need atleast one parameter for it */
+    if (bytesread == NULL && samplesread == NULL)
+      return AVIERR_BADPARAM;
+
+    if (bytesread != NULL)
+      *bytesread = samples * This->sInfo.dwSampleSize;
+    if (samplesread != NULL)
+      *samplesread = samples;
+
+    return AVIERR_OK;
+  }
+
+  /* nothing to read? */
+  if (samples == 0)
+    return AVIERR_OK;
+
+  /* Can I atleast read one sample? */
+  if (buffersize < This->sInfo.dwSampleSize)
+    return AVIERR_BUFFERTOOSMALL;
+
+  buffersize = samples * This->sInfo.dwSampleSize;
+
+  if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
+	       + start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
+    return AVIERR_FILEREAD;
+  if (mmioRead(This->hmmio, (HPSTR)buffer, buffersize) != buffersize)
+    return AVIERR_FILEREAD;
+
+  /* fill out return parameters if given */
+  if (bytesread != NULL)
+    *bytesread = buffersize;
+  if (samplesread != NULL)
+    *samplesread = samples;  
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start,
+					 LONG samples, LPVOID buffer,
+					 LONG buffersize, DWORD flags,
+					 LPLONG sampwritten,
+					 LPLONG byteswritten)
+{
+  IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+  TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
+	buffer, buffersize, flags, sampwritten, byteswritten);
+
+  /* clear return parameters if given */
+  if (sampwritten != NULL)
+    *sampwritten = 0;
+  if (byteswritten != NULL)
+    *byteswritten = 0;
+
+  /* check parameters */
+  if (buffer == NULL && (buffersize > 0 || samples > 0))
+    return AVIERR_BADPARAM;
+
+  /* Have we write permission? */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  /* < 0 means "append" */
+  if (start < 0)
+    start = This->sInfo.dwStart + This->sInfo.dwLength;
+
+  /* check buffersize -- must multiple of samplesize */
+  if (buffersize & ~(This->sInfo.dwSampleSize - 1))
+    return AVIERR_BADSIZE;
+
+  /* have we anything to write? */
+  if (buffer != NULL && buffersize > 0) {
+    This->fDirty = 1;
+
+    if (mmioSeek(This->hmmio, This->ckData.dwDataOffset +
+		 start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
+      return AVIERR_FILEWRITE;
+    if (mmioWrite(This->hmmio, (HPSTR)buffer, buffersize) != buffersize)
+      return AVIERR_FILEWRITE;
+
+    This->sInfo.dwLength = max(This->sInfo.dwLength, start + samples);
+    This->ckData.cksize  = max(This->ckData.cksize,
+			       start * This->sInfo.dwSampleSize + buffersize);
+
+    /* fill out return parameters if given */
+    if (sampwritten != NULL)
+      *sampwritten = samples;
+    if (byteswritten != NULL)
+      *byteswritten = buffersize;
+  }
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start,
+					  LONG samples)
+{
+  IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+  TRACE("(%p,%ld,%ld)\n", iface, start, samples);
+
+  /* check parameters */
+  if (start < 0 || samples < 0)
+    return AVIERR_BADPARAM;
+
+  /* Delete before start of stream? */
+  if (start + samples < This->sInfo.dwStart)
+    return AVIERR_OK;
+
+  /* Delete after end of stream? */
+  if (start > This->sInfo.dwLength)
+    return AVIERR_OK;
+
+  /* For the rest we need write permissions */
+  if ((This->uMode & MMIO_RWMODE) == 0)
+    return AVIERR_READONLY;
+
+  if (start + samples >= This->sInfo.dwLength) {
+    /* deletion at end */
+    samples = This->sInfo.dwLength - start;
+    This->sInfo.dwLength -= samples;
+    This->ckData.cksize  -= samples * This->sInfo.dwSampleSize;
+  } else if (start <= This->sInfo.dwStart) {
+    /* deletion at start */
+    samples = This->sInfo.dwStart - start;
+    start   = This->sInfo.dwStart;
+    This->ckData.dwDataOffset += samples * This->sInfo.dwSampleSize;
+    This->ckData.cksize       -= samples * This->sInfo.dwSampleSize;
+  } else {
+    /* deletion inside stream -- needs playlist and cue's */
+    FIXME(": deletion inside of stream not supported!\n");
+
+    return AVIERR_UNSUPPORTED;
+  }
+
+  This->fDirty = 1;
+
+  return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc,
+					    LPVOID lp, LPLONG lpread)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  assert(This->paf != NULL);
+
+  return IAVIFile_ReadData((PAVIFILE)This->paf, fcc, lp, lpread);
+}
+
+static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
+					     LPVOID lp, LONG size)
+{
+  ICOM_THIS(IAVIStreamImpl,iface);
+
+  return IAVIFile_WriteData((PAVIFILE)This->paf, fcc, lp, size);
+}
+
+static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
+					   LPAVISTREAMINFOW info, LONG infolen)
+{
+  FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
+
+  return E_FAIL;
+}
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
+{
+  MMCKINFO ckRIFF;
+  MMCKINFO ck;
+
+  This->sInfo.dwLength = 0; /* just to be sure */
+  This->fDirty = FALSE;
+
+  /* search for RIFF chunk */
+  if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
+    return AVIFILE_LoadSunFile(This);
+  }
+
+  if (ckRIFF.fccType != formtypeWAVE)
+    return AVIERR_BADFORMAT;
+
+  /* search WAVE format chunk */
+  ck.ckid = ckidWAVEFORMAT;
+  if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck,
+			     &ckRIFF, MMIO_FINDCHUNK != S_OK))
+    return AVIERR_FILEREAD;
+
+  /* get memory for format and read it */
+  This->lpFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, ck.cksize);
+  if (This->lpFormat == NULL)
+    return AVIERR_FILEREAD;
+  This->cbFormat = ck.cksize;
+
+  if (mmioRead(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
+    return AVIERR_FILEREAD;
+  if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+    return AVIERR_FILEREAD;
+
+  /* non-pcm formats have a fact chunk */
+  if (This->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
+    ck.ckid = ckidWAVEFACT;
+    if (mmioDescend(This->hmmio, &ck, NULL, MMIO_FINDCHUNK) != S_OK) {
+      /* FIXME: if codec is installed could ask him */
+      return AVIERR_BADFORMAT;
+    }
+  }
+
+  /* find the big data chunk */
+  This->ckData.ckid = ckidWAVEDATA;
+  if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &This->ckData,
+			     &ckRIFF, MMIO_FINDCHUNK) != S_OK)
+    return AVIERR_FILEREAD;
+
+  memset(&This->sInfo, 0, sizeof(This->sInfo));
+  This->sInfo.fccType      = streamtypeAUDIO;
+  This->sInfo.dwRate       = This->lpFormat->nAvgBytesPerSec;
+  This->sInfo.dwSampleSize =
+    This->sInfo.dwScale    = This->lpFormat->nBlockAlign;
+  This->sInfo.dwLength     = This->ckData.cksize / This->lpFormat->nBlockAlign;
+  This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
+
+  if (mmioAscend(This->hmmio, &This->ckData, 0) != S_OK) {
+    /* seems to be truncated */
+    WARN(": file seems to be truncated!\n");
+    This->ckData.cksize  = mmioSeek(This->hmmio, 0, SEEK_END) -
+      This->ckData.dwDataOffset;
+    This->sInfo.dwLength = This->ckData.cksize / This->lpFormat->nBlockAlign;
+    This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
+  }
+
+  /* ignore errors */
+  FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck, &ckRIFF, 0);
+
+  return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This)
+{
+  FIXME(": pherhpas sun-audio file -- not implemented !\n");
+
+  return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
+{
+  return AVIERR_UNSUPPORTED;
+}
+
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/rsrc.rc	Fri Oct 11 21:13:40 2002
@@ -0,0 +1,46 @@
+/*
+ * Top level resource file for avifil32.dll
+ *
+ */
+
+#include "windef.h"
+#include "winuser.h"
+#include "winver.h"
+#include "avifile_private.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+1 VERSIONINFO
+FILEVERSION	4, 3, 0, 1998
+PRODUCTVERSION	4, 3, 0, 1998
+FILEFLAGSMASK	VS_FFI_FILEFLAGSMASK
+#ifdef NDEBUG
+FILEFLAGS	0
+#else
+FILEFLAGS	VS_FF_DEBUG
+#endif
+FILEOS		VOS_DOS_WINDOWS32
+FILETYPE	VFT_DLL
+{
+  BLOCK "StringFileInfo"
+  {
+    BLOCK "040604B0" /* Deutschland (Standard) */
+    {
+      VALUE "CompanyName", "Wine Developer Team\000"
+      VALUE "FileDescription", "Wine Bibliothek zur Unterstützung von AVI-Dateien\000"
+      VALUE "FileVersion", "4.03.1998\000"
+      VALUE "InternalName", "AVIFIL32\000"
+      VALUE "LegalCopyright", "Copyright \251 Michael Günnewig 2002\000"
+      VALUE "OriginalFileName", "AVIFIL32.DLL\000"
+      VALUE "ProductName", "Wine\000"
+      VALUE "ProductVersion", "1.00\000"
+    }
+  }
+}
+
+/*
+ * Everything specific to any language goes
+ * in one of the specific files.
+ */
+#include "avifile_De.rc"
+#include "avifile_En.rc"
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/avifile_De.rc	Fri Oct 11 21:13:49 2002
@@ -0,0 +1,12 @@
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+
+STRINGTABLE DISCARDABLE
+{
+  IDS_WAVESTREAMFORMAT	"Waveform: %s"
+  IDS_WAVEFILETYPE	"Waveform"
+  IDS_VIDEO		"Video"
+  IDS_AUDIO		"Audio"
+  IDS_AVISTREAMFORMAT	"%s %s #%d"
+  IDS_AVIFILETYPE	"Wine AVI-Standard-Dateibehandlungsroutine"
+  IDS_UNCOMPRESSED      "Unkomprimiert"
+}
--- /dev/null	Sat Feb 23 16:05:24 2002
+++ dlls/avifil32/avifile_En.rc	Fri Oct 11 21:30:16 2002
@@ -0,0 +1,12 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+  IDS_WAVESTREAMFORMAT	"Waveform: %s"
+  IDS_WAVEFILETYPE	"Waveform"
+  IDS_VIDEO		"video"
+  IDS_AUDIO		"audio"
+  IDS_AVISTREAMFORMAT	"%s %s #%d"
+  IDS_AVIFILETYPE	"Wine AVI-default-filehandler"
+  IDS_UNCOMPRESSED      "uncompressed"
+}


  Michael Günnewig

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux