ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

wavfile.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2002 Michael Günnewig
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include <assert.h>
00020 #include <stdarg.h>
00021 
00022 #include "windef.h"
00023 #include "winbase.h"
00024 #include "wingdi.h"
00025 #include "winuser.h"
00026 #include "winnls.h"
00027 #include "winerror.h"
00028 #include "mmsystem.h"
00029 #include "vfw.h"
00030 #include "msacm.h"
00031 
00032 #include "avifile_private.h"
00033 #include "extrachunk.h"
00034 
00035 #include "wine/unicode.h"
00036 #include "wine/debug.h"
00037 
00038 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
00039 
00040 /***********************************************************************/
00041 
00042 #define formtypeWAVE    mmioFOURCC('W','A','V','E')
00043 #define ckidWAVEFORMAT  mmioFOURCC('f','m','t',' ')
00044 #define ckidWAVEFACT    mmioFOURCC('f','a','c','t')
00045 #define ckidWAVEDATA    mmioFOURCC('d','a','t','a')
00046 
00047 /***********************************************************************/
00048 
00049 #define ENDIAN_SWAPWORD(x)  ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
00050 #define ENDIAN_SWAPDWORD(x) (ENDIAN_SWAPWORD((x >> 16) & 0xFFFF) | \
00051                              ENDIAN_SWAPWORD(x & 0xFFFF) << 16)
00052 
00053 #ifdef WORDS_BIGENDIAN
00054 #define BE2H_WORD(x)  (x)
00055 #define BE2H_DWORD(x) (x)
00056 #define LE2H_WORD(x)  ENDIAN_SWAPWORD(x)
00057 #define LE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
00058 #else
00059 #define BE2H_WORD(x)  ENDIAN_SWAPWORD(x)
00060 #define BE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
00061 #define LE2H_WORD(x)  (x)
00062 #define LE2H_DWORD(x) (x)
00063 #endif
00064 
00065 typedef struct {
00066   FOURCC  fccType;
00067   DWORD   offset;
00068   DWORD   size;
00069   INT     encoding;
00070   DWORD   sampleRate;
00071   DWORD   channels;
00072 } SUNAUDIOHEADER;
00073 
00074 #define AU_ENCODING_ULAW_8                 1
00075 #define AU_ENCODING_PCM_8                  2
00076 #define AU_ENCODING_PCM_16                 3
00077 #define AU_ENCODING_PCM_24                 4
00078 #define AU_ENCODING_PCM_32                 5
00079 #define AU_ENCODING_FLOAT                  6
00080 #define AU_ENCODING_DOUBLE                 7
00081 #define AU_ENCODING_ADPCM_G721_32         23
00082 #define AU_ENCODING_ADPCM_G722            24
00083 #define AU_ENCODING_ADPCM_G723_24         25
00084 #define AU_ENCODING_ADPCM_G723_5          26
00085 #define AU_ENCODING_ALAW_8                27
00086 
00087 /***********************************************************************/
00088 
00089 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
00090 static ULONG   WINAPI IAVIFile_fnAddRef(IAVIFile* iface);
00091 static ULONG   WINAPI IAVIFile_fnRelease(IAVIFile* iface);
00092 static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size);
00093 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam);
00094 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi);
00095 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size);
00096 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size);
00097 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface);
00098 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam);
00099 
00100 static const struct IAVIFileVtbl iwavft = {
00101   IAVIFile_fnQueryInterface,
00102   IAVIFile_fnAddRef,
00103   IAVIFile_fnRelease,
00104   IAVIFile_fnInfo,
00105   IAVIFile_fnGetStream,
00106   IAVIFile_fnCreateStream,
00107   IAVIFile_fnWriteData,
00108   IAVIFile_fnReadData,
00109   IAVIFile_fnEndRecord,
00110   IAVIFile_fnDeleteStream
00111 };
00112 
00113 static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile*iface,REFIID refiid,LPVOID*obj);
00114 static ULONG   WINAPI IPersistFile_fnAddRef(IPersistFile*iface);
00115 static ULONG   WINAPI IPersistFile_fnRelease(IPersistFile*iface);
00116 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile*iface,CLSID*pClassID);
00117 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile*iface);
00118 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile*iface,LPCOLESTR pszFileName,DWORD dwMode);
00119 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile*iface,LPCOLESTR pszFileName,BOOL fRemember);
00120 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile*iface,LPCOLESTR pszFileName);
00121 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile*iface,LPOLESTR*ppszFileName);
00122 
00123 static const struct IPersistFileVtbl iwavpft = {
00124   IPersistFile_fnQueryInterface,
00125   IPersistFile_fnAddRef,
00126   IPersistFile_fnRelease,
00127   IPersistFile_fnGetClassID,
00128   IPersistFile_fnIsDirty,
00129   IPersistFile_fnLoad,
00130   IPersistFile_fnSave,
00131   IPersistFile_fnSaveCompleted,
00132   IPersistFile_fnGetCurFile
00133 };
00134 
00135 static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
00136 static ULONG   WINAPI IAVIStream_fnAddRef(IAVIStream*iface);
00137 static ULONG   WINAPI IAVIStream_fnRelease(IAVIStream* iface);
00138 static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
00139 static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
00140 static LONG    WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
00141 static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
00142 static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
00143 static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
00144 static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
00145 static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
00146 static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
00147 static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
00148 static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
00149 
00150 static const struct IAVIStreamVtbl iwavst = {
00151   IAVIStream_fnQueryInterface,
00152   IAVIStream_fnAddRef,
00153   IAVIStream_fnRelease,
00154   IAVIStream_fnCreate,
00155   IAVIStream_fnInfo,
00156   IAVIStream_fnFindSample,
00157   IAVIStream_fnReadFormat,
00158   IAVIStream_fnSetFormat,
00159   IAVIStream_fnRead,
00160   IAVIStream_fnWrite,
00161   IAVIStream_fnDelete,
00162   IAVIStream_fnReadData,
00163   IAVIStream_fnWriteData,
00164   IAVIStream_fnSetInfo
00165 };
00166 
00167 typedef struct _IAVIFileImpl IAVIFileImpl;
00168 
00169 typedef struct _IPersistFileImpl {
00170   /* IUnknown stuff */
00171   const IPersistFileVtbl *lpVtbl;
00172 
00173   /* IPersistFile stuff */
00174   IAVIFileImpl     *paf;
00175 } IPersistFileImpl;
00176 
00177 typedef struct _IAVIStreamImpl {
00178   /* IUnknown stuff */
00179   const IAVIStreamVtbl *lpVtbl;
00180 
00181   /* IAVIStream stuff */
00182   IAVIFileImpl     *paf;
00183 } IAVIStreamImpl;
00184 
00185 struct _IAVIFileImpl {
00186   /* IUnknown stuff */
00187   const IAVIFileVtbl *lpVtbl;
00188   LONG          ref;
00189 
00190   /* IAVIFile, IAVIStream stuff... */
00191   IPersistFileImpl  iPersistFile;
00192   IAVIStreamImpl    iAVIStream;
00193 
00194   AVIFILEINFOW      fInfo;
00195   AVISTREAMINFOW    sInfo;
00196 
00197   LPWAVEFORMATEX    lpFormat;
00198   LONG              cbFormat;
00199 
00200   MMCKINFO          ckData;
00201 
00202   EXTRACHUNKS       extra;
00203 
00204   /* IPersistFile stuff ... */
00205   HMMIO             hmmio;
00206   LPWSTR            szFileName;
00207   UINT              uMode;
00208   BOOL              fDirty;
00209 };
00210 
00211 /***********************************************************************/
00212 
00213 static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
00214 static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This);
00215 static HRESULT AVIFILE_SaveFile(const IAVIFileImpl *This);
00216 
00217 HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppv)
00218 {
00219   IAVIFileImpl *pfile;
00220   HRESULT       hr;
00221 
00222   assert(riid != NULL && ppv != NULL);
00223 
00224   *ppv = NULL;
00225 
00226   pfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIFileImpl));
00227   if (pfile == NULL)
00228     return AVIERR_MEMORY;
00229 
00230   pfile->lpVtbl                = &iwavft;
00231   pfile->iPersistFile.lpVtbl   = &iwavpft;
00232   pfile->iAVIStream.lpVtbl     = &iwavst;
00233   pfile->ref = 0;
00234   pfile->iPersistFile.paf = pfile;
00235   pfile->iAVIStream.paf   = pfile;
00236 
00237   hr = IAVIFile_QueryInterface((IAVIFile*)pfile, riid, ppv);
00238   if (FAILED(hr))
00239     HeapFree(GetProcessHeap(), 0, pfile);
00240 
00241   return hr;
00242 }
00243 
00244 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
00245                         LPVOID *obj)
00246 {
00247   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00248 
00249   TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
00250 
00251   if (IsEqualGUID(&IID_IUnknown, refiid) ||
00252       IsEqualGUID(&IID_IAVIFile, refiid)) {
00253     *obj = iface;
00254     IAVIFile_AddRef(iface);
00255     return S_OK;
00256   } else if (This->fInfo.dwStreams == 1 &&
00257          IsEqualGUID(&IID_IAVIStream, refiid)) {
00258     *obj = &This->iAVIStream;
00259     IAVIFile_AddRef(iface);
00260     return S_OK;
00261   } else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
00262     *obj = &This->iPersistFile;
00263     IAVIFile_AddRef(iface);
00264     return S_OK;
00265   }
00266 
00267   return OLE_E_ENUM_NOMORE;
00268 }
00269 
00270 static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
00271 {
00272   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00273 
00274   TRACE("(%p)\n",iface);
00275 
00276   return InterlockedIncrement(&This->ref);
00277 }
00278 
00279 static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
00280 {
00281   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00282   ULONG ref = InterlockedDecrement(&This->ref);
00283 
00284   TRACE("(%p)\n",iface);
00285 
00286   if (!ref) {
00287     if (This->fDirty) {
00288       /* need to write headers to file */
00289       AVIFILE_SaveFile(This);
00290     }
00291 
00292     if (This->lpFormat != NULL) {
00293       HeapFree(GetProcessHeap(), 0, This->lpFormat);
00294       This->lpFormat = NULL;
00295       This->cbFormat = 0;
00296     }
00297     if (This->extra.lp != NULL) {
00298       HeapFree(GetProcessHeap(), 0, This->extra.lp);
00299       This->extra.lp = NULL;
00300       This->extra.cb = 0;
00301     }
00302     HeapFree(GetProcessHeap(), 0, This->szFileName);
00303     This->szFileName = NULL;
00304     if (This->hmmio != NULL) {
00305       mmioClose(This->hmmio, 0);
00306       This->hmmio = NULL;
00307     }
00308 
00309     HeapFree(GetProcessHeap(), 0, This);
00310     return 0;
00311   }
00312   return ref;
00313 }
00314 
00315 static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, LPAVIFILEINFOW afi,
00316                       LONG size)
00317 {
00318   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00319 
00320   TRACE("(%p,%p,%d)\n",iface,afi,size);
00321 
00322   if (afi == NULL)
00323     return AVIERR_BADPARAM;
00324   if (size < 0)
00325     return AVIERR_BADSIZE;
00326 
00327   /* update file info */
00328   This->fInfo.dwFlags = 0;
00329   This->fInfo.dwCaps  = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
00330   if (This->lpFormat != NULL) {
00331     assert(This->sInfo.dwScale != 0);
00332 
00333     This->fInfo.dwStreams             = 1;
00334     This->fInfo.dwScale               = This->sInfo.dwScale;
00335     This->fInfo.dwRate                = This->sInfo.dwRate;
00336     This->fInfo.dwLength              = This->sInfo.dwLength;
00337     This->fInfo.dwSuggestedBufferSize = This->ckData.cksize;
00338     This->fInfo.dwMaxBytesPerSec =
00339       MulDiv(This->sInfo.dwSampleSize,This->sInfo.dwRate,This->sInfo.dwScale);
00340   }
00341 
00342   memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
00343 
00344   if ((DWORD)size < sizeof(This->fInfo))
00345     return AVIERR_BUFFERTOOSMALL;
00346   return AVIERR_OK;
00347 }
00348 
00349 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
00350                        DWORD fccType, LONG lParam)
00351 {
00352   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00353 
00354   TRACE("(%p,%p,0x%08X,%d)\n", iface, avis, fccType, lParam);
00355 
00356   /* check parameter */
00357   if (avis == NULL)
00358     return AVIERR_BADPARAM;
00359 
00360   *avis = NULL;
00361 
00362   /* Does our stream exists? */
00363   if (lParam != 0 || This->fInfo.dwStreams == 0)
00364     return AVIERR_NODATA;
00365   if (fccType != 0 && fccType != streamtypeAUDIO)
00366     return AVIERR_NODATA;
00367 
00368   *avis = (PAVISTREAM)&This->iAVIStream;
00369   IAVIFile_AddRef(iface);
00370 
00371   return AVIERR_OK;
00372 }
00373 
00374 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
00375                           LPAVISTREAMINFOW asi)
00376 {
00377   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00378 
00379   TRACE("(%p,%p,%p)\n", iface, avis, asi);
00380 
00381   /* check parameters */
00382   if (avis == NULL || asi == NULL)
00383     return AVIERR_BADPARAM;
00384 
00385   *avis = NULL;
00386 
00387   /* We only support one audio stream */
00388   if (This->fInfo.dwStreams != 0 || This->lpFormat != NULL)
00389     return AVIERR_UNSUPPORTED;
00390   if (asi->fccType != streamtypeAUDIO)
00391     return AVIERR_UNSUPPORTED;
00392 
00393   /* Does the user have write permission? */
00394   if ((This->uMode & MMIO_RWMODE) == 0)
00395     return AVIERR_READONLY;
00396 
00397   This->cbFormat = 0;
00398   This->lpFormat = NULL;
00399 
00400   memcpy(&This->sInfo, asi, sizeof(This->sInfo));
00401 
00402   /* make sure streaminfo if okay for us */
00403   This->sInfo.fccHandler          = 0;
00404   This->sInfo.dwFlags             = 0;
00405   This->sInfo.dwCaps              = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
00406   This->sInfo.dwStart             = 0;
00407   This->sInfo.dwInitialFrames     = 0;
00408   This->sInfo.dwFormatChangeCount = 0;
00409   memset(&This->sInfo.rcFrame, 0, sizeof(This->sInfo.rcFrame));
00410 
00411   This->fInfo.dwStreams = 1;
00412   This->fInfo.dwScale   = This->sInfo.dwScale;
00413   This->fInfo.dwRate    = This->sInfo.dwRate;
00414   This->fInfo.dwLength  = This->sInfo.dwLength;
00415 
00416   This->ckData.dwDataOffset = 0;
00417   This->ckData.cksize       = 0;
00418 
00419   *avis = (PAVISTREAM)&This->iAVIStream;
00420   IAVIFile_AddRef(iface);
00421 
00422   return AVIERR_OK;
00423 }
00424 
00425 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid,
00426                        LPVOID lpData, LONG size)
00427 {
00428   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00429 
00430   TRACE("(%p,0x%08X,%p,%d)\n", iface, ckid, lpData, size);
00431 
00432   /* check parameters */
00433   if (lpData == NULL)
00434     return AVIERR_BADPARAM;
00435   if (size < 0)
00436     return AVIERR_BADSIZE;
00437 
00438   /* Do we have write permission? */
00439   if ((This->uMode & MMIO_RWMODE) == 0)
00440     return AVIERR_READONLY;
00441 
00442   This->fDirty = TRUE;
00443 
00444   return WriteExtraChunk(&This->extra, ckid, lpData, size);
00445 }
00446 
00447 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid,
00448                       LPVOID lpData, LONG *size)
00449 {
00450   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00451 
00452   TRACE("(%p,0x%08X,%p,%p)\n", iface, ckid, lpData, size);
00453 
00454   return ReadExtraChunk(&This->extra, ckid, lpData, size);
00455 }
00456 
00457 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
00458 {
00459   TRACE("(%p)\n",iface);
00460 
00461   /* This is only needed for interleaved files.
00462    * We have only one stream, which can't be interleaved.
00463    */
00464   return AVIERR_OK;
00465 }
00466 
00467 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
00468                           LONG lParam)
00469 {
00470   IAVIFileImpl *This = (IAVIFileImpl *)iface;
00471 
00472   TRACE("(%p,0x%08X,%d)\n", iface, fccType, lParam);
00473 
00474   /* check parameter */
00475   if (lParam < 0)
00476     return AVIERR_BADPARAM;
00477 
00478   /* Do we have our audio stream? */
00479   if (lParam != 0 || This->fInfo.dwStreams == 0 ||
00480       (fccType != 0 && fccType != streamtypeAUDIO))
00481     return AVIERR_NODATA;
00482 
00483   /* Have user write permissions? */
00484   if ((This->uMode & MMIO_RWMODE) == 0)
00485     return AVIERR_READONLY;
00486 
00487   HeapFree(GetProcessHeap(), 0, This->lpFormat);
00488   This->lpFormat = NULL;
00489   This->cbFormat = 0;
00490 
00491   /* update infos */
00492   This->ckData.dwDataOffset = 0;
00493   This->ckData.cksize       = 0;
00494 
00495   This->sInfo.dwScale   = 0;
00496   This->sInfo.dwRate    = 0;
00497   This->sInfo.dwLength  = 0;
00498   This->sInfo.dwSuggestedBufferSize = 0;
00499 
00500   This->fInfo.dwStreams = 0;
00501   This->fInfo.dwEditCount++;
00502 
00503   This->fDirty = TRUE;
00504 
00505   return AVIERR_OK;
00506 }
00507 
00508 /***********************************************************************/
00509 
00510 static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface,
00511                             REFIID refiid, LPVOID *obj)
00512 {
00513   IPersistFileImpl *This = (IPersistFileImpl *)iface;
00514 
00515   assert(This->paf != NULL);
00516 
00517   return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
00518 }
00519 
00520 static ULONG   WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
00521 {
00522   IPersistFileImpl *This = (IPersistFileImpl *)iface;
00523 
00524   assert(This->paf != NULL);
00525 
00526   return IAVIFile_AddRef((PAVIFILE)This->paf);
00527 }
00528 
00529 static ULONG   WINAPI IPersistFile_fnRelease(IPersistFile *iface)
00530 {
00531   IPersistFileImpl *This = (IPersistFileImpl *)iface;
00532 
00533   assert(This->paf != NULL);
00534 
00535   return IAVIFile_Release((PAVIFILE)This->paf);
00536 }
00537 
00538 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface,
00539                         LPCLSID pClassID)
00540 {
00541   TRACE("(%p,%p)\n", iface, pClassID);
00542 
00543   if (pClassID == NULL)
00544     return AVIERR_BADPARAM;
00545 
00546   *pClassID = CLSID_WAVFile;
00547 
00548   return AVIERR_OK;
00549 }
00550 
00551 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
00552 {
00553   IPersistFileImpl *This = (IPersistFileImpl *)iface;
00554 
00555   TRACE("(%p)\n", iface);
00556 
00557   assert(This->paf != NULL);
00558 
00559   return (This->paf->fDirty ? S_OK : S_FALSE);
00560 }
00561 
00562 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface,
00563                       LPCOLESTR pszFileName, DWORD dwMode)
00564 {
00565   IAVIFileImpl *This = ((IPersistFileImpl*)iface)->paf;
00566 
00567   WCHAR wszStreamFmt[50];
00568   INT   len;
00569 
00570   TRACE("(%p,%s,0x%08X)\n", iface, debugstr_w(pszFileName), dwMode);
00571 
00572   /* check parameter */
00573   if (pszFileName == NULL)
00574     return AVIERR_BADPARAM;
00575 
00576   assert(This != NULL);
00577   if (This->hmmio != NULL)
00578     return AVIERR_ERROR; /* No reuse of this object for another file! */
00579 
00580   /* remember mode and name */
00581   This->uMode = dwMode;
00582 
00583   len = lstrlenW(pszFileName) + 1;
00584   This->szFileName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00585   if (This->szFileName == NULL)
00586     return AVIERR_MEMORY;
00587   lstrcpyW(This->szFileName, pszFileName);
00588 
00589   /* try to open the file */
00590   This->hmmio = mmioOpenW(This->szFileName, NULL, MMIO_ALLOCBUF | dwMode);
00591   if (This->hmmio == NULL) {
00592     /* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
00593     LPSTR szFileName;
00594     len = WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1,
00595                               NULL, 0, NULL, NULL);
00596     szFileName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
00597     if (szFileName == NULL)
00598       return AVIERR_MEMORY;
00599 
00600     WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1, szFileName,
00601             len, NULL, NULL);
00602 
00603     This->hmmio = mmioOpenA(szFileName, NULL, MMIO_ALLOCBUF | dwMode);
00604     HeapFree(GetProcessHeap(), 0, szFileName);
00605     if (This->hmmio == NULL)
00606       return AVIERR_FILEOPEN;
00607   }
00608 
00609   memset(& This->fInfo, 0, sizeof(This->fInfo));
00610   memset(& This->sInfo, 0, sizeof(This->sInfo));
00611 
00612   LoadStringW(AVIFILE_hModule, IDS_WAVEFILETYPE, This->fInfo.szFileType,
00613           sizeof(This->fInfo.szFileType)/sizeof(This->fInfo.szFileType[0]));
00614   if (LoadStringW(AVIFILE_hModule, IDS_WAVESTREAMFORMAT,
00615           wszStreamFmt, sizeof(wszStreamFmt)/sizeof(wszStreamFmt[0])) > 0) {
00616     wsprintfW(This->sInfo.szName, wszStreamFmt,
00617           AVIFILE_BasenameW(This->szFileName));
00618   }
00619 
00620   /* should we create a new file? */
00621   if (dwMode & OF_CREATE) {
00622     /* nothing more to do */
00623     return AVIERR_OK;
00624   } else
00625     return AVIFILE_LoadFile(This);
00626 }
00627 
00628 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
00629                       LPCOLESTR pszFileName,BOOL fRemember)
00630 {
00631   TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
00632 
00633   /* We write directly to disk, so nothing to do. */
00634 
00635   return AVIERR_OK;
00636 }
00637 
00638 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface,
00639                            LPCOLESTR pszFileName)
00640 {
00641   TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
00642 
00643   /* We write directly to disk, so nothing to do. */
00644 
00645   return AVIERR_OK;
00646 }
00647 
00648 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface,
00649                         LPOLESTR *ppszFileName)
00650 {
00651   IPersistFileImpl *This = (IPersistFileImpl *)iface;
00652 
00653   TRACE("(%p,%p)\n", iface, ppszFileName);
00654 
00655   if (ppszFileName == NULL)
00656     return AVIERR_BADPARAM;
00657 
00658   *ppszFileName = NULL;
00659 
00660   assert(This->paf != NULL);
00661 
00662   if (This->paf->szFileName != NULL) {
00663     int len = lstrlenW(This->paf->szFileName) + 1;
00664 
00665     *ppszFileName = CoTaskMemAlloc(len * sizeof(WCHAR));
00666     if (*ppszFileName == NULL)
00667       return AVIERR_MEMORY;
00668 
00669     strcpyW(*ppszFileName, This->paf->szFileName);
00670   }
00671 
00672   return AVIERR_OK;
00673 }
00674 
00675 /***********************************************************************/
00676 
00677 static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface,
00678                           REFIID refiid, LPVOID *obj)
00679 {
00680   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
00681 
00682   assert(This->paf != NULL);
00683 
00684   return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
00685 }
00686 
00687 static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
00688 {
00689   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
00690 
00691   assert(This->paf != NULL);
00692 
00693   return IAVIFile_AddRef((PAVIFILE)This->paf);
00694 }
00695 
00696 static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface)
00697 {
00698   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
00699 
00700   assert(This->paf != NULL);
00701 
00702   return IAVIFile_Release((PAVIFILE)This->paf);
00703 }
00704 
00705 static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
00706                       LPARAM lParam2)
00707 {
00708   TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
00709 
00710   /* This IAVIStream interface needs an WAVFile */
00711   return AVIERR_UNSUPPORTED;
00712 }
00713 
00714 static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
00715                     LONG size)
00716 {
00717   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
00718 
00719   TRACE("(%p,%p,%d)\n", iface, psi, size);
00720 
00721   if (psi == NULL)
00722     return AVIERR_BADPARAM;
00723   if (size < 0)
00724     return AVIERR_BADSIZE;
00725 
00726   memcpy(psi, &This->paf->sInfo, min((DWORD)size, sizeof(This->paf->sInfo)));
00727 
00728   if ((DWORD)size < sizeof(This->paf->sInfo))
00729     return AVIERR_BUFFERTOOSMALL;
00730   return AVIERR_OK;
00731 }
00732 
00733 static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos,
00734                        LONG flags)
00735 {
00736   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
00737 
00738   TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
00739 
00740   /* Do we have data? */
00741   if (This->lpFormat == NULL)
00742     return -1;
00743 
00744   /* We don't have an index */
00745   if (flags & FIND_INDEX)
00746     return -1;
00747 
00748   if (flags & FIND_FROM_START) {
00749     pos = This->sInfo.dwStart;
00750     flags &= ~(FIND_FROM_START|FIND_PREV);
00751     flags |= FIND_NEXT;
00752   }
00753 
00754   if (flags & FIND_FORMAT) {
00755     if ((flags & FIND_NEXT) && pos > 0)
00756       pos = -1;
00757     else
00758       pos = 0;
00759   }
00760 
00761   if ((flags & FIND_RET) == FIND_LENGTH ||
00762       (flags & FIND_RET) == FIND_SIZE)
00763     return This->sInfo.dwSampleSize;
00764   if ((flags & FIND_RET) == FIND_OFFSET)
00765     return This->ckData.dwDataOffset + pos * This->sInfo.dwSampleSize;
00766 
00767   return pos;
00768 }
00769 
00770 static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
00771                           LPVOID format, LONG *formatsize)
00772 {
00773   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
00774 
00775   TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
00776 
00777   if (formatsize == NULL)
00778     return AVIERR_BADPARAM;
00779 
00780   /* only interested in needed buffersize? */
00781   if (format == NULL || *formatsize <= 0) {
00782     *formatsize = This->paf->cbFormat;
00783 
00784     return AVIERR_OK;
00785   }
00786 
00787   /* copy initial format (only as much as will fit) */
00788   memcpy(format, This->paf->lpFormat, min(*formatsize, This->paf->cbFormat));
00789   if (*formatsize < This->paf->cbFormat) {
00790     *formatsize = This->paf->cbFormat;
00791     return AVIERR_BUFFERTOOSMALL;
00792   }
00793 
00794   *formatsize = This->paf->cbFormat;
00795   return AVIERR_OK;
00796 }
00797 
00798 static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
00799                          LPVOID format, LONG formatsize)
00800 {
00801   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
00802 
00803   TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
00804 
00805   /* check parameters */
00806   if (format == NULL || formatsize <= sizeof(PCMWAVEFORMAT))
00807     return AVIERR_BADPARAM;
00808 
00809   /* We can only do this to an empty wave file, but ignore call
00810    * if still same format */
00811   if (This->lpFormat != NULL) {
00812     if (formatsize != This->cbFormat ||
00813     memcmp(format, This->lpFormat, formatsize) != 0)
00814       return AVIERR_UNSUPPORTED;
00815 
00816     return AVIERR_OK;
00817   }
00818 
00819   /* only support start at position 0 */
00820   if (pos != 0)
00821     return AVIERR_UNSUPPORTED;
00822 
00823   /* Do we have write permission? */
00824   if ((This->uMode & MMIO_RWMODE) == 0)
00825     return AVIERR_READONLY;
00826 
00827   /* get memory for format and copy it */
00828   This->lpFormat = HeapAlloc(GetProcessHeap(), 0, formatsize);
00829   if (This->lpFormat == NULL)
00830     return AVIERR_MEMORY;
00831 
00832   This->cbFormat = formatsize;
00833   memcpy(This->lpFormat, format, formatsize);
00834 
00835   /* update info's about 'data' chunk */
00836   This->ckData.dwDataOffset = formatsize + 7 * sizeof(DWORD);
00837   This->ckData.cksize       = 0;
00838 
00839   /* for non-pcm format we need also a 'fact' chunk */
00840   if (This->lpFormat->wFormatTag != WAVE_FORMAT_PCM)
00841     This->ckData.dwDataOffset += 3 * sizeof(DWORD);
00842 
00843   /* update stream and file info */
00844   This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
00845   This->sInfo.dwScale      = This->lpFormat->nBlockAlign;
00846   This->sInfo.dwRate       = This->lpFormat->nAvgBytesPerSec;
00847   This->sInfo.dwLength     = 0;
00848   This->sInfo.dwSuggestedBufferSize = 0;
00849 
00850   return AVIERR_OK;
00851 }
00852 
00853 static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,
00854                     LONG samples, LPVOID buffer,
00855                     LONG buffersize, LPLONG bytesread,
00856                     LPLONG samplesread)
00857 {
00858   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
00859 
00860   TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface, start, samples, buffer,
00861     buffersize, bytesread, samplesread);
00862 
00863   /* clear return parameters if given */
00864   if (bytesread != NULL)
00865     *bytesread = 0;
00866   if (samplesread != NULL)
00867     *samplesread = 0;
00868 
00869   /* positions without data */
00870   if (start < 0 || (DWORD)start > This->sInfo.dwLength)
00871     return AVIERR_OK;
00872 
00873   /* check samples */
00874   if (samples < 0)
00875     samples = 0;
00876   if (buffersize > 0) {
00877     if (samples > 0)
00878       samples = min((DWORD)samples, buffersize / This->sInfo.dwSampleSize);
00879     else
00880       samples = buffersize / This->sInfo.dwSampleSize;
00881   }
00882 
00883   /* limit to end of stream */
00884   if ((DWORD)(start + samples) > This->sInfo.dwLength)
00885     samples = This->sInfo.dwLength - start;
00886 
00887   /* request only the sizes? */
00888   if (buffer == NULL || buffersize <= 0) {
00889     /* then I need at least one parameter for it */
00890     if (bytesread == NULL && samplesread == NULL)
00891       return AVIERR_BADPARAM;
00892 
00893     if (bytesread != NULL)
00894       *bytesread = samples * This->sInfo.dwSampleSize;
00895     if (samplesread != NULL)
00896       *samplesread = samples;
00897 
00898     return AVIERR_OK;
00899   }
00900 
00901   /* nothing to read? */
00902   if (samples == 0)
00903     return AVIERR_OK;
00904 
00905   /* Can I read at least one sample? */
00906   if ((DWORD)buffersize < This->sInfo.dwSampleSize)
00907     return AVIERR_BUFFERTOOSMALL;
00908 
00909   buffersize = samples * This->sInfo.dwSampleSize;
00910 
00911   if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
00912            + start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
00913     return AVIERR_FILEREAD;
00914   if (mmioRead(This->hmmio, buffer, buffersize) != buffersize)
00915     return AVIERR_FILEREAD;
00916 
00917   /* fill out return parameters if given */
00918   if (bytesread != NULL)
00919     *bytesread = buffersize;
00920   if (samplesread != NULL)
00921     *samplesread = samples;  
00922 
00923   return AVIERR_OK;
00924 }
00925 
00926 static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start,
00927                      LONG samples, LPVOID buffer,
00928                      LONG buffersize, DWORD flags,
00929                      LPLONG sampwritten,
00930                      LPLONG byteswritten)
00931 {
00932   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
00933 
00934   TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface, start, samples,
00935     buffer, buffersize, flags, sampwritten, byteswritten);
00936 
00937   /* clear return parameters if given */
00938   if (sampwritten != NULL)
00939     *sampwritten = 0;
00940   if (byteswritten != NULL)
00941     *byteswritten = 0;
00942 
00943   /* check parameters */
00944   if (buffer == NULL && (buffersize > 0 || samples > 0))
00945     return AVIERR_BADPARAM;
00946 
00947   /* Do we have write permission? */
00948   if ((This->uMode & MMIO_RWMODE) == 0)
00949     return AVIERR_READONLY;
00950 
00951   /* < 0 means "append" */
00952   if (start < 0)
00953     start = This->sInfo.dwStart + This->sInfo.dwLength;
00954 
00955   /* check buffersize -- must multiple of samplesize */
00956   if (buffersize & ~(This->sInfo.dwSampleSize - 1))
00957     return AVIERR_BADSIZE;
00958 
00959   /* do we have anything to write? */
00960   if (buffer != NULL && buffersize > 0) {
00961     This->fDirty = 1;
00962 
00963     if (mmioSeek(This->hmmio, This->ckData.dwDataOffset +
00964          start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
00965       return AVIERR_FILEWRITE;
00966     if (mmioWrite(This->hmmio, buffer, buffersize) != buffersize)
00967       return AVIERR_FILEWRITE;
00968 
00969     This->sInfo.dwLength = max(This->sInfo.dwLength, (DWORD)start + samples);
00970     This->ckData.cksize  = max(This->ckData.cksize,
00971                    start * This->sInfo.dwSampleSize + buffersize);
00972 
00973     /* fill out return parameters if given */
00974     if (sampwritten != NULL)
00975       *sampwritten = samples;
00976     if (byteswritten != NULL)
00977       *byteswritten = buffersize;
00978   }
00979 
00980   return AVIERR_OK;
00981 }
00982 
00983 static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start,
00984                       LONG samples)
00985 {
00986   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
00987 
00988   TRACE("(%p,%d,%d)\n", iface, start, samples);
00989 
00990   /* check parameters */
00991   if (start < 0 || samples < 0)
00992     return AVIERR_BADPARAM;
00993 
00994   /* Delete before start of stream? */
00995   if ((DWORD)(start + samples) < This->sInfo.dwStart)
00996     return AVIERR_OK;
00997 
00998   /* Delete after end of stream? */
00999   if ((DWORD)start > This->sInfo.dwLength)
01000     return AVIERR_OK;
01001 
01002   /* For the rest we need write permissions */
01003   if ((This->uMode & MMIO_RWMODE) == 0)
01004     return AVIERR_READONLY;
01005 
01006   if ((DWORD)(start + samples) >= This->sInfo.dwLength) {
01007     /* deletion at end */
01008     samples = This->sInfo.dwLength - start;
01009     This->sInfo.dwLength -= samples;
01010     This->ckData.cksize  -= samples * This->sInfo.dwSampleSize;
01011   } else if ((DWORD)start <= This->sInfo.dwStart) {
01012     /* deletion at start */
01013     samples = This->sInfo.dwStart - start;
01014     start   = This->sInfo.dwStart;
01015     This->ckData.dwDataOffset += samples * This->sInfo.dwSampleSize;
01016     This->ckData.cksize       -= samples * This->sInfo.dwSampleSize;
01017   } else {
01018     /* deletion inside stream -- needs playlist and cue's */
01019     FIXME(": deletion inside of stream not supported!\n");
01020 
01021     return AVIERR_UNSUPPORTED;
01022   }
01023 
01024   This->fDirty = 1;
01025 
01026   return AVIERR_OK;
01027 }
01028 
01029 static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc,
01030                         LPVOID lp, LPLONG lpread)
01031 {
01032   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
01033 
01034   assert(This->paf != NULL);
01035 
01036   return IAVIFile_ReadData((PAVIFILE)This->paf, fcc, lp, lpread);
01037 }
01038 
01039 static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
01040                          LPVOID lp, LONG size)
01041 {
01042   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
01043 
01044   return IAVIFile_WriteData((PAVIFILE)This->paf, fcc, lp, size);
01045 }
01046 
01047 static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
01048                        LPAVISTREAMINFOW info, LONG infolen)
01049 {
01050   FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
01051 
01052   return E_FAIL;
01053 }
01054 
01055 /***********************************************************************/
01056 
01057 static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
01058 {
01059   MMCKINFO ckRIFF;
01060   MMCKINFO ck;
01061 
01062   This->sInfo.dwLength = 0; /* just to be sure */
01063   This->fDirty = FALSE;
01064 
01065   /* search for RIFF chunk */
01066   ckRIFF.fccType = 0; /* find any */
01067   if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
01068     return AVIFILE_LoadSunFile(This);
01069   }
01070 
01071   if (ckRIFF.fccType != formtypeWAVE)
01072     return AVIERR_BADFORMAT;
01073 
01074   /* search WAVE format chunk */
01075   ck.ckid = ckidWAVEFORMAT;
01076   if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck,
01077                  &ckRIFF, MMIO_FINDCHUNK) != S_OK)
01078     return AVIERR_FILEREAD;
01079 
01080   /* get memory for format and read it */
01081   This->lpFormat = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
01082   if (This->lpFormat == NULL)
01083     return AVIERR_FILEREAD;
01084   This->cbFormat = ck.cksize;
01085 
01086   if (mmioRead(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
01087     return AVIERR_FILEREAD;
01088   if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
01089     return AVIERR_FILEREAD;
01090 
01091   /* Non-pcm formats have a fact chunk.
01092    * We don't need it, so simply add it to the extra chunks.
01093    */
01094 
01095   /* find the big data chunk */
01096   This->ckData.ckid = ckidWAVEDATA;
01097   if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &This->ckData,
01098                  &ckRIFF, MMIO_FINDCHUNK) != S_OK)
01099     return AVIERR_FILEREAD;
01100 
01101   memset(&This->sInfo, 0, sizeof(This->sInfo));
01102   This->sInfo.fccType      = streamtypeAUDIO;
01103   This->sInfo.dwRate       = This->lpFormat->nAvgBytesPerSec;
01104   This->sInfo.dwSampleSize =
01105     This->sInfo.dwScale    = This->lpFormat->nBlockAlign;
01106   This->sInfo.dwLength     = This->ckData.cksize / This->lpFormat->nBlockAlign;
01107   This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
01108 
01109   This->fInfo.dwStreams = 1;
01110 
01111   if (mmioAscend(This->hmmio, &This->ckData, 0) != S_OK) {
01112     /* seems to be truncated */
01113     WARN(": file seems to be truncated!\n");
01114     This->ckData.cksize  = mmioSeek(This->hmmio, 0, SEEK_END) -
01115       This->ckData.dwDataOffset;
01116     This->sInfo.dwLength = This->ckData.cksize / This->lpFormat->nBlockAlign;
01117     This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
01118   }
01119 
01120   /* ignore errors */
01121   FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck, &ckRIFF, 0);
01122 
01123   return AVIERR_OK;
01124 }
01125 
01126 static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This)
01127 {
01128   SUNAUDIOHEADER auhdr;
01129 
01130   mmioSeek(This->hmmio, 0, SEEK_SET);
01131   if (mmioRead(This->hmmio, (HPSTR)&auhdr, sizeof(auhdr)) != sizeof(auhdr))
01132     return AVIERR_FILEREAD;
01133 
01134   if (auhdr.fccType == 0x0064732E) {
01135     /* header in little endian */
01136     This->ckData.dwDataOffset = LE2H_DWORD(auhdr.offset);
01137     This->ckData.cksize       = LE2H_DWORD(auhdr.size);
01138 
01139     auhdr.encoding   = LE2H_DWORD(auhdr.encoding);
01140     auhdr.sampleRate = LE2H_DWORD(auhdr.sampleRate);
01141     auhdr.channels   = LE2H_DWORD(auhdr.channels);
01142   } else if (auhdr.fccType == mmioFOURCC('.','s','n','d')) {
01143     /* header in big endian */
01144     This->ckData.dwDataOffset = BE2H_DWORD(auhdr.offset);
01145     This->ckData.cksize       = BE2H_DWORD(auhdr.size);
01146 
01147     auhdr.encoding   = BE2H_DWORD(auhdr.encoding);
01148     auhdr.sampleRate = BE2H_DWORD(auhdr.sampleRate);
01149     auhdr.channels   = BE2H_DWORD(auhdr.channels);
01150   } else
01151     return AVIERR_FILEREAD;
01152 
01153   if (auhdr.channels < 1)
01154     return AVIERR_BADFORMAT;
01155 
01156   /* get size of header */
01157   switch(auhdr.encoding) {
01158   case AU_ENCODING_ADPCM_G721_32:
01159     This->cbFormat = sizeof(G721_ADPCMWAVEFORMAT); break;
01160   case AU_ENCODING_ADPCM_G723_24:
01161     This->cbFormat = sizeof(G723_ADPCMWAVEFORMAT); break;
01162   case AU_ENCODING_ADPCM_G722:
01163   case AU_ENCODING_ADPCM_G723_5:
01164     WARN("unsupported Sun audio format %d\n", auhdr.encoding);
01165     return AVIERR_UNSUPPORTED; /* FIXME */
01166   default:
01167     This->cbFormat = sizeof(WAVEFORMATEX); break;
01168   };
01169 
01170   This->lpFormat = HeapAlloc(GetProcessHeap(), 0, This->cbFormat);
01171   if (This->lpFormat == NULL)
01172     return AVIERR_MEMORY;
01173 
01174   This->lpFormat->nChannels      = auhdr.channels;
01175   This->lpFormat->nSamplesPerSec = auhdr.sampleRate;
01176   switch(auhdr.encoding) {
01177   case AU_ENCODING_ULAW_8:
01178     This->lpFormat->wFormatTag     = WAVE_FORMAT_MULAW;
01179     This->lpFormat->wBitsPerSample = 8;
01180     break;
01181   case AU_ENCODING_PCM_8:
01182     This->lpFormat->wFormatTag     = WAVE_FORMAT_PCM;
01183     This->lpFormat->wBitsPerSample = 8;
01184     break;
01185   case AU_ENCODING_PCM_16:
01186     This->lpFormat->wFormatTag     = WAVE_FORMAT_PCM;
01187     This->lpFormat->wBitsPerSample = 16;
01188     break;
01189   case AU_ENCODING_PCM_24:
01190     This->lpFormat->wFormatTag     = WAVE_FORMAT_PCM;
01191     This->lpFormat->wBitsPerSample = 24;
01192     break;
01193   case AU_ENCODING_PCM_32:
01194     This->lpFormat->wFormatTag     = WAVE_FORMAT_PCM;
01195     This->lpFormat->wBitsPerSample = 32;
01196     break;
01197   case AU_ENCODING_ALAW_8:
01198     This->lpFormat->wFormatTag     = WAVE_FORMAT_ALAW;
01199     This->lpFormat->wBitsPerSample = 8;
01200     break;
01201   case AU_ENCODING_ADPCM_G721_32:
01202     This->lpFormat->wFormatTag     = WAVE_FORMAT_G721_ADPCM;
01203     This->lpFormat->wBitsPerSample = (3*5*8);
01204     This->lpFormat->nBlockAlign    = 15*15*8;
01205     This->lpFormat->cbSize         = sizeof(WORD);
01206     ((LPG721_ADPCMWAVEFORMAT)This->lpFormat)->nAuxBlockSize = 0;
01207     break;
01208   case AU_ENCODING_ADPCM_G723_24:
01209     This->lpFormat->wFormatTag     = WAVE_FORMAT_G723_ADPCM;
01210     This->lpFormat->wBitsPerSample = (3*5*8);
01211     This->lpFormat->nBlockAlign    = 15*15*8;
01212     This->lpFormat->cbSize         = 2*sizeof(WORD);
01213     ((LPG723_ADPCMWAVEFORMAT)This->lpFormat)->cbExtraSize   = 0;
01214     ((LPG723_ADPCMWAVEFORMAT)This->lpFormat)->nAuxBlockSize = 0;
01215     break;
01216   default:
01217     WARN("unsupported Sun audio format %d\n", auhdr.encoding);
01218     return AVIERR_UNSUPPORTED;
01219   };
01220 
01221   This->lpFormat->nBlockAlign =
01222     (This->lpFormat->nChannels * This->lpFormat->wBitsPerSample) / 8;
01223   if (This->lpFormat->nBlockAlign == 0 && This->lpFormat->wBitsPerSample < 8)
01224     This->lpFormat->nBlockAlign++;
01225   This->lpFormat->nAvgBytesPerSec =
01226     This->lpFormat->nBlockAlign * This->lpFormat->nSamplesPerSec;
01227 
01228   This->fDirty = 0;
01229 
01230   This->sInfo.fccType               = streamtypeAUDIO;
01231   This->sInfo.fccHandler            = 0;
01232   This->sInfo.dwFlags               = 0;
01233   This->sInfo.wPriority             = 0;
01234   This->sInfo.wLanguage             = 0;
01235   This->sInfo.dwInitialFrames       = 0;
01236   This->sInfo.dwScale               = This->lpFormat->nBlockAlign;
01237   This->sInfo.dwRate                = This->lpFormat->nAvgBytesPerSec;
01238   This->sInfo.dwStart               = 0;
01239   This->sInfo.dwLength              =
01240     This->ckData.cksize / This->lpFormat->nBlockAlign;
01241   This->sInfo.dwSuggestedBufferSize = This->sInfo.dwLength;
01242   This->sInfo.dwSampleSize          = This->lpFormat->nBlockAlign;
01243 
01244   This->fInfo.dwStreams = 1;
01245   This->fInfo.dwScale   = 1;
01246   This->fInfo.dwRate    = This->lpFormat->nSamplesPerSec;
01247   This->fInfo.dwLength  =
01248     MulDiv(This->ckData.cksize, This->lpFormat->nSamplesPerSec,
01249        This->lpFormat->nAvgBytesPerSec);
01250 
01251   return AVIERR_OK;
01252 }
01253 
01254 static HRESULT AVIFILE_SaveFile(const IAVIFileImpl *This)
01255 {
01256   MMCKINFO ckRIFF;
01257   MMCKINFO ck;
01258 
01259   mmioSeek(This->hmmio, 0, SEEK_SET);
01260 
01261   /* create the RIFF chunk with formtype WAVE */
01262   ckRIFF.fccType = formtypeWAVE;
01263   ckRIFF.cksize  = 0;
01264   if (mmioCreateChunk(This->hmmio, &ckRIFF, MMIO_CREATERIFF) != S_OK)
01265     return AVIERR_FILEWRITE;
01266 
01267   /* the next chunk is the format */
01268   ck.ckid   = ckidWAVEFORMAT;
01269   ck.cksize = This->cbFormat;
01270   if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
01271     return AVIERR_FILEWRITE;
01272   if (This->lpFormat != NULL && This->cbFormat > 0) {
01273     if (mmioWrite(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
01274       return AVIERR_FILEWRITE;
01275   }
01276   if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
01277     return AVIERR_FILEWRITE;
01278 
01279   /* fact chunk is needed for non-pcm waveforms */
01280   if (This->lpFormat != NULL && This->cbFormat > sizeof(PCMWAVEFORMAT) &&
01281       This->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
01282     WAVEFORMATEX wfx;
01283     DWORD        dwFactLength;
01284     HACMSTREAM   has;
01285 
01286     /* try to open an appropriate audio codec to figure out
01287      * data for fact-chunk */
01288     wfx.wFormatTag = WAVE_FORMAT_PCM;
01289     if (acmFormatSuggest(NULL, This->lpFormat, &wfx,
01290              sizeof(wfx), ACM_FORMATSUGGESTF_WFORMATTAG)) {
01291       acmStreamOpen(&has, NULL, This->lpFormat, &wfx, NULL,
01292             0, 0, ACM_STREAMOPENF_NONREALTIME);
01293       acmStreamSize(has, This->ckData.cksize, &dwFactLength,
01294             ACM_STREAMSIZEF_SOURCE);
01295       dwFactLength /= wfx.nBlockAlign;
01296       acmStreamClose(has, 0);
01297 
01298       /* create the fact chunk */
01299       ck.ckid   = ckidWAVEFACT;
01300       ck.cksize = sizeof(dwFactLength);
01301 
01302       /* test for enough space before data chunk */
01303       if (mmioSeek(This->hmmio, 0, SEEK_CUR) > This->ckData.dwDataOffset
01304       - ck.cksize - 4 * sizeof(DWORD))
01305     return AVIERR_FILEWRITE;
01306       if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
01307     return AVIERR_FILEWRITE;
01308       if (mmioWrite(This->hmmio, (HPSTR)&dwFactLength, ck.cksize) != ck.cksize)
01309     return AVIERR_FILEWRITE;
01310       if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
01311     return AVIERR_FILEWRITE;
01312     } else
01313       ERR(": fact chunk is needed for non-pcm files -- currently no codec found, so skipped!\n");
01314   }
01315 
01316   /* if there was extra stuff, we need to fill it with JUNK */
01317   if (mmioSeek(This->hmmio, 0, SEEK_CUR) + 2 * sizeof(DWORD) < This->ckData.dwDataOffset) {
01318     ck.ckid   = ckidAVIPADDING;
01319     ck.cksize = 0;
01320     if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
01321       return AVIERR_FILEWRITE;
01322 
01323     if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
01324          - 2 * sizeof(DWORD), SEEK_SET) == -1)
01325       return AVIERR_FILEWRITE;
01326     if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
01327       return AVIERR_FILEWRITE;
01328   }
01329 
01330   /* create the data chunk */
01331   ck.ckid   = ckidWAVEDATA;
01332   ck.cksize = This->ckData.cksize;
01333   if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
01334     return AVIERR_FILEWRITE;
01335   if (mmioSeek(This->hmmio, This->ckData.cksize, SEEK_CUR) == -1)
01336     return AVIERR_FILEWRITE;
01337   if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
01338     return AVIERR_FILEWRITE;
01339 
01340   /* some optional extra chunks? */
01341   if (This->extra.lp != NULL && This->extra.cb > 0) {
01342     /* chunk headers are already in structure */
01343     if (mmioWrite(This->hmmio, This->extra.lp, This->extra.cb) != This->extra.cb)
01344       return AVIERR_FILEWRITE;
01345   }
01346 
01347   /* close RIFF chunk */
01348   if (mmioAscend(This->hmmio, &ckRIFF, 0) != S_OK)
01349     return AVIERR_FILEWRITE;
01350   if (mmioFlush(This->hmmio, 0) != S_OK)
01351     return AVIERR_FILEWRITE;
01352 
01353   return AVIERR_OK;
01354 }

Generated on Sun May 27 2012 04:22:52 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.