Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwavfile.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
1.7.6.1
|