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