Use proper types/names in all cases. Fix some indentation.
[wine] / dlls / avifil32 / acmstream.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define COM_NO_WINDOWS_H
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 "windowsx.h"
30 #include "mmsystem.h"
31 #include "vfw.h"
32 #include "msacm.h"
33
34 #include "avifile_private.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
39
40 /***********************************************************************/
41
42 static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
43 static ULONG   WINAPI ACMStream_fnAddRef(IAVIStream*iface);
44 static ULONG   WINAPI ACMStream_fnRelease(IAVIStream* iface);
45 static HRESULT WINAPI ACMStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
46 static HRESULT WINAPI ACMStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
47 static LONG    WINAPI ACMStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
48 static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
49 static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
50 static HRESULT WINAPI ACMStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
51 static HRESULT WINAPI ACMStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
52 static HRESULT WINAPI ACMStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
53 static HRESULT WINAPI ACMStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
54 static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
55 static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
56
57 struct IAVIStreamVtbl iacmst = {
58   ACMStream_fnQueryInterface,
59   ACMStream_fnAddRef,
60   ACMStream_fnRelease,
61   ACMStream_fnCreate,
62   ACMStream_fnInfo,
63   ACMStream_fnFindSample,
64   ACMStream_fnReadFormat,
65   ACMStream_fnSetFormat,
66   ACMStream_fnRead,
67   ACMStream_fnWrite,
68   ACMStream_fnDelete,
69   ACMStream_fnReadData,
70   ACMStream_fnWriteData,
71   ACMStream_fnSetInfo
72 };
73
74 typedef struct _IAVIStreamImpl {
75   /* IUnknown stuff */
76   IAVIStreamVtbl *lpVtbl;
77   DWORD           ref;
78
79   /* IAVIStream stuff */
80   PAVISTREAM      pStream;
81   AVISTREAMINFOW  sInfo;
82
83   HACMSTREAM      has;
84
85   LPWAVEFORMATEX  lpInFormat;
86   LONG            cbInFormat;
87
88   LPWAVEFORMATEX  lpOutFormat;
89   LONG            cbOutFormat;
90
91   ACMSTREAMHEADER acmStreamHdr;
92 } IAVIStreamImpl;
93
94 /***********************************************************************/
95
96 #define CONVERT_STREAM_to_THIS(a) { \
97            acmStreamSize(This->has,(a)*This->lpInFormat->nBlockAlign,\
98                          &(a), ACM_STREAMSIZEF_SOURCE); \
99            (a) /= This->lpOutFormat->nBlockAlign; }
100 #define CONVERT_THIS_to_STREAM(a) { \
101            acmStreamSize(This->has,(a)*This->lpOutFormat->nBlockAlign,\
102                          &(a), ACM_STREAMSIZEF_DESTINATION); \
103            (a) /= This->lpInFormat->nBlockAlign; }
104
105 static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This);
106
107 HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppv)
108 {
109   IAVIStreamImpl *pstream;
110   HRESULT         hr;
111
112   assert(riid != NULL && ppv != NULL);
113
114   *ppv = NULL;
115
116   pstream = (IAVIStreamImpl*)LocalAlloc(LPTR, sizeof(IAVIStreamImpl));
117   if (pstream == NULL)
118     return AVIERR_MEMORY;
119
120   pstream->lpVtbl = &iacmst;
121
122   hr = IAVIStream_QueryInterface((IAVIStream*)pstream, riid, ppv);
123   if (FAILED(hr))
124     LocalFree((HLOCAL)pstream);
125
126   return hr;
127 }
128
129 static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream *iface,
130                                                   REFIID refiid, LPVOID *obj)
131 {
132   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
133
134   TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
135
136   if (IsEqualGUID(&IID_IUnknown, refiid) ||
137       IsEqualGUID(&IID_IAVIStream, refiid)) {
138     *obj = This;
139     IAVIStream_AddRef(iface);
140
141     return S_OK;
142   }
143
144   return OLE_E_ENUM_NOMORE;
145 }
146
147 static ULONG WINAPI ACMStream_fnAddRef(IAVIStream *iface)
148 {
149   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
150
151   TRACE("(%p) -> %ld\n", iface, This->ref + 1);
152
153   /* also add reference to the nested stream */
154   if (This->pStream != NULL)
155     IAVIStream_AddRef(This->pStream);
156
157   return ++(This->ref);
158 }
159
160 static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface)
161 {
162   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
163
164   TRACE("(%p) -> %ld\n", iface, This->ref - 1);
165
166   if (This->ref == 0) {
167     /* destruct */
168     if (This->has != NULL) {
169       if (This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
170         acmStreamUnprepareHeader(This->has, &This->acmStreamHdr, 0);
171       acmStreamClose(This->has, 0);
172       This->has = NULL;
173     }
174     if (This->acmStreamHdr.pbSrc != NULL) {
175       GlobalFreePtr(This->acmStreamHdr.pbSrc);
176       This->acmStreamHdr.pbSrc = NULL;
177     }
178     if (This->acmStreamHdr.pbDst != NULL) {
179       GlobalFreePtr(This->acmStreamHdr.pbDst);
180       This->acmStreamHdr.pbDst = NULL;
181     }
182     if (This->lpInFormat != NULL) {
183       GlobalFreePtr(This->lpInFormat);
184       This->lpInFormat = NULL;
185       This->cbInFormat = 0;
186     }
187     if (This->lpOutFormat != NULL) {
188       GlobalFreePtr(This->lpOutFormat);
189       This->lpOutFormat = NULL;
190       This->cbOutFormat = 0;
191     }
192     if (This->pStream != NULL) {
193       IAVIStream_Release(This->pStream);
194       This->pStream = NULL;
195     }
196     LocalFree((HLOCAL)This);
197
198     return 0;
199   }
200
201   /* also release reference to the nested stream */
202   if (This->pStream != NULL)
203     IAVIStream_Release(This->pStream);
204
205   return --This->ref;
206 }
207
208 /* lParam1: PAVISTREAM
209  * lParam2: LPAVICOMPRESSOPTIONS -- even if doc's say LPWAVEFORMAT
210  */
211 static HRESULT WINAPI ACMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
212                                           LPARAM lParam2)
213 {
214   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
215
216   TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
217
218   /* check for swapped parameters */
219   if ((LPVOID)lParam1 != NULL &&
220       ((LPAVICOMPRESSOPTIONS)lParam1)->fccType == streamtypeAUDIO) {
221     register LPARAM tmp = lParam1;
222
223     lParam1 = lParam2;
224     lParam2 = tmp;
225   }
226
227   if ((LPVOID)lParam1 == NULL)
228     return AVIERR_BADPARAM;
229
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 */
233
234   This->sInfo.fccHandler = 0; /* be paranoid */
235
236   /* FIXME: check ACM version? Which version does we need? */
237
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;
242
243     if (((LPWAVEFORMATEX)lParam2)->wFormatTag != WAVE_FORMAT_PCM)
244       This->cbOutFormat = sizeof(WAVEFORMATEX) + ((LPWAVEFORMATEX)lParam2)->cbSize;
245     else
246       This->cbOutFormat = sizeof(PCMWAVEFORMAT);
247
248     This->lpOutFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, This->cbOutFormat);
249     if (This->lpOutFormat == NULL)
250       return AVIERR_MEMORY;
251
252     memcpy(This->lpOutFormat, (LPVOID)lParam2, This->cbOutFormat);
253   } else {
254     This->lpOutFormat = NULL;
255     This->cbOutFormat = 0;
256   }
257
258   This->pStream = (PAVISTREAM)lParam1;
259   IAVIStream_AddRef(This->pStream);
260
261   return AVIERR_OK;
262 }
263
264 static HRESULT WINAPI ACMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
265                                         LONG size)
266 {
267   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
268
269   TRACE("(%p,%p,%ld)\n", iface, psi, size);
270
271   if (psi == NULL)
272     return AVIERR_BADPARAM;
273   if (size < 0)
274     return AVIERR_BADSIZE;
275
276   /* Need codec to correct some values in structure */
277   if (This->has == NULL) {
278     HRESULT hr = AVIFILE_OpenCompressor(This);
279
280     if (FAILED(hr))
281       return hr;
282   }
283
284   memcpy(psi, &This->sInfo, min(size, (LONG)sizeof(This->sInfo)));
285
286   if (size < (LONG)sizeof(This->sInfo))
287     return AVIERR_BUFFERTOOSMALL;
288   return AVIERR_OK;
289 }
290
291 static LONG WINAPI ACMStream_fnFindSample(IAVIStream *iface, LONG pos,
292                                            LONG flags)
293 {
294   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
295
296   TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
297
298   if (flags & FIND_FROM_START) {
299     pos = This->sInfo.dwStart;
300     flags &= ~(FIND_FROM_START|FIND_PREV);
301     flags |= FIND_NEXT;
302   }
303
304   /* convert pos from our 'space' to This->pStream's one */
305   CONVERT_THIS_to_STREAM(pos);
306
307   /* ask stream */
308   pos = IAVIStream_FindSample(This->pStream, pos, flags);
309
310   if (pos != -1) {
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);
314   }
315
316   return pos;
317 }
318
319 static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream *iface, LONG pos,
320                                               LPVOID format, LONG *formatsize)
321 {
322   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
323
324   TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
325
326   if (formatsize == NULL)
327     return AVIERR_BADPARAM;
328
329   if (This->has == NULL) {
330     HRESULT hr = AVIFILE_OpenCompressor(This);
331
332     if (FAILED(hr))
333       return hr;
334   }
335
336   /* only interested in needed buffersize? */
337   if (format == NULL || *formatsize <= 0) {
338     *formatsize = This->cbOutFormat;
339
340     return AVIERR_OK;
341   }
342
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;
348   }
349
350   *formatsize = This->cbOutFormat;
351   return AVIERR_OK;
352 }
353
354 static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream *iface, LONG pos,
355                                              LPVOID format, LONG formatsize)
356 {
357   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
358
359   HRESULT hr;
360
361   TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
362
363   /* check parameters */
364   if (format == NULL || formatsize <= 0)
365     return AVIERR_BADPARAM;
366
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;
373
374     return AVIERR_OK;
375   }
376
377   /* Does the nested stream support writing? */
378   if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
379     return AVIERR_READONLY;
380
381   This->lpInFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, formatsize);
382   if (This->lpInFormat == NULL)
383     return AVIERR_MEMORY;
384   This->cbInFormat = formatsize;
385   memcpy(This->lpInFormat, format, formatsize);
386
387   /* initialize formats and get compressor */
388   hr = AVIFILE_OpenCompressor(This);
389   if (FAILED(hr))
390     return hr;
391
392   CONVERT_THIS_to_STREAM(pos);
393
394   /* tell the nested stream the new format */
395   return IAVIStream_SetFormat(This->pStream, pos, This->lpOutFormat,
396                               This->cbOutFormat);
397 }
398
399 static HRESULT WINAPI ACMStream_fnRead(IAVIStream *iface, LONG start,
400                                         LONG samples, LPVOID buffer,
401                                         LONG buffersize, LPLONG bytesread,
402                                         LPLONG samplesread)
403 {
404   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
405
406   HRESULT hr;
407   DWORD   size;
408
409   TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
410         buffersize, bytesread, samplesread);
411
412   /* clear return parameters if given */
413   if (bytesread != NULL)
414     *bytesread = 0;
415   if (samplesread != NULL)
416     *samplesread = 0;
417
418   /* Do we have our compressor? */
419   if (This->has == NULL) {
420     hr = AVIFILE_OpenCompressor(This);
421
422     if (FAILED(hr))
423       return hr;
424   }
425
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);
431   }
432
433   /* read as much as fit? */
434   if (samples == -1)
435     samples = buffersize / This->lpOutFormat->nBlockAlign;
436   /* limit to buffersize */
437   if (samples * This->lpOutFormat->nBlockAlign > buffersize)
438     samples = buffersize / This->lpOutFormat->nBlockAlign;
439
440   /* only return needed size? */
441   if (buffer == NULL || buffersize <= 0 || samples == 0) {
442     if (bytesread == NULL && samplesread == NULL)
443       return AVIERR_BADPARAM;
444
445     if (bytesread != NULL)
446       *bytesread = samples * This->lpOutFormat->nBlockAlign;
447     if (samplesread != NULL)
448       *samplesread = samples;
449
450     return AVIERR_OK;
451   }
452
453   /* map our positions to pStream positions */
454   CONVERT_THIS_to_STREAM(start);
455
456   /* our needed internal buffersize */
457   size = samples * This->lpInFormat->nBlockAlign;
458
459   /* Need to free destination buffer used for writing? */
460   if (This->acmStreamHdr.pbDst != NULL) {
461     GlobalFreePtr(This->acmStreamHdr.pbDst);
462     This->acmStreamHdr.pbDst     = NULL;
463     This->acmStreamHdr.dwDstUser = 0;
464   }
465
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 = GlobalAllocPtr(GMEM_MOVEABLE, size);
471     else
472       This->acmStreamHdr.pbSrc = GlobalReAllocPtr(This->acmStreamHdr.pbSrc,
473                                                   size, GMEM_MOVEABLE);
474     if (This->acmStreamHdr.pbSrc == NULL)
475       return AVIERR_MEMORY;
476     This->acmStreamHdr.dwSrcUser = size;
477   }
478
479   This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
480   This->acmStreamHdr.cbSrcLengthUsed = 0;
481   This->acmStreamHdr.cbDstLengthUsed = 0;
482   This->acmStreamHdr.cbSrcLength     = size;
483
484   /* read source data */
485   hr = IAVIStream_Read(This->pStream, start, -1, This->acmStreamHdr.pbSrc,
486                        This->acmStreamHdr.cbSrcLength,
487                        &This->acmStreamHdr.cbSrcLength, NULL);
488   if (FAILED(hr) || This->acmStreamHdr.cbSrcLength == 0)
489     return hr;
490
491   /* need to prepare stream? */
492   This->acmStreamHdr.pbDst       = buffer;
493   This->acmStreamHdr.cbDstLength = buffersize;
494   if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
495     if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
496       This->acmStreamHdr.pbDst       = NULL;
497       This->acmStreamHdr.cbDstLength = 0;
498       return AVIERR_COMPRESSOR;
499     }
500   }
501
502   /* now do the conversion */
503   /* FIXME: use ACM_CONVERTF_* flags */
504   if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
505     hr = AVIERR_COMPRESSOR;
506
507   This->acmStreamHdr.pbDst       = NULL;
508   This->acmStreamHdr.cbDstLength = 0;
509
510   /* fill out return parameters if given */
511   if (bytesread != NULL)
512     *bytesread = This->acmStreamHdr.cbDstLengthUsed;
513   if (samplesread != NULL)
514     *samplesread =
515       This->acmStreamHdr.cbDstLengthUsed / This->lpOutFormat->nBlockAlign;
516
517   return hr;
518 }
519
520 static HRESULT WINAPI ACMStream_fnWrite(IAVIStream *iface, LONG start,
521                                          LONG samples, LPVOID buffer,
522                                          LONG buffersize, DWORD flags,
523                                          LPLONG sampwritten,
524                                          LPLONG byteswritten)
525 {
526   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
527
528   HRESULT hr;
529   ULONG   size;
530
531   TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
532         buffer, buffersize, flags, sampwritten, byteswritten);
533
534   /* clear return parameters if given */
535   if (sampwritten != NULL)
536     *sampwritten = 0;
537   if (byteswritten != NULL)
538     *byteswritten = 0;
539
540   /* check parameters */
541   if (buffer == NULL && (buffersize > 0 || samples > 0))
542     return AVIERR_BADPARAM;
543
544   /* Have we write capability? */
545   if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
546     return AVIERR_READONLY;
547
548   /* also need a compressor */
549   if (This->has == NULL)
550     return AVIERR_NOCOMPRESSOR;
551
552   /* map our sizes to pStream sizes */
553   size = buffersize;
554   CONVERT_THIS_to_STREAM(size);
555   CONVERT_THIS_to_STREAM(start);
556
557   /* no bytes to write? -- short circuit */
558   if (size == 0) {
559     return IAVIStream_Write(This->pStream, -1, samples, buffer, size,
560                             flags, sampwritten, byteswritten);
561   }
562
563   /* Need to free source buffer used for reading? */
564   if (This->acmStreamHdr.pbSrc != NULL) {
565     GlobalFreePtr(This->acmStreamHdr.pbSrc);
566     This->acmStreamHdr.pbSrc     = NULL;
567     This->acmStreamHdr.dwSrcUser = 0;
568   }
569
570   /* Need bigger destination buffer? */
571   if (This->acmStreamHdr.pbDst == NULL ||
572       This->acmStreamHdr.dwDstUser < size) {
573     if (This->acmStreamHdr.pbDst == NULL)
574       This->acmStreamHdr.pbDst = GlobalAllocPtr(GMEM_MOVEABLE, size);
575     else
576       This->acmStreamHdr.pbDst = GlobalReAllocPtr(This->acmStreamHdr.pbDst,
577                                                   size, GMEM_MOVEABLE);
578     if (This->acmStreamHdr.pbDst == NULL)
579       return AVIERR_MEMORY;
580     This->acmStreamHdr.dwDstUser = size;
581   }
582   This->acmStreamHdr.cbStruct        = sizeof(This->acmStreamHdr);
583   This->acmStreamHdr.cbSrcLengthUsed = 0;
584   This->acmStreamHdr.cbDstLengthUsed = 0;
585   This->acmStreamHdr.cbDstLength     = This->acmStreamHdr.dwDstUser;
586
587   /* need to prepare stream? */
588   This->acmStreamHdr.pbSrc       = buffer;
589   This->acmStreamHdr.cbSrcLength = buffersize;
590   if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
591     if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
592       This->acmStreamHdr.pbSrc       = NULL;
593       This->acmStreamHdr.cbSrcLength = 0;
594       return AVIERR_COMPRESSOR;
595     }
596   }
597
598   /* now do the conversion */
599   /* FIXME: use ACM_CONVERTF_* flags */
600   if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
601     hr = AVIERR_COMPRESSOR;
602   else
603     hr = AVIERR_OK;
604
605   This->acmStreamHdr.pbSrc       = NULL;
606   This->acmStreamHdr.cbSrcLength = 0;
607
608   if (FAILED(hr))
609     return hr;
610
611   return IAVIStream_Write(This->pStream,-1,This->acmStreamHdr.cbDstLengthUsed /
612                           This->lpOutFormat->nBlockAlign,This->acmStreamHdr.pbDst,
613                           This->acmStreamHdr.cbDstLengthUsed,flags,sampwritten,
614                           byteswritten);
615 }
616
617 static HRESULT WINAPI ACMStream_fnDelete(IAVIStream *iface, LONG start,
618                                           LONG samples)
619 {
620   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
621
622   TRACE("(%p,%ld,%ld)\n", iface, start, samples);
623
624   /* check parameters */
625   if (start < 0 || samples < 0)
626     return AVIERR_BADPARAM;
627
628   /* Delete before start of stream? */
629   if ((DWORD)(start + samples) < This->sInfo.dwStart)
630     return AVIERR_OK;
631
632   /* Delete after end of stream? */
633   if ((DWORD)start > This->sInfo.dwLength)
634     return AVIERR_OK;
635
636   /* For the rest we need write capability */
637   if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
638     return AVIERR_READONLY;
639
640   /* A compressor is also necessary */
641   if (This->has == NULL)
642     return AVIERR_NOCOMPRESSOR;
643
644   /* map our positions to pStream positions */
645   CONVERT_THIS_to_STREAM(start);
646   CONVERT_THIS_to_STREAM(samples);
647
648   return IAVIStream_Delete(This->pStream, start, samples);
649 }
650
651 static HRESULT WINAPI ACMStream_fnReadData(IAVIStream *iface, DWORD fcc,
652                                             LPVOID lp, LPLONG lpread)
653 {
654   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
655
656   TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
657
658   assert(This->pStream != NULL);
659
660   return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
661 }
662
663 static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
664                                              LPVOID lp, LONG size)
665 {
666   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
667
668   TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
669
670   assert(This->pStream != NULL);
671
672   return IAVIStream_WriteData(This->pStream, fcc, lp, size);
673 }
674
675 static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream *iface,
676                                            LPAVISTREAMINFOW info, LONG infolen)
677 {
678   FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
679
680   return E_FAIL;
681 }
682
683 /***********************************************************************/
684
685 static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This)
686 {
687   HRESULT hr;
688
689   /* pre-conditions */
690   assert(This != NULL);
691   assert(This->pStream != NULL);
692
693   if (This->has != NULL)
694     return AVIERR_OK;
695
696   if (This->lpInFormat == NULL) {
697     /* decode or encode the data from pStream */
698     hr = AVIStreamFormatSize(This->pStream, This->sInfo.dwStart, &This->cbInFormat);
699     if (FAILED(hr))
700       return hr;
701     This->lpInFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, This->cbInFormat);
702     if (This->lpInFormat == NULL)
703       return AVIERR_MEMORY;
704
705     hr = IAVIStream_ReadFormat(This->pStream, This->sInfo.dwStart,
706                                This->lpInFormat, &This->cbInFormat);
707     if (FAILED(hr))
708       return hr;
709
710     if (This->lpOutFormat == NULL) {
711       /* we must decode to default format */
712       This->cbOutFormat = sizeof(PCMWAVEFORMAT);
713       This->lpOutFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, This->cbOutFormat);
714       if (This->lpOutFormat == NULL)
715         return AVIERR_MEMORY;
716
717       This->lpOutFormat->wFormatTag = WAVE_FORMAT_PCM;
718       if (acmFormatSuggest(NULL, This->lpInFormat, This->lpOutFormat,
719                            This->cbOutFormat, ACM_FORMATSUGGESTF_WFORMATTAG) != S_OK)
720         return AVIERR_NOCOMPRESSOR;
721     }
722   } else if (This->lpOutFormat == NULL)
723     return AVIERR_ERROR; /* To what should I encode? */
724
725   if (acmStreamOpen(&This->has, NULL, This->lpInFormat, This->lpOutFormat,
726                     NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME) != S_OK)
727     return AVIERR_NOCOMPRESSOR;
728
729   /* update AVISTREAMINFO structure */
730   This->sInfo.dwSampleSize = This->lpOutFormat->nBlockAlign;
731   This->sInfo.dwScale      = This->lpOutFormat->nBlockAlign;
732   This->sInfo.dwRate       = This->lpOutFormat->nAvgBytesPerSec;
733   This->sInfo.dwQuality    = (DWORD)ICQUALITY_DEFAULT;
734   SetRectEmpty(&This->sInfo.rcFrame);
735
736   /* convert positions ansd sizes to output format */
737   CONVERT_STREAM_to_THIS(This->sInfo.dwStart);
738   CONVERT_STREAM_to_THIS(This->sInfo.dwLength);
739   CONVERT_STREAM_to_THIS(This->sInfo.dwSuggestedBufferSize);
740
741   return AVIERR_OK;
742 }