2 * Copyright 2002 Michael Günnewig
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "avifile_private.h"
31 #include "extrachunk.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(avifile
);
37 /***********************************************************************/
39 #define formtypeWAVE mmioFOURCC('W','A','V','E')
40 #define ckidWAVEFORMAT mmioFOURCC('f','m','t',' ')
41 #define ckidWAVEFACT mmioFOURCC('f','a','c','t')
42 #define ckidWAVEDATA mmioFOURCC('d','a','t','a')
44 /***********************************************************************/
46 static HRESULT WINAPI
IAVIFile_fnQueryInterface(IAVIFile
* iface
,REFIID refiid
,LPVOID
*obj
);
47 static ULONG WINAPI
IAVIFile_fnAddRef(IAVIFile
* iface
);
48 static ULONG WINAPI
IAVIFile_fnRelease(IAVIFile
* iface
);
49 static HRESULT WINAPI
IAVIFile_fnInfo(IAVIFile
*iface
,AVIFILEINFOW
*afi
,LONG size
);
50 static HRESULT WINAPI
IAVIFile_fnGetStream(IAVIFile
*iface
,PAVISTREAM
*avis
,DWORD fccType
,LONG lParam
);
51 static HRESULT WINAPI
IAVIFile_fnCreateStream(IAVIFile
*iface
,PAVISTREAM
*avis
,AVISTREAMINFOW
*asi
);
52 static HRESULT WINAPI
IAVIFile_fnWriteData(IAVIFile
*iface
,DWORD ckid
,LPVOID lpData
,LONG size
);
53 static HRESULT WINAPI
IAVIFile_fnReadData(IAVIFile
*iface
,DWORD ckid
,LPVOID lpData
,LONG
*size
);
54 static HRESULT WINAPI
IAVIFile_fnEndRecord(IAVIFile
*iface
);
55 static HRESULT WINAPI
IAVIFile_fnDeleteStream(IAVIFile
*iface
,DWORD fccType
,LONG lParam
);
57 struct ICOM_VTABLE(IAVIFile
) iwavft
= {
58 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
59 IAVIFile_fnQueryInterface
,
64 IAVIFile_fnCreateStream
,
68 IAVIFile_fnDeleteStream
71 static HRESULT WINAPI
IPersistFile_fnQueryInterface(IPersistFile
*iface
,REFIID refiid
,LPVOID
*obj
);
72 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
*iface
);
73 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
*iface
);
74 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
*iface
,CLSID
*pClassID
);
75 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
*iface
);
76 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
*iface
,LPCOLESTR pszFileName
,DWORD dwMode
);
77 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
*iface
,LPCOLESTR pszFileName
,BOOL fRemember
);
78 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
*iface
,LPCOLESTR pszFileName
);
79 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
*iface
,LPOLESTR
*ppszFileName
);
81 struct ICOM_VTABLE(IPersistFile
) iwavpft
= {
82 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
83 IPersistFile_fnQueryInterface
,
84 IPersistFile_fnAddRef
,
85 IPersistFile_fnRelease
,
86 IPersistFile_fnGetClassID
,
87 IPersistFile_fnIsDirty
,
90 IPersistFile_fnSaveCompleted
,
91 IPersistFile_fnGetCurFile
94 static HRESULT WINAPI
IAVIStream_fnQueryInterface(IAVIStream
*iface
,REFIID refiid
,LPVOID
*obj
);
95 static ULONG WINAPI
IAVIStream_fnAddRef(IAVIStream
*iface
);
96 static ULONG WINAPI
IAVIStream_fnRelease(IAVIStream
* iface
);
97 static HRESULT WINAPI
IAVIStream_fnCreate(IAVIStream
*iface
,LPARAM lParam1
,LPARAM lParam2
);
98 static HRESULT WINAPI
IAVIStream_fnInfo(IAVIStream
*iface
,AVISTREAMINFOW
*psi
,LONG size
);
99 static LONG WINAPI
IAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,LONG flags
);
100 static HRESULT WINAPI
IAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG
*formatsize
);
101 static HRESULT WINAPI
IAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG formatsize
);
102 static HRESULT WINAPI
IAVIStream_fnRead(IAVIStream
*iface
,LONG start
,LONG samples
,LPVOID buffer
,LONG buffersize
,LONG
*bytesread
,LONG
*samplesread
);
103 static HRESULT WINAPI
IAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,LONG samples
,LPVOID buffer
,LONG buffersize
,DWORD flags
,LONG
*sampwritten
,LONG
*byteswritten
);
104 static HRESULT WINAPI
IAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,LONG samples
);
105 static HRESULT WINAPI
IAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,LPVOID lp
,LONG
*lpread
);
106 static HRESULT WINAPI
IAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,LPVOID lp
,LONG size
);
107 static HRESULT WINAPI
IAVIStream_fnSetInfo(IAVIStream
*iface
,AVISTREAMINFOW
*info
,LONG infolen
);
109 struct ICOM_VTABLE(IAVIStream
) iwavst
= {
110 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
111 IAVIStream_fnQueryInterface
,
113 IAVIStream_fnRelease
,
116 IAVIStream_fnFindSample
,
117 IAVIStream_fnReadFormat
,
118 IAVIStream_fnSetFormat
,
122 IAVIStream_fnReadData
,
123 IAVIStream_fnWriteData
,
127 typedef struct _IAVIFileImpl IAVIFileImpl
;
129 typedef struct _IPersistFileImpl
{
131 ICOM_VFIELD(IPersistFile
);
133 /* IPersistFile stuff */
137 typedef struct _IAVIStreamImpl
{
139 ICOM_VFIELD(IAVIStream
);
141 /* IAVIStream stuff */
145 struct _IAVIFileImpl
{
147 ICOM_VFIELD(IAVIFile
);
150 /* IAVIFile, IAVIStream stuff... */
151 IPersistFileImpl iPersistFile
;
152 IAVIStreamImpl iAVIStream
;
155 AVISTREAMINFOW sInfo
;
157 LPWAVEFORMATEX lpFormat
;
164 /* IPersistFile stuff ... */
171 /***********************************************************************/
173 static HRESULT
AVIFILE_LoadFile(IAVIFileImpl
*This
);
174 static HRESULT
AVIFILE_LoadSunFile(IAVIFileImpl
*This
);
175 static HRESULT
AVIFILE_SaveFile(IAVIFileImpl
*This
);
177 HRESULT
AVIFILE_CreateWAVFile(REFIID riid
, LPVOID
*ppv
)
182 assert(riid
!= NULL
&& ppv
!= NULL
);
186 pfile
= (IAVIFileImpl
*)LocalAlloc(LPTR
, sizeof(IAVIFileImpl
));
188 return AVIERR_MEMORY
;
190 ICOM_VTBL(pfile
) = &iwavft
;
191 ICOM_VTBL(&pfile
->iPersistFile
) = &iwavpft
;
192 ICOM_VTBL(&pfile
->iAVIStream
) = &iwavst
;
194 pfile
->iPersistFile
.paf
= pfile
;
195 pfile
->iAVIStream
.paf
= pfile
;
197 hr
= IUnknown_QueryInterface((IUnknown
*)pfile
, riid
, ppv
);
199 LocalFree((HLOCAL
)pfile
);
204 static HRESULT WINAPI
IAVIFile_fnQueryInterface(IAVIFile
*iface
, REFIID refiid
,
207 ICOM_THIS(IAVIFileImpl
,iface
);
209 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(refiid
), obj
);
211 if (IsEqualGUID(&IID_IUnknown
, refiid
) ||
212 IsEqualGUID(&IID_IAVIFile
, refiid
)) {
215 } else if (This
->fInfo
.dwStreams
== 1 &&
216 IsEqualGUID(&IID_IAVIStream
, refiid
)) {
217 *obj
= &This
->iAVIStream
;
219 } else if (IsEqualGUID(&IID_IPersistFile
, refiid
)) {
220 *obj
= &This
->iPersistFile
;
224 return OLE_E_ENUM_NOMORE
;
227 static ULONG WINAPI
IAVIFile_fnAddRef(IAVIFile
*iface
)
229 ICOM_THIS(IAVIFileImpl
,iface
);
231 TRACE("(%p)\n",iface
);
233 return ++(This
->ref
);
236 static ULONG WINAPI
IAVIFile_fnRelease(IAVIFile
*iface
)
238 ICOM_THIS(IAVIFileImpl
,iface
);
240 TRACE("(%p)\n",iface
);
242 if (!--(This
->ref
)) {
244 /* need to write headers to file */
245 AVIFILE_SaveFile(This
);
248 if (This
->lpFormat
!= NULL
) {
249 GlobalFreePtr(This
->lpFormat
);
250 This
->lpFormat
= NULL
;
253 if (This
->extra
.lp
!= NULL
) {
254 GlobalFreePtr(This
->extra
.lp
);
255 This
->extra
.lp
= NULL
;
258 if (This
->szFileName
!= NULL
) {
259 LocalFree((HLOCAL
)This
->szFileName
);
260 This
->szFileName
= NULL
;
262 if (This
->hmmio
!= (HMMIO
)NULL
) {
263 mmioClose(This
->hmmio
, 0);
264 This
->hmmio
= (HMMIO
)NULL
;
267 LocalFree((HLOCAL
)This
);
273 static HRESULT WINAPI
IAVIFile_fnInfo(IAVIFile
*iface
, LPAVIFILEINFOW afi
,
276 ICOM_THIS(IAVIFileImpl
,iface
);
278 TRACE("(%p,%p,%ld)\n",iface
,afi
,size
);
281 return AVIERR_BADPARAM
;
283 return AVIERR_BADSIZE
;
285 /* update file info */
286 This
->fInfo
.dwFlags
= 0;
287 This
->fInfo
.dwCaps
= AVIFILECAPS_CANREAD
|AVIFILECAPS_CANWRITE
;
288 if (This
->lpFormat
!= NULL
) {
289 assert(This
->sInfo
.dwScale
!= 0);
291 This
->fInfo
.dwStreams
= 1;
292 This
->fInfo
.dwScale
= This
->sInfo
.dwScale
;
293 This
->fInfo
.dwRate
= This
->sInfo
.dwRate
;
294 This
->fInfo
.dwLength
= This
->sInfo
.dwLength
;
295 This
->fInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
296 This
->fInfo
.dwMaxBytesPerSec
=
297 MulDiv(This
->sInfo
.dwSampleSize
,This
->sInfo
.dwRate
,This
->sInfo
.dwScale
);
300 memcpy(afi
, &This
->fInfo
, min(size
, sizeof(This
->fInfo
)));
302 if (size
< sizeof(This
->fInfo
))
303 return AVIERR_BUFFERTOOSMALL
;
307 static HRESULT WINAPI
IAVIFile_fnGetStream(IAVIFile
*iface
, PAVISTREAM
*avis
,
308 DWORD fccType
, LONG lParam
)
310 ICOM_THIS(IAVIFileImpl
,iface
);
312 TRACE("(%p,%p,0x%08lX,%ld)\n", iface
, avis
, fccType
, lParam
);
314 /* check parameter */
316 return AVIERR_BADPARAM
;
320 /* Does our stream exists? */
321 if (lParam
!= 0 || This
->fInfo
.dwStreams
== 0)
322 return AVIERR_NODATA
;
323 if (fccType
!= 0 && fccType
!= streamtypeAUDIO
)
324 return AVIERR_NODATA
;
326 *avis
= (PAVISTREAM
)&This
->iAVIStream
;
327 IAVIFile_AddRef(iface
);
332 static HRESULT WINAPI
IAVIFile_fnCreateStream(IAVIFile
*iface
,PAVISTREAM
*avis
,
333 LPAVISTREAMINFOW asi
)
335 ICOM_THIS(IAVIFileImpl
,iface
);
337 TRACE("(%p,%p,%p)\n", iface
, avis
, asi
);
339 /* check parameters */
340 if (avis
== NULL
|| asi
== NULL
)
341 return AVIERR_BADPARAM
;
345 /* We only support one audio stream */
346 if (This
->fInfo
.dwStreams
!= 0 || This
->lpFormat
!= NULL
)
347 return AVIERR_UNSUPPORTED
;
348 if (asi
->fccType
!= streamtypeAUDIO
)
349 return AVIERR_UNSUPPORTED
;
351 /* Does the user have write permission? */
352 if ((This
->uMode
& MMIO_RWMODE
) == 0)
353 return AVIERR_READONLY
;
356 This
->lpFormat
= NULL
;
358 memcpy(&This
->sInfo
, asi
, sizeof(This
->sInfo
));
360 /* make sure streaminfo if okay for us */
361 This
->sInfo
.fccHandler
= 0;
362 This
->sInfo
.dwFlags
= 0;
363 This
->sInfo
.dwCaps
= AVIFILECAPS_CANREAD
|AVIFILECAPS_CANWRITE
;
364 This
->sInfo
.dwStart
= 0;
365 This
->sInfo
.dwInitialFrames
= 0;
366 This
->sInfo
.dwFormatChangeCount
= 0;
367 memset(&This
->sInfo
.rcFrame
, 0, sizeof(This
->sInfo
.rcFrame
));
369 This
->fInfo
.dwStreams
= 1;
370 This
->fInfo
.dwScale
= This
->sInfo
.dwScale
;
371 This
->fInfo
.dwRate
= This
->sInfo
.dwRate
;
372 This
->fInfo
.dwLength
= This
->sInfo
.dwLength
;
374 This
->ckData
.dwDataOffset
= 0;
375 This
->ckData
.cksize
= 0;
377 *avis
= (PAVISTREAM
)&This
->iAVIStream
;
378 IAVIFile_AddRef(iface
);
383 static HRESULT WINAPI
IAVIFile_fnWriteData(IAVIFile
*iface
, DWORD ckid
,
384 LPVOID lpData
, LONG size
)
386 ICOM_THIS(IAVIFileImpl
,iface
);
388 TRACE("(%p,0x%08lX,%p,%ld)\n", iface
, ckid
, lpData
, size
);
390 /* check parameters */
392 return AVIERR_BADPARAM
;
394 return AVIERR_BADSIZE
;
396 /* Do we have write permission? */
397 if ((This
->uMode
& MMIO_RWMODE
) == 0)
398 return AVIERR_READONLY
;
402 return WriteExtraChunk(&This
->extra
, ckid
, lpData
, size
);
405 static HRESULT WINAPI
IAVIFile_fnReadData(IAVIFile
*iface
, DWORD ckid
,
406 LPVOID lpData
, LONG
*size
)
408 ICOM_THIS(IAVIFileImpl
,iface
);
410 TRACE("(%p,0x%08lX,%p,%p)\n", iface
, ckid
, lpData
, size
);
412 return ReadExtraChunk(&This
->extra
, ckid
, lpData
, size
);
415 static HRESULT WINAPI
IAVIFile_fnEndRecord(IAVIFile
*iface
)
417 TRACE("(%p)\n",iface
);
419 /* This is only needed for interleaved files.
420 * We have only one stream, which can't be interleaved.
425 static HRESULT WINAPI
IAVIFile_fnDeleteStream(IAVIFile
*iface
, DWORD fccType
,
428 ICOM_THIS(IAVIFileImpl
,iface
);
430 TRACE("(%p,0x%08lX,%ld)\n", iface
, fccType
, lParam
);
432 /* check parameter */
434 return AVIERR_BADPARAM
;
436 /* Have we our audio stream? */
437 if (lParam
!= 0 || This
->fInfo
.dwStreams
== 0 ||
438 (fccType
!= 0 && fccType
!= streamtypeAUDIO
))
439 return AVIERR_NODATA
;
441 /* Have user write permissions? */
442 if ((This
->uMode
& MMIO_RWMODE
) == 0)
443 return AVIERR_READONLY
;
445 GlobalFreePtr(This
->lpFormat
);
446 This
->lpFormat
= NULL
;
450 This
->ckData
.dwDataOffset
= 0;
451 This
->ckData
.cksize
= 0;
453 This
->sInfo
.dwScale
= 0;
454 This
->sInfo
.dwRate
= 0;
455 This
->sInfo
.dwLength
= 0;
456 This
->sInfo
.dwSuggestedBufferSize
= 0;
458 This
->fInfo
.dwStreams
= 0;
459 This
->fInfo
.dwEditCount
++;
466 /***********************************************************************/
468 static HRESULT WINAPI
IPersistFile_fnQueryInterface(IPersistFile
*iface
,
469 REFIID refiid
, LPVOID
*obj
)
471 ICOM_THIS(IPersistFileImpl
,iface
);
473 assert(This
->paf
!= NULL
);
475 return IAVIFile_QueryInterface((PAVIFILE
)This
->paf
, refiid
, obj
);
478 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
*iface
)
480 ICOM_THIS(IPersistFileImpl
,iface
);
482 assert(This
->paf
!= NULL
);
484 return IAVIFile_AddRef((PAVIFILE
)This
->paf
);
487 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
*iface
)
489 ICOM_THIS(IPersistFileImpl
,iface
);
491 assert(This
->paf
!= NULL
);
493 return IAVIFile_Release((PAVIFILE
)This
->paf
);
496 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
*iface
,
499 TRACE("(%p,%p)\n", iface
, pClassID
);
501 if (pClassID
== NULL
)
502 return AVIERR_BADPARAM
;
504 memcpy(pClassID
, &CLSID_WAVFile
, sizeof(CLSID_WAVFile
));
509 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
*iface
)
511 ICOM_THIS(IPersistFileImpl
,iface
);
513 TRACE("(%p)\n", iface
);
515 assert(This
->paf
!= NULL
);
517 return (This
->paf
->fDirty
? S_OK
: S_FALSE
);
520 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
*iface
,
521 LPCOLESTR pszFileName
, DWORD dwMode
)
523 IAVIFileImpl
*This
= ((IPersistFileImpl
*)iface
)->paf
;
525 WCHAR wszStreamFmt
[50];
528 TRACE("(%p,%s,0x%08lX)\n", iface
, debugstr_w(pszFileName
), dwMode
);
530 /* check parameter */
531 if (pszFileName
== NULL
)
532 return AVIERR_BADPARAM
;
534 assert(This
!= NULL
);
535 if (This
->hmmio
!= (HMMIO
)NULL
)
536 return AVIERR_ERROR
; /* No reuse of this object for another file! */
538 /* remeber mode and name */
539 This
->uMode
= dwMode
;
541 len
= lstrlenW(pszFileName
) + 1;
542 This
->szFileName
= (LPWSTR
)LocalAlloc(LPTR
, len
* sizeof(WCHAR
));
543 if (This
->szFileName
== NULL
)
544 return AVIERR_MEMORY
;
545 lstrcpyW(This
->szFileName
, pszFileName
);
547 /* try to open the file */
548 This
->hmmio
= mmioOpenW(This
->szFileName
, NULL
, MMIO_ALLOCBUF
| dwMode
);
549 if (This
->hmmio
== (HMMIO
)NULL
)
550 return AVIERR_FILEOPEN
;
552 memset(& This
->fInfo
, 0, sizeof(This
->fInfo
));
553 memset(& This
->sInfo
, 0, sizeof(This
->sInfo
));
555 LoadStringW(AVIFILE_hModule
, IDS_WAVEFILETYPE
, This
->fInfo
.szFileType
,
556 sizeof(This
->fInfo
.szFileType
));
557 if (LoadStringW(AVIFILE_hModule
, IDS_WAVESTREAMFORMAT
,
558 wszStreamFmt
, sizeof(wszStreamFmt
)) > 0) {
559 wsprintfW(This
->sInfo
.szName
, wszStreamFmt
,
560 AVIFILE_BasenameW(This
->szFileName
));
563 /* should we create a new file? */
564 if (dwMode
& OF_CREATE
) {
565 /* nothing more to do */
568 return AVIFILE_LoadFile(This
);
571 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
*iface
,
572 LPCOLESTR pszFileName
,BOOL fRemember
)
574 TRACE("(%p,%s,%d)\n", iface
, debugstr_w(pszFileName
), fRemember
);
576 /* We write directly to disk, so nothing to do. */
581 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
*iface
,
582 LPCOLESTR pszFileName
)
584 TRACE("(%p,%s)\n", iface
, debugstr_w(pszFileName
));
586 /* We write directly to disk, so nothing to do. */
591 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
*iface
,
592 LPOLESTR
*ppszFileName
)
594 ICOM_THIS(IPersistFileImpl
,iface
);
596 TRACE("(%p,%p)\n", iface
, ppszFileName
);
598 if (ppszFileName
== NULL
)
599 return AVIERR_BADPARAM
;
601 *ppszFileName
= NULL
;
603 assert(This
->paf
!= NULL
);
605 if (This
->paf
->szFileName
!= NULL
) {
606 int len
= lstrlenW(This
->paf
->szFileName
);
608 *ppszFileName
= (LPOLESTR
)GlobalAllocPtr(GHND
, len
* sizeof(WCHAR
));
609 if (*ppszFileName
== NULL
)
610 return AVIERR_MEMORY
;
612 memcpy(*ppszFileName
, This
->paf
->szFileName
, len
* sizeof(WCHAR
));
618 /***********************************************************************/
620 static HRESULT WINAPI
IAVIStream_fnQueryInterface(IAVIStream
*iface
,
621 REFIID refiid
, LPVOID
*obj
)
623 ICOM_THIS(IAVIStreamImpl
,iface
);
625 assert(This
->paf
!= NULL
);
627 return IAVIFile_QueryInterface((PAVIFILE
)This
->paf
, refiid
, obj
);
630 static ULONG WINAPI
IAVIStream_fnAddRef(IAVIStream
*iface
)
632 ICOM_THIS(IAVIStreamImpl
,iface
);
634 assert(This
->paf
!= NULL
);
636 return IAVIFile_AddRef((PAVIFILE
)This
->paf
);
639 static ULONG WINAPI
IAVIStream_fnRelease(IAVIStream
* iface
)
641 ICOM_THIS(IAVIStreamImpl
,iface
);
643 assert(This
->paf
!= NULL
);
645 return IAVIFile_Release((PAVIFILE
)This
->paf
);
648 static HRESULT WINAPI
IAVIStream_fnCreate(IAVIStream
*iface
, LPARAM lParam1
,
651 TRACE("(%p,0x%08lX,0x%08lX)\n", iface
, lParam1
, lParam2
);
653 /* This IAVIStream interface needs an WAVFile */
654 return AVIERR_UNSUPPORTED
;
657 static HRESULT WINAPI
IAVIStream_fnInfo(IAVIStream
*iface
,LPAVISTREAMINFOW psi
,
660 ICOM_THIS(IAVIStreamImpl
,iface
);
662 TRACE("(%p,%p,%ld)\n", iface
, psi
, size
);
665 return AVIERR_BADPARAM
;
667 return AVIERR_BADSIZE
;
669 memcpy(psi
, &This
->paf
->sInfo
, min(size
, sizeof(This
->paf
->sInfo
)));
671 if (size
< sizeof(This
->paf
->sInfo
))
672 return AVIERR_BUFFERTOOSMALL
;
676 static LONG WINAPI
IAVIStream_fnFindSample(IAVIStream
*iface
, LONG pos
,
679 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
681 TRACE("(%p,%ld,0x%08lX)\n",iface
,pos
,flags
);
683 /* Do we have data? */
684 if (This
->lpFormat
== NULL
)
687 /* We don't have an index */
688 if (flags
& FIND_INDEX
)
691 if (flags
& FIND_FROM_START
) {
692 pos
= This
->sInfo
.dwStart
;
693 flags
&= ~(FIND_FROM_START
|FIND_PREV
);
697 if (flags
& FIND_FORMAT
) {
698 if ((flags
& FIND_NEXT
) && pos
> 0)
704 if (flags
& (FIND_LENGTH
|FIND_SIZE
))
705 return This
->sInfo
.dwSampleSize
;
706 if (flags
& FIND_OFFSET
)
707 return This
->ckData
.dwDataOffset
+ pos
* This
->sInfo
.dwSampleSize
;
712 static HRESULT WINAPI
IAVIStream_fnReadFormat(IAVIStream
*iface
, LONG pos
,
713 LPVOID format
, LONG
*formatsize
)
715 ICOM_THIS(IAVIStreamImpl
,iface
);
717 TRACE("(%p,%ld,%p,%p)\n", iface
, pos
, format
, formatsize
);
719 if (formatsize
== NULL
)
720 return AVIERR_BADPARAM
;
722 /* only interested in needed buffersize? */
723 if (format
== NULL
|| *formatsize
<= 0) {
724 *formatsize
= This
->paf
->cbFormat
;
729 /* copy initial format (only as much as will fit) */
730 memcpy(format
, This
->paf
->lpFormat
, min(*formatsize
, This
->paf
->cbFormat
));
731 if (*formatsize
< This
->paf
->cbFormat
) {
732 *formatsize
= This
->paf
->cbFormat
;
733 return AVIERR_BUFFERTOOSMALL
;
736 *formatsize
= This
->paf
->cbFormat
;
740 static HRESULT WINAPI
IAVIStream_fnSetFormat(IAVIStream
*iface
, LONG pos
,
741 LPVOID format
, LONG formatsize
)
743 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
745 TRACE("(%p,%ld,%p,%ld)\n", iface
, pos
, format
, formatsize
);
747 /* check parameters */
748 if (format
== NULL
|| formatsize
<= sizeof(PCMWAVEFORMAT
))
749 return AVIERR_BADPARAM
;
751 /* We can only do this to an empty wave file, but ignore call
752 * if still same format */
753 if (This
->lpFormat
!= NULL
) {
754 if (formatsize
!= This
->cbFormat
||
755 memcmp(format
, This
->lpFormat
, formatsize
) != 0)
756 return AVIERR_UNSUPPORTED
;
761 /* only support start at position 0 */
763 return AVIERR_UNSUPPORTED
;
765 /* Do we have write permission? */
766 if ((This
->uMode
& MMIO_RWMODE
) == 0)
767 return AVIERR_READONLY
;
769 /* get memory for format and copy it */
770 This
->lpFormat
= (LPWAVEFORMATEX
)GlobalAllocPtr(GMEM_MOVEABLE
, formatsize
);
771 if (This
->lpFormat
== NULL
)
772 return AVIERR_MEMORY
;
774 This
->cbFormat
= formatsize
;
775 memcpy(This
->lpFormat
, format
, formatsize
);
777 /* update info's about 'data' chunk */
778 This
->ckData
.dwDataOffset
= formatsize
+ 7 * sizeof(DWORD
);
779 This
->ckData
.cksize
= 0;
781 /* for non-pcm format we need also a 'fact' chunk */
782 if (This
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
783 This
->ckData
.dwDataOffset
+= 3 * sizeof(DWORD
);
785 /* update stream and file info */
786 This
->sInfo
.dwSampleSize
= This
->lpFormat
->nBlockAlign
;
787 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
788 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
789 This
->sInfo
.dwLength
= 0;
790 This
->sInfo
.dwSuggestedBufferSize
= 0;
795 static HRESULT WINAPI
IAVIStream_fnRead(IAVIStream
*iface
, LONG start
,
796 LONG samples
, LPVOID buffer
,
797 LONG buffersize
, LPLONG bytesread
,
800 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
802 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface
, start
, samples
, buffer
,
803 buffersize
, bytesread
, samplesread
);
805 /* clear return parameters if given */
806 if (bytesread
!= NULL
)
808 if (samplesread
!= NULL
)
811 /* positions without data */
812 if (start
< 0 || start
> This
->sInfo
.dwLength
)
818 if (buffersize
> 0) {
820 samples
= min(samples
, buffersize
/ This
->sInfo
.dwSampleSize
);
822 samples
= buffersize
/ This
->sInfo
.dwSampleSize
;
825 /* limit to end of stream */
826 if (start
+ samples
> This
->sInfo
.dwLength
)
827 samples
= This
->sInfo
.dwLength
- start
;
829 /* request only the sizes? */
830 if (buffer
== NULL
|| buffersize
<= 0) {
831 /* then I need atleast one parameter for it */
832 if (bytesread
== NULL
&& samplesread
== NULL
)
833 return AVIERR_BADPARAM
;
835 if (bytesread
!= NULL
)
836 *bytesread
= samples
* This
->sInfo
.dwSampleSize
;
837 if (samplesread
!= NULL
)
838 *samplesread
= samples
;
843 /* nothing to read? */
847 /* Can I atleast read one sample? */
848 if (buffersize
< This
->sInfo
.dwSampleSize
)
849 return AVIERR_BUFFERTOOSMALL
;
851 buffersize
= samples
* This
->sInfo
.dwSampleSize
;
853 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
854 + start
* This
->sInfo
.dwSampleSize
, SEEK_SET
) == -1)
855 return AVIERR_FILEREAD
;
856 if (mmioRead(This
->hmmio
, (HPSTR
)buffer
, buffersize
) != buffersize
)
857 return AVIERR_FILEREAD
;
859 /* fill out return parameters if given */
860 if (bytesread
!= NULL
)
861 *bytesread
= buffersize
;
862 if (samplesread
!= NULL
)
863 *samplesread
= samples
;
868 static HRESULT WINAPI
IAVIStream_fnWrite(IAVIStream
*iface
, LONG start
,
869 LONG samples
, LPVOID buffer
,
870 LONG buffersize
, DWORD flags
,
874 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
876 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface
, start
, samples
,
877 buffer
, buffersize
, flags
, sampwritten
, byteswritten
);
879 /* clear return parameters if given */
880 if (sampwritten
!= NULL
)
882 if (byteswritten
!= NULL
)
885 /* check parameters */
886 if (buffer
== NULL
&& (buffersize
> 0 || samples
> 0))
887 return AVIERR_BADPARAM
;
889 /* Have we write permission? */
890 if ((This
->uMode
& MMIO_RWMODE
) == 0)
891 return AVIERR_READONLY
;
893 /* < 0 means "append" */
895 start
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
;
897 /* check buffersize -- must multiple of samplesize */
898 if (buffersize
& ~(This
->sInfo
.dwSampleSize
- 1))
899 return AVIERR_BADSIZE
;
901 /* have we anything to write? */
902 if (buffer
!= NULL
&& buffersize
> 0) {
905 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
+
906 start
* This
->sInfo
.dwSampleSize
, SEEK_SET
) == -1)
907 return AVIERR_FILEWRITE
;
908 if (mmioWrite(This
->hmmio
, (HPSTR
)buffer
, buffersize
) != buffersize
)
909 return AVIERR_FILEWRITE
;
911 This
->sInfo
.dwLength
= max(This
->sInfo
.dwLength
, start
+ samples
);
912 This
->ckData
.cksize
= max(This
->ckData
.cksize
,
913 start
* This
->sInfo
.dwSampleSize
+ buffersize
);
915 /* fill out return parameters if given */
916 if (sampwritten
!= NULL
)
917 *sampwritten
= samples
;
918 if (byteswritten
!= NULL
)
919 *byteswritten
= buffersize
;
925 static HRESULT WINAPI
IAVIStream_fnDelete(IAVIStream
*iface
, LONG start
,
928 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
930 TRACE("(%p,%ld,%ld)\n", iface
, start
, samples
);
932 /* check parameters */
933 if (start
< 0 || samples
< 0)
934 return AVIERR_BADPARAM
;
936 /* Delete before start of stream? */
937 if (start
+ samples
< This
->sInfo
.dwStart
)
940 /* Delete after end of stream? */
941 if (start
> This
->sInfo
.dwLength
)
944 /* For the rest we need write permissions */
945 if ((This
->uMode
& MMIO_RWMODE
) == 0)
946 return AVIERR_READONLY
;
948 if (start
+ samples
>= This
->sInfo
.dwLength
) {
949 /* deletion at end */
950 samples
= This
->sInfo
.dwLength
- start
;
951 This
->sInfo
.dwLength
-= samples
;
952 This
->ckData
.cksize
-= samples
* This
->sInfo
.dwSampleSize
;
953 } else if (start
<= This
->sInfo
.dwStart
) {
954 /* deletion at start */
955 samples
= This
->sInfo
.dwStart
- start
;
956 start
= This
->sInfo
.dwStart
;
957 This
->ckData
.dwDataOffset
+= samples
* This
->sInfo
.dwSampleSize
;
958 This
->ckData
.cksize
-= samples
* This
->sInfo
.dwSampleSize
;
960 /* deletion inside stream -- needs playlist and cue's */
961 FIXME(": deletion inside of stream not supported!\n");
963 return AVIERR_UNSUPPORTED
;
971 static HRESULT WINAPI
IAVIStream_fnReadData(IAVIStream
*iface
, DWORD fcc
,
972 LPVOID lp
, LPLONG lpread
)
974 ICOM_THIS(IAVIStreamImpl
,iface
);
976 assert(This
->paf
!= NULL
);
978 return IAVIFile_ReadData((PAVIFILE
)This
->paf
, fcc
, lp
, lpread
);
981 static HRESULT WINAPI
IAVIStream_fnWriteData(IAVIStream
*iface
, DWORD fcc
,
982 LPVOID lp
, LONG size
)
984 ICOM_THIS(IAVIStreamImpl
,iface
);
986 return IAVIFile_WriteData((PAVIFILE
)This
->paf
, fcc
, lp
, size
);
989 static HRESULT WINAPI
IAVIStream_fnSetInfo(IAVIStream
*iface
,
990 LPAVISTREAMINFOW info
, LONG infolen
)
992 FIXME("(%p,%p,%ld): stub\n", iface
, info
, infolen
);
997 /***********************************************************************/
999 static HRESULT
AVIFILE_LoadFile(IAVIFileImpl
*This
)
1004 This
->sInfo
.dwLength
= 0; /* just to be sure */
1005 This
->fDirty
= FALSE
;
1007 /* search for RIFF chunk */
1008 ckRIFF
.fccType
= 0; /* find any */
1009 if (mmioDescend(This
->hmmio
, &ckRIFF
, NULL
, MMIO_FINDRIFF
) != S_OK
) {
1010 return AVIFILE_LoadSunFile(This
);
1013 if (ckRIFF
.fccType
!= formtypeWAVE
)
1014 return AVIERR_BADFORMAT
;
1016 /* search WAVE format chunk */
1017 ck
.ckid
= ckidWAVEFORMAT
;
1018 if (FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &ck
,
1019 &ckRIFF
, MMIO_FINDCHUNK
) != S_OK
)
1020 return AVIERR_FILEREAD
;
1022 /* get memory for format and read it */
1023 This
->lpFormat
= (LPWAVEFORMATEX
)GlobalAllocPtr(GMEM_MOVEABLE
, ck
.cksize
);
1024 if (This
->lpFormat
== NULL
)
1025 return AVIERR_FILEREAD
;
1026 This
->cbFormat
= ck
.cksize
;
1028 if (mmioRead(This
->hmmio
, (HPSTR
)This
->lpFormat
, ck
.cksize
) != ck
.cksize
)
1029 return AVIERR_FILEREAD
;
1030 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1031 return AVIERR_FILEREAD
;
1033 /* Non-pcm formats have a fact chunk.
1034 * We don't need it, so simply add it to the extra chunks.
1037 /* find the big data chunk */
1038 This
->ckData
.ckid
= ckidWAVEDATA
;
1039 if (FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &This
->ckData
,
1040 &ckRIFF
, MMIO_FINDCHUNK
) != S_OK
)
1041 return AVIERR_FILEREAD
;
1043 memset(&This
->sInfo
, 0, sizeof(This
->sInfo
));
1044 This
->sInfo
.fccType
= streamtypeAUDIO
;
1045 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
1046 This
->sInfo
.dwSampleSize
=
1047 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
1048 This
->sInfo
.dwLength
= This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1049 This
->sInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
1051 This
->fInfo
.dwStreams
= 1;
1053 if (mmioAscend(This
->hmmio
, &This
->ckData
, 0) != S_OK
) {
1054 /* seems to be truncated */
1055 WARN(": file seems to be truncated!\n");
1056 This
->ckData
.cksize
= mmioSeek(This
->hmmio
, 0, SEEK_END
) -
1057 This
->ckData
.dwDataOffset
;
1058 This
->sInfo
.dwLength
= This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1059 This
->sInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
1063 FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &ck
, &ckRIFF
, 0);
1068 static HRESULT
AVIFILE_LoadSunFile(IAVIFileImpl
*This
)
1070 FIXME(": pherhaps sun-audio file -- not implemented !\n");
1072 return AVIERR_UNSUPPORTED
;
1075 static HRESULT
AVIFILE_SaveFile(IAVIFileImpl
*This
)
1080 mmioSeek(This
->hmmio
, 0, SEEK_SET
);
1082 /* create the RIFF chunk with formtype WAVE */
1083 ckRIFF
.fccType
= formtypeWAVE
;
1085 if (mmioCreateChunk(This
->hmmio
, &ckRIFF
, MMIO_CREATERIFF
) != S_OK
)
1086 return AVIERR_FILEWRITE
;
1088 /* the next chunk is the format */
1089 ck
.ckid
= ckidWAVEFORMAT
;
1090 ck
.cksize
= This
->cbFormat
;
1091 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1092 return AVIERR_FILEWRITE
;
1093 if (This
->lpFormat
!= NULL
&& This
->cbFormat
> 0) {
1094 if (mmioWrite(This
->hmmio
, (HPSTR
)This
->lpFormat
, ck
.cksize
) != ck
.cksize
)
1095 return AVIERR_FILEWRITE
;
1097 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1098 return AVIERR_FILEWRITE
;
1100 /* fact chunk is needed for non-pcm waveforms */
1101 if (This
->lpFormat
!= NULL
&& This
->cbFormat
> sizeof(PCMWAVEFORMAT
) &&
1102 This
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
1107 /* try to open an appropriate audio codec to figure out
1108 * data for fact-chunk */
1109 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
1110 if (acmFormatSuggest((HACMDRIVER
)NULL
, This
->lpFormat
, &wfx
,
1111 sizeof(wfx
), ACM_FORMATSUGGESTF_WFORMATTAG
)) {
1112 acmStreamOpen(&has
, (HACMDRIVER
)NULL
, This
->lpFormat
, &wfx
, NULL
,
1113 0, 0, ACM_STREAMOPENF_NONREALTIME
);
1114 acmStreamSize(has
, This
->ckData
.cksize
, &dwFactLength
,
1115 ACM_STREAMSIZEF_SOURCE
);
1116 dwFactLength
/= wfx
.nBlockAlign
;
1117 acmStreamClose(has
, 0);
1119 /* crete the fact chunk */
1120 ck
.ckid
= ckidWAVEFACT
;
1121 ck
.cksize
= sizeof(dwFactLength
);
1123 /* test for enough space before data chunk */
1124 if (mmioSeek(This
->hmmio
, 0, SEEK_CUR
) > This
->ckData
.dwDataOffset
1125 - ck
.cksize
- 4 * sizeof(DWORD
))
1126 return AVIERR_FILEWRITE
;
1127 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1128 return AVIERR_FILEWRITE
;
1129 if (mmioWrite(This
->hmmio
, (HPSTR
)&dwFactLength
, ck
.cksize
) != ck
.cksize
)
1130 return AVIERR_FILEWRITE
;
1131 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1132 return AVIERR_FILEWRITE
;
1134 ERR(": fact chunk is needed for non-pcm files -- currently no codec found, so skipped!\n");
1137 /* if here was extra stuff, we need to fill it with JUNK */
1138 if (mmioSeek(This
->hmmio
, 0, SEEK_CUR
) + 2 * sizeof(DWORD
) < This
->ckData
.dwDataOffset
) {
1139 ck
.ckid
= ckidAVIPADDING
;
1141 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1142 return AVIERR_FILEWRITE
;
1144 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
1145 - 2 * sizeof(DWORD
), SEEK_SET
) == -1)
1146 return AVIERR_FILEWRITE
;
1147 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1148 return AVIERR_FILEWRITE
;
1151 /* crete the data chunk */
1152 ck
.ckid
= ckidWAVEDATA
;
1153 ck
.cksize
= This
->ckData
.cksize
;
1154 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1155 return AVIERR_FILEWRITE
;
1156 if (mmioSeek(This
->hmmio
, This
->ckData
.cksize
, SEEK_CUR
) == -1)
1157 return AVIERR_FILEWRITE
;
1158 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1159 return AVIERR_FILEWRITE
;
1161 /* some optional extra chunks? */
1162 if (This
->extra
.lp
!= NULL
&& This
->extra
.cb
> 0) {
1163 /* chunk headers are already in structure */
1164 if (mmioWrite(This
->hmmio
, This
->extra
.lp
, This
->extra
.cb
) != This
->extra
.cb
)
1165 return AVIERR_FILEWRITE
;
1168 /* close RIFF chunk */
1169 if (mmioAscend(This
->hmmio
, &ckRIFF
, 0) != S_OK
)
1170 return AVIERR_FILEWRITE
;
1171 if (mmioFlush(This
->hmmio
, 0) != S_OK
)
1172 return AVIERR_FILEWRITE
;