]> git.sesse.net Git - vlc/blob - libs/loader/afl.c
8800df16dbb7d56722e493952b04908dd2bfff3c
[vlc] / libs / loader / afl.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 1998 Patrick Stridvall
5  * Copyright (C) 1999 Eric Pouech
6  *
7  * Originally distributed under LPGL 2.1 (or later) by the Wine project.
8  *
9  * Modified for use with MPlayer, detailed CVS changelog at
10  * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
11  *
12  * File now distributed as part of VLC media player with no modifications.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  */
28
29 /**************************************************************************
30
31
32   This file will contain an interface to ACM drivers.
33   Its content will be based mainly on wine/dlls/msacm32
34   actually, for audio decompression only the following functions
35   are needed:
36   
37   acmStreamOpen ( takes formats of src and dest, returns stream handle )
38   acmStreamPrepareHeader ( takes stream handler and info on data )
39   acmStreamConvert ( the same as PrepareHeader )
40   acmStreamUnprepareHeader
41   acmStreamClose
42   acmStreamSize
43   maybe acmStreamReset
44   
45   In future I'll also add functions for format enumeration, 
46   but not right now.
47
48   Modified for use with MPlayer, detailed CVS changelog at
49   http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
50   
51 ***************************************************************************/
52 #include "config.h"
53
54 #include "wine/winbase.h"
55 #include "wine/windef.h"
56 #include "wine/winuser.h"
57 #include "wine/vfw.h"
58 #include "wine/winestring.h"
59 #include "wine/driver.h"
60 #include "wine/winerror.h"
61 #include "wine/msacm.h"
62 #include "wine/msacmdrv.h"
63 #include "wineacm.h"
64 #ifndef __MINGW32__
65 #include "ext.h"
66 #endif
67 #include "driver.h"
68
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #pragma pack(1)
73 #define OpenDriverA DrvOpen
74 #define CloseDriver DrvClose
75
76 static inline PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
77 {
78     return (PWINE_ACMSTREAM)has;
79 }
80
81 /***********************************************************************
82  *           acmDriverAddA (MSACM32.2)
83  */
84 MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
85                               LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
86 {
87     if (!phadid)
88         return MMSYSERR_INVALPARAM;
89     
90     /* Check if any unknown flags */
91     if (fdwAdd & 
92         ~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND|
93           ACM_DRIVERADDF_GLOBAL))
94         return MMSYSERR_INVALFLAG;
95     
96     /* Check if any incompatible flags */
97     if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) && 
98         (fdwAdd & ACM_DRIVERADDF_NOTIFYHWND))
99         return MMSYSERR_INVALFLAG;
100     
101     /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a 
102      * LoadDriver on it, to be sure we can call SendDriverMessage on the
103      * hDrvr handle.
104      */
105     *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, 0, hinstModule);
106     
107     /* FIXME: lParam, dwPriority and fdwAdd ignored */
108     
109     return MMSYSERR_NOERROR;
110 }
111
112 /***********************************************************************
113  *           acmDriverClose (MSACM32.4)
114  */
115 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
116 {
117     PWINE_ACMDRIVER  p;
118     PWINE_ACMDRIVER* tp;
119     
120     if (fdwClose)
121         return MMSYSERR_INVALFLAG;
122     
123     p = MSACM_GetDriver(had);
124     if (!p)
125         return MMSYSERR_INVALHANDLE;
126
127     for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) {
128         if (*tp == p) {
129             *tp = (*tp)->pNextACMDriver;
130             break;
131         }
132     }
133     
134     if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList)
135         CloseDriver(p->hDrvr);
136     
137     HeapFree(MSACM_hHeap, 0, p);
138     
139     return MMSYSERR_NOERROR;
140 }
141
142 /***********************************************************************
143  *           acmDriverEnum (MSACM32.7)
144  */
145 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum)
146 {
147     PWINE_ACMDRIVERID   p;
148     DWORD               fdwSupport;
149
150     if (!fnCallback) {
151         return MMSYSERR_INVALPARAM;
152     }
153     
154     if (fdwEnum && ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
155         return MMSYSERR_INVALFLAG;
156     }
157     
158     for (p = MSACM_pFirstACMDriverID; p; p = p->pNextACMDriverID) {
159         fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
160         if (!p->bEnabled) {
161             if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
162                 fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
163             else
164                 continue;
165         }
166         (*fnCallback)((HACMDRIVERID) p, dwInstance, fdwSupport);
167     }
168     
169     return MMSYSERR_NOERROR;
170 }
171
172 /***********************************************************************
173  *           acmDriverID (MSACM32.8)
174  */
175 MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
176 {
177     PWINE_ACMOBJ pao;
178     
179     pao = MSACM_GetObj(hao);
180     if (!pao)
181         return MMSYSERR_INVALHANDLE;
182     
183     if (!phadid)
184         return MMSYSERR_INVALPARAM;
185     
186     if (fdwDriverID)
187         return MMSYSERR_INVALFLAG;
188     
189     *phadid = (HACMDRIVERID) pao->pACMDriverID;
190     
191     return MMSYSERR_NOERROR;
192 }
193
194 /***********************************************************************
195  *           acmDriverMessage (MSACM32.9)
196  * FIXME
197  *   Not implemented
198  */
199 LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
200 {
201     PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
202     if (!pad)
203         return MMSYSERR_INVALPARAM;
204     
205     /* FIXME: Check if uMsg legal */
206     
207     if (!SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2))
208         return MMSYSERR_NOTSUPPORTED;
209     
210     return MMSYSERR_NOERROR;
211 }
212
213
214 /***********************************************************************
215  *           acmDriverOpen (MSACM32.10)
216  */
217 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
218 {
219     PWINE_ACMDRIVERID   padid;
220     PWINE_ACMDRIVER     pad;
221     ICOPEN              icopen;
222     HDRVR               hdrv;
223
224
225     TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen);
226
227     if (!phad)
228         return MMSYSERR_INVALPARAM;
229     
230     padid = MSACM_GetDriverID(hadid); 
231     if (!padid)
232         return MMSYSERR_INVALHANDLE;
233     
234     if (fdwOpen)
235         return MMSYSERR_INVALFLAG;
236     
237     pad = (PWINE_ACMDRIVER) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
238     if (!pad)
239         return MMSYSERR_NOMEM;
240
241     pad->obj.pACMDriverID = padid;
242     icopen.fccType              = mmioFOURCC('a', 'u', 'd', 'c');
243     icopen.fccHandler           = (long)padid->pszFileName;
244     icopen.dwSize               = sizeof(ICOPEN);
245     icopen.dwFlags              = 0;
246
247     icopen.pV1Reserved = padid->pszFileName;
248     if (!padid->hInstModule)
249         pad->hDrvr = OpenDriverA((long)&icopen);
250     else
251         pad->hDrvr = padid->hInstModule;
252     
253     if (!pad->hDrvr) {
254         HeapFree(MSACM_hHeap, 0, pad);
255         return MMSYSERR_ERROR;
256     }
257
258     pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
259
260     /* insert new pad at beg of list */
261     pad->pNextACMDriver = padid->pACMDriverList;
262     padid->pACMDriverList = pad;
263
264     /* FIXME: Create a WINE_ACMDRIVER32 */
265     *phad = (HACMDRIVER)pad;
266
267     return MMSYSERR_NOERROR;
268 }
269
270 /***********************************************************************
271  *           acmDriverRemove (MSACM32.12)
272  */
273 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
274 {
275     PWINE_ACMDRIVERID padid;
276     
277     padid = MSACM_GetDriverID(hadid);
278     if (!padid)
279         return MMSYSERR_INVALHANDLE;
280     
281     if (fdwRemove)
282         return MMSYSERR_INVALFLAG;
283     
284     MSACM_UnregisterDriver(padid);
285     
286     return MMSYSERR_NOERROR;
287 }
288
289
290
291 /**********************************************************************/
292
293 HANDLE MSACM_hHeap = (HANDLE) NULL;
294 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
295 PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
296
297 /***********************************************************************
298  *           MSACM_RegisterDriver32() 
299  */
300 PWINE_ACMDRIVERID MSACM_RegisterDriver(const char* pszFileName,
301                                        WORD wFormatTag,
302                                        HINSTANCE hinstModule)
303 {
304     PWINE_ACMDRIVERID padid;
305
306     TRACE("('%s', '%x', 0x%08x)\n", pszFileName, wFormatTag, hinstModule);
307
308 #ifndef WIN32_LOADER
309         MSACM_hHeap = GetProcessHeap();
310 #endif
311     padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
312     padid->pszFileName = (char*)malloc(strlen(pszFileName)+1);
313     strcpy(padid->pszFileName, pszFileName);
314 //    1~strdup(pszDriverAlias);
315     padid->wFormatTag = wFormatTag;
316     padid->hInstModule = hinstModule;
317     padid->bEnabled = TRUE;
318     padid->pACMDriverList = NULL;
319     padid->pNextACMDriverID = NULL;
320     padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
321     if (MSACM_pLastACMDriverID)
322         MSACM_pLastACMDriverID->pNextACMDriverID = padid;
323     MSACM_pLastACMDriverID = padid;
324     if (!MSACM_pFirstACMDriverID)
325         MSACM_pFirstACMDriverID = padid;
326     
327     return padid;
328 }
329
330
331 /***********************************************************************
332  *           MSACM_UnregisterDriver32()
333  */
334 PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
335 {
336     PWINE_ACMDRIVERID pNextACMDriverID;
337     
338     while (p->pACMDriverList)
339         acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
340     
341     free( p->pszFileName );
342     
343     if (p == MSACM_pFirstACMDriverID)
344         MSACM_pFirstACMDriverID = p->pNextACMDriverID;
345     if (p == MSACM_pLastACMDriverID)
346         MSACM_pLastACMDriverID = p->pPrevACMDriverID;
347
348     if (p->pPrevACMDriverID)
349         p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
350     if (p->pNextACMDriverID)
351         p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
352     
353     pNextACMDriverID = p->pNextACMDriverID;
354     
355     HeapFree(MSACM_hHeap, 0, p);
356     
357     return pNextACMDriverID;
358 }
359
360 /***********************************************************************
361  *           MSACM_UnregisterAllDrivers32()
362  * FIXME
363  *   Where should this function be called?
364  */
365 void MSACM_UnregisterAllDrivers(void)
366 {
367     PWINE_ACMDRIVERID p;
368
369     for (p = MSACM_pFirstACMDriverID; p; p = MSACM_UnregisterDriver(p));
370 }
371
372 /***********************************************************************
373  *           MSACM_GetDriverID32() 
374  */
375 PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
376 {
377     return (PWINE_ACMDRIVERID)hDriverID;
378 }
379
380 /***********************************************************************
381  *           MSACM_GetDriver32()
382  */
383 PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
384 {
385     return (PWINE_ACMDRIVER)hDriver;
386 }
387
388 /***********************************************************************
389  *           MSACM_GetObj32()
390  */
391 PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj)
392 {
393     return (PWINE_ACMOBJ)hObj;
394 }
395
396
397
398 /***********************************************************************
399  *           acmStreamOpen (MSACM32.40)
400  */
401 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
402                               PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
403                               DWORD dwInstance, DWORD fdwOpen)
404 {
405     PWINE_ACMSTREAM     was;
406     PWINE_ACMDRIVER     wad;
407     MMRESULT            ret;
408     int                 wfxSrcSize;
409     int                 wfxDstSize;
410     
411     TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
412           phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
413
414     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
415           pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, 
416           pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
417
418     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
419           pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, 
420           pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
421
422 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
423     wfxSrcSize = SIZEOF_WFX(pwfxSrc);
424     wfxDstSize = SIZEOF_WFX(pwfxDst);
425 #undef SIZEOF_WFX
426
427     was = (PWINE_ACMSTREAM) HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
428     if (was == NULL)
429         return MMSYSERR_NOMEM;
430     was->drvInst.cbStruct = sizeof(was->drvInst);
431     was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
432     memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
433     // LHACM is checking for 0x1
434     // but if this will not help
435     // was->drvInst.pwfxSrc->wFormatTag = 1;
436     was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
437     memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
438     if (pwfltr) {
439         was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
440         memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
441     } else {
442         was->drvInst.pwfltr = NULL;
443     }
444     was->drvInst.dwCallback = dwCallback;    
445     was->drvInst.dwInstance = dwInstance;
446     was->drvInst.fdwOpen = fdwOpen;
447     was->drvInst.fdwDriver = 0L;  
448     was->drvInst.dwDriver = 0L;     
449     was->drvInst.has = (HACMSTREAM)was;
450     
451     if (had) {
452         if (!(wad = MSACM_GetDriver(had))) {
453             ret = MMSYSERR_INVALPARAM;
454             goto errCleanUp;
455         }
456         
457         was->obj.pACMDriverID = wad->obj.pACMDriverID;
458         was->pDrv = wad;
459         was->hAcmDriver = 0; /* not to close it in acmStreamClose */
460
461         ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
462         if (ret != MMSYSERR_NOERROR)
463             goto errCleanUp;
464     } else {
465         PWINE_ACMDRIVERID wadi;
466         short drv_tag;
467         ret = ACMERR_NOTPOSSIBLE;
468 /*      if(pwfxSrc->wFormatTag==1)//compression
469             drv_tag=pwfxDst->wFormatTag;
470             else
471             if(pwfxDst->wFormatTag==1)//decompression
472                 drv_tag=pwfxSrc->wFormatTag;
473                 else
474                 goto errCleanUp;
475
476             ret=acmDriverOpen2(drv_tag); 
477             if (ret == MMSYSERR_NOERROR) {
478                 if ((wad = MSACM_GetDriver(had)) != 0) {
479                     was->obj.pACMDriverID = wad->obj.pACMDriverID;
480                     was->pDrv = wad;
481                     was->hAcmDriver = had;
482                     
483                     ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
484                     if (ret == MMSYSERR_NOERROR) {
485                         if (fdwOpen & ACM_STREAMOPENF_QUERY) {
486                             acmDriverClose(had, 0L);
487                         }
488                         break;
489                     }
490                 }
491                 acmDriverClose(had, 0L);*/
492         //if(MSACM_pFirstACMDriverID==NULL)
493         //    MSACM_RegisterAllDrivers();
494         
495         for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID)
496         {
497             /* Check Format */
498             if ((int)wadi->wFormatTag != (int)pwfxSrc->wFormatTag) continue;
499
500             ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
501             if (ret == MMSYSERR_NOERROR) {
502                 if ((wad = MSACM_GetDriver(had)) != 0) {
503                     was->obj.pACMDriverID = wad->obj.pACMDriverID;
504                     was->pDrv = wad;
505                     was->hAcmDriver = had;
506                     
507                     ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
508                     //lhacm - crash printf("RETOPEN %d\n", ret);
509                     //ret = 0;
510                     if (ret == MMSYSERR_NOERROR) {
511                         if (fdwOpen & ACM_STREAMOPENF_QUERY) {
512                             acmDriverClose(had, 0L);
513                         }
514                         break;
515                     }
516                 }
517                 // no match, close this acm driver and try next one 
518                 acmDriverClose(had, 0L);
519             }
520         }
521         if (ret != MMSYSERR_NOERROR) {
522             ret = ACMERR_NOTPOSSIBLE;
523             goto errCleanUp;
524         }
525     }
526     ret = MMSYSERR_NOERROR;
527     if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
528         if (phas)
529             *phas = (HACMSTREAM)was;
530         TRACE("=> (%d)\n", ret);
531 #ifdef WIN32_LOADER
532         CodecAlloc();
533 #endif
534         return ret;
535     }
536 errCleanUp:             
537     if (phas)
538         *phas = (HACMSTREAM)0;
539     HeapFree(MSACM_hHeap, 0, was);
540     TRACE("=> (%d)\n", ret);
541     return ret;
542 }
543
544
545 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
546 {
547     PWINE_ACMSTREAM     was;
548     MMRESULT            ret;
549                 
550     TRACE("(0x%08x, %ld)\n", has, fdwClose);
551     
552     if ((was = ACM_GetStream(has)) == NULL) {
553         return MMSYSERR_INVALHANDLE;
554     }
555     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
556     if (ret == MMSYSERR_NOERROR) {
557         if (was->hAcmDriver)
558             acmDriverClose(was->hAcmDriver, 0L);        
559         HeapFree(MSACM_hHeap, 0, was);
560 #ifdef WIN32_LOADER
561         CodecRelease();
562 #endif
563     }
564     TRACE("=> (%d)\n", ret);
565     return ret;
566 }
567
568 /***********************************************************************
569  *           acmStreamConvert (MSACM32.38)
570  */
571 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, 
572                                  DWORD fdwConvert)
573 {
574     PWINE_ACMSTREAM     was;
575     MMRESULT            ret = MMSYSERR_NOERROR;
576     PACMDRVSTREAMHEADER padsh;
577
578     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
579
580     if ((was = ACM_GetStream(has)) == NULL)
581         return MMSYSERR_INVALHANDLE;
582     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
583         return MMSYSERR_INVALPARAM;
584
585     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
586         return ACMERR_UNPREPARED;
587
588     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
589      * size. some fields are private to msacm internals, and are exposed
590      * in ACMSTREAMHEADER in the dwReservedDriver array
591      */
592     padsh = (PACMDRVSTREAMHEADER)pash;
593
594     /* check that pointers have not been modified */
595     if (padsh->pbPreparedSrc != padsh->pbSrc ||
596         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
597         padsh->pbPreparedDst != padsh->pbDst ||
598         padsh->cbPreparedDstLength < padsh->cbDstLength) {
599         return MMSYSERR_INVALPARAM;
600     }   
601
602     padsh->fdwConvert = fdwConvert;
603
604     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
605     if (ret == MMSYSERR_NOERROR) {
606         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
607     }
608     TRACE("=> (%d)\n", ret);
609     return ret;
610 }
611
612
613 /***********************************************************************
614  *           acmStreamPrepareHeader (MSACM32.41)
615  */
616 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
617                                        DWORD fdwPrepare)
618 {
619     PWINE_ACMSTREAM     was;
620     MMRESULT            ret = MMSYSERR_NOERROR;
621     PACMDRVSTREAMHEADER padsh;
622
623     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
624     
625     if ((was = ACM_GetStream(has)) == NULL)
626         return MMSYSERR_INVALHANDLE;
627     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
628         return MMSYSERR_INVALPARAM;
629     if (fdwPrepare)
630         ret = MMSYSERR_INVALFLAG;
631
632     if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
633         return MMSYSERR_NOERROR;
634
635     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
636      * size. some fields are private to msacm internals, and are exposed
637      * in ACMSTREAMHEADER in the dwReservedDriver array
638      */
639     padsh = (PACMDRVSTREAMHEADER)pash;
640
641     padsh->fdwConvert = fdwPrepare;
642     padsh->padshNext = NULL;
643     padsh->fdwDriver = padsh->dwDriver = 0L;
644
645     padsh->fdwPrepared = 0;
646     padsh->dwPrepared = 0;
647     padsh->pbPreparedSrc = 0;
648     padsh->cbPreparedSrcLength = 0;
649     padsh->pbPreparedDst = 0;
650     padsh->cbPreparedDstLength = 0;
651
652     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
653     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
654         ret = MMSYSERR_NOERROR;
655         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
656         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
657         padsh->fdwPrepared = padsh->fdwStatus;
658         padsh->dwPrepared = 0;
659         padsh->pbPreparedSrc = padsh->pbSrc;
660         padsh->cbPreparedSrcLength = padsh->cbSrcLength;
661         padsh->pbPreparedDst = padsh->pbDst;
662         padsh->cbPreparedDstLength = padsh->cbDstLength;
663     } else {
664         padsh->fdwPrepared = 0;
665         padsh->dwPrepared = 0;
666         padsh->pbPreparedSrc = 0;
667         padsh->cbPreparedSrcLength = 0;
668         padsh->pbPreparedDst = 0;
669         padsh->cbPreparedDstLength = 0;
670     }
671     TRACE("=> (%d)\n", ret);
672     return ret;
673 }
674
675 /***********************************************************************
676  *           acmStreamReset (MSACM32.42)
677  */
678 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
679 {
680     PWINE_ACMSTREAM     was;
681     MMRESULT            ret = MMSYSERR_NOERROR;
682
683     TRACE("(0x%08x, %ld)\n", has, fdwReset);
684
685     if (fdwReset) {
686         ret = MMSYSERR_INVALFLAG;
687     } else if ((was = ACM_GetStream(has)) == NULL) {
688         return MMSYSERR_INVALHANDLE;
689     } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
690         ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
691     }
692     TRACE("=> (%d)\n", ret);
693     return ret;
694 }
695
696 /***********************************************************************
697  *           acmStreamSize (MSACM32.43)
698  */
699 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, 
700                               LPDWORD pdwOutputBytes, DWORD fdwSize)
701 {
702     PWINE_ACMSTREAM     was;
703     ACMDRVSTREAMSIZE    adss;
704     MMRESULT            ret;
705     
706     TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
707     
708     if ((was = ACM_GetStream(has)) == NULL) {
709         return MMSYSERR_INVALHANDLE;
710     }
711     if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
712         return MMSYSERR_INVALFLAG;
713     }
714
715     *pdwOutputBytes = 0L;
716     
717     switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
718     case ACM_STREAMSIZEF_DESTINATION:
719         adss.cbDstLength = cbInput;
720         adss.cbSrcLength = 0;
721         break;
722     case ACM_STREAMSIZEF_SOURCE:
723         adss.cbSrcLength = cbInput;
724         adss.cbDstLength = 0;
725         break;
726     default:    
727         return MMSYSERR_INVALFLAG;
728     }
729     
730     adss.cbStruct = sizeof(adss);
731     adss.fdwSize = fdwSize;
732     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, 
733                             (DWORD)&was->drvInst, (DWORD)&adss);
734     if (ret == MMSYSERR_NOERROR) {
735         switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
736         case ACM_STREAMSIZEF_DESTINATION:
737             *pdwOutputBytes = adss.cbSrcLength;
738             break;
739         case ACM_STREAMSIZEF_SOURCE:
740             *pdwOutputBytes = adss.cbDstLength;
741             break;
742         }
743     }
744     TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
745     return ret;
746 }
747
748 /***********************************************************************
749  *           acmStreamUnprepareHeader (MSACM32.44)
750  */
751 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
752                                          DWORD fdwUnprepare)
753 {
754     PWINE_ACMSTREAM     was;
755     MMRESULT            ret = MMSYSERR_NOERROR;
756     PACMDRVSTREAMHEADER padsh;
757
758     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
759     
760     if ((was = ACM_GetStream(has)) == NULL)
761         return MMSYSERR_INVALHANDLE;
762     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
763         return MMSYSERR_INVALPARAM;
764
765     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
766         return ACMERR_UNPREPARED;
767
768     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
769      * size. some fields are private to msacm internals, and are exposed
770      * in ACMSTREAMHEADER in the dwReservedDriver array
771      */
772     padsh = (PACMDRVSTREAMHEADER)pash;
773
774     /* check that pointers have not been modified */
775     if (padsh->pbPreparedSrc != padsh->pbSrc ||
776         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
777         padsh->pbPreparedDst != padsh->pbDst ||
778         padsh->cbPreparedDstLength < padsh->cbDstLength) {
779         return MMSYSERR_INVALPARAM;
780     }   
781
782     padsh->fdwConvert = fdwUnprepare;
783
784     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
785     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
786         ret = MMSYSERR_NOERROR;
787         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
788     }
789     TRACE("=> (%d)\n", ret);
790     return ret;
791 }