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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "avifile_private.h"
34 #include "extrachunk.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(avifile
);
41 /***********************************************************************/
43 #define formtypeWAVE mmioFOURCC('W','A','V','E')
44 #define ckidWAVEFORMAT mmioFOURCC('f','m','t',' ')
45 #define ckidWAVEFACT mmioFOURCC('f','a','c','t')
46 #define ckidWAVEDATA mmioFOURCC('d','a','t','a')
48 /***********************************************************************/
50 #define ENDIAN_SWAPWORD(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
51 #define ENDIAN_SWAPDWORD(x) (ENDIAN_SWAPWORD((x >> 16) & 0xFFFF) | \
52 ENDIAN_SWAPWORD(x & 0xFFFF) << 16)
54 #ifdef WORDS_BIGENDIAN
55 #define BE2H_WORD(x) (x)
56 #define BE2H_DWORD(x) (x)
57 #define LE2H_WORD(x) ENDIAN_SWAPWORD(x)
58 #define LE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
60 #define BE2H_WORD(x) ENDIAN_SWAPWORD(x)
61 #define BE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
62 #define LE2H_WORD(x) (x)
63 #define LE2H_DWORD(x) (x)
75 #define AU_ENCODING_ULAW_8 1
76 #define AU_ENCODING_PCM_8 2
77 #define AU_ENCODING_PCM_16 3
78 #define AU_ENCODING_PCM_24 4
79 #define AU_ENCODING_PCM_32 5
80 #define AU_ENCODING_FLOAT 6
81 #define AU_ENCODING_DOUBLE 7
82 #define AU_ENCODING_ADPCM_G721_32 23
83 #define AU_ENCODING_ADPCM_G722 24
84 #define AU_ENCODING_ADPCM_G723_24 25
85 #define AU_ENCODING_ADPCM_G723_5 26
86 #define AU_ENCODING_ALAW_8 27
88 /***********************************************************************/
90 typedef struct _IAVIFileImpl
{
91 IUnknown IUnknown_inner
;
92 IAVIFile IAVIFile_iface
;
93 IPersistFile IPersistFile_iface
;
94 IAVIStream IAVIStream_iface
;
97 /* IAVIFile, IAVIStream stuff... */
101 LPWAVEFORMATEX lpFormat
;
108 /* IPersistFile stuff ... */
115 /***********************************************************************/
117 static HRESULT
AVIFILE_LoadFile(IAVIFileImpl
*This
);
118 static HRESULT
AVIFILE_LoadSunFile(IAVIFileImpl
*This
);
119 static HRESULT
AVIFILE_SaveFile(const IAVIFileImpl
*This
);
121 static inline IAVIFileImpl
*impl_from_IUnknown(IUnknown
*iface
)
123 return CONTAINING_RECORD(iface
, IAVIFileImpl
, IUnknown_inner
);
126 static HRESULT WINAPI
IUnknown_fnQueryInterface(IUnknown
*iface
, REFIID riid
, void **ret_iface
)
128 IAVIFileImpl
*This
= impl_from_IUnknown(iface
);
130 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ret_iface
);
132 if (IsEqualGUID(&IID_IUnknown
, riid
))
133 *ret_iface
= &This
->IUnknown_inner
;
134 else if (IsEqualGUID(&IID_IAVIFile
, riid
))
135 *ret_iface
= &This
->IAVIFile_iface
;
136 else if (IsEqualGUID(&IID_IAVIStream
, riid
))
137 *ret_iface
= &This
->IAVIStream_iface
;
138 else if (IsEqualGUID(&IID_IPersistFile
, riid
))
139 *ret_iface
= &This
->IPersistFile_iface
;
141 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ret_iface
);
143 return E_NOINTERFACE
;
146 /* Violation of the COM aggregation ref counting rule */
147 IUnknown_AddRef(&This
->IUnknown_inner
);
151 static ULONG WINAPI
IUnknown_fnAddRef(IUnknown
*iface
)
153 IAVIFileImpl
*This
= impl_from_IUnknown(iface
);
154 ULONG ref
= InterlockedIncrement(&This
->ref
);
156 TRACE("(%p) ref=%d\n", This
, ref
);
161 static ULONG WINAPI
IUnknown_fnRelease(IUnknown
*iface
)
163 IAVIFileImpl
*This
= impl_from_IUnknown(iface
);
164 ULONG ref
= InterlockedDecrement(&This
->ref
);
166 TRACE("(%p) ref=%d\n", This
, ref
);
169 /* need to write headers to file */
171 AVIFILE_SaveFile(This
);
173 HeapFree(GetProcessHeap(), 0, This
->lpFormat
);
174 This
->lpFormat
= NULL
;
176 HeapFree(GetProcessHeap(), 0, This
->extra
.lp
);
177 This
->extra
.lp
= NULL
;
179 HeapFree(GetProcessHeap(), 0, This
->szFileName
);
180 This
->szFileName
= NULL
;
182 mmioClose(This
->hmmio
, 0);
185 HeapFree(GetProcessHeap(), 0, This
);
191 static const IUnknownVtbl unk_vtbl
=
193 IUnknown_fnQueryInterface
,
198 static inline IAVIFileImpl
*impl_from_IAVIFile(IAVIFile
*iface
)
200 return CONTAINING_RECORD(iface
, IAVIFileImpl
, IAVIFile_iface
);
203 static HRESULT WINAPI
IAVIFile_fnQueryInterface(IAVIFile
*iface
, REFIID riid
, void **ret_iface
)
205 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
207 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ret_iface
);
210 static ULONG WINAPI
IAVIFile_fnAddRef(IAVIFile
*iface
)
212 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
214 return IUnknown_AddRef(This
->outer_unk
);
217 static ULONG WINAPI
IAVIFile_fnRelease(IAVIFile
*iface
)
219 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
221 return IUnknown_Release(This
->outer_unk
);
224 static HRESULT WINAPI
IAVIFile_fnInfo(IAVIFile
*iface
, AVIFILEINFOW
*afi
, LONG size
)
226 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
228 TRACE("(%p,%p,%d)\n",iface
,afi
,size
);
231 return AVIERR_BADPARAM
;
233 return AVIERR_BADSIZE
;
235 /* update file info */
236 This
->fInfo
.dwFlags
= 0;
237 This
->fInfo
.dwCaps
= AVIFILECAPS_CANREAD
|AVIFILECAPS_CANWRITE
;
238 if (This
->lpFormat
!= NULL
) {
239 assert(This
->sInfo
.dwScale
!= 0);
241 This
->fInfo
.dwStreams
= 1;
242 This
->fInfo
.dwScale
= This
->sInfo
.dwScale
;
243 This
->fInfo
.dwRate
= This
->sInfo
.dwRate
;
244 This
->fInfo
.dwLength
= This
->sInfo
.dwLength
;
245 This
->fInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
246 This
->fInfo
.dwMaxBytesPerSec
=
247 MulDiv(This
->sInfo
.dwSampleSize
,This
->sInfo
.dwRate
,This
->sInfo
.dwScale
);
250 memcpy(afi
, &This
->fInfo
, min((DWORD
)size
, sizeof(This
->fInfo
)));
252 if ((DWORD
)size
< sizeof(This
->fInfo
))
253 return AVIERR_BUFFERTOOSMALL
;
257 static HRESULT WINAPI
IAVIFile_fnGetStream(IAVIFile
*iface
, IAVIStream
**avis
, DWORD fccType
,
260 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
262 TRACE("(%p,%p,0x%08X,%d)\n", iface
, avis
, fccType
, lParam
);
264 /* check parameter */
266 return AVIERR_BADPARAM
;
270 /* Does our stream exists? */
271 if (lParam
!= 0 || This
->fInfo
.dwStreams
== 0)
272 return AVIERR_NODATA
;
273 if (fccType
!= 0 && fccType
!= streamtypeAUDIO
)
274 return AVIERR_NODATA
;
276 *avis
= &This
->IAVIStream_iface
;
277 IAVIStream_AddRef(*avis
);
282 static HRESULT WINAPI
IAVIFile_fnCreateStream(IAVIFile
*iface
, IAVIStream
**avis
,
285 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
287 TRACE("(%p,%p,%p)\n", iface
, avis
, asi
);
289 /* check parameters */
290 if (avis
== NULL
|| asi
== NULL
)
291 return AVIERR_BADPARAM
;
295 /* We only support one audio stream */
296 if (This
->fInfo
.dwStreams
!= 0 || This
->lpFormat
!= NULL
)
297 return AVIERR_UNSUPPORTED
;
298 if (asi
->fccType
!= streamtypeAUDIO
)
299 return AVIERR_UNSUPPORTED
;
301 /* Does the user have write permission? */
302 if ((This
->uMode
& MMIO_RWMODE
) == 0)
303 return AVIERR_READONLY
;
306 This
->lpFormat
= NULL
;
308 memcpy(&This
->sInfo
, asi
, sizeof(This
->sInfo
));
310 /* make sure streaminfo if okay for us */
311 This
->sInfo
.fccHandler
= 0;
312 This
->sInfo
.dwFlags
= 0;
313 This
->sInfo
.dwCaps
= AVIFILECAPS_CANREAD
|AVIFILECAPS_CANWRITE
;
314 This
->sInfo
.dwStart
= 0;
315 This
->sInfo
.dwInitialFrames
= 0;
316 This
->sInfo
.dwFormatChangeCount
= 0;
317 SetRectEmpty(&This
->sInfo
.rcFrame
);
319 This
->fInfo
.dwStreams
= 1;
320 This
->fInfo
.dwScale
= This
->sInfo
.dwScale
;
321 This
->fInfo
.dwRate
= This
->sInfo
.dwRate
;
322 This
->fInfo
.dwLength
= This
->sInfo
.dwLength
;
324 This
->ckData
.dwDataOffset
= 0;
325 This
->ckData
.cksize
= 0;
327 *avis
= &This
->IAVIStream_iface
;
328 IAVIStream_AddRef(*avis
);
333 static HRESULT WINAPI
IAVIFile_fnWriteData(IAVIFile
*iface
, DWORD ckid
, void *lpData
, LONG size
)
335 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
337 TRACE("(%p,0x%08X,%p,%d)\n", iface
, ckid
, lpData
, size
);
339 /* check parameters */
341 return AVIERR_BADPARAM
;
343 return AVIERR_BADSIZE
;
345 /* Do we have write permission? */
346 if ((This
->uMode
& MMIO_RWMODE
) == 0)
347 return AVIERR_READONLY
;
351 return WriteExtraChunk(&This
->extra
, ckid
, lpData
, size
);
354 static HRESULT WINAPI
IAVIFile_fnReadData(IAVIFile
*iface
, DWORD ckid
, void *lpData
, LONG
*size
)
356 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
358 TRACE("(%p,0x%08X,%p,%p)\n", iface
, ckid
, lpData
, size
);
360 return ReadExtraChunk(&This
->extra
, ckid
, lpData
, size
);
363 static HRESULT WINAPI
IAVIFile_fnEndRecord(IAVIFile
*iface
)
365 TRACE("(%p)\n",iface
);
367 /* This is only needed for interleaved files.
368 * We have only one stream, which can't be interleaved.
373 static HRESULT WINAPI
IAVIFile_fnDeleteStream(IAVIFile
*iface
, DWORD fccType
, LONG lParam
)
375 IAVIFileImpl
*This
= impl_from_IAVIFile(iface
);
377 TRACE("(%p,0x%08X,%d)\n", iface
, fccType
, lParam
);
379 /* check parameter */
381 return AVIERR_BADPARAM
;
383 /* Do we have our audio stream? */
384 if (lParam
!= 0 || This
->fInfo
.dwStreams
== 0 ||
385 (fccType
!= 0 && fccType
!= streamtypeAUDIO
))
386 return AVIERR_NODATA
;
388 /* Have user write permissions? */
389 if ((This
->uMode
& MMIO_RWMODE
) == 0)
390 return AVIERR_READONLY
;
392 HeapFree(GetProcessHeap(), 0, This
->lpFormat
);
393 This
->lpFormat
= NULL
;
397 This
->ckData
.dwDataOffset
= 0;
398 This
->ckData
.cksize
= 0;
400 This
->sInfo
.dwScale
= 0;
401 This
->sInfo
.dwRate
= 0;
402 This
->sInfo
.dwLength
= 0;
403 This
->sInfo
.dwSuggestedBufferSize
= 0;
405 This
->fInfo
.dwStreams
= 0;
406 This
->fInfo
.dwEditCount
++;
413 static const struct IAVIFileVtbl iwavft
= {
414 IAVIFile_fnQueryInterface
,
418 IAVIFile_fnGetStream
,
419 IAVIFile_fnCreateStream
,
420 IAVIFile_fnWriteData
,
422 IAVIFile_fnEndRecord
,
423 IAVIFile_fnDeleteStream
426 /***********************************************************************/
428 static inline IAVIFileImpl
*impl_from_IPersistFile(IPersistFile
*iface
)
430 return CONTAINING_RECORD(iface
, IAVIFileImpl
, IPersistFile_iface
);
433 static HRESULT WINAPI
IPersistFile_fnQueryInterface(IPersistFile
*iface
, REFIID riid
,
436 IAVIFileImpl
*This
= impl_from_IPersistFile(iface
);
438 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ret_iface
);
441 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
*iface
)
443 IAVIFileImpl
*This
= impl_from_IPersistFile(iface
);
445 return IUnknown_AddRef(This
->outer_unk
);
448 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
*iface
)
450 IAVIFileImpl
*This
= impl_from_IPersistFile(iface
);
452 return IUnknown_Release(This
->outer_unk
);
455 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
*iface
,
458 TRACE("(%p,%p)\n", iface
, pClassID
);
460 if (pClassID
== NULL
)
461 return AVIERR_BADPARAM
;
463 *pClassID
= CLSID_WAVFile
;
468 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
*iface
)
470 IAVIFileImpl
*This
= impl_from_IPersistFile(iface
);
472 TRACE("(%p)\n", iface
);
474 return (This
->fDirty
? S_OK
: S_FALSE
);
477 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
*iface
, LPCOLESTR pszFileName
, DWORD dwMode
)
479 IAVIFileImpl
*This
= impl_from_IPersistFile(iface
);
480 WCHAR wszStreamFmt
[50];
483 TRACE("(%p,%s,0x%08X)\n", iface
, debugstr_w(pszFileName
), dwMode
);
485 /* check parameter */
486 if (pszFileName
== NULL
)
487 return AVIERR_BADPARAM
;
489 if (This
->hmmio
!= NULL
)
490 return AVIERR_ERROR
; /* No reuse of this object for another file! */
492 /* remember mode and name */
493 This
->uMode
= dwMode
;
495 len
= lstrlenW(pszFileName
) + 1;
496 This
->szFileName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
497 if (This
->szFileName
== NULL
)
498 return AVIERR_MEMORY
;
499 lstrcpyW(This
->szFileName
, pszFileName
);
501 /* try to open the file */
502 This
->hmmio
= mmioOpenW(This
->szFileName
, NULL
, MMIO_ALLOCBUF
| dwMode
);
503 if (This
->hmmio
== NULL
) {
504 /* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
506 len
= WideCharToMultiByte(CP_ACP
, 0, This
->szFileName
, -1,
507 NULL
, 0, NULL
, NULL
);
508 szFileName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(CHAR
));
509 if (szFileName
== NULL
)
510 return AVIERR_MEMORY
;
512 WideCharToMultiByte(CP_ACP
, 0, This
->szFileName
, -1, szFileName
,
515 This
->hmmio
= mmioOpenA(szFileName
, NULL
, MMIO_ALLOCBUF
| dwMode
);
516 HeapFree(GetProcessHeap(), 0, szFileName
);
517 if (This
->hmmio
== NULL
)
518 return AVIERR_FILEOPEN
;
521 memset(& This
->fInfo
, 0, sizeof(This
->fInfo
));
522 memset(& This
->sInfo
, 0, sizeof(This
->sInfo
));
524 LoadStringW(AVIFILE_hModule
, IDS_WAVEFILETYPE
, This
->fInfo
.szFileType
,
525 sizeof(This
->fInfo
.szFileType
)/sizeof(This
->fInfo
.szFileType
[0]));
526 if (LoadStringW(AVIFILE_hModule
, IDS_WAVESTREAMFORMAT
,
527 wszStreamFmt
, sizeof(wszStreamFmt
)/sizeof(wszStreamFmt
[0])) > 0) {
528 wsprintfW(This
->sInfo
.szName
, wszStreamFmt
,
529 AVIFILE_BasenameW(This
->szFileName
));
532 /* should we create a new file? */
533 if (dwMode
& OF_CREATE
) {
534 /* nothing more to do */
537 return AVIFILE_LoadFile(This
);
540 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
*iface
,
541 LPCOLESTR pszFileName
,BOOL fRemember
)
543 TRACE("(%p,%s,%d)\n", iface
, debugstr_w(pszFileName
), fRemember
);
545 /* We write directly to disk, so nothing to do. */
550 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
*iface
,
551 LPCOLESTR pszFileName
)
553 TRACE("(%p,%s)\n", iface
, debugstr_w(pszFileName
));
555 /* We write directly to disk, so nothing to do. */
560 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
*iface
, LPOLESTR
*ppszFileName
)
562 IAVIFileImpl
*This
= impl_from_IPersistFile(iface
);
564 TRACE("(%p,%p)\n", iface
, ppszFileName
);
566 if (ppszFileName
== NULL
)
567 return AVIERR_BADPARAM
;
569 *ppszFileName
= NULL
;
571 if (This
->szFileName
) {
572 int len
= lstrlenW(This
->szFileName
) + 1;
574 *ppszFileName
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
575 if (*ppszFileName
== NULL
)
576 return AVIERR_MEMORY
;
578 strcpyW(*ppszFileName
, This
->szFileName
);
584 static const struct IPersistFileVtbl iwavpft
= {
585 IPersistFile_fnQueryInterface
,
586 IPersistFile_fnAddRef
,
587 IPersistFile_fnRelease
,
588 IPersistFile_fnGetClassID
,
589 IPersistFile_fnIsDirty
,
592 IPersistFile_fnSaveCompleted
,
593 IPersistFile_fnGetCurFile
596 /***********************************************************************/
598 static inline IAVIFileImpl
*impl_from_IAVIStream(IAVIStream
*iface
)
600 return CONTAINING_RECORD(iface
, IAVIFileImpl
, IAVIStream_iface
);
603 static HRESULT WINAPI
IAVIStream_fnQueryInterface(IAVIStream
*iface
, REFIID riid
, void **ret_iface
)
605 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
607 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ret_iface
);
610 static ULONG WINAPI
IAVIStream_fnAddRef(IAVIStream
*iface
)
612 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
614 return IUnknown_AddRef(This
->outer_unk
);
617 static ULONG WINAPI
IAVIStream_fnRelease(IAVIStream
* iface
)
619 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
621 return IUnknown_Release(This
->outer_unk
);
624 static HRESULT WINAPI
IAVIStream_fnCreate(IAVIStream
*iface
, LPARAM lParam1
,
627 TRACE("(%p,0x%08lX,0x%08lX)\n", iface
, lParam1
, lParam2
);
629 /* This IAVIStream interface needs an WAVFile */
630 return AVIERR_UNSUPPORTED
;
633 static HRESULT WINAPI
IAVIStream_fnInfo(IAVIStream
*iface
, AVISTREAMINFOW
*psi
, LONG size
)
635 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
637 TRACE("(%p,%p,%d)\n", iface
, psi
, size
);
640 return AVIERR_BADPARAM
;
642 return AVIERR_BADSIZE
;
644 memcpy(psi
, &This
->sInfo
, min((DWORD
)size
, sizeof(This
->sInfo
)));
646 if ((DWORD
)size
< sizeof(This
->sInfo
))
647 return AVIERR_BUFFERTOOSMALL
;
651 static LONG WINAPI
IAVIStream_fnFindSample(IAVIStream
*iface
, LONG pos
, LONG flags
)
653 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
655 TRACE("(%p,%d,0x%08X)\n",iface
,pos
,flags
);
657 /* Do we have data? */
658 if (This
->lpFormat
== NULL
)
661 /* We don't have an index */
662 if (flags
& FIND_INDEX
)
665 if (flags
& FIND_FROM_START
) {
666 pos
= This
->sInfo
.dwStart
;
667 flags
&= ~(FIND_FROM_START
|FIND_PREV
);
671 if (flags
& FIND_FORMAT
) {
672 if ((flags
& FIND_NEXT
) && pos
> 0)
678 if ((flags
& FIND_RET
) == FIND_LENGTH
||
679 (flags
& FIND_RET
) == FIND_SIZE
)
680 return This
->sInfo
.dwSampleSize
;
681 if ((flags
& FIND_RET
) == FIND_OFFSET
)
682 return This
->ckData
.dwDataOffset
+ pos
* This
->sInfo
.dwSampleSize
;
687 static HRESULT WINAPI
IAVIStream_fnReadFormat(IAVIStream
*iface
, LONG pos
, void *format
,
690 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
692 TRACE("(%p,%d,%p,%p)\n", iface
, pos
, format
, formatsize
);
694 if (formatsize
== NULL
)
695 return AVIERR_BADPARAM
;
697 /* only interested in needed buffersize? */
698 if (format
== NULL
|| *formatsize
<= 0) {
699 *formatsize
= This
->cbFormat
;
704 /* copy initial format (only as much as will fit) */
705 memcpy(format
, This
->lpFormat
, min(*formatsize
, This
->cbFormat
));
706 if (*formatsize
< This
->cbFormat
) {
707 *formatsize
= This
->cbFormat
;
708 return AVIERR_BUFFERTOOSMALL
;
711 *formatsize
= This
->cbFormat
;
715 static HRESULT WINAPI
IAVIStream_fnSetFormat(IAVIStream
*iface
, LONG pos
, void *format
,
718 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
720 TRACE("(%p,%d,%p,%d)\n", iface
, pos
, format
, formatsize
);
722 /* check parameters */
723 if (format
== NULL
|| formatsize
<= sizeof(PCMWAVEFORMAT
))
724 return AVIERR_BADPARAM
;
726 /* We can only do this to an empty wave file, but ignore call
727 * if still same format */
728 if (This
->lpFormat
!= NULL
) {
729 if (formatsize
!= This
->cbFormat
||
730 memcmp(format
, This
->lpFormat
, formatsize
) != 0)
731 return AVIERR_UNSUPPORTED
;
736 /* only support start at position 0 */
738 return AVIERR_UNSUPPORTED
;
740 /* Do we have write permission? */
741 if ((This
->uMode
& MMIO_RWMODE
) == 0)
742 return AVIERR_READONLY
;
744 /* get memory for format and copy it */
745 This
->lpFormat
= HeapAlloc(GetProcessHeap(), 0, formatsize
);
746 if (This
->lpFormat
== NULL
)
747 return AVIERR_MEMORY
;
749 This
->cbFormat
= formatsize
;
750 memcpy(This
->lpFormat
, format
, formatsize
);
752 /* update info's about 'data' chunk */
753 This
->ckData
.dwDataOffset
= formatsize
+ 7 * sizeof(DWORD
);
754 This
->ckData
.cksize
= 0;
756 /* for non-pcm format we need also a 'fact' chunk */
757 if (This
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
758 This
->ckData
.dwDataOffset
+= 3 * sizeof(DWORD
);
760 /* update stream and file info */
761 This
->sInfo
.dwSampleSize
= This
->lpFormat
->nBlockAlign
;
762 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
763 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
764 This
->sInfo
.dwLength
= 0;
765 This
->sInfo
.dwSuggestedBufferSize
= 0;
770 static HRESULT WINAPI
IAVIStream_fnRead(IAVIStream
*iface
, LONG start
, LONG samples
, void *buffer
,
771 LONG buffersize
, LONG
*bytesread
, LONG
*samplesread
)
773 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
775 TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface
, start
, samples
, buffer
,
776 buffersize
, bytesread
, samplesread
);
778 /* clear return parameters if given */
779 if (bytesread
!= NULL
)
781 if (samplesread
!= NULL
)
784 /* positions without data */
785 if (start
< 0 || (DWORD
)start
> This
->sInfo
.dwLength
)
791 if (buffersize
> 0) {
793 samples
= min((DWORD
)samples
, buffersize
/ This
->sInfo
.dwSampleSize
);
795 samples
= buffersize
/ This
->sInfo
.dwSampleSize
;
798 /* limit to end of stream */
799 if ((DWORD
)(start
+ samples
) > This
->sInfo
.dwLength
)
800 samples
= This
->sInfo
.dwLength
- start
;
802 /* request only the sizes? */
803 if (buffer
== NULL
|| buffersize
<= 0) {
804 /* then I need at least one parameter for it */
805 if (bytesread
== NULL
&& samplesread
== NULL
)
806 return AVIERR_BADPARAM
;
808 if (bytesread
!= NULL
)
809 *bytesread
= samples
* This
->sInfo
.dwSampleSize
;
810 if (samplesread
!= NULL
)
811 *samplesread
= samples
;
816 /* nothing to read? */
820 /* Can I read at least one sample? */
821 if ((DWORD
)buffersize
< This
->sInfo
.dwSampleSize
)
822 return AVIERR_BUFFERTOOSMALL
;
824 buffersize
= samples
* This
->sInfo
.dwSampleSize
;
826 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
827 + start
* This
->sInfo
.dwSampleSize
, SEEK_SET
) == -1)
828 return AVIERR_FILEREAD
;
829 if (mmioRead(This
->hmmio
, buffer
, buffersize
) != buffersize
)
830 return AVIERR_FILEREAD
;
832 /* fill out return parameters if given */
833 if (bytesread
!= NULL
)
834 *bytesread
= buffersize
;
835 if (samplesread
!= NULL
)
836 *samplesread
= samples
;
841 static HRESULT WINAPI
IAVIStream_fnWrite(IAVIStream
*iface
, LONG start
, LONG samples
, void *buffer
,
842 LONG buffersize
, DWORD flags
, LONG
*sampwritten
, LONG
*byteswritten
)
844 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
846 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface
, start
, samples
,
847 buffer
, buffersize
, flags
, sampwritten
, byteswritten
);
849 /* clear return parameters if given */
850 if (sampwritten
!= NULL
)
852 if (byteswritten
!= NULL
)
855 /* check parameters */
856 if (buffer
== NULL
&& (buffersize
> 0 || samples
> 0))
857 return AVIERR_BADPARAM
;
859 /* Do we have write permission? */
860 if ((This
->uMode
& MMIO_RWMODE
) == 0)
861 return AVIERR_READONLY
;
863 /* < 0 means "append" */
865 start
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
;
867 /* check buffersize -- must multiple of samplesize */
868 if (buffersize
& ~(This
->sInfo
.dwSampleSize
- 1))
869 return AVIERR_BADSIZE
;
871 /* do we have anything to write? */
872 if (buffer
!= NULL
&& buffersize
> 0) {
875 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
+
876 start
* This
->sInfo
.dwSampleSize
, SEEK_SET
) == -1)
877 return AVIERR_FILEWRITE
;
878 if (mmioWrite(This
->hmmio
, buffer
, buffersize
) != buffersize
)
879 return AVIERR_FILEWRITE
;
881 This
->sInfo
.dwLength
= max(This
->sInfo
.dwLength
, (DWORD
)start
+ samples
);
882 This
->ckData
.cksize
= max(This
->ckData
.cksize
,
883 start
* This
->sInfo
.dwSampleSize
+ buffersize
);
885 /* fill out return parameters if given */
886 if (sampwritten
!= NULL
)
887 *sampwritten
= samples
;
888 if (byteswritten
!= NULL
)
889 *byteswritten
= buffersize
;
895 static HRESULT WINAPI
IAVIStream_fnDelete(IAVIStream
*iface
, LONG start
, LONG samples
)
897 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
899 TRACE("(%p,%d,%d)\n", iface
, start
, samples
);
901 /* check parameters */
902 if (start
< 0 || samples
< 0)
903 return AVIERR_BADPARAM
;
905 /* Delete before start of stream? */
906 if ((DWORD
)(start
+ samples
) < This
->sInfo
.dwStart
)
909 /* Delete after end of stream? */
910 if ((DWORD
)start
> This
->sInfo
.dwLength
)
913 /* For the rest we need write permissions */
914 if ((This
->uMode
& MMIO_RWMODE
) == 0)
915 return AVIERR_READONLY
;
917 if ((DWORD
)(start
+ samples
) >= This
->sInfo
.dwLength
) {
918 /* deletion at end */
919 samples
= This
->sInfo
.dwLength
- start
;
920 This
->sInfo
.dwLength
-= samples
;
921 This
->ckData
.cksize
-= samples
* This
->sInfo
.dwSampleSize
;
922 } else if ((DWORD
)start
<= This
->sInfo
.dwStart
) {
923 /* deletion at start */
924 samples
= This
->sInfo
.dwStart
- start
;
925 start
= This
->sInfo
.dwStart
;
926 This
->ckData
.dwDataOffset
+= samples
* This
->sInfo
.dwSampleSize
;
927 This
->ckData
.cksize
-= samples
* This
->sInfo
.dwSampleSize
;
929 /* deletion inside stream -- needs playlist and cue's */
930 FIXME(": deletion inside of stream not supported!\n");
932 return AVIERR_UNSUPPORTED
;
940 static HRESULT WINAPI
IAVIStream_fnReadData(IAVIStream
*iface
, DWORD fcc
, void *lp
, LONG
*lpread
)
942 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
944 return IAVIFile_ReadData(&This
->IAVIFile_iface
, fcc
, lp
, lpread
);
947 static HRESULT WINAPI
IAVIStream_fnWriteData(IAVIStream
*iface
, DWORD fcc
, void *lp
, LONG size
)
949 IAVIFileImpl
*This
= impl_from_IAVIStream(iface
);
951 return IAVIFile_WriteData(&This
->IAVIFile_iface
, fcc
, lp
, size
);
954 static HRESULT WINAPI
IAVIStream_fnSetInfo(IAVIStream
*iface
,
955 LPAVISTREAMINFOW info
, LONG infolen
)
957 FIXME("(%p,%p,%d): stub\n", iface
, info
, infolen
);
962 static const struct IAVIStreamVtbl iwavst
= {
963 IAVIStream_fnQueryInterface
,
965 IAVIStream_fnRelease
,
968 IAVIStream_fnFindSample
,
969 IAVIStream_fnReadFormat
,
970 IAVIStream_fnSetFormat
,
974 IAVIStream_fnReadData
,
975 IAVIStream_fnWriteData
,
979 HRESULT
AVIFILE_CreateWAVFile(IUnknown
*outer_unk
, REFIID riid
, void **ret_iface
)
986 pfile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pfile
));
988 return AVIERR_MEMORY
;
990 pfile
->IUnknown_inner
.lpVtbl
= &unk_vtbl
;
991 pfile
->IAVIFile_iface
.lpVtbl
= &iwavft
;
992 pfile
->IPersistFile_iface
.lpVtbl
= &iwavpft
;
993 pfile
->IAVIStream_iface
.lpVtbl
= &iwavst
;
996 pfile
->outer_unk
= outer_unk
;
998 pfile
->outer_unk
= &pfile
->IUnknown_inner
;
1000 hr
= IUnknown_QueryInterface(&pfile
->IUnknown_inner
, riid
, ret_iface
);
1001 IUnknown_Release(&pfile
->IUnknown_inner
);
1006 /***********************************************************************/
1008 static HRESULT
AVIFILE_LoadFile(IAVIFileImpl
*This
)
1013 This
->sInfo
.dwLength
= 0; /* just to be sure */
1014 This
->fDirty
= FALSE
;
1016 /* search for RIFF chunk */
1017 ckRIFF
.fccType
= 0; /* find any */
1018 if (mmioDescend(This
->hmmio
, &ckRIFF
, NULL
, MMIO_FINDRIFF
) != S_OK
) {
1019 return AVIFILE_LoadSunFile(This
);
1022 if (ckRIFF
.fccType
!= formtypeWAVE
)
1023 return AVIERR_BADFORMAT
;
1025 /* search WAVE format chunk */
1026 ck
.ckid
= ckidWAVEFORMAT
;
1027 if (FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &ck
,
1028 &ckRIFF
, MMIO_FINDCHUNK
) != S_OK
)
1029 return AVIERR_FILEREAD
;
1031 /* get memory for format and read it */
1032 This
->lpFormat
= HeapAlloc(GetProcessHeap(), 0, ck
.cksize
);
1033 if (This
->lpFormat
== NULL
)
1034 return AVIERR_FILEREAD
;
1035 This
->cbFormat
= ck
.cksize
;
1037 if (mmioRead(This
->hmmio
, (HPSTR
)This
->lpFormat
, ck
.cksize
) != ck
.cksize
)
1038 return AVIERR_FILEREAD
;
1039 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1040 return AVIERR_FILEREAD
;
1042 /* Non-pcm formats have a fact chunk.
1043 * We don't need it, so simply add it to the extra chunks.
1046 /* find the big data chunk */
1047 This
->ckData
.ckid
= ckidWAVEDATA
;
1048 if (FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &This
->ckData
,
1049 &ckRIFF
, MMIO_FINDCHUNK
) != S_OK
)
1050 return AVIERR_FILEREAD
;
1052 memset(&This
->sInfo
, 0, sizeof(This
->sInfo
));
1053 This
->sInfo
.fccType
= streamtypeAUDIO
;
1054 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
1055 This
->sInfo
.dwSampleSize
=
1056 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
1057 This
->sInfo
.dwLength
= This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1058 This
->sInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
1060 This
->fInfo
.dwStreams
= 1;
1062 if (mmioAscend(This
->hmmio
, &This
->ckData
, 0) != S_OK
) {
1063 /* seems to be truncated */
1064 WARN(": file seems to be truncated!\n");
1065 This
->ckData
.cksize
= mmioSeek(This
->hmmio
, 0, SEEK_END
) -
1066 This
->ckData
.dwDataOffset
;
1067 This
->sInfo
.dwLength
= This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1068 This
->sInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
1072 FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &ck
, &ckRIFF
, 0);
1077 static HRESULT
AVIFILE_LoadSunFile(IAVIFileImpl
*This
)
1079 SUNAUDIOHEADER auhdr
;
1081 mmioSeek(This
->hmmio
, 0, SEEK_SET
);
1082 if (mmioRead(This
->hmmio
, (HPSTR
)&auhdr
, sizeof(auhdr
)) != sizeof(auhdr
))
1083 return AVIERR_FILEREAD
;
1085 if (auhdr
.fccType
== 0x0064732E) {
1086 /* header in little endian */
1087 This
->ckData
.dwDataOffset
= LE2H_DWORD(auhdr
.offset
);
1088 This
->ckData
.cksize
= LE2H_DWORD(auhdr
.size
);
1090 auhdr
.encoding
= LE2H_DWORD(auhdr
.encoding
);
1091 auhdr
.sampleRate
= LE2H_DWORD(auhdr
.sampleRate
);
1092 auhdr
.channels
= LE2H_DWORD(auhdr
.channels
);
1093 } else if (auhdr
.fccType
== mmioFOURCC('.','s','n','d')) {
1094 /* header in big endian */
1095 This
->ckData
.dwDataOffset
= BE2H_DWORD(auhdr
.offset
);
1096 This
->ckData
.cksize
= BE2H_DWORD(auhdr
.size
);
1098 auhdr
.encoding
= BE2H_DWORD(auhdr
.encoding
);
1099 auhdr
.sampleRate
= BE2H_DWORD(auhdr
.sampleRate
);
1100 auhdr
.channels
= BE2H_DWORD(auhdr
.channels
);
1102 return AVIERR_FILEREAD
;
1104 if (auhdr
.channels
< 1)
1105 return AVIERR_BADFORMAT
;
1107 /* get size of header */
1108 switch(auhdr
.encoding
) {
1109 case AU_ENCODING_ADPCM_G721_32
:
1110 This
->cbFormat
= sizeof(G721_ADPCMWAVEFORMAT
); break;
1111 case AU_ENCODING_ADPCM_G723_24
:
1112 This
->cbFormat
= sizeof(G723_ADPCMWAVEFORMAT
); break;
1113 case AU_ENCODING_ADPCM_G722
:
1114 case AU_ENCODING_ADPCM_G723_5
:
1115 WARN("unsupported Sun audio format %d\n", auhdr
.encoding
);
1116 return AVIERR_UNSUPPORTED
; /* FIXME */
1118 This
->cbFormat
= sizeof(WAVEFORMATEX
); break;
1121 This
->lpFormat
= HeapAlloc(GetProcessHeap(), 0, This
->cbFormat
);
1122 if (This
->lpFormat
== NULL
)
1123 return AVIERR_MEMORY
;
1125 This
->lpFormat
->nChannels
= auhdr
.channels
;
1126 This
->lpFormat
->nSamplesPerSec
= auhdr
.sampleRate
;
1127 switch(auhdr
.encoding
) {
1128 case AU_ENCODING_ULAW_8
:
1129 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_MULAW
;
1130 This
->lpFormat
->wBitsPerSample
= 8;
1132 case AU_ENCODING_PCM_8
:
1133 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_PCM
;
1134 This
->lpFormat
->wBitsPerSample
= 8;
1136 case AU_ENCODING_PCM_16
:
1137 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_PCM
;
1138 This
->lpFormat
->wBitsPerSample
= 16;
1140 case AU_ENCODING_PCM_24
:
1141 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_PCM
;
1142 This
->lpFormat
->wBitsPerSample
= 24;
1144 case AU_ENCODING_PCM_32
:
1145 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_PCM
;
1146 This
->lpFormat
->wBitsPerSample
= 32;
1148 case AU_ENCODING_ALAW_8
:
1149 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_ALAW
;
1150 This
->lpFormat
->wBitsPerSample
= 8;
1152 case AU_ENCODING_ADPCM_G721_32
:
1153 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_G721_ADPCM
;
1154 This
->lpFormat
->wBitsPerSample
= (3*5*8);
1155 This
->lpFormat
->nBlockAlign
= 15*15*8;
1156 This
->lpFormat
->cbSize
= sizeof(WORD
);
1157 ((LPG721_ADPCMWAVEFORMAT
)This
->lpFormat
)->nAuxBlockSize
= 0;
1159 case AU_ENCODING_ADPCM_G723_24
:
1160 This
->lpFormat
->wFormatTag
= WAVE_FORMAT_G723_ADPCM
;
1161 This
->lpFormat
->wBitsPerSample
= (3*5*8);
1162 This
->lpFormat
->nBlockAlign
= 15*15*8;
1163 This
->lpFormat
->cbSize
= 2*sizeof(WORD
);
1164 ((LPG723_ADPCMWAVEFORMAT
)This
->lpFormat
)->cbExtraSize
= 0;
1165 ((LPG723_ADPCMWAVEFORMAT
)This
->lpFormat
)->nAuxBlockSize
= 0;
1168 WARN("unsupported Sun audio format %d\n", auhdr
.encoding
);
1169 return AVIERR_UNSUPPORTED
;
1172 This
->lpFormat
->nBlockAlign
=
1173 (This
->lpFormat
->nChannels
* This
->lpFormat
->wBitsPerSample
) / 8;
1174 if (This
->lpFormat
->nBlockAlign
== 0 && This
->lpFormat
->wBitsPerSample
< 8)
1175 This
->lpFormat
->nBlockAlign
++;
1176 This
->lpFormat
->nAvgBytesPerSec
=
1177 This
->lpFormat
->nBlockAlign
* This
->lpFormat
->nSamplesPerSec
;
1179 This
->fDirty
= FALSE
;
1181 This
->sInfo
.fccType
= streamtypeAUDIO
;
1182 This
->sInfo
.fccHandler
= 0;
1183 This
->sInfo
.dwFlags
= 0;
1184 This
->sInfo
.wPriority
= 0;
1185 This
->sInfo
.wLanguage
= 0;
1186 This
->sInfo
.dwInitialFrames
= 0;
1187 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
1188 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
1189 This
->sInfo
.dwStart
= 0;
1190 This
->sInfo
.dwLength
=
1191 This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1192 This
->sInfo
.dwSuggestedBufferSize
= This
->sInfo
.dwLength
;
1193 This
->sInfo
.dwSampleSize
= This
->lpFormat
->nBlockAlign
;
1195 This
->fInfo
.dwStreams
= 1;
1196 This
->fInfo
.dwScale
= 1;
1197 This
->fInfo
.dwRate
= This
->lpFormat
->nSamplesPerSec
;
1198 This
->fInfo
.dwLength
=
1199 MulDiv(This
->ckData
.cksize
, This
->lpFormat
->nSamplesPerSec
,
1200 This
->lpFormat
->nAvgBytesPerSec
);
1205 static HRESULT
AVIFILE_SaveFile(const IAVIFileImpl
*This
)
1210 mmioSeek(This
->hmmio
, 0, SEEK_SET
);
1212 /* create the RIFF chunk with formtype WAVE */
1213 ckRIFF
.fccType
= formtypeWAVE
;
1215 if (mmioCreateChunk(This
->hmmio
, &ckRIFF
, MMIO_CREATERIFF
) != S_OK
)
1216 return AVIERR_FILEWRITE
;
1218 /* the next chunk is the format */
1219 ck
.ckid
= ckidWAVEFORMAT
;
1220 ck
.cksize
= This
->cbFormat
;
1221 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1222 return AVIERR_FILEWRITE
;
1223 if (This
->lpFormat
!= NULL
&& This
->cbFormat
> 0) {
1224 if (mmioWrite(This
->hmmio
, (HPSTR
)This
->lpFormat
, ck
.cksize
) != ck
.cksize
)
1225 return AVIERR_FILEWRITE
;
1227 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1228 return AVIERR_FILEWRITE
;
1230 /* fact chunk is needed for non-pcm waveforms */
1231 if (This
->lpFormat
!= NULL
&& This
->cbFormat
> sizeof(PCMWAVEFORMAT
) &&
1232 This
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
1237 /* try to open an appropriate audio codec to figure out
1238 * data for fact-chunk */
1239 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
1240 if (acmFormatSuggest(NULL
, This
->lpFormat
, &wfx
,
1241 sizeof(wfx
), ACM_FORMATSUGGESTF_WFORMATTAG
)) {
1242 acmStreamOpen(&has
, NULL
, This
->lpFormat
, &wfx
, NULL
,
1243 0, 0, ACM_STREAMOPENF_NONREALTIME
);
1244 acmStreamSize(has
, This
->ckData
.cksize
, &dwFactLength
,
1245 ACM_STREAMSIZEF_SOURCE
);
1246 dwFactLength
/= wfx
.nBlockAlign
;
1247 acmStreamClose(has
, 0);
1249 /* create the fact chunk */
1250 ck
.ckid
= ckidWAVEFACT
;
1251 ck
.cksize
= sizeof(dwFactLength
);
1253 /* test for enough space before data chunk */
1254 if (mmioSeek(This
->hmmio
, 0, SEEK_CUR
) > This
->ckData
.dwDataOffset
1255 - ck
.cksize
- 4 * sizeof(DWORD
))
1256 return AVIERR_FILEWRITE
;
1257 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1258 return AVIERR_FILEWRITE
;
1259 if (mmioWrite(This
->hmmio
, (HPSTR
)&dwFactLength
, ck
.cksize
) != ck
.cksize
)
1260 return AVIERR_FILEWRITE
;
1261 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1262 return AVIERR_FILEWRITE
;
1264 ERR(": fact chunk is needed for non-pcm files -- currently no codec found, so skipped!\n");
1267 /* if there was extra stuff, we need to fill it with JUNK */
1268 if (mmioSeek(This
->hmmio
, 0, SEEK_CUR
) + 2 * sizeof(DWORD
) < This
->ckData
.dwDataOffset
) {
1269 ck
.ckid
= ckidAVIPADDING
;
1271 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1272 return AVIERR_FILEWRITE
;
1274 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
1275 - 2 * sizeof(DWORD
), SEEK_SET
) == -1)
1276 return AVIERR_FILEWRITE
;
1277 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1278 return AVIERR_FILEWRITE
;
1281 /* create the data chunk */
1282 ck
.ckid
= ckidWAVEDATA
;
1283 ck
.cksize
= This
->ckData
.cksize
;
1284 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1285 return AVIERR_FILEWRITE
;
1286 if (mmioSeek(This
->hmmio
, This
->ckData
.cksize
, SEEK_CUR
) == -1)
1287 return AVIERR_FILEWRITE
;
1288 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1289 return AVIERR_FILEWRITE
;
1291 /* some optional extra chunks? */
1292 if (This
->extra
.lp
!= NULL
&& This
->extra
.cb
> 0) {
1293 /* chunk headers are already in structure */
1294 if (mmioWrite(This
->hmmio
, This
->extra
.lp
, This
->extra
.cb
) != This
->extra
.cb
)
1295 return AVIERR_FILEWRITE
;
1298 /* close RIFF chunk */
1299 if (mmioAscend(This
->hmmio
, &ckRIFF
, 0) != S_OK
)
1300 return AVIERR_FILEWRITE
;
1301 if (mmioFlush(This
->hmmio
, 0) != S_OK
)
1302 return AVIERR_FILEWRITE
;