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
19 #define COM_NO_WINDOWS_H
33 #include "avifile_private.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
39 /***********************************************************************/
41 static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
42 static ULONG WINAPI ACMStream_fnAddRef(IAVIStream*iface);
43 static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface);
44 static HRESULT WINAPI ACMStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
45 static HRESULT WINAPI ACMStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
46 static LONG WINAPI ACMStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
47 static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
48 static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
49 static HRESULT WINAPI ACMStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
50 static HRESULT WINAPI ACMStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
51 static HRESULT WINAPI ACMStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
52 static HRESULT WINAPI ACMStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
53 static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
54 static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
56 static const struct IAVIStreamVtbl iacmst = {
57 ACMStream_fnQueryInterface,
62 ACMStream_fnFindSample,
63 ACMStream_fnReadFormat,
64 ACMStream_fnSetFormat,
69 ACMStream_fnWriteData,
73 typedef struct _IAVIStreamImpl {
75 const IAVIStreamVtbl *lpVtbl;
78 /* IAVIStream stuff */
84 LPWAVEFORMATEX lpInFormat;
87 LPWAVEFORMATEX lpOutFormat;
90 ACMSTREAMHEADER acmStreamHdr;
93 /***********************************************************************/
95 #define CONVERT_STREAM_to_THIS(a) do { \
97 acmStreamSize(This->has,*(a) * This->lpInFormat->nBlockAlign,\
98 &__bytes, ACM_STREAMSIZEF_SOURCE); \
99 *(a) = __bytes / This->lpOutFormat->nBlockAlign; } while(0)
101 #define CONVERT_THIS_to_STREAM(a) do { \
103 acmStreamSize(This->has,*(a) * This->lpOutFormat->nBlockAlign,\
104 &__bytes, ACM_STREAMSIZEF_DESTINATION); \
105 *(a) = __bytes / This->lpInFormat->nBlockAlign; } while(0)
107 static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This);
109 HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppv)
111 IAVIStreamImpl *pstream;
114 assert(riid != NULL && ppv != NULL);
118 pstream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIStreamImpl));
120 return AVIERR_MEMORY;
122 pstream->lpVtbl = &iacmst;
124 hr = IAVIStream_QueryInterface((IAVIStream*)pstream, riid, ppv);
126 HeapFree(GetProcessHeap(), 0, pstream);
131 static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream *iface,
132 REFIID refiid, LPVOID *obj)
134 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
136 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
138 if (IsEqualGUID(&IID_IUnknown, refiid) ||
139 IsEqualGUID(&IID_IAVIStream, refiid)) {
141 IAVIStream_AddRef(iface);
146 return OLE_E_ENUM_NOMORE;
149 static ULONG WINAPI ACMStream_fnAddRef(IAVIStream *iface)
151 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
152 ULONG ref = InterlockedIncrement(&This->ref);
154 TRACE("(%p) -> %ld\n", iface, ref);
156 /* also add reference to the nested stream */
157 if (This->pStream != NULL)
158 IAVIStream_AddRef(This->pStream);
163 static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface)
165 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
166 ULONG ref = InterlockedDecrement(&This->ref);
168 TRACE("(%p) -> %ld\n", iface, ref);
172 if (This->has != NULL) {
173 if (This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
174 acmStreamUnprepareHeader(This->has, &This->acmStreamHdr, 0);
175 acmStreamClose(This->has, 0);
178 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc);
179 This->acmStreamHdr.pbSrc = NULL;
180 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbDst);
181 This->acmStreamHdr.pbDst = NULL;
182 if (This->lpInFormat != NULL) {
183 HeapFree(GetProcessHeap(), 0, This->lpInFormat);
184 This->lpInFormat = NULL;
185 This->cbInFormat = 0;
187 if (This->lpOutFormat != NULL) {
188 HeapFree(GetProcessHeap(), 0, This->lpOutFormat);
189 This->lpOutFormat = NULL;
190 This->cbOutFormat = 0;
192 if (This->pStream != NULL) {
193 IAVIStream_Release(This->pStream);
194 This->pStream = NULL;
196 HeapFree(GetProcessHeap(), 0, This);
201 /* also release reference to the nested stream */
202 if (This->pStream != NULL)
203 IAVIStream_Release(This->pStream);
208 /* lParam1: PAVISTREAM
209 * lParam2: LPAVICOMPRESSOPTIONS -- even if doc's say LPWAVEFORMAT
211 static HRESULT WINAPI ACMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
214 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
216 TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
218 /* check for swapped parameters */
219 if ((LPVOID)lParam1 != NULL &&
220 ((LPAVICOMPRESSOPTIONS)lParam1)->fccType == streamtypeAUDIO) {
221 register LPARAM tmp = lParam1;
227 if ((LPVOID)lParam1 == NULL)
228 return AVIERR_BADPARAM;
230 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
231 if (This->sInfo.fccType != streamtypeAUDIO)
232 return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
234 This->sInfo.fccHandler = 0; /* be paranoid */
236 /* FIXME: check ACM version? Which version does we need? */
238 if ((LPVOID)lParam2 != NULL) {
239 /* We only need the format from the compress-options */
240 if (((LPAVICOMPRESSOPTIONS)lParam2)->fccType == streamtypeAUDIO)
241 lParam2 = (LPARAM)((LPAVICOMPRESSOPTIONS)lParam2)->lpFormat;
243 if (((LPWAVEFORMATEX)lParam2)->wFormatTag != WAVE_FORMAT_PCM)
244 This->cbOutFormat = sizeof(WAVEFORMATEX) + ((LPWAVEFORMATEX)lParam2)->cbSize;
246 This->cbOutFormat = sizeof(PCMWAVEFORMAT);
248 This->lpOutFormat = HeapAlloc(GetProcessHeap(), 0, This->cbOutFormat);
249 if (This->lpOutFormat == NULL)
250 return AVIERR_MEMORY;
252 memcpy(This->lpOutFormat, (LPVOID)lParam2, This->cbOutFormat);
254 This->lpOutFormat = NULL;
255 This->cbOutFormat = 0;
258 This->pStream = (PAVISTREAM)lParam1;
259 IAVIStream_AddRef(This->pStream);
264 static HRESULT WINAPI ACMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
267 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
269 TRACE("(%p,%p,%ld)\n", iface, psi, size);
272 return AVIERR_BADPARAM;
274 return AVIERR_BADSIZE;
276 /* Need codec to correct some values in structure */
277 if (This->has == NULL) {
278 HRESULT hr = AVIFILE_OpenCompressor(This);
284 memcpy(psi, &This->sInfo, min(size, (LONG)sizeof(This->sInfo)));
286 if (size < (LONG)sizeof(This->sInfo))
287 return AVIERR_BUFFERTOOSMALL;
291 static LONG WINAPI ACMStream_fnFindSample(IAVIStream *iface, LONG pos,
294 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
296 TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
298 if (flags & FIND_FROM_START) {
299 pos = This->sInfo.dwStart;
300 flags &= ~(FIND_FROM_START|FIND_PREV);
304 /* convert pos from our 'space' to This->pStream's one */
305 CONVERT_THIS_to_STREAM(&pos);
308 pos = IAVIStream_FindSample(This->pStream, pos, flags);
311 /* convert pos back to our 'space' if it's no size or physical pos */
312 if ((flags & FIND_RET) == 0)
313 CONVERT_STREAM_to_THIS(&pos);
319 static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream *iface, LONG pos,
320 LPVOID format, LONG *formatsize)
322 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
324 TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
326 if (formatsize == NULL)
327 return AVIERR_BADPARAM;
329 if (This->has == NULL) {
330 HRESULT hr = AVIFILE_OpenCompressor(This);
336 /* only interested in needed buffersize? */
337 if (format == NULL || *formatsize <= 0) {
338 *formatsize = This->cbOutFormat;
343 /* copy initial format (only as much as will fit) */
344 memcpy(format, This->lpOutFormat, min(*formatsize, This->cbOutFormat));
345 if (*formatsize < This->cbOutFormat) {
346 *formatsize = This->cbOutFormat;
347 return AVIERR_BUFFERTOOSMALL;
350 *formatsize = This->cbOutFormat;
354 static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream *iface, LONG pos,
355 LPVOID format, LONG formatsize)
357 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
361 TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
363 /* check parameters */
364 if (format == NULL || formatsize <= 0)
365 return AVIERR_BADPARAM;
367 /* Input format already known?
368 * Changing is unsupported, but be quiet if it's the same */
369 if (This->lpInFormat != NULL) {
370 if (This->cbInFormat != formatsize ||
371 memcmp(format, This->lpInFormat, formatsize) != 0)
372 return AVIERR_UNSUPPORTED;
377 /* Does the nested stream support writing? */
378 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
379 return AVIERR_READONLY;
381 This->lpInFormat = HeapAlloc(GetProcessHeap(), 0, formatsize);
382 if (This->lpInFormat == NULL)
383 return AVIERR_MEMORY;
384 This->cbInFormat = formatsize;
385 memcpy(This->lpInFormat, format, formatsize);
387 /* initialize formats and get compressor */
388 hr = AVIFILE_OpenCompressor(This);
392 CONVERT_THIS_to_STREAM(&pos);
394 /* tell the nested stream the new format */
395 return IAVIStream_SetFormat(This->pStream, pos, This->lpOutFormat,
399 static HRESULT WINAPI ACMStream_fnRead(IAVIStream *iface, LONG start,
400 LONG samples, LPVOID buffer,
401 LONG buffersize, LPLONG bytesread,
404 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
409 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
410 buffersize, bytesread, samplesread);
412 /* clear return parameters if given */
413 if (bytesread != NULL)
415 if (samplesread != NULL)
418 /* Do we have our compressor? */
419 if (This->has == NULL) {
420 hr = AVIFILE_OpenCompressor(This);
426 /* only need to pass through? */
427 if (This->cbInFormat == This->cbOutFormat &&
428 memcmp(This->lpInFormat, This->lpOutFormat, This->cbInFormat) == 0) {
429 return IAVIStream_Read(This->pStream, start, samples, buffer, buffersize,
430 bytesread, samplesread);
433 /* read as much as fit? */
435 samples = buffersize / This->lpOutFormat->nBlockAlign;
436 /* limit to buffersize */
437 if (samples * This->lpOutFormat->nBlockAlign > buffersize)
438 samples = buffersize / This->lpOutFormat->nBlockAlign;
440 /* only return needed size? */
441 if (buffer == NULL || buffersize <= 0 || samples == 0) {
442 if (bytesread == NULL && samplesread == NULL)
443 return AVIERR_BADPARAM;
445 if (bytesread != NULL)
446 *bytesread = samples * This->lpOutFormat->nBlockAlign;
447 if (samplesread != NULL)
448 *samplesread = samples;
453 /* map our positions to pStream positions */
454 CONVERT_THIS_to_STREAM(&start);
456 /* our needed internal buffersize */
457 size = samples * This->lpInFormat->nBlockAlign;
459 /* Need to free destination buffer used for writing? */
460 if (This->acmStreamHdr.pbDst != NULL) {
461 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbDst);
462 This->acmStreamHdr.pbDst = NULL;
463 This->acmStreamHdr.dwDstUser = 0;
466 /* need bigger source buffer? */
467 if (This->acmStreamHdr.pbSrc == NULL ||
468 This->acmStreamHdr.dwSrcUser < size) {
469 if (This->acmStreamHdr.pbSrc == NULL)
470 This->acmStreamHdr.pbSrc = HeapAlloc(GetProcessHeap(), 0, size);
472 This->acmStreamHdr.pbDst = HeapReAlloc(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc, size);
473 if (This->acmStreamHdr.pbSrc == NULL)
474 return AVIERR_MEMORY;
475 This->acmStreamHdr.dwSrcUser = size;
478 This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
479 This->acmStreamHdr.cbSrcLengthUsed = 0;
480 This->acmStreamHdr.cbDstLengthUsed = 0;
481 This->acmStreamHdr.cbSrcLength = size;
483 /* read source data */
484 hr = IAVIStream_Read(This->pStream, start, -1, This->acmStreamHdr.pbSrc,
485 This->acmStreamHdr.cbSrcLength,
486 (LONG *)&This->acmStreamHdr.cbSrcLength, NULL);
487 if (FAILED(hr) || This->acmStreamHdr.cbSrcLength == 0)
490 /* need to prepare stream? */
491 This->acmStreamHdr.pbDst = buffer;
492 This->acmStreamHdr.cbDstLength = buffersize;
493 if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
494 if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
495 This->acmStreamHdr.pbDst = NULL;
496 This->acmStreamHdr.cbDstLength = 0;
497 return AVIERR_COMPRESSOR;
501 /* now do the conversion */
502 /* FIXME: use ACM_CONVERTF_* flags */
503 if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
504 hr = AVIERR_COMPRESSOR;
506 This->acmStreamHdr.pbDst = NULL;
507 This->acmStreamHdr.cbDstLength = 0;
509 /* fill out return parameters if given */
510 if (bytesread != NULL)
511 *bytesread = This->acmStreamHdr.cbDstLengthUsed;
512 if (samplesread != NULL)
514 This->acmStreamHdr.cbDstLengthUsed / This->lpOutFormat->nBlockAlign;
519 static HRESULT WINAPI ACMStream_fnWrite(IAVIStream *iface, LONG start,
520 LONG samples, LPVOID buffer,
521 LONG buffersize, DWORD flags,
525 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
530 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
531 buffer, buffersize, flags, sampwritten, byteswritten);
533 /* clear return parameters if given */
534 if (sampwritten != NULL)
536 if (byteswritten != NULL)
539 /* check parameters */
540 if (buffer == NULL && (buffersize > 0 || samples > 0))
541 return AVIERR_BADPARAM;
543 /* Have we write capability? */
544 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
545 return AVIERR_READONLY;
547 /* also need a compressor */
548 if (This->has == NULL)
549 return AVIERR_NOCOMPRESSOR;
551 /* map our sizes to pStream sizes */
553 CONVERT_THIS_to_STREAM(&size);
554 CONVERT_THIS_to_STREAM(&start);
556 /* no bytes to write? -- short circuit */
558 return IAVIStream_Write(This->pStream, -1, samples, buffer, size,
559 flags, sampwritten, byteswritten);
562 /* Need to free source buffer used for reading? */
563 if (This->acmStreamHdr.pbSrc != NULL) {
564 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc);
565 This->acmStreamHdr.pbSrc = NULL;
566 This->acmStreamHdr.dwSrcUser = 0;
569 /* Need bigger destination buffer? */
570 if (This->acmStreamHdr.pbDst == NULL ||
571 This->acmStreamHdr.dwDstUser < size) {
572 if (This->acmStreamHdr.pbDst == NULL)
573 This->acmStreamHdr.pbDst = HeapAlloc(GetProcessHeap(), 0, size);
575 This->acmStreamHdr.pbDst = HeapReAlloc(GetProcessHeap(), 0, This->acmStreamHdr.pbDst, size);
576 if (This->acmStreamHdr.pbDst == NULL)
577 return AVIERR_MEMORY;
578 This->acmStreamHdr.dwDstUser = size;
580 This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
581 This->acmStreamHdr.cbSrcLengthUsed = 0;
582 This->acmStreamHdr.cbDstLengthUsed = 0;
583 This->acmStreamHdr.cbDstLength = This->acmStreamHdr.dwDstUser;
585 /* need to prepare stream? */
586 This->acmStreamHdr.pbSrc = buffer;
587 This->acmStreamHdr.cbSrcLength = buffersize;
588 if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
589 if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
590 This->acmStreamHdr.pbSrc = NULL;
591 This->acmStreamHdr.cbSrcLength = 0;
592 return AVIERR_COMPRESSOR;
596 /* now do the conversion */
597 /* FIXME: use ACM_CONVERTF_* flags */
598 if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
599 hr = AVIERR_COMPRESSOR;
603 This->acmStreamHdr.pbSrc = NULL;
604 This->acmStreamHdr.cbSrcLength = 0;
609 return IAVIStream_Write(This->pStream,-1,This->acmStreamHdr.cbDstLengthUsed /
610 This->lpOutFormat->nBlockAlign,This->acmStreamHdr.pbDst,
611 This->acmStreamHdr.cbDstLengthUsed,flags,sampwritten,
615 static HRESULT WINAPI ACMStream_fnDelete(IAVIStream *iface, LONG start,
618 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
620 TRACE("(%p,%ld,%ld)\n", iface, start, samples);
622 /* check parameters */
623 if (start < 0 || samples < 0)
624 return AVIERR_BADPARAM;
626 /* Delete before start of stream? */
627 if ((DWORD)(start + samples) < This->sInfo.dwStart)
630 /* Delete after end of stream? */
631 if ((DWORD)start > This->sInfo.dwLength)
634 /* For the rest we need write capability */
635 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
636 return AVIERR_READONLY;
638 /* A compressor is also necessary */
639 if (This->has == NULL)
640 return AVIERR_NOCOMPRESSOR;
642 /* map our positions to pStream positions */
643 CONVERT_THIS_to_STREAM(&start);
644 CONVERT_THIS_to_STREAM(&samples);
646 return IAVIStream_Delete(This->pStream, start, samples);
649 static HRESULT WINAPI ACMStream_fnReadData(IAVIStream *iface, DWORD fcc,
650 LPVOID lp, LPLONG lpread)
652 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
654 TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
656 assert(This->pStream != NULL);
658 return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
661 static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
662 LPVOID lp, LONG size)
664 IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
666 TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
668 assert(This->pStream != NULL);
670 return IAVIStream_WriteData(This->pStream, fcc, lp, size);
673 static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream *iface,
674 LPAVISTREAMINFOW info, LONG infolen)
676 FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
681 /***********************************************************************/
683 static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This)
688 assert(This != NULL);
689 assert(This->pStream != NULL);
691 if (This->has != NULL)
694 if (This->lpInFormat == NULL) {
695 /* decode or encode the data from pStream */
696 hr = AVIStreamFormatSize(This->pStream, This->sInfo.dwStart, &This->cbInFormat);
699 This->lpInFormat = HeapAlloc(GetProcessHeap(), 0, This->cbInFormat);
700 if (This->lpInFormat == NULL)
701 return AVIERR_MEMORY;
703 hr = IAVIStream_ReadFormat(This->pStream, This->sInfo.dwStart,
704 This->lpInFormat, &This->cbInFormat);
708 if (This->lpOutFormat == NULL) {
709 /* we must decode to default format */
710 This->cbOutFormat = sizeof(PCMWAVEFORMAT);
711 This->lpOutFormat = HeapAlloc(GetProcessHeap(), 0, This->cbOutFormat);
712 if (This->lpOutFormat == NULL)
713 return AVIERR_MEMORY;
715 This->lpOutFormat->wFormatTag = WAVE_FORMAT_PCM;
716 if (acmFormatSuggest(NULL, This->lpInFormat, This->lpOutFormat,
717 This->cbOutFormat, ACM_FORMATSUGGESTF_WFORMATTAG) != S_OK)
718 return AVIERR_NOCOMPRESSOR;
720 } else if (This->lpOutFormat == NULL)
721 return AVIERR_ERROR; /* To what should I encode? */
723 if (acmStreamOpen(&This->has, NULL, This->lpInFormat, This->lpOutFormat,
724 NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME) != S_OK)
725 return AVIERR_NOCOMPRESSOR;
727 /* update AVISTREAMINFO structure */
728 This->sInfo.dwSampleSize = This->lpOutFormat->nBlockAlign;
729 This->sInfo.dwScale = This->lpOutFormat->nBlockAlign;
730 This->sInfo.dwRate = This->lpOutFormat->nAvgBytesPerSec;
731 This->sInfo.dwQuality = (DWORD)ICQUALITY_DEFAULT;
732 SetRectEmpty(&This->sInfo.rcFrame);
734 /* convert positions ansd sizes to output format */
735 CONVERT_STREAM_to_THIS(&This->sInfo.dwStart);
736 CONVERT_STREAM_to_THIS(&This->sInfo.dwLength);
737 CONVERT_STREAM_to_THIS(&This->sInfo.dwSuggestedBufferSize);