Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/avifil32/wavfile.c
4389 views
1
/*
2
* Copyright 2002 Michael Günnewig
3
*
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.
8
*
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.
13
*
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
17
*/
18
19
#define COBJMACROS
20
#include <assert.h>
21
#include <stdarg.h>
22
23
#include "windef.h"
24
#include "winbase.h"
25
#include "wingdi.h"
26
#include "winuser.h"
27
#include "winnls.h"
28
#include "winerror.h"
29
#include "mmsystem.h"
30
#include "vfw.h"
31
#include "msacm.h"
32
33
#include "avifile_private.h"
34
#include "extrachunk.h"
35
36
#include "wine/debug.h"
37
38
WINE_DEFAULT_DEBUG_CHANNEL(avifile);
39
40
/***********************************************************************/
41
42
#define formtypeWAVE mmioFOURCC('W','A','V','E')
43
#define ckidWAVEFORMAT mmioFOURCC('f','m','t',' ')
44
#define ckidWAVEFACT mmioFOURCC('f','a','c','t')
45
#define ckidWAVEDATA mmioFOURCC('d','a','t','a')
46
47
/***********************************************************************/
48
49
#define ENDIAN_SWAPWORD(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
50
#define ENDIAN_SWAPDWORD(x) (ENDIAN_SWAPWORD((x >> 16) & 0xFFFF) | \
51
ENDIAN_SWAPWORD(x & 0xFFFF) << 16)
52
53
#ifdef WORDS_BIGENDIAN
54
#define BE2H_WORD(x) (x)
55
#define BE2H_DWORD(x) (x)
56
#define LE2H_WORD(x) ENDIAN_SWAPWORD(x)
57
#define LE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
58
#else
59
#define BE2H_WORD(x) ENDIAN_SWAPWORD(x)
60
#define BE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
61
#define LE2H_WORD(x) (x)
62
#define LE2H_DWORD(x) (x)
63
#endif
64
65
typedef struct {
66
FOURCC fccType;
67
DWORD offset;
68
DWORD size;
69
INT encoding;
70
DWORD sampleRate;
71
DWORD channels;
72
} SUNAUDIOHEADER;
73
74
#define AU_ENCODING_ULAW_8 1
75
#define AU_ENCODING_PCM_8 2
76
#define AU_ENCODING_PCM_16 3
77
#define AU_ENCODING_PCM_24 4
78
#define AU_ENCODING_PCM_32 5
79
#define AU_ENCODING_FLOAT 6
80
#define AU_ENCODING_DOUBLE 7
81
#define AU_ENCODING_ADPCM_G721_32 23
82
#define AU_ENCODING_ADPCM_G722 24
83
#define AU_ENCODING_ADPCM_G723_24 25
84
#define AU_ENCODING_ADPCM_G723_5 26
85
#define AU_ENCODING_ALAW_8 27
86
87
/***********************************************************************/
88
89
typedef struct _IAVIFileImpl {
90
IUnknown IUnknown_inner;
91
IAVIFile IAVIFile_iface;
92
IPersistFile IPersistFile_iface;
93
IAVIStream IAVIStream_iface;
94
IUnknown *outer_unk;
95
LONG ref;
96
/* IAVIFile, IAVIStream stuff... */
97
AVIFILEINFOW fInfo;
98
AVISTREAMINFOW sInfo;
99
100
LPWAVEFORMATEX lpFormat;
101
LONG cbFormat;
102
103
MMCKINFO ckData;
104
105
EXTRACHUNKS extra;
106
107
/* IPersistFile stuff ... */
108
HMMIO hmmio;
109
LPWSTR szFileName;
110
UINT uMode;
111
BOOL fDirty;
112
} IAVIFileImpl;
113
114
/***********************************************************************/
115
116
static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
117
static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This);
118
static HRESULT AVIFILE_SaveFile(const IAVIFileImpl *This);
119
120
static inline IAVIFileImpl *impl_from_IUnknown(IUnknown *iface)
121
{
122
return CONTAINING_RECORD(iface, IAVIFileImpl, IUnknown_inner);
123
}
124
125
static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ret_iface)
126
{
127
IAVIFileImpl *This = impl_from_IUnknown(iface);
128
129
TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ret_iface);
130
131
if (IsEqualGUID(&IID_IUnknown, riid))
132
*ret_iface = &This->IUnknown_inner;
133
else if (IsEqualGUID(&IID_IAVIFile, riid))
134
*ret_iface = &This->IAVIFile_iface;
135
else if (IsEqualGUID(&IID_IAVIStream, riid))
136
*ret_iface = &This->IAVIStream_iface;
137
else if (IsEqualGUID(&IID_IPersistFile, riid))
138
*ret_iface = &This->IPersistFile_iface;
139
else {
140
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ret_iface);
141
*ret_iface = NULL;
142
return E_NOINTERFACE;
143
}
144
145
/* Violation of the COM aggregation ref counting rule */
146
IUnknown_AddRef(&This->IUnknown_inner);
147
return S_OK;
148
}
149
150
static ULONG WINAPI IUnknown_fnAddRef(IUnknown *iface)
151
{
152
IAVIFileImpl *This = impl_from_IUnknown(iface);
153
ULONG ref = InterlockedIncrement(&This->ref);
154
155
TRACE("(%p) ref=%ld\n", This, ref);
156
157
return ref;
158
}
159
160
static ULONG WINAPI IUnknown_fnRelease(IUnknown *iface)
161
{
162
IAVIFileImpl *This = impl_from_IUnknown(iface);
163
ULONG ref = InterlockedDecrement(&This->ref);
164
165
TRACE("(%p) ref=%ld\n", This, ref);
166
167
if (!ref) {
168
/* need to write headers to file */
169
if (This->fDirty)
170
AVIFILE_SaveFile(This);
171
172
free(This->lpFormat);
173
This->lpFormat = NULL;
174
This->cbFormat = 0;
175
free(This->extra.lp);
176
This->extra.lp = NULL;
177
This->extra.cb = 0;
178
free(This->szFileName);
179
This->szFileName = NULL;
180
if (This->hmmio) {
181
mmioClose(This->hmmio, 0);
182
This->hmmio = NULL;
183
}
184
free(This);
185
}
186
187
return ref;
188
}
189
190
static const IUnknownVtbl unk_vtbl =
191
{
192
IUnknown_fnQueryInterface,
193
IUnknown_fnAddRef,
194
IUnknown_fnRelease
195
};
196
197
static inline IAVIFileImpl *impl_from_IAVIFile(IAVIFile *iface)
198
{
199
return CONTAINING_RECORD(iface, IAVIFileImpl, IAVIFile_iface);
200
}
201
202
static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID riid, void **ret_iface)
203
{
204
IAVIFileImpl *This = impl_from_IAVIFile(iface);
205
206
return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
207
}
208
209
static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
210
{
211
IAVIFileImpl *This = impl_from_IAVIFile(iface);
212
213
return IUnknown_AddRef(This->outer_unk);
214
}
215
216
static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
217
{
218
IAVIFileImpl *This = impl_from_IAVIFile(iface);
219
220
return IUnknown_Release(This->outer_unk);
221
}
222
223
static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, AVIFILEINFOW *afi, LONG size)
224
{
225
IAVIFileImpl *This = impl_from_IAVIFile(iface);
226
227
TRACE("(%p,%p,%ld)\n",iface,afi,size);
228
229
if (afi == NULL)
230
return AVIERR_BADPARAM;
231
if (size < 0)
232
return AVIERR_BADSIZE;
233
234
/* update file info */
235
This->fInfo.dwFlags = 0;
236
This->fInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
237
if (This->lpFormat != NULL) {
238
assert(This->sInfo.dwScale != 0);
239
240
This->fInfo.dwStreams = 1;
241
This->fInfo.dwScale = This->sInfo.dwScale;
242
This->fInfo.dwRate = This->sInfo.dwRate;
243
This->fInfo.dwLength = This->sInfo.dwLength;
244
This->fInfo.dwSuggestedBufferSize = This->ckData.cksize;
245
This->fInfo.dwMaxBytesPerSec =
246
MulDiv(This->sInfo.dwSampleSize,This->sInfo.dwRate,This->sInfo.dwScale);
247
}
248
249
memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
250
251
if ((DWORD)size < sizeof(This->fInfo))
252
return AVIERR_BUFFERTOOSMALL;
253
return AVIERR_OK;
254
}
255
256
static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, IAVIStream **avis, DWORD fccType,
257
LONG lParam)
258
{
259
IAVIFileImpl *This = impl_from_IAVIFile(iface);
260
261
TRACE("(%p,%p,0x%08lX,%ld)\n", iface, avis, fccType, lParam);
262
263
/* check parameter */
264
if (avis == NULL)
265
return AVIERR_BADPARAM;
266
267
*avis = NULL;
268
269
/* Does our stream exists? */
270
if (lParam != 0 || This->fInfo.dwStreams == 0)
271
return AVIERR_NODATA;
272
if (fccType != 0 && fccType != streamtypeAUDIO)
273
return AVIERR_NODATA;
274
275
*avis = &This->IAVIStream_iface;
276
IAVIStream_AddRef(*avis);
277
278
return AVIERR_OK;
279
}
280
281
static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface, IAVIStream **avis,
282
AVISTREAMINFOW *asi)
283
{
284
IAVIFileImpl *This = impl_from_IAVIFile(iface);
285
286
TRACE("(%p,%p,%p)\n", iface, avis, asi);
287
288
/* check parameters */
289
if (avis == NULL || asi == NULL)
290
return AVIERR_BADPARAM;
291
292
*avis = NULL;
293
294
/* We only support one audio stream */
295
if (This->fInfo.dwStreams != 0 || This->lpFormat != NULL)
296
return AVIERR_UNSUPPORTED;
297
if (asi->fccType != streamtypeAUDIO)
298
return AVIERR_UNSUPPORTED;
299
300
/* Does the user have write permission? */
301
if ((This->uMode & MMIO_RWMODE) == 0)
302
return AVIERR_READONLY;
303
304
This->cbFormat = 0;
305
This->lpFormat = NULL;
306
307
memcpy(&This->sInfo, asi, sizeof(This->sInfo));
308
309
/* make sure streaminfo if okay for us */
310
This->sInfo.fccHandler = 0;
311
This->sInfo.dwFlags = 0;
312
This->sInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
313
This->sInfo.dwStart = 0;
314
This->sInfo.dwInitialFrames = 0;
315
This->sInfo.dwFormatChangeCount = 0;
316
SetRectEmpty(&This->sInfo.rcFrame);
317
318
This->fInfo.dwStreams = 1;
319
This->fInfo.dwScale = This->sInfo.dwScale;
320
This->fInfo.dwRate = This->sInfo.dwRate;
321
This->fInfo.dwLength = This->sInfo.dwLength;
322
323
This->ckData.dwDataOffset = 0;
324
This->ckData.cksize = 0;
325
326
*avis = &This->IAVIStream_iface;
327
IAVIStream_AddRef(*avis);
328
329
return AVIERR_OK;
330
}
331
332
static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid, void *lpData, LONG size)
333
{
334
IAVIFileImpl *This = impl_from_IAVIFile(iface);
335
336
TRACE("(%p,0x%08lX,%p,%ld)\n", iface, ckid, lpData, size);
337
338
/* check parameters */
339
if (lpData == NULL)
340
return AVIERR_BADPARAM;
341
if (size < 0)
342
return AVIERR_BADSIZE;
343
344
/* Do we have write permission? */
345
if ((This->uMode & MMIO_RWMODE) == 0)
346
return AVIERR_READONLY;
347
348
This->fDirty = TRUE;
349
350
return WriteExtraChunk(&This->extra, ckid, lpData, size);
351
}
352
353
static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid, void *lpData, LONG *size)
354
{
355
IAVIFileImpl *This = impl_from_IAVIFile(iface);
356
357
TRACE("(%p,0x%08lX,%p,%p)\n", iface, ckid, lpData, size);
358
359
return ReadExtraChunk(&This->extra, ckid, lpData, size);
360
}
361
362
static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
363
{
364
TRACE("(%p)\n",iface);
365
366
/* This is only needed for interleaved files.
367
* We have only one stream, which can't be interleaved.
368
*/
369
return AVIERR_OK;
370
}
371
372
static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType, LONG lParam)
373
{
374
IAVIFileImpl *This = impl_from_IAVIFile(iface);
375
376
TRACE("(%p,0x%08lX,%ld)\n", iface, fccType, lParam);
377
378
/* check parameter */
379
if (lParam < 0)
380
return AVIERR_BADPARAM;
381
382
/* Do we have our audio stream? */
383
if (lParam != 0 || This->fInfo.dwStreams == 0 ||
384
(fccType != 0 && fccType != streamtypeAUDIO))
385
return AVIERR_NODATA;
386
387
/* Have user write permissions? */
388
if ((This->uMode & MMIO_RWMODE) == 0)
389
return AVIERR_READONLY;
390
391
free(This->lpFormat);
392
This->lpFormat = NULL;
393
This->cbFormat = 0;
394
395
/* update infos */
396
This->ckData.dwDataOffset = 0;
397
This->ckData.cksize = 0;
398
399
This->sInfo.dwScale = 0;
400
This->sInfo.dwRate = 0;
401
This->sInfo.dwLength = 0;
402
This->sInfo.dwSuggestedBufferSize = 0;
403
404
This->fInfo.dwStreams = 0;
405
This->fInfo.dwEditCount++;
406
407
This->fDirty = TRUE;
408
409
return AVIERR_OK;
410
}
411
412
static const struct IAVIFileVtbl iwavft = {
413
IAVIFile_fnQueryInterface,
414
IAVIFile_fnAddRef,
415
IAVIFile_fnRelease,
416
IAVIFile_fnInfo,
417
IAVIFile_fnGetStream,
418
IAVIFile_fnCreateStream,
419
IAVIFile_fnWriteData,
420
IAVIFile_fnReadData,
421
IAVIFile_fnEndRecord,
422
IAVIFile_fnDeleteStream
423
};
424
425
/***********************************************************************/
426
427
static inline IAVIFileImpl *impl_from_IPersistFile(IPersistFile *iface)
428
{
429
return CONTAINING_RECORD(iface, IAVIFileImpl, IPersistFile_iface);
430
}
431
432
static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface, REFIID riid,
433
void **ret_iface)
434
{
435
IAVIFileImpl *This = impl_from_IPersistFile(iface);
436
437
return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
438
}
439
440
static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
441
{
442
IAVIFileImpl *This = impl_from_IPersistFile(iface);
443
444
return IUnknown_AddRef(This->outer_unk);
445
}
446
447
static ULONG WINAPI IPersistFile_fnRelease(IPersistFile *iface)
448
{
449
IAVIFileImpl *This = impl_from_IPersistFile(iface);
450
451
return IUnknown_Release(This->outer_unk);
452
}
453
454
static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface,
455
LPCLSID pClassID)
456
{
457
TRACE("(%p,%p)\n", iface, pClassID);
458
459
if (pClassID == NULL)
460
return AVIERR_BADPARAM;
461
462
*pClassID = CLSID_WAVFile;
463
464
return AVIERR_OK;
465
}
466
467
static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
468
{
469
IAVIFileImpl *This = impl_from_IPersistFile(iface);
470
471
TRACE("(%p)\n", iface);
472
473
return (This->fDirty ? S_OK : S_FALSE);
474
}
475
476
static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
477
{
478
IAVIFileImpl *This = impl_from_IPersistFile(iface);
479
WCHAR wszStreamFmt[50];
480
INT len;
481
482
TRACE("(%p,%s,0x%08lX)\n", iface, debugstr_w(pszFileName), dwMode);
483
484
/* check parameter */
485
if (pszFileName == NULL)
486
return AVIERR_BADPARAM;
487
488
if (This->hmmio != NULL)
489
return AVIERR_ERROR; /* No reuse of this object for another file! */
490
491
/* remember mode and name */
492
This->uMode = dwMode;
493
494
len = lstrlenW(pszFileName) + 1;
495
This->szFileName = malloc(len * sizeof(WCHAR));
496
if (This->szFileName == NULL)
497
return AVIERR_MEMORY;
498
lstrcpyW(This->szFileName, pszFileName);
499
500
/* try to open the file */
501
This->hmmio = mmioOpenW(This->szFileName, NULL, MMIO_ALLOCBUF | dwMode);
502
if (This->hmmio == NULL) {
503
/* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
504
LPSTR szFileName;
505
len = WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1,
506
NULL, 0, NULL, NULL);
507
szFileName = malloc(len * sizeof(CHAR));
508
if (szFileName == NULL)
509
return AVIERR_MEMORY;
510
511
WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1, szFileName,
512
len, NULL, NULL);
513
514
This->hmmio = mmioOpenA(szFileName, NULL, MMIO_ALLOCBUF | dwMode);
515
free(szFileName);
516
if (This->hmmio == NULL)
517
return AVIERR_FILEOPEN;
518
}
519
520
memset(& This->fInfo, 0, sizeof(This->fInfo));
521
memset(& This->sInfo, 0, sizeof(This->sInfo));
522
523
LoadStringW(AVIFILE_hModule, IDS_WAVEFILETYPE, This->fInfo.szFileType,
524
ARRAY_SIZE(This->fInfo.szFileType));
525
if (LoadStringW(AVIFILE_hModule, IDS_WAVESTREAMFORMAT,
526
wszStreamFmt, ARRAY_SIZE(wszStreamFmt)) > 0) {
527
wsprintfW(This->sInfo.szName, wszStreamFmt,
528
AVIFILE_BasenameW(This->szFileName));
529
}
530
531
/* should we create a new file? */
532
if (dwMode & OF_CREATE) {
533
/* nothing more to do */
534
return AVIERR_OK;
535
} else
536
return AVIFILE_LoadFile(This);
537
}
538
539
static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
540
LPCOLESTR pszFileName,BOOL fRemember)
541
{
542
TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
543
544
/* We write directly to disk, so nothing to do. */
545
546
return AVIERR_OK;
547
}
548
549
static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface,
550
LPCOLESTR pszFileName)
551
{
552
TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
553
554
/* We write directly to disk, so nothing to do. */
555
556
return AVIERR_OK;
557
}
558
559
static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface, LPOLESTR *ppszFileName)
560
{
561
IAVIFileImpl *This = impl_from_IPersistFile(iface);
562
563
TRACE("(%p,%p)\n", iface, ppszFileName);
564
565
if (ppszFileName == NULL)
566
return AVIERR_BADPARAM;
567
568
*ppszFileName = NULL;
569
570
if (This->szFileName) {
571
int len = lstrlenW(This->szFileName) + 1;
572
573
*ppszFileName = CoTaskMemAlloc(len * sizeof(WCHAR));
574
if (*ppszFileName == NULL)
575
return AVIERR_MEMORY;
576
577
lstrcpyW(*ppszFileName, This->szFileName);
578
}
579
580
return AVIERR_OK;
581
}
582
583
static const struct IPersistFileVtbl iwavpft = {
584
IPersistFile_fnQueryInterface,
585
IPersistFile_fnAddRef,
586
IPersistFile_fnRelease,
587
IPersistFile_fnGetClassID,
588
IPersistFile_fnIsDirty,
589
IPersistFile_fnLoad,
590
IPersistFile_fnSave,
591
IPersistFile_fnSaveCompleted,
592
IPersistFile_fnGetCurFile
593
};
594
595
/***********************************************************************/
596
597
static inline IAVIFileImpl *impl_from_IAVIStream(IAVIStream *iface)
598
{
599
return CONTAINING_RECORD(iface, IAVIFileImpl, IAVIStream_iface);
600
}
601
602
static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface, REFIID riid, void **ret_iface)
603
{
604
IAVIFileImpl *This = impl_from_IAVIStream(iface);
605
606
return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
607
}
608
609
static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
610
{
611
IAVIFileImpl *This = impl_from_IAVIStream(iface);
612
613
return IUnknown_AddRef(This->outer_unk);
614
}
615
616
static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface)
617
{
618
IAVIFileImpl *This = impl_from_IAVIStream(iface);
619
620
return IUnknown_Release(This->outer_unk);
621
}
622
623
static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
624
LPARAM lParam2)
625
{
626
TRACE("(%p,0x%08IX,0x%08IX)\n", iface, lParam1, lParam2);
627
628
/* This IAVIStream interface needs an WAVFile */
629
return AVIERR_UNSUPPORTED;
630
}
631
632
static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface, AVISTREAMINFOW *psi, LONG size)
633
{
634
IAVIFileImpl *This = impl_from_IAVIStream(iface);
635
636
TRACE("(%p,%p,%ld)\n", iface, psi, size);
637
638
if (psi == NULL)
639
return AVIERR_BADPARAM;
640
if (size < 0)
641
return AVIERR_BADSIZE;
642
643
memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
644
645
if ((DWORD)size < sizeof(This->sInfo))
646
return AVIERR_BUFFERTOOSMALL;
647
return AVIERR_OK;
648
}
649
650
static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos, LONG flags)
651
{
652
IAVIFileImpl *This = impl_from_IAVIStream(iface);
653
654
TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
655
656
/* Do we have data? */
657
if (This->lpFormat == NULL)
658
return -1;
659
660
/* We don't have an index */
661
if (flags & FIND_INDEX)
662
return -1;
663
664
if (flags & FIND_FROM_START) {
665
pos = This->sInfo.dwStart;
666
flags &= ~(FIND_FROM_START|FIND_PREV);
667
flags |= FIND_NEXT;
668
}
669
670
if (flags & FIND_FORMAT) {
671
if ((flags & FIND_NEXT) && pos > 0)
672
pos = -1;
673
else
674
pos = 0;
675
}
676
677
if ((flags & FIND_RET) == FIND_LENGTH ||
678
(flags & FIND_RET) == FIND_SIZE)
679
return This->sInfo.dwSampleSize;
680
if ((flags & FIND_RET) == FIND_OFFSET)
681
return This->ckData.dwDataOffset + pos * This->sInfo.dwSampleSize;
682
683
return pos;
684
}
685
686
static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos, void *format,
687
LONG *formatsize)
688
{
689
IAVIFileImpl *This = impl_from_IAVIStream(iface);
690
691
TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
692
693
if (formatsize == NULL)
694
return AVIERR_BADPARAM;
695
696
/* only interested in needed buffersize? */
697
if (format == NULL || *formatsize <= 0) {
698
*formatsize = This->cbFormat;
699
700
return AVIERR_OK;
701
}
702
703
/* copy initial format (only as much as will fit) */
704
memcpy(format, This->lpFormat, min(*formatsize, This->cbFormat));
705
if (*formatsize < This->cbFormat) {
706
*formatsize = This->cbFormat;
707
return AVIERR_BUFFERTOOSMALL;
708
}
709
710
*formatsize = This->cbFormat;
711
return AVIERR_OK;
712
}
713
714
static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos, void *format,
715
LONG formatsize)
716
{
717
IAVIFileImpl *This = impl_from_IAVIStream(iface);
718
719
TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
720
721
/* check parameters */
722
if (format == NULL || formatsize <= sizeof(PCMWAVEFORMAT))
723
return AVIERR_BADPARAM;
724
725
/* We can only do this to an empty wave file, but ignore call
726
* if still same format */
727
if (This->lpFormat != NULL) {
728
if (formatsize != This->cbFormat ||
729
memcmp(format, This->lpFormat, formatsize) != 0)
730
return AVIERR_UNSUPPORTED;
731
732
return AVIERR_OK;
733
}
734
735
/* only support start at position 0 */
736
if (pos != 0)
737
return AVIERR_UNSUPPORTED;
738
739
/* Do we have write permission? */
740
if ((This->uMode & MMIO_RWMODE) == 0)
741
return AVIERR_READONLY;
742
743
/* get memory for format and copy it */
744
This->lpFormat = malloc(formatsize);
745
if (This->lpFormat == NULL)
746
return AVIERR_MEMORY;
747
748
This->cbFormat = formatsize;
749
memcpy(This->lpFormat, format, formatsize);
750
751
/* update info's about 'data' chunk */
752
This->ckData.dwDataOffset = formatsize + 7 * sizeof(DWORD);
753
This->ckData.cksize = 0;
754
755
/* for non-pcm format we need also a 'fact' chunk */
756
if (This->lpFormat->wFormatTag != WAVE_FORMAT_PCM)
757
This->ckData.dwDataOffset += 3 * sizeof(DWORD);
758
759
/* update stream and file info */
760
This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
761
This->sInfo.dwScale = This->lpFormat->nBlockAlign;
762
This->sInfo.dwRate = This->lpFormat->nAvgBytesPerSec;
763
This->sInfo.dwLength = 0;
764
This->sInfo.dwSuggestedBufferSize = 0;
765
766
return AVIERR_OK;
767
}
768
769
static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start, LONG samples, void *buffer,
770
LONG buffersize, LONG *bytesread, LONG *samplesread)
771
{
772
IAVIFileImpl *This = impl_from_IAVIStream(iface);
773
774
TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
775
buffersize, bytesread, samplesread);
776
777
/* clear return parameters if given */
778
if (bytesread != NULL)
779
*bytesread = 0;
780
if (samplesread != NULL)
781
*samplesread = 0;
782
783
/* positions without data */
784
if (start < 0 || (DWORD)start > This->sInfo.dwLength)
785
return AVIERR_OK;
786
787
/* check samples */
788
if (samples < 0)
789
samples = 0;
790
if (buffersize > 0) {
791
if (samples > 0)
792
samples = min((DWORD)samples, buffersize / This->sInfo.dwSampleSize);
793
else
794
samples = buffersize / This->sInfo.dwSampleSize;
795
}
796
797
/* limit to end of stream */
798
if ((DWORD)(start + samples) > This->sInfo.dwLength)
799
samples = This->sInfo.dwLength - start;
800
801
/* request only the sizes? */
802
if (buffer == NULL || buffersize <= 0) {
803
/* then I need at least one parameter for it */
804
if (bytesread == NULL && samplesread == NULL)
805
return AVIERR_BADPARAM;
806
807
if (bytesread != NULL)
808
*bytesread = samples * This->sInfo.dwSampleSize;
809
if (samplesread != NULL)
810
*samplesread = samples;
811
812
return AVIERR_OK;
813
}
814
815
/* nothing to read? */
816
if (samples == 0)
817
return AVIERR_OK;
818
819
/* Can I read at least one sample? */
820
if ((DWORD)buffersize < This->sInfo.dwSampleSize)
821
return AVIERR_BUFFERTOOSMALL;
822
823
buffersize = samples * This->sInfo.dwSampleSize;
824
825
if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
826
+ start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
827
return AVIERR_FILEREAD;
828
if (mmioRead(This->hmmio, buffer, buffersize) != buffersize)
829
return AVIERR_FILEREAD;
830
831
/* fill out return parameters if given */
832
if (bytesread != NULL)
833
*bytesread = buffersize;
834
if (samplesread != NULL)
835
*samplesread = samples;
836
837
return AVIERR_OK;
838
}
839
840
static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start, LONG samples, void *buffer,
841
LONG buffersize, DWORD flags, LONG *sampwritten, LONG *byteswritten)
842
{
843
IAVIFileImpl *This = impl_from_IAVIStream(iface);
844
845
TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
846
buffer, buffersize, flags, sampwritten, byteswritten);
847
848
/* clear return parameters if given */
849
if (sampwritten != NULL)
850
*sampwritten = 0;
851
if (byteswritten != NULL)
852
*byteswritten = 0;
853
854
/* check parameters */
855
if (buffer == NULL && (buffersize > 0 || samples > 0))
856
return AVIERR_BADPARAM;
857
858
/* Do we have write permission? */
859
if ((This->uMode & MMIO_RWMODE) == 0)
860
return AVIERR_READONLY;
861
862
/* < 0 means "append" */
863
if (start < 0)
864
start = This->sInfo.dwStart + This->sInfo.dwLength;
865
866
/* check buffersize -- must multiple of samplesize */
867
if (buffersize & ~(This->sInfo.dwSampleSize - 1))
868
return AVIERR_BADSIZE;
869
870
/* do we have anything to write? */
871
if (buffer != NULL && buffersize > 0) {
872
This->fDirty = TRUE;
873
874
if (mmioSeek(This->hmmio, This->ckData.dwDataOffset +
875
start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
876
return AVIERR_FILEWRITE;
877
if (mmioWrite(This->hmmio, buffer, buffersize) != buffersize)
878
return AVIERR_FILEWRITE;
879
880
This->sInfo.dwLength = max(This->sInfo.dwLength, (DWORD)start + samples);
881
This->ckData.cksize = max(This->ckData.cksize,
882
start * This->sInfo.dwSampleSize + buffersize);
883
884
/* fill out return parameters if given */
885
if (sampwritten != NULL)
886
*sampwritten = samples;
887
if (byteswritten != NULL)
888
*byteswritten = buffersize;
889
}
890
891
return AVIERR_OK;
892
}
893
894
static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start, LONG samples)
895
{
896
IAVIFileImpl *This = impl_from_IAVIStream(iface);
897
898
TRACE("(%p,%ld,%ld)\n", iface, start, samples);
899
900
/* check parameters */
901
if (start < 0 || samples < 0)
902
return AVIERR_BADPARAM;
903
904
/* Delete before start of stream? */
905
if ((DWORD)(start + samples) < This->sInfo.dwStart)
906
return AVIERR_OK;
907
908
/* Delete after end of stream? */
909
if ((DWORD)start > This->sInfo.dwLength)
910
return AVIERR_OK;
911
912
/* For the rest we need write permissions */
913
if ((This->uMode & MMIO_RWMODE) == 0)
914
return AVIERR_READONLY;
915
916
if ((DWORD)(start + samples) >= This->sInfo.dwLength) {
917
/* deletion at end */
918
samples = This->sInfo.dwLength - start;
919
This->sInfo.dwLength -= samples;
920
This->ckData.cksize -= samples * This->sInfo.dwSampleSize;
921
} else if ((DWORD)start <= This->sInfo.dwStart) {
922
/* deletion at start */
923
samples = This->sInfo.dwStart - start;
924
start = This->sInfo.dwStart;
925
This->ckData.dwDataOffset += samples * This->sInfo.dwSampleSize;
926
This->ckData.cksize -= samples * This->sInfo.dwSampleSize;
927
} else {
928
/* deletion inside stream -- needs playlist and cue's */
929
FIXME(": deletion inside of stream not supported!\n");
930
931
return AVIERR_UNSUPPORTED;
932
}
933
934
This->fDirty = TRUE;
935
936
return AVIERR_OK;
937
}
938
939
static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc, void *lp, LONG *lpread)
940
{
941
IAVIFileImpl *This = impl_from_IAVIStream(iface);
942
943
return IAVIFile_ReadData(&This->IAVIFile_iface, fcc, lp, lpread);
944
}
945
946
static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc, void *lp, LONG size)
947
{
948
IAVIFileImpl *This = impl_from_IAVIStream(iface);
949
950
return IAVIFile_WriteData(&This->IAVIFile_iface, fcc, lp, size);
951
}
952
953
static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
954
LPAVISTREAMINFOW info, LONG infolen)
955
{
956
FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
957
958
return E_FAIL;
959
}
960
961
static const struct IAVIStreamVtbl iwavst = {
962
IAVIStream_fnQueryInterface,
963
IAVIStream_fnAddRef,
964
IAVIStream_fnRelease,
965
IAVIStream_fnCreate,
966
IAVIStream_fnInfo,
967
IAVIStream_fnFindSample,
968
IAVIStream_fnReadFormat,
969
IAVIStream_fnSetFormat,
970
IAVIStream_fnRead,
971
IAVIStream_fnWrite,
972
IAVIStream_fnDelete,
973
IAVIStream_fnReadData,
974
IAVIStream_fnWriteData,
975
IAVIStream_fnSetInfo
976
};
977
978
HRESULT AVIFILE_CreateWAVFile(IUnknown *outer_unk, REFIID riid, void **ret_iface)
979
{
980
IAVIFileImpl *pfile;
981
HRESULT hr;
982
983
*ret_iface = NULL;
984
985
pfile = calloc(1, sizeof(*pfile));
986
if (!pfile)
987
return AVIERR_MEMORY;
988
989
pfile->IUnknown_inner.lpVtbl = &unk_vtbl;
990
pfile->IAVIFile_iface.lpVtbl = &iwavft;
991
pfile->IPersistFile_iface.lpVtbl = &iwavpft;
992
pfile->IAVIStream_iface.lpVtbl = &iwavst;
993
pfile->ref = 1;
994
if (outer_unk)
995
pfile->outer_unk = outer_unk;
996
else
997
pfile->outer_unk = &pfile->IUnknown_inner;
998
999
hr = IUnknown_QueryInterface(&pfile->IUnknown_inner, riid, ret_iface);
1000
IUnknown_Release(&pfile->IUnknown_inner);
1001
1002
return hr;
1003
}
1004
1005
/***********************************************************************/
1006
1007
static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
1008
{
1009
MMCKINFO ckRIFF;
1010
MMCKINFO ck;
1011
1012
This->sInfo.dwLength = 0; /* just to be sure */
1013
This->fDirty = FALSE;
1014
1015
/* search for RIFF chunk */
1016
ckRIFF.fccType = 0; /* find any */
1017
if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
1018
return AVIFILE_LoadSunFile(This);
1019
}
1020
1021
if (ckRIFF.fccType != formtypeWAVE)
1022
return AVIERR_BADFORMAT;
1023
1024
/* search WAVE format chunk */
1025
ck.ckid = ckidWAVEFORMAT;
1026
if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck,
1027
&ckRIFF, MMIO_FINDCHUNK) != S_OK)
1028
return AVIERR_FILEREAD;
1029
1030
/* get memory for format and read it */
1031
This->lpFormat = malloc(ck.cksize);
1032
if (This->lpFormat == NULL)
1033
return AVIERR_FILEREAD;
1034
This->cbFormat = ck.cksize;
1035
1036
if (mmioRead(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
1037
return AVIERR_FILEREAD;
1038
if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1039
return AVIERR_FILEREAD;
1040
1041
/* Non-pcm formats have a fact chunk.
1042
* We don't need it, so simply add it to the extra chunks.
1043
*/
1044
1045
/* find the big data chunk */
1046
This->ckData.ckid = ckidWAVEDATA;
1047
if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &This->ckData,
1048
&ckRIFF, MMIO_FINDCHUNK) != S_OK)
1049
return AVIERR_FILEREAD;
1050
1051
memset(&This->sInfo, 0, sizeof(This->sInfo));
1052
This->sInfo.fccType = streamtypeAUDIO;
1053
This->sInfo.dwRate = This->lpFormat->nAvgBytesPerSec;
1054
This->sInfo.dwSampleSize =
1055
This->sInfo.dwScale = This->lpFormat->nBlockAlign;
1056
This->sInfo.dwLength = This->ckData.cksize / This->lpFormat->nBlockAlign;
1057
This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
1058
1059
This->fInfo.dwStreams = 1;
1060
1061
if (mmioAscend(This->hmmio, &This->ckData, 0) != S_OK) {
1062
/* seems to be truncated */
1063
WARN(": file seems to be truncated!\n");
1064
This->ckData.cksize = mmioSeek(This->hmmio, 0, SEEK_END) -
1065
This->ckData.dwDataOffset;
1066
This->sInfo.dwLength = This->ckData.cksize / This->lpFormat->nBlockAlign;
1067
This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
1068
}
1069
1070
/* ignore errors */
1071
FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck, &ckRIFF, 0);
1072
1073
return AVIERR_OK;
1074
}
1075
1076
static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This)
1077
{
1078
SUNAUDIOHEADER auhdr;
1079
1080
mmioSeek(This->hmmio, 0, SEEK_SET);
1081
if (mmioRead(This->hmmio, (HPSTR)&auhdr, sizeof(auhdr)) != sizeof(auhdr))
1082
return AVIERR_FILEREAD;
1083
1084
if (auhdr.fccType == 0x0064732E) {
1085
/* header in little endian */
1086
This->ckData.dwDataOffset = LE2H_DWORD(auhdr.offset);
1087
This->ckData.cksize = LE2H_DWORD(auhdr.size);
1088
1089
auhdr.encoding = LE2H_DWORD(auhdr.encoding);
1090
auhdr.sampleRate = LE2H_DWORD(auhdr.sampleRate);
1091
auhdr.channels = LE2H_DWORD(auhdr.channels);
1092
} else if (auhdr.fccType == mmioFOURCC('.','s','n','d')) {
1093
/* header in big endian */
1094
This->ckData.dwDataOffset = BE2H_DWORD(auhdr.offset);
1095
This->ckData.cksize = BE2H_DWORD(auhdr.size);
1096
1097
auhdr.encoding = BE2H_DWORD(auhdr.encoding);
1098
auhdr.sampleRate = BE2H_DWORD(auhdr.sampleRate);
1099
auhdr.channels = BE2H_DWORD(auhdr.channels);
1100
} else
1101
return AVIERR_FILEREAD;
1102
1103
if (auhdr.channels < 1)
1104
return AVIERR_BADFORMAT;
1105
1106
/* get size of header */
1107
switch(auhdr.encoding) {
1108
case AU_ENCODING_ADPCM_G721_32:
1109
This->cbFormat = sizeof(G721_ADPCMWAVEFORMAT); break;
1110
case AU_ENCODING_ADPCM_G723_24:
1111
This->cbFormat = sizeof(G723_ADPCMWAVEFORMAT); break;
1112
case AU_ENCODING_ADPCM_G722:
1113
case AU_ENCODING_ADPCM_G723_5:
1114
WARN("unsupported Sun audio format %d\n", auhdr.encoding);
1115
return AVIERR_UNSUPPORTED; /* FIXME */
1116
default:
1117
This->cbFormat = sizeof(WAVEFORMATEX); break;
1118
};
1119
1120
This->lpFormat = malloc(This->cbFormat);
1121
if (This->lpFormat == NULL)
1122
return AVIERR_MEMORY;
1123
1124
This->lpFormat->nChannels = auhdr.channels;
1125
This->lpFormat->nSamplesPerSec = auhdr.sampleRate;
1126
switch(auhdr.encoding) {
1127
case AU_ENCODING_ULAW_8:
1128
This->lpFormat->wFormatTag = WAVE_FORMAT_MULAW;
1129
This->lpFormat->wBitsPerSample = 8;
1130
break;
1131
case AU_ENCODING_PCM_8:
1132
This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
1133
This->lpFormat->wBitsPerSample = 8;
1134
break;
1135
case AU_ENCODING_PCM_16:
1136
This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
1137
This->lpFormat->wBitsPerSample = 16;
1138
break;
1139
case AU_ENCODING_PCM_24:
1140
This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
1141
This->lpFormat->wBitsPerSample = 24;
1142
break;
1143
case AU_ENCODING_PCM_32:
1144
This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
1145
This->lpFormat->wBitsPerSample = 32;
1146
break;
1147
case AU_ENCODING_ALAW_8:
1148
This->lpFormat->wFormatTag = WAVE_FORMAT_ALAW;
1149
This->lpFormat->wBitsPerSample = 8;
1150
break;
1151
case AU_ENCODING_ADPCM_G721_32:
1152
This->lpFormat->wFormatTag = WAVE_FORMAT_G721_ADPCM;
1153
This->lpFormat->wBitsPerSample = (3*5*8);
1154
This->lpFormat->nBlockAlign = 15*15*8;
1155
This->lpFormat->cbSize = sizeof(WORD);
1156
((LPG721_ADPCMWAVEFORMAT)This->lpFormat)->nAuxBlockSize = 0;
1157
break;
1158
case AU_ENCODING_ADPCM_G723_24:
1159
This->lpFormat->wFormatTag = WAVE_FORMAT_G723_ADPCM;
1160
This->lpFormat->wBitsPerSample = (3*5*8);
1161
This->lpFormat->nBlockAlign = 15*15*8;
1162
This->lpFormat->cbSize = 2*sizeof(WORD);
1163
((LPG723_ADPCMWAVEFORMAT)This->lpFormat)->cbExtraSize = 0;
1164
((LPG723_ADPCMWAVEFORMAT)This->lpFormat)->nAuxBlockSize = 0;
1165
break;
1166
default:
1167
WARN("unsupported Sun audio format %d\n", auhdr.encoding);
1168
return AVIERR_UNSUPPORTED;
1169
};
1170
1171
This->lpFormat->nBlockAlign =
1172
(This->lpFormat->nChannels * This->lpFormat->wBitsPerSample) / 8;
1173
if (This->lpFormat->nBlockAlign == 0 && This->lpFormat->wBitsPerSample < 8)
1174
This->lpFormat->nBlockAlign++;
1175
This->lpFormat->nAvgBytesPerSec =
1176
This->lpFormat->nBlockAlign * This->lpFormat->nSamplesPerSec;
1177
1178
This->fDirty = FALSE;
1179
1180
This->sInfo.fccType = streamtypeAUDIO;
1181
This->sInfo.fccHandler = 0;
1182
This->sInfo.dwFlags = 0;
1183
This->sInfo.wPriority = 0;
1184
This->sInfo.wLanguage = 0;
1185
This->sInfo.dwInitialFrames = 0;
1186
This->sInfo.dwScale = This->lpFormat->nBlockAlign;
1187
This->sInfo.dwRate = This->lpFormat->nAvgBytesPerSec;
1188
This->sInfo.dwStart = 0;
1189
This->sInfo.dwLength =
1190
This->ckData.cksize / This->lpFormat->nBlockAlign;
1191
This->sInfo.dwSuggestedBufferSize = This->sInfo.dwLength;
1192
This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
1193
1194
This->fInfo.dwStreams = 1;
1195
This->fInfo.dwScale = 1;
1196
This->fInfo.dwRate = This->lpFormat->nSamplesPerSec;
1197
This->fInfo.dwLength =
1198
MulDiv(This->ckData.cksize, This->lpFormat->nSamplesPerSec,
1199
This->lpFormat->nAvgBytesPerSec);
1200
1201
return AVIERR_OK;
1202
}
1203
1204
static HRESULT AVIFILE_SaveFile(const IAVIFileImpl *This)
1205
{
1206
MMCKINFO ckRIFF;
1207
MMCKINFO ck;
1208
1209
mmioSeek(This->hmmio, 0, SEEK_SET);
1210
1211
/* create the RIFF chunk with formtype WAVE */
1212
ckRIFF.fccType = formtypeWAVE;
1213
ckRIFF.cksize = 0;
1214
if (mmioCreateChunk(This->hmmio, &ckRIFF, MMIO_CREATERIFF) != S_OK)
1215
return AVIERR_FILEWRITE;
1216
1217
/* the next chunk is the format */
1218
ck.ckid = ckidWAVEFORMAT;
1219
ck.cksize = This->cbFormat;
1220
if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
1221
return AVIERR_FILEWRITE;
1222
if (This->lpFormat != NULL && This->cbFormat > 0) {
1223
if (mmioWrite(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
1224
return AVIERR_FILEWRITE;
1225
}
1226
if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1227
return AVIERR_FILEWRITE;
1228
1229
/* fact chunk is needed for non-pcm waveforms */
1230
if (This->lpFormat != NULL && This->cbFormat > sizeof(PCMWAVEFORMAT) &&
1231
This->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1232
WAVEFORMATEX wfx;
1233
DWORD dwFactLength;
1234
HACMSTREAM has;
1235
1236
/* try to open an appropriate audio codec to figure out
1237
* data for fact-chunk */
1238
wfx.wFormatTag = WAVE_FORMAT_PCM;
1239
if (acmFormatSuggest(NULL, This->lpFormat, &wfx,
1240
sizeof(wfx), ACM_FORMATSUGGESTF_WFORMATTAG)) {
1241
acmStreamOpen(&has, NULL, This->lpFormat, &wfx, NULL,
1242
0, 0, ACM_STREAMOPENF_NONREALTIME);
1243
acmStreamSize(has, This->ckData.cksize, &dwFactLength,
1244
ACM_STREAMSIZEF_SOURCE);
1245
dwFactLength /= wfx.nBlockAlign;
1246
acmStreamClose(has, 0);
1247
1248
/* create the fact chunk */
1249
ck.ckid = ckidWAVEFACT;
1250
ck.cksize = sizeof(dwFactLength);
1251
1252
/* test for enough space before data chunk */
1253
if (mmioSeek(This->hmmio, 0, SEEK_CUR) > This->ckData.dwDataOffset
1254
- ck.cksize - 4 * sizeof(DWORD))
1255
return AVIERR_FILEWRITE;
1256
if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
1257
return AVIERR_FILEWRITE;
1258
if (mmioWrite(This->hmmio, (HPSTR)&dwFactLength, ck.cksize) != ck.cksize)
1259
return AVIERR_FILEWRITE;
1260
if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1261
return AVIERR_FILEWRITE;
1262
} else
1263
ERR(": fact chunk is needed for non-pcm files -- currently no codec found, so skipped!\n");
1264
}
1265
1266
/* if there was extra stuff, we need to fill it with JUNK */
1267
if (mmioSeek(This->hmmio, 0, SEEK_CUR) + 2 * sizeof(DWORD) < This->ckData.dwDataOffset) {
1268
ck.ckid = ckidAVIPADDING;
1269
ck.cksize = 0;
1270
if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
1271
return AVIERR_FILEWRITE;
1272
1273
if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
1274
- 2 * sizeof(DWORD), SEEK_SET) == -1)
1275
return AVIERR_FILEWRITE;
1276
if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1277
return AVIERR_FILEWRITE;
1278
}
1279
1280
/* create the data chunk */
1281
ck.ckid = ckidWAVEDATA;
1282
ck.cksize = This->ckData.cksize;
1283
if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
1284
return AVIERR_FILEWRITE;
1285
if (mmioSeek(This->hmmio, This->ckData.cksize, SEEK_CUR) == -1)
1286
return AVIERR_FILEWRITE;
1287
if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
1288
return AVIERR_FILEWRITE;
1289
1290
/* some optional extra chunks? */
1291
if (This->extra.lp != NULL && This->extra.cb > 0) {
1292
/* chunk headers are already in structure */
1293
if (mmioWrite(This->hmmio, This->extra.lp, This->extra.cb) != This->extra.cb)
1294
return AVIERR_FILEWRITE;
1295
}
1296
1297
/* close RIFF chunk */
1298
if (mmioAscend(This->hmmio, &ckRIFF, 0) != S_OK)
1299
return AVIERR_FILEWRITE;
1300
if (mmioFlush(This->hmmio, 0) != S_OK)
1301
return AVIERR_FILEWRITE;
1302
1303
return AVIERR_OK;
1304
}
1305
1306