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