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