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