Implemented MJPG handler.
[wine/multimedia.git] / dlls / msacm / stream.c
blob62d4d2c7b272874568c3439962887ae2988667c1
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MSACM32 library
6 * Copyright 1998 Patrik Stridvall
7 * 1999 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /* TODO
25 * + asynchronous conversion is not implemented
26 * + callback/notification
27 * * acmStreamMessage
28 * + properly close ACM streams
31 #include <string.h>
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "windef.h"
35 #include "wine/debug.h"
36 #include "mmsystem.h"
37 #include "msacm.h"
38 #include "msacmdrv.h"
39 #include "wineacm.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
43 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
45 return (PWINE_ACMSTREAM)has;
48 /***********************************************************************
49 * acmStreamClose (MSACM32.@)
51 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
53 PWINE_ACMSTREAM was;
54 MMRESULT ret;
56 TRACE("(0x%08x, %ld)\n", has, fdwClose);
58 if ((was = ACM_GetStream(has)) == NULL) {
59 return MMSYSERR_INVALHANDLE;
61 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
62 if (ret == MMSYSERR_NOERROR) {
63 if (was->hAcmDriver)
64 acmDriverClose(was->hAcmDriver, 0L);
65 HeapFree(MSACM_hHeap, 0, was);
67 TRACE("=> (%d)\n", ret);
68 return ret;
71 /***********************************************************************
72 * acmStreamConvert (MSACM32.@)
74 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
75 DWORD fdwConvert)
77 PWINE_ACMSTREAM was;
78 MMRESULT ret = MMSYSERR_NOERROR;
79 PACMDRVSTREAMHEADER padsh;
81 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
83 if ((was = ACM_GetStream(has)) == NULL)
84 return MMSYSERR_INVALHANDLE;
85 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
86 return MMSYSERR_INVALPARAM;
88 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
89 return ACMERR_UNPREPARED;
91 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
92 * size. some fields are private to msacm internals, and are exposed
93 * in ACMSTREAMHEADER in the dwReservedDriver array
95 padsh = (PACMDRVSTREAMHEADER)pash;
97 /* check that pointers have not been modified */
98 if (padsh->pbPreparedSrc != padsh->pbSrc ||
99 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
100 padsh->pbPreparedDst != padsh->pbDst ||
101 padsh->cbPreparedDstLength < padsh->cbDstLength) {
102 return MMSYSERR_INVALPARAM;
105 padsh->fdwConvert = fdwConvert;
107 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
108 if (ret == MMSYSERR_NOERROR) {
109 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
111 TRACE("=> (%d)\n", ret);
112 return ret;
115 /***********************************************************************
116 * acmStreamMessage (MSACM32.@)
118 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
119 LPARAM lParam2)
121 FIXME("(0x%08x, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
122 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
123 return MMSYSERR_ERROR;
126 /***********************************************************************
127 * acmStreamOpen (MSACM32.@)
129 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
130 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
131 DWORD dwInstance, DWORD fdwOpen)
133 PWINE_ACMSTREAM was;
134 PWINE_ACMDRIVER wad;
135 MMRESULT ret;
136 int wfxSrcSize;
137 int wfxDstSize;
139 TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
140 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
142 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
143 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
144 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
146 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
147 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
148 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
150 if ((fdwOpen & ACM_STREAMOPENF_QUERY) && phas) return MMSYSERR_INVALPARAM;
151 if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) return MMSYSERR_INVALPARAM;
153 wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
154 if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
155 if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
157 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize +
158 ((pwfltr) ? sizeof(WAVEFILTER) : 0));
159 if (was == NULL)
160 return MMSYSERR_NOMEM;
162 was->drvInst.cbStruct = sizeof(was->drvInst);
163 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
164 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
165 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
166 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
167 if (pwfltr) {
168 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
169 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
170 } else {
171 was->drvInst.pwfltr = NULL;
173 was->drvInst.dwCallback = dwCallback;
174 was->drvInst.dwInstance = dwInstance;
175 was->drvInst.fdwOpen = fdwOpen;
176 was->drvInst.fdwDriver = 0L;
177 was->drvInst.dwDriver = 0L;
178 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
179 was->drvInst.has = 0L;
181 if (had) {
182 if (!(wad = MSACM_GetDriver(had))) {
183 ret = MMSYSERR_INVALPARAM;
184 goto errCleanUp;
187 was->obj.dwType = WINE_ACMOBJ_STREAM;
188 was->obj.pACMDriverID = wad->obj.pACMDriverID;
189 was->pDrv = wad;
190 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
192 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
193 if (ret != MMSYSERR_NOERROR)
194 goto errCleanUp;
195 } else {
196 PWINE_ACMDRIVERID wadi;
198 ret = ACMERR_NOTPOSSIBLE;
199 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
200 if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
201 !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
202 !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
203 continue;
204 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
205 if (ret != MMSYSERR_NOERROR)
206 continue;
207 if ((wad = MSACM_GetDriver(had)) != 0) {
208 was->obj.dwType = WINE_ACMOBJ_STREAM;
209 was->obj.pACMDriverID = wad->obj.pACMDriverID;
210 was->pDrv = wad;
211 was->hAcmDriver = had;
213 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
214 TRACE("%s => %08x\n", wadi->pszDriverAlias, ret);
215 if (ret == MMSYSERR_NOERROR) {
216 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
217 acmDriverClose(had, 0L);
219 break;
222 /* no match, close this acm driver and try next one */
223 acmDriverClose(had, 0L);
225 if (ret != MMSYSERR_NOERROR) {
226 ret = ACMERR_NOTPOSSIBLE;
227 goto errCleanUp;
230 ret = MMSYSERR_NOERROR;
231 was->drvInst.has = (HACMSTREAM)was;
232 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
233 if (phas)
234 *phas = (HACMSTREAM)was;
235 TRACE("=> (%d)\n", ret);
236 return ret;
238 errCleanUp:
239 if (phas)
240 *phas = (HACMSTREAM)0;
241 HeapFree(MSACM_hHeap, 0, was);
242 TRACE("=> (%d)\n", ret);
243 return ret;
247 /***********************************************************************
248 * acmStreamPrepareHeader (MSACM32.@)
250 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
251 DWORD fdwPrepare)
253 PWINE_ACMSTREAM was;
254 MMRESULT ret = MMSYSERR_NOERROR;
255 PACMDRVSTREAMHEADER padsh;
257 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
259 if ((was = ACM_GetStream(has)) == NULL)
260 return MMSYSERR_INVALHANDLE;
261 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
262 return MMSYSERR_INVALPARAM;
263 if (fdwPrepare)
264 ret = MMSYSERR_INVALFLAG;
266 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
267 return MMSYSERR_NOERROR;
269 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
270 * size. some fields are private to msacm internals, and are exposed
271 * in ACMSTREAMHEADER in the dwReservedDriver array
273 padsh = (PACMDRVSTREAMHEADER)pash;
275 padsh->fdwConvert = fdwPrepare;
276 padsh->padshNext = NULL;
277 padsh->fdwDriver = padsh->dwDriver = 0L;
279 padsh->fdwPrepared = 0;
280 padsh->dwPrepared = 0;
281 padsh->pbPreparedSrc = 0;
282 padsh->cbPreparedSrcLength = 0;
283 padsh->pbPreparedDst = 0;
284 padsh->cbPreparedDstLength = 0;
286 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
287 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
288 ret = MMSYSERR_NOERROR;
289 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
290 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
291 padsh->fdwPrepared = padsh->fdwStatus;
292 padsh->dwPrepared = 0;
293 padsh->pbPreparedSrc = padsh->pbSrc;
294 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
295 padsh->pbPreparedDst = padsh->pbDst;
296 padsh->cbPreparedDstLength = padsh->cbDstLength;
297 } else {
298 padsh->fdwPrepared = 0;
299 padsh->dwPrepared = 0;
300 padsh->pbPreparedSrc = 0;
301 padsh->cbPreparedSrcLength = 0;
302 padsh->pbPreparedDst = 0;
303 padsh->cbPreparedDstLength = 0;
305 TRACE("=> (%d)\n", ret);
306 return ret;
309 /***********************************************************************
310 * acmStreamReset (MSACM32.@)
312 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
314 PWINE_ACMSTREAM was;
315 MMRESULT ret = MMSYSERR_NOERROR;
317 TRACE("(0x%08x, %ld)\n", has, fdwReset);
319 if (fdwReset) {
320 ret = MMSYSERR_INVALFLAG;
321 } else if ((was = ACM_GetStream(has)) == NULL) {
322 return MMSYSERR_INVALHANDLE;
323 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
324 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
326 TRACE("=> (%d)\n", ret);
327 return ret;
330 /***********************************************************************
331 * acmStreamSize (MSACM32.@)
333 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
334 LPDWORD pdwOutputBytes, DWORD fdwSize)
336 PWINE_ACMSTREAM was;
337 ACMDRVSTREAMSIZE adss;
338 MMRESULT ret;
340 TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
342 if ((was = ACM_GetStream(has)) == NULL) {
343 return MMSYSERR_INVALHANDLE;
345 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
346 return MMSYSERR_INVALFLAG;
349 *pdwOutputBytes = 0L;
351 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
352 case ACM_STREAMSIZEF_DESTINATION:
353 adss.cbDstLength = cbInput;
354 adss.cbSrcLength = 0;
355 break;
356 case ACM_STREAMSIZEF_SOURCE:
357 adss.cbSrcLength = cbInput;
358 adss.cbDstLength = 0;
359 break;
360 default:
361 return MMSYSERR_INVALFLAG;
364 adss.cbStruct = sizeof(adss);
365 adss.fdwSize = fdwSize;
366 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
367 (DWORD)&was->drvInst, (DWORD)&adss);
368 if (ret == MMSYSERR_NOERROR) {
369 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
370 case ACM_STREAMSIZEF_DESTINATION:
371 *pdwOutputBytes = adss.cbSrcLength;
372 break;
373 case ACM_STREAMSIZEF_SOURCE:
374 *pdwOutputBytes = adss.cbDstLength;
375 break;
378 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
379 return ret;
382 /***********************************************************************
383 * acmStreamUnprepareHeader (MSACM32.@)
385 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
386 DWORD fdwUnprepare)
388 PWINE_ACMSTREAM was;
389 MMRESULT ret = MMSYSERR_NOERROR;
390 PACMDRVSTREAMHEADER padsh;
392 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
394 if ((was = ACM_GetStream(has)) == NULL)
395 return MMSYSERR_INVALHANDLE;
396 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
397 return MMSYSERR_INVALPARAM;
399 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
400 return ACMERR_UNPREPARED;
402 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
403 * size. some fields are private to msacm internals, and are exposed
404 * in ACMSTREAMHEADER in the dwReservedDriver array
406 padsh = (PACMDRVSTREAMHEADER)pash;
408 /* check that pointers have not been modified */
409 if (padsh->pbPreparedSrc != padsh->pbSrc ||
410 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
411 padsh->pbPreparedDst != padsh->pbDst ||
412 padsh->cbPreparedDstLength < padsh->cbDstLength) {
413 return MMSYSERR_INVALPARAM;
416 padsh->fdwConvert = fdwUnprepare;
418 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
419 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
420 ret = MMSYSERR_NOERROR;
421 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
423 TRACE("=> (%d)\n", ret);
424 return ret;