widl: Convert expression lists to standard Wine lists.
[wine/hacks.git] / dlls / mciavi32 / mmoutput.c
blobeab8fd51c965e38eecd86b5f3835a2567d356321
1 /*
2 * Digital video MCI Wine Driver
4 * Copyright 1999, 2000 Eric POUECH
5 * Copyright 2003 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "private_mciavi.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
27 static BOOL MCIAVI_GetInfoAudio(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCKINFO *mmckStream)
29 MMCKINFO mmckInfo;
31 mmioRead(wma->hFile, (LPSTR)&wma->ash_audio, sizeof(wma->ash_audio));
33 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_audio.fccType)),
34 HIBYTE(LOWORD(wma->ash_audio.fccType)),
35 LOBYTE(HIWORD(wma->ash_audio.fccType)),
36 HIBYTE(HIWORD(wma->ash_audio.fccType)));
37 if (wma->ash_audio.fccHandler) /* not all streams specify a handler */
38 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_audio.fccHandler)),
39 HIBYTE(LOWORD(wma->ash_audio.fccHandler)),
40 LOBYTE(HIWORD(wma->ash_audio.fccHandler)),
41 HIBYTE(HIWORD(wma->ash_audio.fccHandler)));
42 else
43 TRACE("ash.fccHandler=0, no handler specified\n");
44 TRACE("ash.dwFlags=%d\n", wma->ash_audio.dwFlags);
45 TRACE("ash.wPriority=%d\n", wma->ash_audio.wPriority);
46 TRACE("ash.wLanguage=%d\n", wma->ash_audio.wLanguage);
47 TRACE("ash.dwInitialFrames=%d\n", wma->ash_audio.dwInitialFrames);
48 TRACE("ash.dwScale=%d\n", wma->ash_audio.dwScale);
49 TRACE("ash.dwRate=%d\n", wma->ash_audio.dwRate);
50 TRACE("ash.dwStart=%d\n", wma->ash_audio.dwStart);
51 TRACE("ash.dwLength=%d\n", wma->ash_audio.dwLength);
52 TRACE("ash.dwSuggestedBufferSize=%d\n", wma->ash_audio.dwSuggestedBufferSize);
53 TRACE("ash.dwQuality=%d\n", wma->ash_audio.dwQuality);
54 TRACE("ash.dwSampleSize=%d\n", wma->ash_audio.dwSampleSize);
55 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma->ash_audio.rcFrame.top, wma->ash_audio.rcFrame.left,
56 wma->ash_audio.rcFrame.bottom, wma->ash_audio.rcFrame.right);
58 /* rewind to the start of the stream */
59 mmioAscend(wma->hFile, mmckStream, 0);
61 mmckInfo.ckid = ckidSTREAMFORMAT;
62 if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) {
63 WARN("Can't find 'strf' chunk\n");
64 return FALSE;
66 if (mmckInfo.cksize < sizeof(WAVEFORMAT)) {
67 WARN("Size of strf chunk (%d) < audio format struct\n", mmckInfo.cksize);
68 return FALSE;
70 wma->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
71 if (!wma->lpWaveFormat) {
72 WARN("Can't alloc WaveFormat\n");
73 return FALSE;
76 mmioRead(wma->hFile, (LPSTR)wma->lpWaveFormat, mmckInfo.cksize);
78 TRACE("waveFormat.wFormatTag=%d\n", wma->lpWaveFormat->wFormatTag);
79 TRACE("waveFormat.nChannels=%d\n", wma->lpWaveFormat->nChannels);
80 TRACE("waveFormat.nSamplesPerSec=%d\n", wma->lpWaveFormat->nSamplesPerSec);
81 TRACE("waveFormat.nAvgBytesPerSec=%d\n", wma->lpWaveFormat->nAvgBytesPerSec);
82 TRACE("waveFormat.nBlockAlign=%d\n", wma->lpWaveFormat->nBlockAlign);
83 TRACE("waveFormat.wBitsPerSample=%d\n", wma->lpWaveFormat->wBitsPerSample);
84 if (mmckInfo.cksize >= sizeof(WAVEFORMATEX))
85 TRACE("waveFormat.cbSize=%d\n", wma->lpWaveFormat->cbSize);
87 return TRUE;
90 static BOOL MCIAVI_GetInfoVideo(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCKINFO* mmckStream)
92 MMCKINFO mmckInfo;
94 mmioRead(wma->hFile, (LPSTR)&wma->ash_video, sizeof(wma->ash_video));
96 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_video.fccType)),
97 HIBYTE(LOWORD(wma->ash_video.fccType)),
98 LOBYTE(HIWORD(wma->ash_video.fccType)),
99 HIBYTE(HIWORD(wma->ash_video.fccType)));
100 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_video.fccHandler)),
101 HIBYTE(LOWORD(wma->ash_video.fccHandler)),
102 LOBYTE(HIWORD(wma->ash_video.fccHandler)),
103 HIBYTE(HIWORD(wma->ash_video.fccHandler)));
104 TRACE("ash.dwFlags=%d\n", wma->ash_video.dwFlags);
105 TRACE("ash.wPriority=%d\n", wma->ash_video.wPriority);
106 TRACE("ash.wLanguage=%d\n", wma->ash_video.wLanguage);
107 TRACE("ash.dwInitialFrames=%d\n", wma->ash_video.dwInitialFrames);
108 TRACE("ash.dwScale=%d\n", wma->ash_video.dwScale);
109 TRACE("ash.dwRate=%d\n", wma->ash_video.dwRate);
110 TRACE("ash.dwStart=%d\n", wma->ash_video.dwStart);
111 TRACE("ash.dwLength=%d\n", wma->ash_video.dwLength);
112 TRACE("ash.dwSuggestedBufferSize=%d\n", wma->ash_video.dwSuggestedBufferSize);
113 TRACE("ash.dwQuality=%d\n", wma->ash_video.dwQuality);
114 TRACE("ash.dwSampleSize=%d\n", wma->ash_video.dwSampleSize);
115 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma->ash_video.rcFrame.top, wma->ash_video.rcFrame.left,
116 wma->ash_video.rcFrame.bottom, wma->ash_video.rcFrame.right);
118 /* rewind to the start of the stream */
119 mmioAscend(wma->hFile, mmckStream, 0);
121 mmckInfo.ckid = ckidSTREAMFORMAT;
122 if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) {
123 WARN("Can't find 'strf' chunk\n");
124 return FALSE;
127 wma->inbih = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
128 if (!wma->inbih) {
129 WARN("Can't alloc input BIH\n");
130 return FALSE;
133 mmioRead(wma->hFile, (LPSTR)wma->inbih, mmckInfo.cksize);
135 TRACE("bih.biSize=%d\n", wma->inbih->biSize);
136 TRACE("bih.biWidth=%d\n", wma->inbih->biWidth);
137 TRACE("bih.biHeight=%d\n", wma->inbih->biHeight);
138 TRACE("bih.biPlanes=%d\n", wma->inbih->biPlanes);
139 TRACE("bih.biBitCount=%d\n", wma->inbih->biBitCount);
140 TRACE("bih.biCompression=%x\n", wma->inbih->biCompression);
141 TRACE("bih.biSizeImage=%d\n", wma->inbih->biSizeImage);
142 TRACE("bih.biXPelsPerMeter=%d\n", wma->inbih->biXPelsPerMeter);
143 TRACE("bih.biYPelsPerMeter=%d\n", wma->inbih->biYPelsPerMeter);
144 TRACE("bih.biClrUsed=%d\n", wma->inbih->biClrUsed);
145 TRACE("bih.biClrImportant=%d\n", wma->inbih->biClrImportant);
147 wma->source.left = 0;
148 wma->source.top = 0;
149 wma->source.right = wma->inbih->biWidth;
150 wma->source.bottom = wma->inbih->biHeight;
152 wma->dest = wma->source;
154 return TRUE;
157 struct AviListBuild {
158 DWORD numVideoFrames;
159 DWORD numAudioAllocated;
160 DWORD numAudioBlocks;
161 DWORD inVideoSize;
162 DWORD inAudioSize;
165 static BOOL MCIAVI_AddFrame(WINE_MCIAVI* wma, LPMMCKINFO mmck,
166 struct AviListBuild* alb)
168 const BYTE *p;
169 DWORD stream_n;
170 DWORD twocc;
172 if (mmck->ckid == ckidAVIPADDING) return TRUE;
174 p = (const BYTE *)&mmck->ckid;
176 if (!isxdigit(p[0]) || !isxdigit(p[1]))
178 WARN("wrongly encoded stream #\n");
179 return FALSE;
182 stream_n = (p[0] <= '9') ? (p[0] - '0') : (tolower(p[0]) - 'a' + 10);
183 stream_n <<= 4;
184 stream_n |= (p[1] <= '9') ? (p[1] - '0') : (tolower(p[1]) - 'a' + 10);
186 TRACE("ckid %4.4s (stream #%d)\n", (LPSTR)&mmck->ckid, stream_n);
188 /* Some (rare?) AVI files have video streams name XXYY where XX = stream number and YY = TWOCC
189 * of the last 2 characters of the biCompression member of the BITMAPINFOHEADER structure.
190 * Ex: fccHandler = IV32 & biCompression = IV32 => stream name = XX32
191 * fccHandler = MSVC & biCompression = CRAM => stream name = XXAM
192 * Another possibility is that these TWOCC are simply ignored.
193 * Default to cktypeDIBcompressed when this case happens.
195 twocc = TWOCCFromFOURCC(mmck->ckid);
196 if (twocc == TWOCCFromFOURCC(wma->inbih->biCompression))
197 twocc = cktypeDIBcompressed;
199 switch (twocc) {
200 case cktypeDIBbits:
201 case cktypeDIBcompressed:
202 case cktypePALchange:
203 if (stream_n != wma->video_stream_n)
205 TRACE("data belongs to another video stream #%d\n", stream_n);
206 return FALSE;
209 TRACE("Adding video frame[%d]: %d bytes\n",
210 alb->numVideoFrames, mmck->cksize);
212 if (alb->numVideoFrames < wma->dwPlayableVideoFrames) {
213 wma->lpVideoIndex[alb->numVideoFrames].dwOffset = mmck->dwDataOffset;
214 wma->lpVideoIndex[alb->numVideoFrames].dwSize = mmck->cksize;
215 if (alb->inVideoSize < mmck->cksize)
216 alb->inVideoSize = mmck->cksize;
217 alb->numVideoFrames++;
218 } else {
219 WARN("Too many video frames\n");
221 break;
222 case cktypeWAVEbytes:
223 if (stream_n != wma->audio_stream_n)
225 TRACE("data belongs to another audio stream #%d\n", stream_n);
226 return FALSE;
229 TRACE("Adding audio frame[%d]: %d bytes\n",
230 alb->numAudioBlocks, mmck->cksize);
231 if (wma->lpWaveFormat) {
232 if (alb->numAudioBlocks >= alb->numAudioAllocated) {
233 alb->numAudioAllocated += 32;
234 if (!wma->lpAudioIndex)
235 wma->lpAudioIndex = HeapAlloc(GetProcessHeap(), 0,
236 alb->numAudioAllocated * sizeof(struct MMIOPos));
237 else
238 wma->lpAudioIndex = HeapReAlloc(GetProcessHeap(), 0, wma->lpAudioIndex,
239 alb->numAudioAllocated * sizeof(struct MMIOPos));
240 if (!wma->lpAudioIndex) return FALSE;
242 wma->lpAudioIndex[alb->numAudioBlocks].dwOffset = mmck->dwDataOffset;
243 wma->lpAudioIndex[alb->numAudioBlocks].dwSize = mmck->cksize;
244 if (alb->inAudioSize < mmck->cksize)
245 alb->inAudioSize = mmck->cksize;
246 alb->numAudioBlocks++;
247 } else {
248 WARN("Wave chunk without wave format... discarding\n");
250 break;
251 default:
252 WARN("Unknown frame type %4.4s\n", (LPSTR)&mmck->ckid);
253 break;
255 return TRUE;
258 BOOL MCIAVI_GetInfo(WINE_MCIAVI* wma)
260 MMCKINFO ckMainRIFF;
261 MMCKINFO mmckHead;
262 MMCKINFO mmckList;
263 MMCKINFO mmckInfo;
264 struct AviListBuild alb;
265 DWORD stream_n;
267 if (mmioDescend(wma->hFile, &ckMainRIFF, NULL, 0) != 0) {
268 WARN("Can't find 'RIFF' chunk\n");
269 return FALSE;
272 if ((ckMainRIFF.ckid != FOURCC_RIFF) || (ckMainRIFF.fccType != formtypeAVI)) {
273 WARN("Can't find 'AVI ' chunk\n");
274 return FALSE;
277 mmckHead.fccType = listtypeAVIHEADER;
278 if (mmioDescend(wma->hFile, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) {
279 WARN("Can't find 'hdrl' list\n");
280 return FALSE;
283 mmckInfo.ckid = ckidAVIMAINHDR;
284 if (mmioDescend(wma->hFile, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) {
285 WARN("Can't find 'avih' chunk\n");
286 return FALSE;
289 mmioRead(wma->hFile, (LPSTR)&wma->mah, sizeof(wma->mah));
291 TRACE("mah.dwMicroSecPerFrame=%d\n", wma->mah.dwMicroSecPerFrame);
292 TRACE("mah.dwMaxBytesPerSec=%d\n", wma->mah.dwMaxBytesPerSec);
293 TRACE("mah.dwPaddingGranularity=%d\n", wma->mah.dwPaddingGranularity);
294 TRACE("mah.dwFlags=%d\n", wma->mah.dwFlags);
295 TRACE("mah.dwTotalFrames=%d\n", wma->mah.dwTotalFrames);
296 TRACE("mah.dwInitialFrames=%d\n", wma->mah.dwInitialFrames);
297 TRACE("mah.dwStreams=%d\n", wma->mah.dwStreams);
298 TRACE("mah.dwSuggestedBufferSize=%d\n", wma->mah.dwSuggestedBufferSize);
299 TRACE("mah.dwWidth=%d\n", wma->mah.dwWidth);
300 TRACE("mah.dwHeight=%d\n", wma->mah.dwHeight);
302 mmioAscend(wma->hFile, &mmckInfo, 0);
304 TRACE("Start of streams\n");
305 wma->video_stream_n = 0;
306 wma->audio_stream_n = 0;
308 for (stream_n = 0; stream_n < wma->mah.dwStreams; stream_n++)
310 MMCKINFO mmckStream;
312 mmckList.fccType = listtypeSTREAMHEADER;
313 if (mmioDescend(wma->hFile, &mmckList, &mmckHead, MMIO_FINDLIST) != 0)
314 break;
316 mmckStream.ckid = ckidSTREAMHEADER;
317 if (mmioDescend(wma->hFile, &mmckStream, &mmckList, MMIO_FINDCHUNK) != 0)
319 WARN("Can't find 'strh' chunk\n");
320 continue;
323 TRACE("Stream #%d fccType %4.4s\n", stream_n, (LPSTR)&mmckStream.fccType);
325 if (mmckStream.fccType == streamtypeVIDEO)
327 TRACE("found video stream\n");
328 if (wma->inbih)
329 WARN("ignoring another video stream\n");
330 else
332 if (!MCIAVI_GetInfoVideo(wma, &mmckList, &mmckStream))
333 return FALSE;
334 wma->video_stream_n = stream_n;
337 else if (mmckStream.fccType == streamtypeAUDIO)
339 TRACE("found audio stream\n");
340 if (wma->lpWaveFormat)
341 WARN("ignoring another audio stream\n");
342 else
344 if (!MCIAVI_GetInfoAudio(wma, &mmckList, &mmckStream))
345 return FALSE;
346 wma->audio_stream_n = stream_n;
349 else
350 TRACE("Unsupported stream type %4.4s\n", (LPSTR)&mmckStream.fccType);
352 mmioAscend(wma->hFile, &mmckList, 0);
355 TRACE("End of streams\n");
357 mmioAscend(wma->hFile, &mmckHead, 0);
359 /* no need to read optional JUNK chunk */
361 mmckList.fccType = listtypeAVIMOVIE;
362 if (mmioDescend(wma->hFile, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) {
363 WARN("Can't find 'movi' list\n");
364 return FALSE;
367 wma->dwPlayableVideoFrames = wma->mah.dwTotalFrames;
368 wma->lpVideoIndex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
369 wma->dwPlayableVideoFrames * sizeof(struct MMIOPos));
370 if (!wma->lpVideoIndex) {
371 WARN("Can't alloc video index array\n");
372 return FALSE;
374 wma->dwPlayableAudioBlocks = 0;
375 wma->lpAudioIndex = NULL;
377 alb.numAudioBlocks = alb.numVideoFrames = 0;
378 alb.inVideoSize = alb.inAudioSize = 0;
379 alb.numAudioAllocated = 0;
381 while (mmioDescend(wma->hFile, &mmckInfo, &mmckList, 0) == 0) {
382 if (mmckInfo.fccType == listtypeAVIRECORD) {
383 MMCKINFO tmp;
385 while (mmioDescend(wma->hFile, &tmp, &mmckInfo, 0) == 0) {
386 MCIAVI_AddFrame(wma, &tmp, &alb);
387 mmioAscend(wma->hFile, &tmp, 0);
389 } else {
390 MCIAVI_AddFrame(wma, &mmckInfo, &alb);
393 mmioAscend(wma->hFile, &mmckInfo, 0);
395 if (alb.numVideoFrames != wma->dwPlayableVideoFrames) {
396 WARN("Found %d video frames (/%d), reducing playable frames\n",
397 alb.numVideoFrames, wma->dwPlayableVideoFrames);
398 wma->dwPlayableVideoFrames = alb.numVideoFrames;
400 wma->dwPlayableAudioBlocks = alb.numAudioBlocks;
402 if (alb.inVideoSize > wma->ash_video.dwSuggestedBufferSize) {
403 WARN("inVideoSize=%d suggestedSize=%d\n", alb.inVideoSize, wma->ash_video.dwSuggestedBufferSize);
404 wma->ash_video.dwSuggestedBufferSize = alb.inVideoSize;
406 if (alb.inAudioSize > wma->ash_audio.dwSuggestedBufferSize) {
407 WARN("inAudioSize=%d suggestedSize=%d\n", alb.inAudioSize, wma->ash_audio.dwSuggestedBufferSize);
408 wma->ash_audio.dwSuggestedBufferSize = alb.inAudioSize;
411 wma->indata = HeapAlloc(GetProcessHeap(), 0, wma->ash_video.dwSuggestedBufferSize);
412 if (!wma->indata) {
413 WARN("Can't alloc input buffer\n");
414 return FALSE;
417 return TRUE;
420 BOOL MCIAVI_OpenVideo(WINE_MCIAVI* wma)
422 HDC hDC;
423 DWORD outSize;
424 FOURCC fcc = wma->ash_video.fccHandler;
426 TRACE("fcc %4.4s\n", (LPSTR)&fcc);
428 wma->dwCachedFrame = -1;
430 /* get the right handle */
431 if (fcc == mmioFOURCC('C','R','A','M')) fcc = mmioFOURCC('M','S','V','C');
433 /* try to get a decompressor for that type */
434 wma->hic = ICLocate(ICTYPE_VIDEO, fcc, wma->inbih, NULL, ICMODE_DECOMPRESS);
435 if (!wma->hic) {
436 /* check for builtin DIB compressions */
437 fcc = wma->inbih->biCompression;
438 if ((fcc == mmioFOURCC('D','I','B',' ')) ||
439 (fcc == mmioFOURCC('R','L','E',' ')) ||
440 (fcc == BI_RGB) || (fcc == BI_RLE8) ||
441 (fcc == BI_RLE4) || (fcc == BI_BITFIELDS))
442 goto paint_frame;
444 WARN("Can't locate codec for the file\n");
445 return FALSE;
448 outSize = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
450 wma->outbih = HeapAlloc(GetProcessHeap(), 0, outSize);
451 if (!wma->outbih) {
452 WARN("Can't alloc output BIH\n");
453 return FALSE;
455 if (!ICGetDisplayFormat(wma->hic, wma->inbih, wma->outbih, 0, 0, 0)) {
456 WARN("Can't open decompressor\n");
457 return FALSE;
460 TRACE("bih.biSize=%d\n", wma->outbih->biSize);
461 TRACE("bih.biWidth=%d\n", wma->outbih->biWidth);
462 TRACE("bih.biHeight=%d\n", wma->outbih->biHeight);
463 TRACE("bih.biPlanes=%d\n", wma->outbih->biPlanes);
464 TRACE("bih.biBitCount=%d\n", wma->outbih->biBitCount);
465 TRACE("bih.biCompression=%x\n", wma->outbih->biCompression);
466 TRACE("bih.biSizeImage=%d\n", wma->outbih->biSizeImage);
467 TRACE("bih.biXPelsPerMeter=%d\n", wma->outbih->biXPelsPerMeter);
468 TRACE("bih.biYPelsPerMeter=%d\n", wma->outbih->biYPelsPerMeter);
469 TRACE("bih.biClrUsed=%d\n", wma->outbih->biClrUsed);
470 TRACE("bih.biClrImportant=%d\n", wma->outbih->biClrImportant);
472 wma->outdata = HeapAlloc(GetProcessHeap(), 0, wma->outbih->biSizeImage);
473 if (!wma->outdata) {
474 WARN("Can't alloc output buffer\n");
475 return FALSE;
478 if (ICSendMessage(wma->hic, ICM_DECOMPRESS_BEGIN,
479 (DWORD)wma->inbih, (DWORD)wma->outbih) != ICERR_OK) {
480 WARN("Can't begin decompression\n");
481 return FALSE;
484 paint_frame:
485 hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
486 if (hDC)
488 MCIAVI_PaintFrame(wma, hDC);
489 ReleaseDC(wma->hWndPaint, hDC);
491 return TRUE;
494 static void CALLBACK MCIAVI_waveCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
495 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
497 WINE_MCIAVI *wma = (WINE_MCIAVI *)MCIAVI_mciGetOpenDev(dwInstance);
499 if (!wma) return;
501 EnterCriticalSection(&wma->cs);
503 switch (uMsg) {
504 case WOM_OPEN:
505 case WOM_CLOSE:
506 break;
507 case WOM_DONE:
508 InterlockedIncrement(&wma->dwEventCount);
509 TRACE("Returning waveHdr=%lx\n", dwParam1);
510 SetEvent(wma->hEvent);
511 break;
512 default:
513 ERR("Unknown uMsg=%d\n", uMsg);
516 LeaveCriticalSection(&wma->cs);
519 DWORD MCIAVI_OpenAudio(WINE_MCIAVI* wma, unsigned* nHdr, LPWAVEHDR* pWaveHdr)
521 DWORD dwRet;
522 LPWAVEHDR waveHdr;
523 unsigned i;
525 dwRet = waveOutOpen((HWAVEOUT *)&wma->hWave, WAVE_MAPPER, wma->lpWaveFormat,
526 (DWORD_PTR)MCIAVI_waveCallback, wma->wDevID, CALLBACK_FUNCTION);
527 if (dwRet != 0) {
528 TRACE("Can't open low level audio device %d\n", dwRet);
529 dwRet = MCIERR_DEVICE_OPEN;
530 wma->hWave = 0;
531 goto cleanUp;
534 /* FIXME: should set up a heuristic to compute the number of wave headers
535 * to be used...
537 *nHdr = 7;
538 waveHdr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
539 *nHdr * (sizeof(WAVEHDR) + wma->ash_audio.dwSuggestedBufferSize));
540 if (!waveHdr) {
541 TRACE("Can't alloc wave headers\n");
542 dwRet = MCIERR_DEVICE_OPEN;
543 goto cleanUp;
546 for (i = 0; i < *nHdr; i++) {
547 /* other fields are zero:ed on allocation */
548 waveHdr[i].lpData = (char*)waveHdr +
549 *nHdr * sizeof(WAVEHDR) + i * wma->ash_audio.dwSuggestedBufferSize;
550 waveHdr[i].dwBufferLength = wma->ash_audio.dwSuggestedBufferSize;
551 if (waveOutPrepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR))) {
552 dwRet = MCIERR_INTERNAL;
553 goto cleanUp;
557 if (wma->dwCurrVideoFrame != 0 && wma->lpWaveFormat) {
558 FIXME("Should recompute dwCurrAudioBlock, except unsynchronized sound & video\n");
560 wma->dwCurrAudioBlock = 0;
562 wma->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
563 wma->dwEventCount = *nHdr - 1;
564 *pWaveHdr = waveHdr;
565 cleanUp:
566 return dwRet;
569 void MCIAVI_PlayAudioBlocks(WINE_MCIAVI* wma, unsigned nHdr, LPWAVEHDR waveHdr)
571 if (!wma->lpAudioIndex)
572 return;
573 TRACE("%d (ec=%u)\n", wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset, wma->dwEventCount);
575 /* push as many blocks as possible => audio gets priority */
576 while (wma->dwStatus != MCI_MODE_STOP && wma->dwStatus != MCI_MODE_NOT_READY &&
577 wma->dwCurrAudioBlock < wma->dwPlayableAudioBlocks) {
578 unsigned whidx = wma->dwCurrAudioBlock % nHdr;
580 ResetEvent(wma->hEvent);
581 if (InterlockedDecrement(&wma->dwEventCount) < 0 ||
582 !wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset)
584 InterlockedIncrement(&wma->dwEventCount);
585 break;
588 mmioSeek(wma->hFile, wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset, SEEK_SET);
589 mmioRead(wma->hFile, waveHdr[whidx].lpData, wma->lpAudioIndex[wma->dwCurrAudioBlock].dwSize);
591 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
592 waveHdr[whidx].dwBufferLength = wma->lpAudioIndex[wma->dwCurrAudioBlock].dwSize;
593 waveOutWrite(wma->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
594 wma->dwCurrAudioBlock++;
598 LRESULT MCIAVI_PaintFrame(WINE_MCIAVI* wma, HDC hDC)
600 void* pBitmapData;
601 LPBITMAPINFO pBitmapInfo;
602 int nWidth;
603 int nHeight;
605 if (!hDC || !wma->inbih)
606 return TRUE;
608 TRACE("Painting frame %u (cached %u)\n", wma->dwCurrVideoFrame, wma->dwCachedFrame);
610 if (wma->dwCurrVideoFrame != wma->dwCachedFrame)
612 if (!wma->lpVideoIndex[wma->dwCurrVideoFrame].dwOffset)
613 return FALSE;
615 if (wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize)
617 mmioSeek(wma->hFile, wma->lpVideoIndex[wma->dwCurrVideoFrame].dwOffset, SEEK_SET);
618 mmioRead(wma->hFile, wma->indata, wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize);
620 wma->inbih->biSizeImage = wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize;
622 if (wma->hic && ICDecompress(wma->hic, 0, wma->inbih, wma->indata,
623 wma->outbih, wma->outdata) != ICERR_OK)
625 WARN("Decompression error\n");
626 return FALSE;
630 wma->dwCachedFrame = wma->dwCurrVideoFrame;
633 if (wma->hic) {
634 pBitmapData = wma->outdata;
635 pBitmapInfo = (LPBITMAPINFO)wma->outbih;
637 nWidth = wma->outbih->biWidth;
638 nHeight = wma->outbih->biHeight;
639 } else {
640 pBitmapData = wma->indata;
641 pBitmapInfo = (LPBITMAPINFO)wma->inbih;
643 nWidth = wma->inbih->biWidth;
644 nHeight = wma->inbih->biHeight;
647 StretchDIBits(hDC,
648 wma->dest.left, wma->dest.top,
649 wma->dest.right - wma->dest.left, wma->dest.bottom - wma->dest.top,
650 wma->source.left, wma->source.top,
651 wma->source.right - wma->source.left, wma->source.bottom - wma->source.top,
652 pBitmapData, pBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
654 return TRUE;