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
19 #define COM_NO_WINDOWS_H
31 #include "avifile_private.h"
32 #include "extrachunk.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(avifile
);
38 /***********************************************************************/
40 #define formtypeWAVE mmioFOURCC('W','A','V','E')
41 #define ckidWAVEFORMAT mmioFOURCC('f','m','t',' ')
42 #define ckidWAVEFACT mmioFOURCC('f','a','c','t')
43 #define ckidWAVEDATA mmioFOURCC('d','a','t','a')
45 /***********************************************************************/
47 static HRESULT WINAPI
IAVIFile_fnQueryInterface(IAVIFile
* iface
,REFIID refiid
,LPVOID
*obj
);
48 static ULONG WINAPI
IAVIFile_fnAddRef(IAVIFile
* iface
);
49 static ULONG WINAPI
IAVIFile_fnRelease(IAVIFile
* iface
);
50 static HRESULT WINAPI
IAVIFile_fnInfo(IAVIFile
*iface
,AVIFILEINFOW
*afi
,LONG size
);
51 static HRESULT WINAPI
IAVIFile_fnGetStream(IAVIFile
*iface
,PAVISTREAM
*avis
,DWORD fccType
,LONG lParam
);
52 static HRESULT WINAPI
IAVIFile_fnCreateStream(IAVIFile
*iface
,PAVISTREAM
*avis
,AVISTREAMINFOW
*asi
);
53 static HRESULT WINAPI
IAVIFile_fnWriteData(IAVIFile
*iface
,DWORD ckid
,LPVOID lpData
,LONG size
);
54 static HRESULT WINAPI
IAVIFile_fnReadData(IAVIFile
*iface
,DWORD ckid
,LPVOID lpData
,LONG
*size
);
55 static HRESULT WINAPI
IAVIFile_fnEndRecord(IAVIFile
*iface
);
56 static HRESULT WINAPI
IAVIFile_fnDeleteStream(IAVIFile
*iface
,DWORD fccType
,LONG lParam
);
58 struct ICOM_VTABLE(IAVIFile
) iwavft
= {
59 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
60 IAVIFile_fnQueryInterface
,
65 IAVIFile_fnCreateStream
,
69 IAVIFile_fnDeleteStream
72 static HRESULT WINAPI
IPersistFile_fnQueryInterface(IPersistFile
*iface
,REFIID refiid
,LPVOID
*obj
);
73 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
*iface
);
74 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
*iface
);
75 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
*iface
,CLSID
*pClassID
);
76 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
*iface
);
77 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
*iface
,LPCOLESTR pszFileName
,DWORD dwMode
);
78 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
*iface
,LPCOLESTR pszFileName
,BOOL fRemember
);
79 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
*iface
,LPCOLESTR pszFileName
);
80 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
*iface
,LPOLESTR
*ppszFileName
);
82 struct ICOM_VTABLE(IPersistFile
) iwavpft
= {
83 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
84 IPersistFile_fnQueryInterface
,
85 IPersistFile_fnAddRef
,
86 IPersistFile_fnRelease
,
87 IPersistFile_fnGetClassID
,
88 IPersistFile_fnIsDirty
,
91 IPersistFile_fnSaveCompleted
,
92 IPersistFile_fnGetCurFile
95 static HRESULT WINAPI
IAVIStream_fnQueryInterface(IAVIStream
*iface
,REFIID refiid
,LPVOID
*obj
);
96 static ULONG WINAPI
IAVIStream_fnAddRef(IAVIStream
*iface
);
97 static ULONG WINAPI
IAVIStream_fnRelease(IAVIStream
* iface
);
98 static HRESULT WINAPI
IAVIStream_fnCreate(IAVIStream
*iface
,LPARAM lParam1
,LPARAM lParam2
);
99 static HRESULT WINAPI
IAVIStream_fnInfo(IAVIStream
*iface
,AVISTREAMINFOW
*psi
,LONG size
);
100 static LONG WINAPI
IAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,LONG flags
);
101 static HRESULT WINAPI
IAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG
*formatsize
);
102 static HRESULT WINAPI
IAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG formatsize
);
103 static HRESULT WINAPI
IAVIStream_fnRead(IAVIStream
*iface
,LONG start
,LONG samples
,LPVOID buffer
,LONG buffersize
,LONG
*bytesread
,LONG
*samplesread
);
104 static HRESULT WINAPI
IAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,LONG samples
,LPVOID buffer
,LONG buffersize
,DWORD flags
,LONG
*sampwritten
,LONG
*byteswritten
);
105 static HRESULT WINAPI
IAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,LONG samples
);
106 static HRESULT WINAPI
IAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,LPVOID lp
,LONG
*lpread
);
107 static HRESULT WINAPI
IAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,LPVOID lp
,LONG size
);
108 static HRESULT WINAPI
IAVIStream_fnSetInfo(IAVIStream
*iface
,AVISTREAMINFOW
*info
,LONG infolen
);
110 struct ICOM_VTABLE(IAVIStream
) iwavst
= {
111 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
112 IAVIStream_fnQueryInterface
,
114 IAVIStream_fnRelease
,
117 IAVIStream_fnFindSample
,
118 IAVIStream_fnReadFormat
,
119 IAVIStream_fnSetFormat
,
123 IAVIStream_fnReadData
,
124 IAVIStream_fnWriteData
,
128 typedef struct _IAVIFileImpl IAVIFileImpl
;
130 typedef struct _IPersistFileImpl
{
132 ICOM_VFIELD(IPersistFile
);
134 /* IPersistFile stuff */
138 typedef struct _IAVIStreamImpl
{
140 ICOM_VFIELD(IAVIStream
);
142 /* IAVIStream stuff */
146 struct _IAVIFileImpl
{
148 ICOM_VFIELD(IAVIFile
);
151 /* IAVIFile, IAVIStream stuff... */
152 IPersistFileImpl iPersistFile
;
153 IAVIStreamImpl iAVIStream
;
156 AVISTREAMINFOW sInfo
;
158 LPWAVEFORMATEX lpFormat
;
165 /* IPersistFile stuff ... */
172 /***********************************************************************/
174 static HRESULT
AVIFILE_LoadFile(IAVIFileImpl
*This
);
175 static HRESULT
AVIFILE_LoadSunFile(IAVIFileImpl
*This
);
176 static HRESULT
AVIFILE_SaveFile(IAVIFileImpl
*This
);
178 HRESULT
AVIFILE_CreateWAVFile(REFIID riid
, LPVOID
*ppv
)
183 assert(riid
!= NULL
&& ppv
!= NULL
);
187 pfile
= (IAVIFileImpl
*)LocalAlloc(LPTR
, sizeof(IAVIFileImpl
));
189 return AVIERR_MEMORY
;
191 ICOM_VTBL(pfile
) = &iwavft
;
192 ICOM_VTBL(&pfile
->iPersistFile
) = &iwavpft
;
193 ICOM_VTBL(&pfile
->iAVIStream
) = &iwavst
;
195 pfile
->iPersistFile
.paf
= pfile
;
196 pfile
->iAVIStream
.paf
= pfile
;
198 hr
= IUnknown_QueryInterface((IUnknown
*)pfile
, riid
, ppv
);
200 LocalFree((HLOCAL
)pfile
);
205 static HRESULT WINAPI
IAVIFile_fnQueryInterface(IAVIFile
*iface
, REFIID refiid
,
208 ICOM_THIS(IAVIFileImpl
,iface
);
210 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(refiid
), obj
);
212 if (IsEqualGUID(&IID_IUnknown
, refiid
) ||
213 IsEqualGUID(&IID_IAVIFile
, refiid
)) {
216 } else if (This
->fInfo
.dwStreams
== 1 &&
217 IsEqualGUID(&IID_IAVIStream
, refiid
)) {
218 *obj
= &This
->iAVIStream
;
220 } else if (IsEqualGUID(&IID_IPersistFile
, refiid
)) {
221 *obj
= &This
->iPersistFile
;
225 return OLE_E_ENUM_NOMORE
;
228 static ULONG WINAPI
IAVIFile_fnAddRef(IAVIFile
*iface
)
230 ICOM_THIS(IAVIFileImpl
,iface
);
232 TRACE("(%p)\n",iface
);
234 return ++(This
->ref
);
237 static ULONG WINAPI
IAVIFile_fnRelease(IAVIFile
*iface
)
239 ICOM_THIS(IAVIFileImpl
,iface
);
241 TRACE("(%p)\n",iface
);
243 if (!--(This
->ref
)) {
245 /* need to write headers to file */
246 AVIFILE_SaveFile(This
);
249 if (This
->lpFormat
!= NULL
) {
250 GlobalFreePtr(This
->lpFormat
);
251 This
->lpFormat
= NULL
;
254 if (This
->extra
.lp
!= NULL
) {
255 GlobalFreePtr(This
->extra
.lp
);
256 This
->extra
.lp
= NULL
;
259 if (This
->szFileName
!= NULL
) {
260 LocalFree((HLOCAL
)This
->szFileName
);
261 This
->szFileName
= NULL
;
263 if (This
->hmmio
!= NULL
) {
264 mmioClose(This
->hmmio
, 0);
268 LocalFree((HLOCAL
)This
);
274 static HRESULT WINAPI
IAVIFile_fnInfo(IAVIFile
*iface
, LPAVIFILEINFOW afi
,
277 ICOM_THIS(IAVIFileImpl
,iface
);
279 TRACE("(%p,%p,%ld)\n",iface
,afi
,size
);
282 return AVIERR_BADPARAM
;
284 return AVIERR_BADSIZE
;
286 /* update file info */
287 This
->fInfo
.dwFlags
= 0;
288 This
->fInfo
.dwCaps
= AVIFILECAPS_CANREAD
|AVIFILECAPS_CANWRITE
;
289 if (This
->lpFormat
!= NULL
) {
290 assert(This
->sInfo
.dwScale
!= 0);
292 This
->fInfo
.dwStreams
= 1;
293 This
->fInfo
.dwScale
= This
->sInfo
.dwScale
;
294 This
->fInfo
.dwRate
= This
->sInfo
.dwRate
;
295 This
->fInfo
.dwLength
= This
->sInfo
.dwLength
;
296 This
->fInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
297 This
->fInfo
.dwMaxBytesPerSec
=
298 MulDiv(This
->sInfo
.dwSampleSize
,This
->sInfo
.dwRate
,This
->sInfo
.dwScale
);
301 memcpy(afi
, &This
->fInfo
, min(size
, sizeof(This
->fInfo
)));
303 if (size
< sizeof(This
->fInfo
))
304 return AVIERR_BUFFERTOOSMALL
;
308 static HRESULT WINAPI
IAVIFile_fnGetStream(IAVIFile
*iface
, PAVISTREAM
*avis
,
309 DWORD fccType
, LONG lParam
)
311 ICOM_THIS(IAVIFileImpl
,iface
);
313 TRACE("(%p,%p,0x%08lX,%ld)\n", iface
, avis
, fccType
, lParam
);
315 /* check parameter */
317 return AVIERR_BADPARAM
;
321 /* Does our stream exists? */
322 if (lParam
!= 0 || This
->fInfo
.dwStreams
== 0)
323 return AVIERR_NODATA
;
324 if (fccType
!= 0 && fccType
!= streamtypeAUDIO
)
325 return AVIERR_NODATA
;
327 *avis
= (PAVISTREAM
)&This
->iAVIStream
;
328 IAVIFile_AddRef(iface
);
333 static HRESULT WINAPI
IAVIFile_fnCreateStream(IAVIFile
*iface
,PAVISTREAM
*avis
,
334 LPAVISTREAMINFOW asi
)
336 ICOM_THIS(IAVIFileImpl
,iface
);
338 TRACE("(%p,%p,%p)\n", iface
, avis
, asi
);
340 /* check parameters */
341 if (avis
== NULL
|| asi
== NULL
)
342 return AVIERR_BADPARAM
;
346 /* We only support one audio stream */
347 if (This
->fInfo
.dwStreams
!= 0 || This
->lpFormat
!= NULL
)
348 return AVIERR_UNSUPPORTED
;
349 if (asi
->fccType
!= streamtypeAUDIO
)
350 return AVIERR_UNSUPPORTED
;
352 /* Does the user have write permission? */
353 if ((This
->uMode
& MMIO_RWMODE
) == 0)
354 return AVIERR_READONLY
;
357 This
->lpFormat
= NULL
;
359 memcpy(&This
->sInfo
, asi
, sizeof(This
->sInfo
));
361 /* make sure streaminfo if okay for us */
362 This
->sInfo
.fccHandler
= 0;
363 This
->sInfo
.dwFlags
= 0;
364 This
->sInfo
.dwCaps
= AVIFILECAPS_CANREAD
|AVIFILECAPS_CANWRITE
;
365 This
->sInfo
.dwStart
= 0;
366 This
->sInfo
.dwInitialFrames
= 0;
367 This
->sInfo
.dwFormatChangeCount
= 0;
368 memset(&This
->sInfo
.rcFrame
, 0, sizeof(This
->sInfo
.rcFrame
));
370 This
->fInfo
.dwStreams
= 1;
371 This
->fInfo
.dwScale
= This
->sInfo
.dwScale
;
372 This
->fInfo
.dwRate
= This
->sInfo
.dwRate
;
373 This
->fInfo
.dwLength
= This
->sInfo
.dwLength
;
375 This
->ckData
.dwDataOffset
= 0;
376 This
->ckData
.cksize
= 0;
378 *avis
= (PAVISTREAM
)&This
->iAVIStream
;
379 IAVIFile_AddRef(iface
);
384 static HRESULT WINAPI
IAVIFile_fnWriteData(IAVIFile
*iface
, DWORD ckid
,
385 LPVOID lpData
, LONG size
)
387 ICOM_THIS(IAVIFileImpl
,iface
);
389 TRACE("(%p,0x%08lX,%p,%ld)\n", iface
, ckid
, lpData
, size
);
391 /* check parameters */
393 return AVIERR_BADPARAM
;
395 return AVIERR_BADSIZE
;
397 /* Do we have write permission? */
398 if ((This
->uMode
& MMIO_RWMODE
) == 0)
399 return AVIERR_READONLY
;
403 return WriteExtraChunk(&This
->extra
, ckid
, lpData
, size
);
406 static HRESULT WINAPI
IAVIFile_fnReadData(IAVIFile
*iface
, DWORD ckid
,
407 LPVOID lpData
, LONG
*size
)
409 ICOM_THIS(IAVIFileImpl
,iface
);
411 TRACE("(%p,0x%08lX,%p,%p)\n", iface
, ckid
, lpData
, size
);
413 return ReadExtraChunk(&This
->extra
, ckid
, lpData
, size
);
416 static HRESULT WINAPI
IAVIFile_fnEndRecord(IAVIFile
*iface
)
418 TRACE("(%p)\n",iface
);
420 /* This is only needed for interleaved files.
421 * We have only one stream, which can't be interleaved.
426 static HRESULT WINAPI
IAVIFile_fnDeleteStream(IAVIFile
*iface
, DWORD fccType
,
429 ICOM_THIS(IAVIFileImpl
,iface
);
431 TRACE("(%p,0x%08lX,%ld)\n", iface
, fccType
, lParam
);
433 /* check parameter */
435 return AVIERR_BADPARAM
;
437 /* Have we our audio stream? */
438 if (lParam
!= 0 || This
->fInfo
.dwStreams
== 0 ||
439 (fccType
!= 0 && fccType
!= streamtypeAUDIO
))
440 return AVIERR_NODATA
;
442 /* Have user write permissions? */
443 if ((This
->uMode
& MMIO_RWMODE
) == 0)
444 return AVIERR_READONLY
;
446 GlobalFreePtr(This
->lpFormat
);
447 This
->lpFormat
= NULL
;
451 This
->ckData
.dwDataOffset
= 0;
452 This
->ckData
.cksize
= 0;
454 This
->sInfo
.dwScale
= 0;
455 This
->sInfo
.dwRate
= 0;
456 This
->sInfo
.dwLength
= 0;
457 This
->sInfo
.dwSuggestedBufferSize
= 0;
459 This
->fInfo
.dwStreams
= 0;
460 This
->fInfo
.dwEditCount
++;
467 /***********************************************************************/
469 static HRESULT WINAPI
IPersistFile_fnQueryInterface(IPersistFile
*iface
,
470 REFIID refiid
, LPVOID
*obj
)
472 ICOM_THIS(IPersistFileImpl
,iface
);
474 assert(This
->paf
!= NULL
);
476 return IAVIFile_QueryInterface((PAVIFILE
)This
->paf
, refiid
, obj
);
479 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
*iface
)
481 ICOM_THIS(IPersistFileImpl
,iface
);
483 assert(This
->paf
!= NULL
);
485 return IAVIFile_AddRef((PAVIFILE
)This
->paf
);
488 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
*iface
)
490 ICOM_THIS(IPersistFileImpl
,iface
);
492 assert(This
->paf
!= NULL
);
494 return IAVIFile_Release((PAVIFILE
)This
->paf
);
497 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
*iface
,
500 TRACE("(%p,%p)\n", iface
, pClassID
);
502 if (pClassID
== NULL
)
503 return AVIERR_BADPARAM
;
505 memcpy(pClassID
, &CLSID_WAVFile
, sizeof(CLSID_WAVFile
));
510 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
*iface
)
512 ICOM_THIS(IPersistFileImpl
,iface
);
514 TRACE("(%p)\n", iface
);
516 assert(This
->paf
!= NULL
);
518 return (This
->paf
->fDirty
? S_OK
: S_FALSE
);
521 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
*iface
,
522 LPCOLESTR pszFileName
, DWORD dwMode
)
524 IAVIFileImpl
*This
= ((IPersistFileImpl
*)iface
)->paf
;
526 WCHAR wszStreamFmt
[50];
529 TRACE("(%p,%s,0x%08lX)\n", iface
, debugstr_w(pszFileName
), dwMode
);
531 /* check parameter */
532 if (pszFileName
== NULL
)
533 return AVIERR_BADPARAM
;
535 assert(This
!= NULL
);
536 if (This
->hmmio
!= NULL
)
537 return AVIERR_ERROR
; /* No reuse of this object for another file! */
539 /* remeber mode and name */
540 This
->uMode
= dwMode
;
542 len
= lstrlenW(pszFileName
) + 1;
543 This
->szFileName
= (LPWSTR
)LocalAlloc(LPTR
, len
* sizeof(WCHAR
));
544 if (This
->szFileName
== NULL
)
545 return AVIERR_MEMORY
;
546 lstrcpyW(This
->szFileName
, pszFileName
);
548 /* try to open the file */
549 This
->hmmio
= mmioOpenW(This
->szFileName
, NULL
, MMIO_ALLOCBUF
| dwMode
);
550 if (This
->hmmio
== NULL
)
551 return AVIERR_FILEOPEN
;
553 memset(& This
->fInfo
, 0, sizeof(This
->fInfo
));
554 memset(& This
->sInfo
, 0, sizeof(This
->sInfo
));
556 LoadStringW(AVIFILE_hModule
, IDS_WAVEFILETYPE
, This
->fInfo
.szFileType
,
557 sizeof(This
->fInfo
.szFileType
));
558 if (LoadStringW(AVIFILE_hModule
, IDS_WAVESTREAMFORMAT
,
559 wszStreamFmt
, sizeof(wszStreamFmt
)) > 0) {
560 wsprintfW(This
->sInfo
.szName
, wszStreamFmt
,
561 AVIFILE_BasenameW(This
->szFileName
));
564 /* should we create a new file? */
565 if (dwMode
& OF_CREATE
) {
566 /* nothing more to do */
569 return AVIFILE_LoadFile(This
);
572 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
*iface
,
573 LPCOLESTR pszFileName
,BOOL fRemember
)
575 TRACE("(%p,%s,%d)\n", iface
, debugstr_w(pszFileName
), fRemember
);
577 /* We write directly to disk, so nothing to do. */
582 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
*iface
,
583 LPCOLESTR pszFileName
)
585 TRACE("(%p,%s)\n", iface
, debugstr_w(pszFileName
));
587 /* We write directly to disk, so nothing to do. */
592 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
*iface
,
593 LPOLESTR
*ppszFileName
)
595 ICOM_THIS(IPersistFileImpl
,iface
);
597 TRACE("(%p,%p)\n", iface
, ppszFileName
);
599 if (ppszFileName
== NULL
)
600 return AVIERR_BADPARAM
;
602 *ppszFileName
= NULL
;
604 assert(This
->paf
!= NULL
);
606 if (This
->paf
->szFileName
!= NULL
) {
607 int len
= lstrlenW(This
->paf
->szFileName
);
609 *ppszFileName
= (LPOLESTR
)GlobalAllocPtr(GHND
, len
* sizeof(WCHAR
));
610 if (*ppszFileName
== NULL
)
611 return AVIERR_MEMORY
;
613 memcpy(*ppszFileName
, This
->paf
->szFileName
, len
* sizeof(WCHAR
));
619 /***********************************************************************/
621 static HRESULT WINAPI
IAVIStream_fnQueryInterface(IAVIStream
*iface
,
622 REFIID refiid
, LPVOID
*obj
)
624 ICOM_THIS(IAVIStreamImpl
,iface
);
626 assert(This
->paf
!= NULL
);
628 return IAVIFile_QueryInterface((PAVIFILE
)This
->paf
, refiid
, obj
);
631 static ULONG WINAPI
IAVIStream_fnAddRef(IAVIStream
*iface
)
633 ICOM_THIS(IAVIStreamImpl
,iface
);
635 assert(This
->paf
!= NULL
);
637 return IAVIFile_AddRef((PAVIFILE
)This
->paf
);
640 static ULONG WINAPI
IAVIStream_fnRelease(IAVIStream
* iface
)
642 ICOM_THIS(IAVIStreamImpl
,iface
);
644 assert(This
->paf
!= NULL
);
646 return IAVIFile_Release((PAVIFILE
)This
->paf
);
649 static HRESULT WINAPI
IAVIStream_fnCreate(IAVIStream
*iface
, LPARAM lParam1
,
652 TRACE("(%p,0x%08lX,0x%08lX)\n", iface
, lParam1
, lParam2
);
654 /* This IAVIStream interface needs an WAVFile */
655 return AVIERR_UNSUPPORTED
;
658 static HRESULT WINAPI
IAVIStream_fnInfo(IAVIStream
*iface
,LPAVISTREAMINFOW psi
,
661 ICOM_THIS(IAVIStreamImpl
,iface
);
663 TRACE("(%p,%p,%ld)\n", iface
, psi
, size
);
666 return AVIERR_BADPARAM
;
668 return AVIERR_BADSIZE
;
670 memcpy(psi
, &This
->paf
->sInfo
, min(size
, sizeof(This
->paf
->sInfo
)));
672 if (size
< sizeof(This
->paf
->sInfo
))
673 return AVIERR_BUFFERTOOSMALL
;
677 static LONG WINAPI
IAVIStream_fnFindSample(IAVIStream
*iface
, LONG pos
,
680 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
682 TRACE("(%p,%ld,0x%08lX)\n",iface
,pos
,flags
);
684 /* Do we have data? */
685 if (This
->lpFormat
== NULL
)
688 /* We don't have an index */
689 if (flags
& FIND_INDEX
)
692 if (flags
& FIND_FROM_START
) {
693 pos
= This
->sInfo
.dwStart
;
694 flags
&= ~(FIND_FROM_START
|FIND_PREV
);
698 if (flags
& FIND_FORMAT
) {
699 if ((flags
& FIND_NEXT
) && pos
> 0)
705 if (flags
& (FIND_LENGTH
|FIND_SIZE
))
706 return This
->sInfo
.dwSampleSize
;
707 if (flags
& FIND_OFFSET
)
708 return This
->ckData
.dwDataOffset
+ pos
* This
->sInfo
.dwSampleSize
;
713 static HRESULT WINAPI
IAVIStream_fnReadFormat(IAVIStream
*iface
, LONG pos
,
714 LPVOID format
, LONG
*formatsize
)
716 ICOM_THIS(IAVIStreamImpl
,iface
);
718 TRACE("(%p,%ld,%p,%p)\n", iface
, pos
, format
, formatsize
);
720 if (formatsize
== NULL
)
721 return AVIERR_BADPARAM
;
723 /* only interested in needed buffersize? */
724 if (format
== NULL
|| *formatsize
<= 0) {
725 *formatsize
= This
->paf
->cbFormat
;
730 /* copy initial format (only as much as will fit) */
731 memcpy(format
, This
->paf
->lpFormat
, min(*formatsize
, This
->paf
->cbFormat
));
732 if (*formatsize
< This
->paf
->cbFormat
) {
733 *formatsize
= This
->paf
->cbFormat
;
734 return AVIERR_BUFFERTOOSMALL
;
737 *formatsize
= This
->paf
->cbFormat
;
741 static HRESULT WINAPI
IAVIStream_fnSetFormat(IAVIStream
*iface
, LONG pos
,
742 LPVOID format
, LONG formatsize
)
744 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
746 TRACE("(%p,%ld,%p,%ld)\n", iface
, pos
, format
, formatsize
);
748 /* check parameters */
749 if (format
== NULL
|| formatsize
<= sizeof(PCMWAVEFORMAT
))
750 return AVIERR_BADPARAM
;
752 /* We can only do this to an empty wave file, but ignore call
753 * if still same format */
754 if (This
->lpFormat
!= NULL
) {
755 if (formatsize
!= This
->cbFormat
||
756 memcmp(format
, This
->lpFormat
, formatsize
) != 0)
757 return AVIERR_UNSUPPORTED
;
762 /* only support start at position 0 */
764 return AVIERR_UNSUPPORTED
;
766 /* Do we have write permission? */
767 if ((This
->uMode
& MMIO_RWMODE
) == 0)
768 return AVIERR_READONLY
;
770 /* get memory for format and copy it */
771 This
->lpFormat
= (LPWAVEFORMATEX
)GlobalAllocPtr(GMEM_MOVEABLE
, formatsize
);
772 if (This
->lpFormat
== NULL
)
773 return AVIERR_MEMORY
;
775 This
->cbFormat
= formatsize
;
776 memcpy(This
->lpFormat
, format
, formatsize
);
778 /* update info's about 'data' chunk */
779 This
->ckData
.dwDataOffset
= formatsize
+ 7 * sizeof(DWORD
);
780 This
->ckData
.cksize
= 0;
782 /* for non-pcm format we need also a 'fact' chunk */
783 if (This
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
)
784 This
->ckData
.dwDataOffset
+= 3 * sizeof(DWORD
);
786 /* update stream and file info */
787 This
->sInfo
.dwSampleSize
= This
->lpFormat
->nBlockAlign
;
788 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
789 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
790 This
->sInfo
.dwLength
= 0;
791 This
->sInfo
.dwSuggestedBufferSize
= 0;
796 static HRESULT WINAPI
IAVIStream_fnRead(IAVIStream
*iface
, LONG start
,
797 LONG samples
, LPVOID buffer
,
798 LONG buffersize
, LPLONG bytesread
,
801 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
803 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface
, start
, samples
, buffer
,
804 buffersize
, bytesread
, samplesread
);
806 /* clear return parameters if given */
807 if (bytesread
!= NULL
)
809 if (samplesread
!= NULL
)
812 /* positions without data */
813 if (start
< 0 || start
> This
->sInfo
.dwLength
)
819 if (buffersize
> 0) {
821 samples
= min(samples
, buffersize
/ This
->sInfo
.dwSampleSize
);
823 samples
= buffersize
/ This
->sInfo
.dwSampleSize
;
826 /* limit to end of stream */
827 if (start
+ samples
> This
->sInfo
.dwLength
)
828 samples
= This
->sInfo
.dwLength
- start
;
830 /* request only the sizes? */
831 if (buffer
== NULL
|| buffersize
<= 0) {
832 /* then I need atleast one parameter for it */
833 if (bytesread
== NULL
&& samplesread
== NULL
)
834 return AVIERR_BADPARAM
;
836 if (bytesread
!= NULL
)
837 *bytesread
= samples
* This
->sInfo
.dwSampleSize
;
838 if (samplesread
!= NULL
)
839 *samplesread
= samples
;
844 /* nothing to read? */
848 /* Can I atleast read one sample? */
849 if (buffersize
< This
->sInfo
.dwSampleSize
)
850 return AVIERR_BUFFERTOOSMALL
;
852 buffersize
= samples
* This
->sInfo
.dwSampleSize
;
854 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
855 + start
* This
->sInfo
.dwSampleSize
, SEEK_SET
) == -1)
856 return AVIERR_FILEREAD
;
857 if (mmioRead(This
->hmmio
, (HPSTR
)buffer
, buffersize
) != buffersize
)
858 return AVIERR_FILEREAD
;
860 /* fill out return parameters if given */
861 if (bytesread
!= NULL
)
862 *bytesread
= buffersize
;
863 if (samplesread
!= NULL
)
864 *samplesread
= samples
;
869 static HRESULT WINAPI
IAVIStream_fnWrite(IAVIStream
*iface
, LONG start
,
870 LONG samples
, LPVOID buffer
,
871 LONG buffersize
, DWORD flags
,
875 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
877 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface
, start
, samples
,
878 buffer
, buffersize
, flags
, sampwritten
, byteswritten
);
880 /* clear return parameters if given */
881 if (sampwritten
!= NULL
)
883 if (byteswritten
!= NULL
)
886 /* check parameters */
887 if (buffer
== NULL
&& (buffersize
> 0 || samples
> 0))
888 return AVIERR_BADPARAM
;
890 /* Have we write permission? */
891 if ((This
->uMode
& MMIO_RWMODE
) == 0)
892 return AVIERR_READONLY
;
894 /* < 0 means "append" */
896 start
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
;
898 /* check buffersize -- must multiple of samplesize */
899 if (buffersize
& ~(This
->sInfo
.dwSampleSize
- 1))
900 return AVIERR_BADSIZE
;
902 /* have we anything to write? */
903 if (buffer
!= NULL
&& buffersize
> 0) {
906 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
+
907 start
* This
->sInfo
.dwSampleSize
, SEEK_SET
) == -1)
908 return AVIERR_FILEWRITE
;
909 if (mmioWrite(This
->hmmio
, (HPSTR
)buffer
, buffersize
) != buffersize
)
910 return AVIERR_FILEWRITE
;
912 This
->sInfo
.dwLength
= max(This
->sInfo
.dwLength
, start
+ samples
);
913 This
->ckData
.cksize
= max(This
->ckData
.cksize
,
914 start
* This
->sInfo
.dwSampleSize
+ buffersize
);
916 /* fill out return parameters if given */
917 if (sampwritten
!= NULL
)
918 *sampwritten
= samples
;
919 if (byteswritten
!= NULL
)
920 *byteswritten
= buffersize
;
926 static HRESULT WINAPI
IAVIStream_fnDelete(IAVIStream
*iface
, LONG start
,
929 IAVIFileImpl
*This
= ((IAVIStreamImpl
*)iface
)->paf
;
931 TRACE("(%p,%ld,%ld)\n", iface
, start
, samples
);
933 /* check parameters */
934 if (start
< 0 || samples
< 0)
935 return AVIERR_BADPARAM
;
937 /* Delete before start of stream? */
938 if (start
+ samples
< This
->sInfo
.dwStart
)
941 /* Delete after end of stream? */
942 if (start
> This
->sInfo
.dwLength
)
945 /* For the rest we need write permissions */
946 if ((This
->uMode
& MMIO_RWMODE
) == 0)
947 return AVIERR_READONLY
;
949 if (start
+ samples
>= This
->sInfo
.dwLength
) {
950 /* deletion at end */
951 samples
= This
->sInfo
.dwLength
- start
;
952 This
->sInfo
.dwLength
-= samples
;
953 This
->ckData
.cksize
-= samples
* This
->sInfo
.dwSampleSize
;
954 } else if (start
<= This
->sInfo
.dwStart
) {
955 /* deletion at start */
956 samples
= This
->sInfo
.dwStart
- start
;
957 start
= This
->sInfo
.dwStart
;
958 This
->ckData
.dwDataOffset
+= samples
* This
->sInfo
.dwSampleSize
;
959 This
->ckData
.cksize
-= samples
* This
->sInfo
.dwSampleSize
;
961 /* deletion inside stream -- needs playlist and cue's */
962 FIXME(": deletion inside of stream not supported!\n");
964 return AVIERR_UNSUPPORTED
;
972 static HRESULT WINAPI
IAVIStream_fnReadData(IAVIStream
*iface
, DWORD fcc
,
973 LPVOID lp
, LPLONG lpread
)
975 ICOM_THIS(IAVIStreamImpl
,iface
);
977 assert(This
->paf
!= NULL
);
979 return IAVIFile_ReadData((PAVIFILE
)This
->paf
, fcc
, lp
, lpread
);
982 static HRESULT WINAPI
IAVIStream_fnWriteData(IAVIStream
*iface
, DWORD fcc
,
983 LPVOID lp
, LONG size
)
985 ICOM_THIS(IAVIStreamImpl
,iface
);
987 return IAVIFile_WriteData((PAVIFILE
)This
->paf
, fcc
, lp
, size
);
990 static HRESULT WINAPI
IAVIStream_fnSetInfo(IAVIStream
*iface
,
991 LPAVISTREAMINFOW info
, LONG infolen
)
993 FIXME("(%p,%p,%ld): stub\n", iface
, info
, infolen
);
998 /***********************************************************************/
1000 static HRESULT
AVIFILE_LoadFile(IAVIFileImpl
*This
)
1005 This
->sInfo
.dwLength
= 0; /* just to be sure */
1006 This
->fDirty
= FALSE
;
1008 /* search for RIFF chunk */
1009 ckRIFF
.fccType
= 0; /* find any */
1010 if (mmioDescend(This
->hmmio
, &ckRIFF
, NULL
, MMIO_FINDRIFF
) != S_OK
) {
1011 return AVIFILE_LoadSunFile(This
);
1014 if (ckRIFF
.fccType
!= formtypeWAVE
)
1015 return AVIERR_BADFORMAT
;
1017 /* search WAVE format chunk */
1018 ck
.ckid
= ckidWAVEFORMAT
;
1019 if (FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &ck
,
1020 &ckRIFF
, MMIO_FINDCHUNK
) != S_OK
)
1021 return AVIERR_FILEREAD
;
1023 /* get memory for format and read it */
1024 This
->lpFormat
= (LPWAVEFORMATEX
)GlobalAllocPtr(GMEM_MOVEABLE
, ck
.cksize
);
1025 if (This
->lpFormat
== NULL
)
1026 return AVIERR_FILEREAD
;
1027 This
->cbFormat
= ck
.cksize
;
1029 if (mmioRead(This
->hmmio
, (HPSTR
)This
->lpFormat
, ck
.cksize
) != ck
.cksize
)
1030 return AVIERR_FILEREAD
;
1031 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1032 return AVIERR_FILEREAD
;
1034 /* Non-pcm formats have a fact chunk.
1035 * We don't need it, so simply add it to the extra chunks.
1038 /* find the big data chunk */
1039 This
->ckData
.ckid
= ckidWAVEDATA
;
1040 if (FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &This
->ckData
,
1041 &ckRIFF
, MMIO_FINDCHUNK
) != S_OK
)
1042 return AVIERR_FILEREAD
;
1044 memset(&This
->sInfo
, 0, sizeof(This
->sInfo
));
1045 This
->sInfo
.fccType
= streamtypeAUDIO
;
1046 This
->sInfo
.dwRate
= This
->lpFormat
->nAvgBytesPerSec
;
1047 This
->sInfo
.dwSampleSize
=
1048 This
->sInfo
.dwScale
= This
->lpFormat
->nBlockAlign
;
1049 This
->sInfo
.dwLength
= This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1050 This
->sInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
1052 This
->fInfo
.dwStreams
= 1;
1054 if (mmioAscend(This
->hmmio
, &This
->ckData
, 0) != S_OK
) {
1055 /* seems to be truncated */
1056 WARN(": file seems to be truncated!\n");
1057 This
->ckData
.cksize
= mmioSeek(This
->hmmio
, 0, SEEK_END
) -
1058 This
->ckData
.dwDataOffset
;
1059 This
->sInfo
.dwLength
= This
->ckData
.cksize
/ This
->lpFormat
->nBlockAlign
;
1060 This
->sInfo
.dwSuggestedBufferSize
= This
->ckData
.cksize
;
1064 FindChunkAndKeepExtras(&This
->extra
, This
->hmmio
, &ck
, &ckRIFF
, 0);
1069 static HRESULT
AVIFILE_LoadSunFile(IAVIFileImpl
*This
)
1071 FIXME(": pherhaps sun-audio file -- not implemented !\n");
1073 return AVIERR_UNSUPPORTED
;
1076 static HRESULT
AVIFILE_SaveFile(IAVIFileImpl
*This
)
1081 mmioSeek(This
->hmmio
, 0, SEEK_SET
);
1083 /* create the RIFF chunk with formtype WAVE */
1084 ckRIFF
.fccType
= formtypeWAVE
;
1086 if (mmioCreateChunk(This
->hmmio
, &ckRIFF
, MMIO_CREATERIFF
) != S_OK
)
1087 return AVIERR_FILEWRITE
;
1089 /* the next chunk is the format */
1090 ck
.ckid
= ckidWAVEFORMAT
;
1091 ck
.cksize
= This
->cbFormat
;
1092 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1093 return AVIERR_FILEWRITE
;
1094 if (This
->lpFormat
!= NULL
&& This
->cbFormat
> 0) {
1095 if (mmioWrite(This
->hmmio
, (HPSTR
)This
->lpFormat
, ck
.cksize
) != ck
.cksize
)
1096 return AVIERR_FILEWRITE
;
1098 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1099 return AVIERR_FILEWRITE
;
1101 /* fact chunk is needed for non-pcm waveforms */
1102 if (This
->lpFormat
!= NULL
&& This
->cbFormat
> sizeof(PCMWAVEFORMAT
) &&
1103 This
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
1108 /* try to open an appropriate audio codec to figure out
1109 * data for fact-chunk */
1110 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
1111 if (acmFormatSuggest(NULL
, This
->lpFormat
, &wfx
,
1112 sizeof(wfx
), ACM_FORMATSUGGESTF_WFORMATTAG
)) {
1113 acmStreamOpen(&has
, NULL
, This
->lpFormat
, &wfx
, NULL
,
1114 0, 0, ACM_STREAMOPENF_NONREALTIME
);
1115 acmStreamSize(has
, This
->ckData
.cksize
, &dwFactLength
,
1116 ACM_STREAMSIZEF_SOURCE
);
1117 dwFactLength
/= wfx
.nBlockAlign
;
1118 acmStreamClose(has
, 0);
1120 /* crete the fact chunk */
1121 ck
.ckid
= ckidWAVEFACT
;
1122 ck
.cksize
= sizeof(dwFactLength
);
1124 /* test for enough space before data chunk */
1125 if (mmioSeek(This
->hmmio
, 0, SEEK_CUR
) > This
->ckData
.dwDataOffset
1126 - ck
.cksize
- 4 * sizeof(DWORD
))
1127 return AVIERR_FILEWRITE
;
1128 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1129 return AVIERR_FILEWRITE
;
1130 if (mmioWrite(This
->hmmio
, (HPSTR
)&dwFactLength
, ck
.cksize
) != ck
.cksize
)
1131 return AVIERR_FILEWRITE
;
1132 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1133 return AVIERR_FILEWRITE
;
1135 ERR(": fact chunk is needed for non-pcm files -- currently no codec found, so skipped!\n");
1138 /* if here was extra stuff, we need to fill it with JUNK */
1139 if (mmioSeek(This
->hmmio
, 0, SEEK_CUR
) + 2 * sizeof(DWORD
) < This
->ckData
.dwDataOffset
) {
1140 ck
.ckid
= ckidAVIPADDING
;
1142 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1143 return AVIERR_FILEWRITE
;
1145 if (mmioSeek(This
->hmmio
, This
->ckData
.dwDataOffset
1146 - 2 * sizeof(DWORD
), SEEK_SET
) == -1)
1147 return AVIERR_FILEWRITE
;
1148 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1149 return AVIERR_FILEWRITE
;
1152 /* crete the data chunk */
1153 ck
.ckid
= ckidWAVEDATA
;
1154 ck
.cksize
= This
->ckData
.cksize
;
1155 if (mmioCreateChunk(This
->hmmio
, &ck
, 0) != S_OK
)
1156 return AVIERR_FILEWRITE
;
1157 if (mmioSeek(This
->hmmio
, This
->ckData
.cksize
, SEEK_CUR
) == -1)
1158 return AVIERR_FILEWRITE
;
1159 if (mmioAscend(This
->hmmio
, &ck
, 0) != S_OK
)
1160 return AVIERR_FILEWRITE
;
1162 /* some optional extra chunks? */
1163 if (This
->extra
.lp
!= NULL
&& This
->extra
.cb
> 0) {
1164 /* chunk headers are already in structure */
1165 if (mmioWrite(This
->hmmio
, This
->extra
.lp
, This
->extra
.cb
) != This
->extra
.cb
)
1166 return AVIERR_FILEWRITE
;
1169 /* close RIFF chunk */
1170 if (mmioAscend(This
->hmmio
, &ckRIFF
, 0) != S_OK
)
1171 return AVIERR_FILEWRITE
;
1172 if (mmioFlush(This
->hmmio
, 0) != S_OK
)
1173 return AVIERR_FILEWRITE
;