Implement A->W call for GetNamedSecurityInfo.
[wine] / dlls / winmm / mciavi / mmoutput.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * Digital video MCI Wine Driver
5  *
6  * Copyright 1999, 2000 Eric POUECH
7  * Copyright 2003 Dmitry Timoshkov
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "private_mciavi.h"
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
28
29 static BOOL MCIAVI_GetInfoAudio(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCKINFO *mmckStream)
30 {
31     MMCKINFO    mmckInfo;
32
33     mmioRead(wma->hFile, (LPSTR)&wma->ash_audio, sizeof(wma->ash_audio));
34
35     TRACE("ash.fccType='%c%c%c%c'\n",           LOBYTE(LOWORD(wma->ash_audio.fccType)),
36                                                 HIBYTE(LOWORD(wma->ash_audio.fccType)),
37                                                 LOBYTE(HIWORD(wma->ash_audio.fccType)),
38                                                 HIBYTE(HIWORD(wma->ash_audio.fccType)));
39     TRACE("ash.fccHandler='%c%c%c%c'\n",        LOBYTE(LOWORD(wma->ash_audio.fccHandler)),
40                                                 HIBYTE(LOWORD(wma->ash_audio.fccHandler)),
41                                                 LOBYTE(HIWORD(wma->ash_audio.fccHandler)),
42                                                 HIBYTE(HIWORD(wma->ash_audio.fccHandler)));
43     TRACE("ash.dwFlags=%ld\n",                  wma->ash_audio.dwFlags);
44     TRACE("ash.wPriority=%d\n",                 wma->ash_audio.wPriority);
45     TRACE("ash.wLanguage=%d\n",                 wma->ash_audio.wLanguage);
46     TRACE("ash.dwInitialFrames=%ld\n",          wma->ash_audio.dwInitialFrames);
47     TRACE("ash.dwScale=%ld\n",                  wma->ash_audio.dwScale);
48     TRACE("ash.dwRate=%ld\n",                   wma->ash_audio.dwRate);
49     TRACE("ash.dwStart=%ld\n",                  wma->ash_audio.dwStart);
50     TRACE("ash.dwLength=%ld\n",                 wma->ash_audio.dwLength);
51     TRACE("ash.dwSuggestedBufferSize=%ld\n",    wma->ash_audio.dwSuggestedBufferSize);
52     TRACE("ash.dwQuality=%ld\n",                wma->ash_audio.dwQuality);
53     TRACE("ash.dwSampleSize=%ld\n",             wma->ash_audio.dwSampleSize);
54     TRACE("ash.rcFrame=(%d,%d,%d,%d)\n",        wma->ash_audio.rcFrame.top, wma->ash_audio.rcFrame.left,
55           wma->ash_audio.rcFrame.bottom, wma->ash_audio.rcFrame.right);
56
57     /* rewind to the start of the stream */
58     mmioAscend(wma->hFile, mmckStream, 0);
59
60     mmckInfo.ckid = ckidSTREAMFORMAT;
61     if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) {
62        WARN("Can't find 'strf' chunk\n");
63         return FALSE;
64     }
65     if (mmckInfo.cksize < sizeof(WAVEFORMAT)) {
66         WARN("Size of strf chunk (%ld) < audio format struct\n", mmckInfo.cksize);
67         return FALSE;
68     }
69     wma->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
70     if (!wma->lpWaveFormat) {
71         WARN("Can't alloc WaveFormat\n");
72         return FALSE;
73     }
74
75     mmioRead(wma->hFile, (LPSTR)wma->lpWaveFormat, mmckInfo.cksize);
76
77     TRACE("waveFormat.wFormatTag=%d\n",         wma->lpWaveFormat->wFormatTag);
78     TRACE("waveFormat.nChannels=%d\n",          wma->lpWaveFormat->nChannels);
79     TRACE("waveFormat.nSamplesPerSec=%ld\n",    wma->lpWaveFormat->nSamplesPerSec);
80     TRACE("waveFormat.nAvgBytesPerSec=%ld\n",   wma->lpWaveFormat->nAvgBytesPerSec);
81     TRACE("waveFormat.nBlockAlign=%d\n",        wma->lpWaveFormat->nBlockAlign);
82     TRACE("waveFormat.wBitsPerSample=%d\n",     wma->lpWaveFormat->wBitsPerSample);
83     if (mmckInfo.cksize >= sizeof(WAVEFORMATEX))
84         TRACE("waveFormat.cbSize=%d\n",                 wma->lpWaveFormat->cbSize);
85
86     return TRUE;
87 }
88
89 static BOOL MCIAVI_GetInfoVideo(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCKINFO* mmckStream)
90 {
91     MMCKINFO    mmckInfo;
92
93     mmioRead(wma->hFile, (LPSTR)&wma->ash_video, sizeof(wma->ash_video));
94
95     TRACE("ash.fccType='%c%c%c%c'\n",           LOBYTE(LOWORD(wma->ash_video.fccType)),
96                                                 HIBYTE(LOWORD(wma->ash_video.fccType)),
97                                                 LOBYTE(HIWORD(wma->ash_video.fccType)),
98                                                 HIBYTE(HIWORD(wma->ash_video.fccType)));
99     TRACE("ash.fccHandler='%c%c%c%c'\n",        LOBYTE(LOWORD(wma->ash_video.fccHandler)),
100                                                 HIBYTE(LOWORD(wma->ash_video.fccHandler)),
101                                                 LOBYTE(HIWORD(wma->ash_video.fccHandler)),
102                                                 HIBYTE(HIWORD(wma->ash_video.fccHandler)));
103     TRACE("ash.dwFlags=%ld\n",                  wma->ash_video.dwFlags);
104     TRACE("ash.wPriority=%d\n",                 wma->ash_video.wPriority);
105     TRACE("ash.wLanguage=%d\n",                 wma->ash_video.wLanguage);
106     TRACE("ash.dwInitialFrames=%ld\n",          wma->ash_video.dwInitialFrames);
107     TRACE("ash.dwScale=%ld\n",                  wma->ash_video.dwScale);
108     TRACE("ash.dwRate=%ld\n",                   wma->ash_video.dwRate);
109     TRACE("ash.dwStart=%ld\n",                  wma->ash_video.dwStart);
110     TRACE("ash.dwLength=%ld\n",                 wma->ash_video.dwLength);
111     TRACE("ash.dwSuggestedBufferSize=%ld\n",    wma->ash_video.dwSuggestedBufferSize);
112     TRACE("ash.dwQuality=%ld\n",                wma->ash_video.dwQuality);
113     TRACE("ash.dwSampleSize=%ld\n",             wma->ash_video.dwSampleSize);
114     TRACE("ash.rcFrame=(%d,%d,%d,%d)\n",        wma->ash_video.rcFrame.top, wma->ash_video.rcFrame.left,
115           wma->ash_video.rcFrame.bottom, wma->ash_video.rcFrame.right);
116
117     /* rewind to the start of the stream */
118     mmioAscend(wma->hFile, mmckStream, 0);
119
120     mmckInfo.ckid = ckidSTREAMFORMAT;
121     if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) {
122        WARN("Can't find 'strf' chunk\n");
123         return FALSE;
124     }
125
126     wma->inbih = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
127     if (!wma->inbih) {
128         WARN("Can't alloc input BIH\n");
129         return FALSE;
130     }
131
132     mmioRead(wma->hFile, (LPSTR)wma->inbih, mmckInfo.cksize);
133
134     TRACE("bih.biSize=%ld\n",           wma->inbih->biSize);
135     TRACE("bih.biWidth=%ld\n",          wma->inbih->biWidth);
136     TRACE("bih.biHeight=%ld\n",         wma->inbih->biHeight);
137     TRACE("bih.biPlanes=%d\n",          wma->inbih->biPlanes);
138     TRACE("bih.biBitCount=%d\n",        wma->inbih->biBitCount);
139     TRACE("bih.biCompression=%lx\n",    wma->inbih->biCompression);
140     TRACE("bih.biSizeImage=%ld\n",      wma->inbih->biSizeImage);
141     TRACE("bih.biXPelsPerMeter=%ld\n",  wma->inbih->biXPelsPerMeter);
142     TRACE("bih.biYPelsPerMeter=%ld\n",  wma->inbih->biYPelsPerMeter);
143     TRACE("bih.biClrUsed=%ld\n",        wma->inbih->biClrUsed);
144     TRACE("bih.biClrImportant=%ld\n",   wma->inbih->biClrImportant);
145
146     wma->source.left = 0;
147     wma->source.top = 0;
148     wma->source.right = wma->inbih->biWidth;
149     wma->source.bottom = wma->inbih->biHeight;
150
151     wma->dest = wma->source;
152
153     return TRUE;
154 }
155
156 struct AviListBuild {
157     DWORD       numVideoFrames;
158     DWORD       numAudioAllocated;
159     DWORD       numAudioBlocks;
160     DWORD       inVideoSize;
161     DWORD       inAudioSize;
162 };
163
164 static BOOL     MCIAVI_AddFrame(WINE_MCIAVI* wma, LPMMCKINFO mmck,
165                                 struct AviListBuild* alb)
166 {
167     const BYTE *p;
168     DWORD stream_n;
169     DWORD twocc;
170
171     if (mmck->ckid == ckidAVIPADDING) return TRUE;
172
173     p = (const BYTE *)&mmck->ckid;
174
175     if (!isxdigit(p[0]) || !isxdigit(p[1]))
176     {
177         WARN("wrongly encoded stream #\n");
178         return FALSE;
179     }
180
181     stream_n = (p[0] <= '9') ? (p[0] - '0') : (tolower(p[0]) - 'a' + 10);
182     stream_n <<= 4;
183     stream_n |= (p[1] <= '9') ? (p[1] - '0') : (tolower(p[1]) - 'a' + 10);
184
185     TRACE("ckid %4.4s (stream #%ld)\n", (LPSTR)&mmck->ckid, stream_n);
186
187     /* Some (rare?) AVI files have video streams name XXYY where XX = stream number and YY = TWOCC
188      * of the last 2 characters of the biCompression member of the BITMAPINFOHEADER structure.
189      * Ex: fccHandler = IV32 & biCompression = IV32 => stream name = XX32
190      *     fccHandler = MSVC & biCompression = CRAM => stream name = XXAM
191      * Another possibility is that these TWOCC are simply ignored.
192      * Default to cktypeDIBcompressed when this case happens.
193      */
194     twocc = TWOCCFromFOURCC(mmck->ckid);
195     if (twocc == TWOCCFromFOURCC(wma->inbih->biCompression))
196         twocc = cktypeDIBcompressed;
197     
198     switch (twocc) {
199     case cktypeDIBbits:
200     case cktypeDIBcompressed:
201     case cktypePALchange:
202         if (stream_n != wma->video_stream_n)
203         {
204             TRACE("data belongs to another video stream #%ld\n", stream_n);
205             return FALSE;
206         }
207
208         TRACE("Adding video frame[%ld]: %ld bytes\n",
209               alb->numVideoFrames, mmck->cksize);
210
211         if (alb->numVideoFrames < wma->dwPlayableVideoFrames) {
212             wma->lpVideoIndex[alb->numVideoFrames].dwOffset = mmck->dwDataOffset;
213             wma->lpVideoIndex[alb->numVideoFrames].dwSize = mmck->cksize;
214             if (alb->inVideoSize < mmck->cksize)
215                 alb->inVideoSize = mmck->cksize;
216             alb->numVideoFrames++;
217         } else {
218             WARN("Too many video frames\n");
219         }
220         break;
221     case cktypeWAVEbytes:
222         if (stream_n != wma->audio_stream_n)
223         {
224             TRACE("data belongs to another audio stream #%ld\n", stream_n);
225             return FALSE;
226         }
227
228         TRACE("Adding audio frame[%ld]: %ld bytes\n",
229               alb->numAudioBlocks, mmck->cksize);
230         if (wma->lpWaveFormat) {
231             if (alb->numAudioBlocks >= alb->numAudioAllocated) {
232                 alb->numAudioAllocated += 32;
233                 if (!wma->lpAudioIndex)
234                     wma->lpAudioIndex = HeapAlloc(GetProcessHeap(), 0,
235                                                   alb->numAudioAllocated * sizeof(struct MMIOPos));
236                 else
237                     wma->lpAudioIndex = HeapReAlloc(GetProcessHeap(), 0, wma->lpAudioIndex,
238                                                     alb->numAudioAllocated * sizeof(struct MMIOPos));
239                 if (!wma->lpAudioIndex) return FALSE;
240             }
241             wma->lpAudioIndex[alb->numAudioBlocks].dwOffset = mmck->dwDataOffset;
242             wma->lpAudioIndex[alb->numAudioBlocks].dwSize = mmck->cksize;
243             if (alb->inAudioSize < mmck->cksize)
244                 alb->inAudioSize = mmck->cksize;
245             alb->numAudioBlocks++;
246         } else {
247             WARN("Wave chunk without wave format... discarding\n");
248         }
249         break;
250     default:
251         WARN("Unknown frame type %4.4s\n", (LPSTR)&mmck->ckid);
252         break;
253     }
254     return TRUE;
255 }
256
257 BOOL MCIAVI_GetInfo(WINE_MCIAVI* wma)
258 {
259     MMCKINFO            ckMainRIFF;
260     MMCKINFO            mmckHead;
261     MMCKINFO            mmckList;
262     MMCKINFO            mmckInfo;
263     struct AviListBuild alb;
264     DWORD stream_n;
265
266     if (mmioDescend(wma->hFile, &ckMainRIFF, NULL, 0) != 0) {
267         WARN("Can't find 'RIFF' chunk\n");
268         return FALSE;
269     }
270
271     if ((ckMainRIFF.ckid != FOURCC_RIFF) || (ckMainRIFF.fccType != formtypeAVI)) {
272         WARN("Can't find 'AVI ' chunk\n");
273         return FALSE;
274     }
275
276     mmckHead.fccType = listtypeAVIHEADER;
277     if (mmioDescend(wma->hFile, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) {
278         WARN("Can't find 'hdrl' list\n");
279         return FALSE;
280     }
281
282     mmckInfo.ckid = ckidAVIMAINHDR;
283     if (mmioDescend(wma->hFile, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) {
284         WARN("Can't find 'avih' chunk\n");
285         return FALSE;
286     }
287
288     mmioRead(wma->hFile, (LPSTR)&wma->mah, sizeof(wma->mah));
289
290     TRACE("mah.dwMicroSecPerFrame=%ld\n",       wma->mah.dwMicroSecPerFrame);
291     TRACE("mah.dwMaxBytesPerSec=%ld\n",         wma->mah.dwMaxBytesPerSec);
292     TRACE("mah.dwPaddingGranularity=%ld\n",     wma->mah.dwPaddingGranularity);
293     TRACE("mah.dwFlags=%ld\n",                  wma->mah.dwFlags);
294     TRACE("mah.dwTotalFrames=%ld\n",            wma->mah.dwTotalFrames);
295     TRACE("mah.dwInitialFrames=%ld\n",          wma->mah.dwInitialFrames);
296     TRACE("mah.dwStreams=%ld\n",                wma->mah.dwStreams);
297     TRACE("mah.dwSuggestedBufferSize=%ld\n",    wma->mah.dwSuggestedBufferSize);
298     TRACE("mah.dwWidth=%ld\n",                  wma->mah.dwWidth);
299     TRACE("mah.dwHeight=%ld\n",                 wma->mah.dwHeight);
300
301     mmioAscend(wma->hFile, &mmckInfo, 0);
302
303     TRACE("Start of streams\n");
304     wma->video_stream_n = 0;
305     wma->audio_stream_n = 0;
306
307     for (stream_n = 0; stream_n < wma->mah.dwStreams; stream_n++)
308     {
309         MMCKINFO mmckStream;
310
311         mmckList.fccType = listtypeSTREAMHEADER;
312         if (mmioDescend(wma->hFile, &mmckList, &mmckHead, MMIO_FINDLIST) != 0)
313             break;
314
315         mmckStream.ckid = ckidSTREAMHEADER;
316         if (mmioDescend(wma->hFile, &mmckStream, &mmckList, MMIO_FINDCHUNK) != 0)
317         {
318             WARN("Can't find 'strh' chunk\n");
319             continue;
320         }
321
322         TRACE("Stream #%ld fccType %4.4s\n", stream_n, (LPSTR)&mmckStream.fccType);
323
324         if (mmckStream.fccType == streamtypeVIDEO)
325         {
326             TRACE("found video stream\n");
327             if (wma->inbih)
328                 WARN("ignoring another video stream\n");
329             else
330             {
331                 if (!MCIAVI_GetInfoVideo(wma, &mmckList, &mmckStream))
332                     return FALSE;
333                 wma->video_stream_n = stream_n;
334             }
335         }
336         else if (mmckStream.fccType == streamtypeAUDIO)
337         {
338             TRACE("found audio stream\n");
339             if (wma->lpWaveFormat)
340                 WARN("ignoring another audio stream\n");
341             else
342             {
343                 if (!MCIAVI_GetInfoAudio(wma, &mmckList, &mmckStream))
344                     return FALSE;
345                 wma->audio_stream_n = stream_n;
346             }
347         }
348         else
349             TRACE("Unsupported stream type %4.4s\n", (LPSTR)&mmckStream.fccType);
350
351         mmioAscend(wma->hFile, &mmckList, 0);
352     }
353
354     TRACE("End of streams\n");
355
356     mmioAscend(wma->hFile, &mmckHead, 0);
357
358     /* no need to read optional JUNK chunk */
359
360     mmckList.fccType = listtypeAVIMOVIE;
361     if (mmioDescend(wma->hFile, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) {
362         WARN("Can't find 'movi' list\n");
363         return FALSE;
364     }
365
366     wma->dwPlayableVideoFrames = wma->mah.dwTotalFrames;
367     wma->lpVideoIndex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
368                                   wma->dwPlayableVideoFrames * sizeof(struct MMIOPos));
369     if (!wma->lpVideoIndex) {
370         WARN("Can't alloc video index array\n");
371         return FALSE;
372     }
373     wma->dwPlayableAudioBlocks = 0;
374     wma->lpAudioIndex = NULL;
375
376     alb.numAudioBlocks = alb.numVideoFrames = 0;
377     alb.inVideoSize = alb.inAudioSize = 0;
378     alb.numAudioAllocated = 0;
379
380     while (mmioDescend(wma->hFile, &mmckInfo, &mmckList, 0) == 0) {
381         if (mmckInfo.fccType == listtypeAVIRECORD) {
382             MMCKINFO    tmp;
383
384             while (mmioDescend(wma->hFile, &tmp, &mmckInfo, 0) == 0) {
385                 MCIAVI_AddFrame(wma, &tmp, &alb);
386                 mmioAscend(wma->hFile, &tmp, 0);
387             }
388         } else {
389             MCIAVI_AddFrame(wma, &mmckInfo, &alb);
390         }
391
392         mmioAscend(wma->hFile, &mmckInfo, 0);
393     }
394     if (alb.numVideoFrames != wma->dwPlayableVideoFrames) {
395         WARN("Found %ld video frames (/%ld), reducing playable frames\n",
396              alb.numVideoFrames, wma->dwPlayableVideoFrames);
397         wma->dwPlayableVideoFrames = alb.numVideoFrames;
398     }
399     wma->dwPlayableAudioBlocks = alb.numAudioBlocks;
400
401     if (alb.inVideoSize > wma->ash_video.dwSuggestedBufferSize) {
402         WARN("inVideoSize=%ld suggestedSize=%ld\n", alb.inVideoSize, wma->ash_video.dwSuggestedBufferSize);
403         wma->ash_video.dwSuggestedBufferSize = alb.inVideoSize;
404     }
405     if (alb.inAudioSize > wma->ash_audio.dwSuggestedBufferSize) {
406         WARN("inAudioSize=%ld suggestedSize=%ld\n", alb.inAudioSize, wma->ash_audio.dwSuggestedBufferSize);
407         wma->ash_audio.dwSuggestedBufferSize = alb.inAudioSize;
408     }
409
410     wma->indata = HeapAlloc(GetProcessHeap(), 0, wma->ash_video.dwSuggestedBufferSize);
411     if (!wma->indata) {
412         WARN("Can't alloc input buffer\n");
413         return FALSE;
414     }
415
416     return TRUE;
417 }
418
419 BOOL    MCIAVI_OpenVideo(WINE_MCIAVI* wma)
420 {
421     HDC hDC;
422     DWORD       outSize;
423     FOURCC      fcc = wma->ash_video.fccHandler;
424
425     TRACE("fcc %4.4s\n", (LPSTR)&fcc);
426
427     wma->dwCachedFrame = -1;
428
429     /* get the right handle */
430     if (fcc == mmioFOURCC('C','R','A','M')) fcc = mmioFOURCC('M','S','V','C');
431
432     /* try to get a decompressor for that type */
433     wma->hic = ICLocate(ICTYPE_VIDEO, fcc, wma->inbih, NULL, ICMODE_DECOMPRESS);
434     if (!wma->hic) {
435         /* check for builtin DIB compressions */
436         fcc = wma->inbih->biCompression;
437         if ((fcc == mmioFOURCC('D','I','B',' ')) ||
438             (fcc == mmioFOURCC('R','L','E',' ')) ||
439             (fcc == BI_RGB) || (fcc == BI_RLE8) ||
440             (fcc == BI_RLE4) || (fcc == BI_BITFIELDS))
441             goto paint_frame;
442
443         WARN("Can't locate codec for the file\n");
444         return FALSE;
445     }
446
447     outSize = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
448
449     wma->outbih = HeapAlloc(GetProcessHeap(), 0, outSize);
450     if (!wma->outbih) {
451         WARN("Can't alloc output BIH\n");
452         return FALSE;
453     }
454     if (!ICGetDisplayFormat(wma->hic, wma->inbih, wma->outbih, 0, 0, 0)) {
455         WARN("Can't open decompressor\n");
456         return FALSE;
457     }
458
459     TRACE("bih.biSize=%ld\n",           wma->outbih->biSize);
460     TRACE("bih.biWidth=%ld\n",          wma->outbih->biWidth);
461     TRACE("bih.biHeight=%ld\n",         wma->outbih->biHeight);
462     TRACE("bih.biPlanes=%d\n",          wma->outbih->biPlanes);
463     TRACE("bih.biBitCount=%d\n",        wma->outbih->biBitCount);
464     TRACE("bih.biCompression=%lx\n",    wma->outbih->biCompression);
465     TRACE("bih.biSizeImage=%ld\n",      wma->outbih->biSizeImage);
466     TRACE("bih.biXPelsPerMeter=%ld\n",  wma->outbih->biXPelsPerMeter);
467     TRACE("bih.biYPelsPerMeter=%ld\n",  wma->outbih->biYPelsPerMeter);
468     TRACE("bih.biClrUsed=%ld\n",        wma->outbih->biClrUsed);
469     TRACE("bih.biClrImportant=%ld\n",   wma->outbih->biClrImportant);
470
471     wma->outdata = HeapAlloc(GetProcessHeap(), 0, wma->outbih->biSizeImage);
472     if (!wma->outdata) {
473         WARN("Can't alloc output buffer\n");
474         return FALSE;
475     }
476
477     if (ICSendMessage(wma->hic, ICM_DECOMPRESS_BEGIN,
478                       (DWORD)wma->inbih, (DWORD)wma->outbih) != ICERR_OK) {
479         WARN("Can't begin decompression\n");
480         return FALSE;
481     }
482
483 paint_frame:
484     hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
485     if (hDC)
486     {
487         MCIAVI_PaintFrame(wma, hDC);
488         ReleaseDC(wma->hWndPaint, hDC);
489     }
490     return TRUE;
491 }
492
493 static void CALLBACK MCIAVI_waveCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
494                                         DWORD_PTR dwParam1, DWORD_PTR dwParam2)
495 {
496     WINE_MCIAVI *wma = (WINE_MCIAVI *)MCIAVI_mciGetOpenDev(dwInstance);
497
498     if (!wma) return;
499
500     EnterCriticalSection(&wma->cs);
501
502     switch (uMsg) {
503     case WOM_OPEN:
504     case WOM_CLOSE:
505         break;
506     case WOM_DONE:
507         InterlockedIncrement(&wma->dwEventCount);
508         TRACE("Returning waveHdr=%lx\n", dwParam1);
509         SetEvent(wma->hEvent);
510         break;
511     default:
512         ERR("Unknown uMsg=%d\n", uMsg);
513     }
514
515     LeaveCriticalSection(&wma->cs);
516 }
517
518 DWORD MCIAVI_OpenAudio(WINE_MCIAVI* wma, unsigned* nHdr, LPWAVEHDR* pWaveHdr)
519 {
520     DWORD       dwRet;
521     LPWAVEHDR   waveHdr;
522     unsigned    i;
523
524     dwRet = waveOutOpen((HWAVEOUT *)&wma->hWave, WAVE_MAPPER, wma->lpWaveFormat,
525                        (DWORD_PTR)MCIAVI_waveCallback, wma->wDevID, CALLBACK_FUNCTION);
526     if (dwRet != 0) {
527         TRACE("Can't open low level audio device %ld\n", dwRet);
528         dwRet = MCIERR_DEVICE_OPEN;
529         wma->hWave = 0;
530         goto cleanUp;
531     }
532
533     /* FIXME: should set up a heuristic to compute the number of wave headers
534      * to be used...
535      */
536     *nHdr = 7;
537     waveHdr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
538                         *nHdr * (sizeof(WAVEHDR) + wma->ash_audio.dwSuggestedBufferSize));
539     if (!waveHdr) {
540         TRACE("Can't alloc wave headers\n");
541         dwRet = MCIERR_DEVICE_OPEN;
542         goto cleanUp;
543     }
544
545     for (i = 0; i < *nHdr; i++) {
546         /* other fields are zero:ed on allocation */
547         waveHdr[i].lpData = (char*)waveHdr +
548             *nHdr * sizeof(WAVEHDR) + i * wma->ash_audio.dwSuggestedBufferSize;
549         waveHdr[i].dwBufferLength = wma->ash_audio.dwSuggestedBufferSize;
550         if (waveOutPrepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR))) {
551             dwRet = MCIERR_INTERNAL;
552             goto cleanUp;
553         }
554     }
555
556     if (wma->dwCurrVideoFrame != 0 && wma->lpWaveFormat) {
557         FIXME("Should recompute dwCurrAudioBlock, except unsynchronized sound & video\n");
558     }
559     wma->dwCurrAudioBlock = 0;
560
561     wma->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
562     wma->dwEventCount = *nHdr - 1;
563     *pWaveHdr = waveHdr;
564  cleanUp:
565     return dwRet;
566 }
567
568 void MCIAVI_PlayAudioBlocks(WINE_MCIAVI* wma, unsigned nHdr, LPWAVEHDR waveHdr)
569 {
570     if (!wma->lpAudioIndex) 
571         return;
572     TRACE("%ld (ec=%lu)\n", wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset, wma->dwEventCount);
573
574     /* push as many blocks as possible => audio gets priority */
575     while (wma->dwStatus != MCI_MODE_STOP && wma->dwStatus != MCI_MODE_NOT_READY &&
576            wma->dwCurrAudioBlock < wma->dwPlayableAudioBlocks) {
577         unsigned        whidx = wma->dwCurrAudioBlock % nHdr;
578
579         ResetEvent(wma->hEvent);
580         if (InterlockedDecrement(&wma->dwEventCount) < 0 ||
581             !wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset)
582         {
583             InterlockedIncrement(&wma->dwEventCount);
584             break;
585         }
586
587         mmioSeek(wma->hFile, wma->lpAudioIndex[wma->dwCurrAudioBlock].dwOffset, SEEK_SET);
588         mmioRead(wma->hFile, waveHdr[whidx].lpData, wma->lpAudioIndex[wma->dwCurrAudioBlock].dwSize);
589
590         waveHdr[whidx].dwFlags &= ~WHDR_DONE;
591         waveHdr[whidx].dwBufferLength = wma->lpAudioIndex[wma->dwCurrAudioBlock].dwSize;
592         waveOutWrite(wma->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
593         wma->dwCurrAudioBlock++;
594     }
595 }
596
597 LRESULT MCIAVI_PaintFrame(WINE_MCIAVI* wma, HDC hDC)
598 {
599     void*               pBitmapData = NULL;
600     LPBITMAPINFO        pBitmapInfo = NULL;
601     HDC                 hdcMem;
602     HBITMAP             hbmOld;
603     int                 nWidth;
604     int                 nHeight;
605
606     if (!hDC || !wma->inbih)
607         return TRUE;
608
609     TRACE("Painting frame %lu (cached %lu)\n", wma->dwCurrVideoFrame, wma->dwCachedFrame);
610
611     if (wma->dwCurrVideoFrame != wma->dwCachedFrame)
612     {
613         if (!wma->lpVideoIndex[wma->dwCurrVideoFrame].dwOffset)
614             return FALSE;
615
616         if (wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize)
617         {
618             mmioSeek(wma->hFile, wma->lpVideoIndex[wma->dwCurrVideoFrame].dwOffset, SEEK_SET);
619             mmioRead(wma->hFile, wma->indata, wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize);
620
621             /* FIXME ? */
622             wma->inbih->biSizeImage = wma->lpVideoIndex[wma->dwCurrVideoFrame].dwSize;
623
624             if (wma->hic && ICDecompress(wma->hic, 0, wma->inbih, wma->indata,
625                                          wma->outbih, wma->outdata) != ICERR_OK)
626             {
627                 WARN("Decompression error\n");
628                 return FALSE;
629             }
630         }
631
632         wma->dwCachedFrame = wma->dwCurrVideoFrame;
633     }
634
635     if (wma->hic) {
636         pBitmapData = wma->outdata;
637         pBitmapInfo = (LPBITMAPINFO)wma->outbih;
638
639         nWidth = wma->outbih->biWidth;
640         nHeight = wma->outbih->biHeight;
641     } else {
642         pBitmapData = wma->indata;
643         pBitmapInfo = (LPBITMAPINFO)wma->inbih;
644
645         nWidth = wma->inbih->biWidth;
646         nHeight = wma->inbih->biHeight;
647     }
648
649     if (!wma->hbmFrame)
650         wma->hbmFrame = CreateCompatibleBitmap(hDC, nWidth, nHeight);
651
652     SetDIBits(hDC, wma->hbmFrame, 0, nHeight, pBitmapData, pBitmapInfo, DIB_RGB_COLORS);
653
654     hdcMem = CreateCompatibleDC(hDC);
655     hbmOld = SelectObject(hdcMem, wma->hbmFrame);
656
657     StretchBlt(hDC,
658                wma->dest.left, wma->dest.top, wma->dest.right, wma->dest.bottom,
659                hdcMem,
660                wma->source.left, wma->source.top, wma->source.right, wma->source.bottom,
661                SRCCOPY);
662
663     SelectObject(hdcMem, hbmOld);
664     DeleteDC(hdcMem);
665     return TRUE;
666 }