dmsynth: Correctly handle internal connections with controls.
[wine.git] / dlls / mciavi32 / mmoutput.c
blobdd8f96e131403a571799dcc16186e4dc8c075cc0
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 TRACE("ash.fccType=%s\n", debugstr_fourcc(wma->ash_audio.fccType));
32 if (wma->ash_audio.fccHandler) /* not all streams specify a handler */
33 TRACE("ash.fccHandler=%s\n", debugstr_fourcc(wma->ash_audio.fccHandler));
34 else
35 TRACE("ash.fccHandler=0, no handler specified\n");
36 TRACE("ash.dwFlags=%ld\n", wma->ash_audio.dwFlags);
37 TRACE("ash.wPriority=%d\n", wma->ash_audio.wPriority);
38 TRACE("ash.wLanguage=%d\n", wma->ash_audio.wLanguage);
39 TRACE("ash.dwInitialFrames=%ld\n", wma->ash_audio.dwInitialFrames);
40 TRACE("ash.dwScale=%ld\n", wma->ash_audio.dwScale);
41 TRACE("ash.dwRate=%ld\n", wma->ash_audio.dwRate);
42 TRACE("ash.dwStart=%ld\n", wma->ash_audio.dwStart);
43 TRACE("ash.dwLength=%ld\n", wma->ash_audio.dwLength);
44 TRACE("ash.dwSuggestedBufferSize=%ld\n", wma->ash_audio.dwSuggestedBufferSize);
45 TRACE("ash.dwQuality=%ld\n", wma->ash_audio.dwQuality);
46 TRACE("ash.dwSampleSize=%ld\n", wma->ash_audio.dwSampleSize);
47 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma->ash_audio.rcFrame.top, wma->ash_audio.rcFrame.left,
48 wma->ash_audio.rcFrame.bottom, wma->ash_audio.rcFrame.right);
50 /* rewind to the start of the stream */
51 mmioAscend(wma->hFile, mmckStream, 0);
53 mmckInfo.ckid = ckidSTREAMFORMAT;
54 if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) {
55 WARN("Can't find 'strf' chunk\n");
56 return FALSE;
58 if (mmckInfo.cksize < sizeof(WAVEFORMAT)) {
59 WARN("Size of strf chunk (%ld) < audio format struct\n", mmckInfo.cksize);
60 return FALSE;
62 wma->lpWaveFormat = malloc(mmckInfo.cksize);
63 if (!wma->lpWaveFormat) {
64 WARN("Can't alloc WaveFormat\n");
65 return FALSE;
68 mmioRead(wma->hFile, (LPSTR)wma->lpWaveFormat, mmckInfo.cksize);
70 TRACE("waveFormat.wFormatTag=%d\n", wma->lpWaveFormat->wFormatTag);
71 TRACE("waveFormat.nChannels=%d\n", wma->lpWaveFormat->nChannels);
72 TRACE("waveFormat.nSamplesPerSec=%ld\n", wma->lpWaveFormat->nSamplesPerSec);
73 TRACE("waveFormat.nAvgBytesPerSec=%ld\n", wma->lpWaveFormat->nAvgBytesPerSec);
74 TRACE("waveFormat.nBlockAlign=%d\n", wma->lpWaveFormat->nBlockAlign);
75 TRACE("waveFormat.wBitsPerSample=%d\n", wma->lpWaveFormat->wBitsPerSample);
76 if (mmckInfo.cksize >= sizeof(WAVEFORMATEX))
77 TRACE("waveFormat.cbSize=%d\n", wma->lpWaveFormat->cbSize);
79 return TRUE;
82 static BOOL MCIAVI_GetInfoVideo(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCKINFO* mmckStream)
84 MMCKINFO mmckInfo;
86 TRACE("ash.fccType=%s\n", debugstr_fourcc(wma->ash_video.fccType));
87 TRACE("ash.fccHandler=%s\n", debugstr_fourcc(wma->ash_video.fccHandler));
88 TRACE("ash.dwFlags=%ld\n", wma->ash_video.dwFlags);
89 TRACE("ash.wPriority=%d\n", wma->ash_video.wPriority);
90 TRACE("ash.wLanguage=%d\n", wma->ash_video.wLanguage);
91 TRACE("ash.dwInitialFrames=%ld\n", wma->ash_video.dwInitialFrames);
92 TRACE("ash.dwScale=%ld\n", wma->ash_video.dwScale);
93 TRACE("ash.dwRate=%ld\n", wma->ash_video.dwRate);
94 TRACE("ash.dwStart=%ld\n", wma->ash_video.dwStart);
95 TRACE("ash.dwLength=%ld\n", wma->ash_video.dwLength);
96 TRACE("ash.dwSuggestedBufferSize=%ld\n", wma->ash_video.dwSuggestedBufferSize);
97 TRACE("ash.dwQuality=%ld\n", wma->ash_video.dwQuality);
98 TRACE("ash.dwSampleSize=%ld\n", wma->ash_video.dwSampleSize);
99 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma->ash_video.rcFrame.top, wma->ash_video.rcFrame.left,
100 wma->ash_video.rcFrame.bottom, wma->ash_video.rcFrame.right);
102 /* rewind to the start of the stream */
103 mmioAscend(wma->hFile, mmckStream, 0);
105 mmckInfo.ckid = ckidSTREAMFORMAT;
106 if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) {
107 WARN("Can't find 'strf' chunk\n");
108 return FALSE;
111 wma->inbih = malloc(mmckInfo.cksize);
112 if (!wma->inbih) {
113 WARN("Can't alloc input BIH\n");
114 return FALSE;
117 mmioRead(wma->hFile, (LPSTR)wma->inbih, mmckInfo.cksize);
119 TRACE("bih.biSize=%ld\n", wma->inbih->biSize);
120 TRACE("bih.biWidth=%ld\n", wma->inbih->biWidth);
121 TRACE("bih.biHeight=%ld\n", wma->inbih->biHeight);
122 TRACE("bih.biPlanes=%d\n", wma->inbih->biPlanes);
123 TRACE("bih.biBitCount=%d\n", wma->inbih->biBitCount);
124 TRACE("bih.biCompression=%lx\n", wma->inbih->biCompression);
125 TRACE("bih.biSizeImage=%ld\n", wma->inbih->biSizeImage);
126 TRACE("bih.biXPelsPerMeter=%ld\n", wma->inbih->biXPelsPerMeter);
127 TRACE("bih.biYPelsPerMeter=%ld\n", wma->inbih->biYPelsPerMeter);
128 TRACE("bih.biClrUsed=%ld\n", wma->inbih->biClrUsed);
129 TRACE("bih.biClrImportant=%ld\n", wma->inbih->biClrImportant);
131 SetRect(&wma->source, 0, 0, wma->inbih->biWidth, wma->inbih->biHeight);
132 wma->dest = wma->source;
134 return TRUE;
137 struct AviListBuild {
138 DWORD numVideoFrames;
139 DWORD numAudioAllocated;
140 DWORD numAudioBlocks;
141 DWORD inVideoSize;
142 DWORD inAudioSize;
145 static BOOL MCIAVI_AddFrame(WINE_MCIAVI* wma, LPMMCKINFO mmck,
146 struct AviListBuild* alb)
148 const BYTE *p;
149 DWORD stream_n;
150 DWORD twocc;
152 if (mmck->ckid == ckidAVIPADDING) return TRUE;
154 p = (const BYTE *)&mmck->ckid;
156 if (!isxdigit(p[0]) || !isxdigit(p[1]))
158 WARN("wrongly encoded stream #\n");
159 return FALSE;
162 stream_n = (p[0] <= '9') ? (p[0] - '0') : (tolower(p[0]) - 'a' + 10);
163 stream_n <<= 4;
164 stream_n |= (p[1] <= '9') ? (p[1] - '0') : (tolower(p[1]) - 'a' + 10);
166 TRACE("ckid %4.4s (stream #%ld)\n", (LPSTR)&mmck->ckid, stream_n);
168 /* Some (rare?) AVI files have video streams name XXYY where XX = stream number and YY = TWOCC
169 * of the last 2 characters of the biCompression member of the BITMAPINFOHEADER structure.
170 * Ex: fccHandler = IV32 & biCompression = IV32 => stream name = XX32
171 * fccHandler = MSVC & biCompression = CRAM => stream name = XXAM
172 * Another possibility is that these TWOCC are simply ignored.
173 * Default to cktypeDIBcompressed when this case happens.
175 twocc = TWOCCFromFOURCC(mmck->ckid);
176 if (twocc == TWOCCFromFOURCC(wma->inbih->biCompression))
177 twocc = cktypeDIBcompressed;
178 /* Also detect some chunks that seem to be used by Indeo videos where the chunk is named
179 * after the codec. */
180 else if (twocc == LOWORD(wma->ash_video.fccHandler))
181 twocc = cktypeDIBcompressed;
182 switch (twocc) {
183 case cktypeDIBbits:
184 case cktypeDIBcompressed:
185 case cktypePALchange:
186 if (stream_n != wma->video_stream_n)
188 TRACE("data belongs to another video stream #%ld\n", stream_n);
189 return FALSE;
192 TRACE("Adding video frame[%ld]: %ld bytes\n",
193 alb->numVideoFrames, mmck->cksize);
195 if (alb->numVideoFrames < wma->dwPlayableVideoFrames) {
196 wma->lpVideoIndex[alb->numVideoFrames].dwOffset = mmck->dwDataOffset;
197 wma->lpVideoIndex[alb->numVideoFrames].dwSize = mmck->cksize;
198 if (alb->inVideoSize < mmck->cksize)
199 alb->inVideoSize = mmck->cksize;
200 alb->numVideoFrames++;
201 } else {
202 WARN("Too many video frames\n");
204 break;
205 case cktypeWAVEbytes:
206 if (stream_n != wma->audio_stream_n)
208 TRACE("data belongs to another audio stream #%ld\n", stream_n);
209 return FALSE;
212 TRACE("Adding audio frame[%ld]: %ld bytes\n",
213 alb->numAudioBlocks, mmck->cksize);
214 if (wma->lpWaveFormat) {
215 if (alb->numAudioBlocks >= alb->numAudioAllocated) {
216 DWORD newsize = alb->numAudioAllocated + 32;
217 struct MMIOPos* newindex;
219 newindex = realloc(wma->lpAudioIndex, newsize * sizeof(struct MMIOPos));
220 if (!newindex) return FALSE;
221 alb->numAudioAllocated = newsize;
222 wma->lpAudioIndex = newindex;
224 wma->lpAudioIndex[alb->numAudioBlocks].dwOffset = mmck->dwDataOffset;
225 wma->lpAudioIndex[alb->numAudioBlocks].dwSize = mmck->cksize;
226 if (alb->inAudioSize < mmck->cksize)
227 alb->inAudioSize = mmck->cksize;
228 alb->numAudioBlocks++;
229 } else {
230 WARN("Wave chunk without wave format... discarding\n");
232 break;
233 default:
234 WARN("Unknown frame type %4.4s\n", (LPSTR)&mmck->ckid);
235 break;
237 return TRUE;
240 BOOL MCIAVI_GetInfo(WINE_MCIAVI* wma)
242 MMCKINFO ckMainRIFF;
243 MMCKINFO mmckHead;
244 MMCKINFO mmckList;
245 MMCKINFO mmckInfo;
246 AVIStreamHeader strh;
247 struct AviListBuild alb;
248 DWORD stream_n;
250 if (mmioDescend(wma->hFile, &ckMainRIFF, NULL, 0) != 0) {
251 WARN("Can't find 'RIFF' chunk\n");
252 return FALSE;
255 if ((ckMainRIFF.ckid != FOURCC_RIFF) || (ckMainRIFF.fccType != formtypeAVI)) {
256 WARN("Can't find 'AVI ' chunk\n");
257 return FALSE;
260 mmckHead.fccType = listtypeAVIHEADER;
261 if (mmioDescend(wma->hFile, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) {
262 WARN("Can't find 'hdrl' list\n");
263 return FALSE;
266 mmckInfo.ckid = ckidAVIMAINHDR;
267 if (mmioDescend(wma->hFile, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) {
268 WARN("Can't find 'avih' chunk\n");
269 return FALSE;
272 mmioRead(wma->hFile, (LPSTR)&wma->mah, sizeof(wma->mah));
274 TRACE("mah.dwMicroSecPerFrame=%ld\n", wma->mah.dwMicroSecPerFrame);
275 TRACE("mah.dwMaxBytesPerSec=%ld\n", wma->mah.dwMaxBytesPerSec);
276 TRACE("mah.dwPaddingGranularity=%ld\n", wma->mah.dwPaddingGranularity);
277 TRACE("mah.dwFlags=%ld\n", wma->mah.dwFlags);
278 TRACE("mah.dwTotalFrames=%ld\n", wma->mah.dwTotalFrames);
279 TRACE("mah.dwInitialFrames=%ld\n", wma->mah.dwInitialFrames);
280 TRACE("mah.dwStreams=%ld\n", wma->mah.dwStreams);
281 TRACE("mah.dwSuggestedBufferSize=%ld\n", wma->mah.dwSuggestedBufferSize);
282 TRACE("mah.dwWidth=%ld\n", wma->mah.dwWidth);
283 TRACE("mah.dwHeight=%ld\n", wma->mah.dwHeight);
285 mmioAscend(wma->hFile, &mmckInfo, 0);
287 TRACE("Start of streams\n");
288 wma->video_stream_n = 0;
289 wma->audio_stream_n = 0;
291 for (stream_n = 0; stream_n < wma->mah.dwStreams; stream_n++)
293 MMCKINFO mmckStream;
295 mmckList.fccType = listtypeSTREAMHEADER;
296 if (mmioDescend(wma->hFile, &mmckList, &mmckHead, MMIO_FINDLIST) != 0)
297 break;
299 mmckStream.ckid = ckidSTREAMHEADER;
300 if (mmioDescend(wma->hFile, &mmckStream, &mmckList, MMIO_FINDCHUNK) != 0)
302 WARN("Can't find 'strh' chunk\n");
303 continue;
306 mmioRead(wma->hFile, (LPSTR)&strh, sizeof(strh));
308 TRACE("Stream #%ld fccType %4.4s\n", stream_n, (LPSTR)&strh.fccType);
310 if (strh.fccType == streamtypeVIDEO)
312 TRACE("found video stream\n");
313 if (wma->inbih)
314 WARN("ignoring another video stream\n");
315 else
317 wma->ash_video = strh;
319 if (!MCIAVI_GetInfoVideo(wma, &mmckList, &mmckStream))
320 return FALSE;
321 wma->video_stream_n = stream_n;
322 wma->dwSet |= 4;
325 else if (strh.fccType == streamtypeAUDIO)
327 TRACE("found audio stream\n");
328 if (wma->lpWaveFormat)
329 WARN("ignoring another audio stream\n");
330 else
332 wma->ash_audio = strh;
334 if (!MCIAVI_GetInfoAudio(wma, &mmckList, &mmckStream))
335 return FALSE;
336 wma->audio_stream_n = stream_n;
337 wma->dwSet |= 3;
340 else
341 TRACE("Unsupported stream type %4.4s\n", (LPSTR)&strh.fccType);
343 mmioAscend(wma->hFile, &mmckList, 0);
346 TRACE("End of streams\n");
348 mmioAscend(wma->hFile, &mmckHead, 0);
350 /* no need to read optional JUNK chunk */
352 mmckList.fccType = listtypeAVIMOVIE;
353 if (mmioDescend(wma->hFile, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) {
354 WARN("Can't find 'movi' list\n");
355 return FALSE;
358 wma->dwPlayableVideoFrames = wma->mah.dwTotalFrames;
359 wma->lpVideoIndex = calloc(wma->dwPlayableVideoFrames, sizeof(struct MMIOPos));
360 if (!wma->lpVideoIndex) {
361 WARN("Can't alloc video index array\n");
362 return FALSE;
364 wma->dwPlayableAudioBlocks = 0;
365 wma->lpAudioIndex = NULL;
367 alb.numAudioBlocks = alb.numVideoFrames = 0;
368 alb.inVideoSize = alb.inAudioSize = 0;
369 alb.numAudioAllocated = 0;
371 while (mmioDescend(wma->hFile, &mmckInfo, &mmckList, 0) == 0) {
372 if (mmckInfo.fccType == listtypeAVIRECORD) {
373 MMCKINFO tmp;
375 while (mmioDescend(wma->hFile, &tmp, &mmckInfo, 0) == 0) {
376 MCIAVI_AddFrame(wma, &tmp, &alb);
377 mmioAscend(wma->hFile, &tmp, 0);
379 } else {
380 MCIAVI_AddFrame(wma, &mmckInfo, &alb);
383 mmioAscend(wma->hFile, &mmckInfo, 0);
385 if (alb.numVideoFrames != wma->dwPlayableVideoFrames) {
386 WARN("AVI header says %ld frames, we found %ld video frames, reducing playable frames\n",
387 wma->dwPlayableVideoFrames, alb.numVideoFrames);
388 wma->dwPlayableVideoFrames = alb.numVideoFrames;
390 wma->dwPlayableAudioBlocks = alb.numAudioBlocks;
392 if (alb.inVideoSize > wma->ash_video.dwSuggestedBufferSize) {
393 WARN("inVideoSize=%ld suggestedSize=%ld\n", alb.inVideoSize, wma->ash_video.dwSuggestedBufferSize);
394 wma->ash_video.dwSuggestedBufferSize = alb.inVideoSize;
396 if (alb.inAudioSize > wma->ash_audio.dwSuggestedBufferSize) {
397 WARN("inAudioSize=%ld suggestedSize=%ld\n", alb.inAudioSize, wma->ash_audio.dwSuggestedBufferSize);
398 wma->ash_audio.dwSuggestedBufferSize = alb.inAudioSize;
401 wma->indata = malloc(wma->ash_video.dwSuggestedBufferSize);
402 if (!wma->indata) {
403 WARN("Can't alloc input buffer\n");
404 return FALSE;
407 return TRUE;
410 BOOL MCIAVI_OpenVideo(WINE_MCIAVI* wma)
412 HDC hDC;
413 DWORD outSize;
414 FOURCC fcc = wma->ash_video.fccHandler;
416 TRACE("fcc %4.4s\n", (LPSTR)&fcc);
418 wma->dwCachedFrame = -1;
420 /* get the right handle */
421 if (fcc == mmioFOURCC('C','R','A','M')) fcc = mmioFOURCC('M','S','V','C');
423 /* try to get a decompressor for that type */
424 wma->hic = ICLocate(ICTYPE_VIDEO, fcc, wma->inbih, NULL, ICMODE_DECOMPRESS);
425 if (!wma->hic) {
426 /* check for builtin DIB compressions */
427 fcc = wma->inbih->biCompression;
428 if ((fcc == mmioFOURCC('D','I','B',' ')) ||
429 (fcc == mmioFOURCC('R','L','E',' ')) ||
430 (fcc == BI_RGB) || (fcc == BI_RLE8) ||
431 (fcc == BI_RLE4) || (fcc == BI_BITFIELDS))
432 goto paint_frame;
434 WARN("Can't locate codec for the file\n");
435 return FALSE;
438 outSize = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
440 wma->outbih = malloc(outSize);
441 if (!wma->outbih) {
442 WARN("Can't alloc output BIH\n");
443 return FALSE;
445 if (!ICGetDisplayFormat(wma->hic, wma->inbih, wma->outbih, 0, 0, 0)) {
446 WARN("Can't open decompressor\n");
447 return FALSE;
450 TRACE("bih.biSize=%ld\n", wma->outbih->biSize);
451 TRACE("bih.biWidth=%ld\n", wma->outbih->biWidth);
452 TRACE("bih.biHeight=%ld\n", wma->outbih->biHeight);
453 TRACE("bih.biPlanes=%d\n", wma->outbih->biPlanes);
454 TRACE("bih.biBitCount=%d\n", wma->outbih->biBitCount);
455 TRACE("bih.biCompression=%lx\n", wma->outbih->biCompression);
456 TRACE("bih.biSizeImage=%ld\n", wma->outbih->biSizeImage);
457 TRACE("bih.biXPelsPerMeter=%ld\n", wma->outbih->biXPelsPerMeter);
458 TRACE("bih.biYPelsPerMeter=%ld\n", wma->outbih->biYPelsPerMeter);
459 TRACE("bih.biClrUsed=%ld\n", wma->outbih->biClrUsed);
460 TRACE("bih.biClrImportant=%ld\n", wma->outbih->biClrImportant);
462 wma->outdata = malloc(wma->outbih->biSizeImage);
463 if (!wma->outdata) {
464 WARN("Can't alloc output buffer\n");
465 return FALSE;
468 if (ICSendMessage(wma->hic, ICM_DECOMPRESS_BEGIN,
469 (DWORD_PTR)wma->inbih, (DWORD_PTR)wma->outbih) != ICERR_OK) {
470 WARN("Can't begin decompression\n");
471 return FALSE;
474 paint_frame:
475 hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
476 if (hDC)
478 MCIAVI_PaintFrame(wma, hDC);
479 ReleaseDC(wma->hWndPaint, hDC);
481 return TRUE;
484 static void CALLBACK MCIAVI_waveCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
485 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
487 WINE_MCIAVI *wma = MCIAVI_mciGetOpenDev(dwInstance);
489 if (!wma) return;
491 EnterCriticalSection(&wma->cs);
493 switch (uMsg) {
494 case WOM_OPEN:
495 case WOM_CLOSE:
496 break;
497 case WOM_DONE:
498 InterlockedIncrement(&wma->dwEventCount);
499 TRACE("Returning waveHdr=%Ix\n", dwParam1);
500 SetEvent(wma->hEvent);
501 break;
502 default:
503 ERR("Unknown uMsg=%d\n", uMsg);
506 LeaveCriticalSection(&wma->cs);
509 DWORD MCIAVI_OpenAudio(WINE_MCIAVI* wma, unsigned* nHdr, LPWAVEHDR* pWaveHdr)
511 DWORD dwRet;
512 LPWAVEHDR waveHdr;
513 unsigned i;
515 dwRet = waveOutOpen((HWAVEOUT *)&wma->hWave, WAVE_MAPPER, wma->lpWaveFormat,
516 (DWORD_PTR)MCIAVI_waveCallback, wma->wDevID, CALLBACK_FUNCTION);
517 if (dwRet != 0) {
518 TRACE("Can't open low level audio device %ld\n", dwRet);
519 dwRet = MCIERR_DEVICE_OPEN;
520 wma->hWave = 0;
521 goto cleanUp;
524 /* FIXME: should set up a heuristic to compute the number of wave headers
525 * to be used...
527 *nHdr = 7;
528 waveHdr = calloc(*nHdr, sizeof(WAVEHDR) + wma->ash_audio.dwSuggestedBufferSize);
529 if (!waveHdr) {
530 TRACE("Can't alloc wave headers\n");
531 dwRet = MCIERR_DEVICE_OPEN;
532 goto cleanUp;
535 for (i = 0; i < *nHdr; i++) {
536 /* other fields are zero:ed on allocation */
537 waveHdr[i].lpData = (char*)waveHdr +
538 *nHdr * sizeof(WAVEHDR) + i * wma->ash_audio.dwSuggestedBufferSize;
539 waveHdr[i].dwBufferLength = wma->ash_audio.dwSuggestedBufferSize;
540 if (waveOutPrepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR))) {
541 dwRet = MCIERR_INTERNAL;
542 goto cleanUp;
546 if (wma->dwCurrVideoFrame != 0 && wma->lpWaveFormat) {
547 FIXME("Should recompute dwCurrAudioBlock, except unsynchronized sound & video\n");
549 wma->dwCurrAudioBlock = 0;
551 wma->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
552 wma->dwEventCount = *nHdr - 1;
553 *pWaveHdr = waveHdr;
554 cleanUp:
555 return dwRet;
558 void MCIAVI_PlayAudioBlocks(WINE_MCIAVI* wma, unsigned nHdr, LPWAVEHDR waveHdr)
560 if (!wma->lpAudioIndex)
561 return;
562 TRACE("%ld (ec=%lu)\n", wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset, wma->dwEventCount);
564 /* push as many blocks as possible => audio gets priority */
565 while (wma->dwStatus != MCI_MODE_STOP && wma->dwStatus != MCI_MODE_NOT_READY &&
566 wma->dwCurrAudioBlock < wma->dwPlayableAudioBlocks) {
567 unsigned whidx = wma->dwCurrAudioBlock % nHdr;
569 ResetEvent(wma->hEvent);
570 if (InterlockedDecrement(&wma->dwEventCount) < 0 ||
571 !wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset)
573 InterlockedIncrement(&wma->dwEventCount);
574 break;
577 mmioSeek(wma->hFile, wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset, SEEK_SET);
578 mmioRead(wma->hFile, waveHdr[whidx].lpData, wma->lpAudioIndex[wma->dwCurrAudioBlock].dwSize);
580 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
581 waveHdr[whidx].dwBufferLength = wma->lpAudioIndex[wma->dwCurrAudioBlock].dwSize;
582 waveOutWrite(wma->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
583 wma->dwCurrAudioBlock++;
587 double MCIAVI_PaintFrame(WINE_MCIAVI* wma, HDC hDC)
589 void* pBitmapData;
590 LPBITMAPINFO pBitmapInfo;
592 if (!hDC || !wma->inbih)
593 return 0;
595 TRACE("Painting frame %lu (cached %lu)\n", wma->dwCurrVideoFrame, wma->dwCachedFrame);
597 if (wma->dwCurrVideoFrame != wma->dwCachedFrame)
599 if (!wma->lpVideoIndex[wma->dwCurrVideoFrame].dwOffset)
600 return 0;
602 if (wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize)
604 mmioSeek(wma->hFile, wma->lpVideoIndex[wma->dwCurrVideoFrame].dwOffset, SEEK_SET);
605 mmioRead(wma->hFile, wma->indata, wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize);
607 wma->inbih->biSizeImage = wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize;
609 if (wma->hic && ICDecompress(wma->hic, 0, wma->inbih, wma->indata,
610 wma->outbih, wma->outdata) != ICERR_OK)
612 WARN("Decompression error\n");
613 return 0;
617 wma->dwCachedFrame = wma->dwCurrVideoFrame;
620 if (wma->hic) {
621 pBitmapData = wma->outdata;
622 pBitmapInfo = (LPBITMAPINFO)wma->outbih;
623 } else {
624 pBitmapData = wma->indata;
625 pBitmapInfo = (LPBITMAPINFO)wma->inbih;
628 StretchDIBits(hDC,
629 wma->dest.left, wma->dest.top,
630 wma->dest.right - wma->dest.left, wma->dest.bottom - wma->dest.top,
631 wma->source.left, wma->source.top,
632 wma->source.right - wma->source.left, wma->source.bottom - wma->source.top,
633 pBitmapData, pBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
635 return (wma->ash_video.dwScale / (double)wma->ash_video.dwRate) * 1000000;