1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * Digital video MCI Wine Driver
6 * Copyright 1999, 2000 Eric POUECH
7 * Copyright 2003 Dmitry Timoshkov
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 #include "private_mciavi.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(mciavi
);
29 static BOOL
MCIAVI_GetInfoAudio(WINE_MCIAVI
* wma
, const MMCKINFO
* mmckList
, MMCKINFO
*mmckStream
)
33 mmioRead(wma
->hFile
, (LPSTR
)&wma
->ash_audio
, sizeof(wma
->ash_audio
));
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
);
57 /* rewind to the start of the stream */
58 mmioAscend(wma
->hFile
, mmckStream
, 0);
60 mmckInfo
.ckid
= ckidSTREAMFORMAT
;
61 if (mmioDescend(wma
->hFile
, &mmckInfo
, mmckList
, MMIO_FINDCHUNK
) != 0) {
62 WARN("Can't find 'strf' chunk\n");
65 if (mmckInfo
.cksize
< sizeof(WAVEFORMAT
)) {
66 WARN("Size of strf chunk (%ld) < audio format struct\n", mmckInfo
.cksize
);
69 wma
->lpWaveFormat
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
70 if (!wma
->lpWaveFormat
) {
71 WARN("Can't alloc WaveFormat\n");
75 mmioRead(wma
->hFile
, (LPSTR
)wma
->lpWaveFormat
, mmckInfo
.cksize
);
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
);
89 static BOOL
MCIAVI_GetInfoVideo(WINE_MCIAVI
* wma
, const MMCKINFO
* mmckList
, MMCKINFO
* mmckStream
)
93 mmioRead(wma
->hFile
, (LPSTR
)&wma
->ash_video
, sizeof(wma
->ash_video
));
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
);
117 /* rewind to the start of the stream */
118 mmioAscend(wma
->hFile
, mmckStream
, 0);
120 mmckInfo
.ckid
= ckidSTREAMFORMAT
;
121 if (mmioDescend(wma
->hFile
, &mmckInfo
, mmckList
, MMIO_FINDCHUNK
) != 0) {
122 WARN("Can't find 'strf' chunk\n");
126 wma
->inbih
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
128 WARN("Can't alloc input BIH\n");
132 mmioRead(wma
->hFile
, (LPSTR
)wma
->inbih
, mmckInfo
.cksize
);
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
);
146 wma
->source
.left
= 0;
148 wma
->source
.right
= wma
->inbih
->biWidth
;
149 wma
->source
.bottom
= wma
->inbih
->biHeight
;
151 wma
->dest
= wma
->source
;
156 struct AviListBuild
{
157 DWORD numVideoFrames
;
158 DWORD numAudioAllocated
;
159 DWORD numAudioBlocks
;
164 static BOOL
MCIAVI_AddFrame(WINE_MCIAVI
* wma
, LPMMCKINFO mmck
,
165 struct AviListBuild
* alb
)
170 if (mmck
->ckid
== ckidAVIPADDING
) return TRUE
;
172 p
= (const BYTE
*)&mmck
->ckid
;
174 if (!isxdigit(p
[0]) || !isxdigit(p
[1]))
176 WARN("wrongly encoded stream #\n");
180 stream_n
= (p
[0] <= '9') ? (p
[0] - '0') : (tolower(p
[0]) - 'a' + 10);
182 stream_n
|= (p
[1] <= '9') ? (p
[1] - '0') : (tolower(p
[1]) - 'a' + 10);
184 TRACE("ckid %4.4s (stream #%ld)\n", (LPSTR
)&mmck
->ckid
, stream_n
);
186 switch (TWOCCFromFOURCC(mmck
->ckid
)) {
188 case cktypeDIBcompressed
:
189 case cktypePALchange
:
190 if (stream_n
!= wma
->video_stream_n
)
192 TRACE("data belongs to another video stream #%ld\n", stream_n
);
196 TRACE("Adding video frame[%ld]: %ld bytes\n",
197 alb
->numVideoFrames
, mmck
->cksize
);
199 if (alb
->numVideoFrames
< wma
->dwPlayableVideoFrames
) {
200 wma
->lpVideoIndex
[alb
->numVideoFrames
].dwOffset
= mmck
->dwDataOffset
;
201 wma
->lpVideoIndex
[alb
->numVideoFrames
].dwSize
= mmck
->cksize
;
202 if (alb
->inVideoSize
< mmck
->cksize
)
203 alb
->inVideoSize
= mmck
->cksize
;
204 alb
->numVideoFrames
++;
206 WARN("Too many video frames\n");
209 case cktypeWAVEbytes
:
210 if (stream_n
!= wma
->audio_stream_n
)
212 TRACE("data belongs to another audio stream #%ld\n", stream_n
);
216 TRACE("Adding audio frame[%ld]: %ld bytes\n",
217 alb
->numAudioBlocks
, mmck
->cksize
);
218 if (wma
->lpWaveFormat
) {
219 if (alb
->numAudioBlocks
>= alb
->numAudioAllocated
) {
220 alb
->numAudioAllocated
+= 32;
221 if (!wma
->lpAudioIndex
)
222 wma
->lpAudioIndex
= HeapAlloc(GetProcessHeap(), 0,
223 alb
->numAudioAllocated
* sizeof(struct MMIOPos
));
225 wma
->lpAudioIndex
= HeapReAlloc(GetProcessHeap(), 0, wma
->lpAudioIndex
,
226 alb
->numAudioAllocated
* sizeof(struct MMIOPos
));
227 if (!wma
->lpAudioIndex
) return FALSE
;
229 wma
->lpAudioIndex
[alb
->numAudioBlocks
].dwOffset
= mmck
->dwDataOffset
;
230 wma
->lpAudioIndex
[alb
->numAudioBlocks
].dwSize
= mmck
->cksize
;
231 if (alb
->inAudioSize
< mmck
->cksize
)
232 alb
->inAudioSize
= mmck
->cksize
;
233 alb
->numAudioBlocks
++;
235 WARN("Wave chunk without wave format... discarding\n");
239 WARN("Unknown frame type %4.4s\n", (LPSTR
)&mmck
->ckid
);
245 BOOL
MCIAVI_GetInfo(WINE_MCIAVI
* wma
)
251 struct AviListBuild alb
;
254 if (mmioDescend(wma
->hFile
, &ckMainRIFF
, NULL
, 0) != 0) {
255 WARN("Can't find 'RIFF' chunk\n");
259 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) || (ckMainRIFF
.fccType
!= formtypeAVI
)) {
260 WARN("Can't find 'AVI ' chunk\n");
264 mmckHead
.fccType
= listtypeAVIHEADER
;
265 if (mmioDescend(wma
->hFile
, &mmckHead
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
266 WARN("Can't find 'hdrl' list\n");
270 mmckInfo
.ckid
= ckidAVIMAINHDR
;
271 if (mmioDescend(wma
->hFile
, &mmckInfo
, &mmckHead
, MMIO_FINDCHUNK
) != 0) {
272 WARN("Can't find 'avih' chunk\n");
276 mmioRead(wma
->hFile
, (LPSTR
)&wma
->mah
, sizeof(wma
->mah
));
278 TRACE("mah.dwMicroSecPerFrame=%ld\n", wma
->mah
.dwMicroSecPerFrame
);
279 TRACE("mah.dwMaxBytesPerSec=%ld\n", wma
->mah
.dwMaxBytesPerSec
);
280 TRACE("mah.dwPaddingGranularity=%ld\n", wma
->mah
.dwPaddingGranularity
);
281 TRACE("mah.dwFlags=%ld\n", wma
->mah
.dwFlags
);
282 TRACE("mah.dwTotalFrames=%ld\n", wma
->mah
.dwTotalFrames
);
283 TRACE("mah.dwInitialFrames=%ld\n", wma
->mah
.dwInitialFrames
);
284 TRACE("mah.dwStreams=%ld\n", wma
->mah
.dwStreams
);
285 TRACE("mah.dwSuggestedBufferSize=%ld\n", wma
->mah
.dwSuggestedBufferSize
);
286 TRACE("mah.dwWidth=%ld\n", wma
->mah
.dwWidth
);
287 TRACE("mah.dwHeight=%ld\n", wma
->mah
.dwHeight
);
289 mmioAscend(wma
->hFile
, &mmckInfo
, 0);
291 TRACE("Start of streams\n");
292 wma
->video_stream_n
= 0;
293 wma
->audio_stream_n
= 0;
295 for (stream_n
= 0; stream_n
< wma
->mah
.dwStreams
; stream_n
++)
299 mmckList
.fccType
= listtypeSTREAMHEADER
;
300 if (mmioDescend(wma
->hFile
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) != 0)
303 mmckStream
.ckid
= ckidSTREAMHEADER
;
304 if (mmioDescend(wma
->hFile
, &mmckStream
, &mmckList
, MMIO_FINDCHUNK
) != 0)
306 WARN("Can't find 'strh' chunk\n");
310 TRACE("Stream #%ld fccType %4.4s\n", stream_n
, (LPSTR
)&mmckStream
.fccType
);
312 if (mmckStream
.fccType
== streamtypeVIDEO
)
314 TRACE("found video stream\n");
316 WARN("ignoring another video stream\n");
319 if (!MCIAVI_GetInfoVideo(wma
, &mmckList
, &mmckStream
))
321 wma
->video_stream_n
= stream_n
;
324 else if (mmckStream
.fccType
== streamtypeAUDIO
)
326 TRACE("found audio stream\n");
327 if (wma
->lpWaveFormat
)
328 WARN("ignoring another audio stream\n");
331 if (!MCIAVI_GetInfoAudio(wma
, &mmckList
, &mmckStream
))
333 wma
->audio_stream_n
= stream_n
;
337 TRACE("Unsupported stream type %4.4s\n", (LPSTR
)&mmckStream
.fccType
);
339 mmioAscend(wma
->hFile
, &mmckList
, 0);
342 TRACE("End of streams\n");
344 mmioAscend(wma
->hFile
, &mmckHead
, 0);
346 /* no need to read optional JUNK chunk */
348 mmckList
.fccType
= listtypeAVIMOVIE
;
349 if (mmioDescend(wma
->hFile
, &mmckList
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
350 WARN("Can't find 'movi' list\n");
354 wma
->dwPlayableVideoFrames
= wma
->mah
.dwTotalFrames
;
355 wma
->lpVideoIndex
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
356 wma
->dwPlayableVideoFrames
* sizeof(struct MMIOPos
));
357 if (!wma
->lpVideoIndex
) {
358 WARN("Can't alloc video index array\n");
361 wma
->dwPlayableAudioBlocks
= 0;
362 wma
->lpAudioIndex
= NULL
;
364 alb
.numAudioBlocks
= alb
.numVideoFrames
= 0;
365 alb
.inVideoSize
= alb
.inAudioSize
= 0;
366 alb
.numAudioAllocated
= 0;
368 while (mmioDescend(wma
->hFile
, &mmckInfo
, &mmckList
, 0) == 0) {
369 if (mmckInfo
.fccType
== listtypeAVIRECORD
) {
372 while (mmioDescend(wma
->hFile
, &tmp
, &mmckInfo
, 0) == 0) {
373 MCIAVI_AddFrame(wma
, &tmp
, &alb
);
374 mmioAscend(wma
->hFile
, &tmp
, 0);
377 MCIAVI_AddFrame(wma
, &mmckInfo
, &alb
);
380 mmioAscend(wma
->hFile
, &mmckInfo
, 0);
382 if (alb
.numVideoFrames
!= wma
->dwPlayableVideoFrames
) {
383 WARN("Found %ld video frames (/%ld), reducing playable frames\n",
384 alb
.numVideoFrames
, wma
->dwPlayableVideoFrames
);
385 wma
->dwPlayableVideoFrames
= alb
.numVideoFrames
;
387 wma
->dwPlayableAudioBlocks
= alb
.numAudioBlocks
;
389 if (alb
.inVideoSize
> wma
->ash_video
.dwSuggestedBufferSize
) {
390 WARN("inVideoSize=%ld suggestedSize=%ld\n", alb
.inVideoSize
, wma
->ash_video
.dwSuggestedBufferSize
);
391 wma
->ash_video
.dwSuggestedBufferSize
= alb
.inVideoSize
;
393 if (alb
.inAudioSize
> wma
->ash_audio
.dwSuggestedBufferSize
) {
394 WARN("inAudioSize=%ld suggestedSize=%ld\n", alb
.inAudioSize
, wma
->ash_audio
.dwSuggestedBufferSize
);
395 wma
->ash_audio
.dwSuggestedBufferSize
= alb
.inAudioSize
;
398 wma
->indata
= HeapAlloc(GetProcessHeap(), 0, wma
->ash_video
.dwSuggestedBufferSize
);
400 WARN("Can't alloc input buffer\n");
407 BOOL
MCIAVI_OpenVideo(WINE_MCIAVI
* wma
)
410 FOURCC fcc
= wma
->ash_video
.fccHandler
;
412 TRACE("fcc %4.4s\n", (LPSTR
)&fcc
);
414 /* check for builtin DIB compressions */
415 if ((fcc
== mmioFOURCC('D','I','B',' ')) ||
416 (fcc
== mmioFOURCC('R','L','E',' ')) ||
417 (fcc
== BI_RGB
) || (fcc
== BI_RLE8
) ||
418 (fcc
== BI_RLE4
) || (fcc
== BI_BITFIELDS
))
421 MCIAVI_DrawFrame(wma
);
425 /* get the right handle */
426 if (fcc
== 0) fcc
= wma
->inbih
->biCompression
;
427 if (fcc
== mmioFOURCC('C','R','A','M')) fcc
= mmioFOURCC('M','S','V','C');
429 /* try to get a decompressor for that type */
430 wma
->hic
= ICLocate(ICTYPE_VIDEO
, fcc
, wma
->inbih
, NULL
, ICMODE_DECOMPRESS
);
432 WARN("Can't locate codec for the file\n");
436 outSize
= sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
);
438 wma
->outbih
= HeapAlloc(GetProcessHeap(), 0, outSize
);
440 WARN("Can't alloc output BIH\n");
443 if (!ICGetDisplayFormat(wma
->hic
, wma
->inbih
, wma
->outbih
, 0, 0, 0)) {
444 WARN("Can't open decompressor\n");
448 TRACE("bih.biSize=%ld\n", wma
->outbih
->biSize
);
449 TRACE("bih.biWidth=%ld\n", wma
->outbih
->biWidth
);
450 TRACE("bih.biHeight=%ld\n", wma
->outbih
->biHeight
);
451 TRACE("bih.biPlanes=%d\n", wma
->outbih
->biPlanes
);
452 TRACE("bih.biBitCount=%d\n", wma
->outbih
->biBitCount
);
453 TRACE("bih.biCompression=%lx\n", wma
->outbih
->biCompression
);
454 TRACE("bih.biSizeImage=%ld\n", wma
->outbih
->biSizeImage
);
455 TRACE("bih.biXPelsPerMeter=%ld\n", wma
->outbih
->biXPelsPerMeter
);
456 TRACE("bih.biYPelsPerMeter=%ld\n", wma
->outbih
->biYPelsPerMeter
);
457 TRACE("bih.biClrUsed=%ld\n", wma
->outbih
->biClrUsed
);
458 TRACE("bih.biClrImportant=%ld\n", wma
->outbih
->biClrImportant
);
460 wma
->outdata
= HeapAlloc(GetProcessHeap(), 0, wma
->outbih
->biSizeImage
);
462 WARN("Can't alloc output buffer\n");
466 if (ICSendMessage(wma
->hic
, ICM_DECOMPRESS_BEGIN
,
467 (DWORD
)wma
->inbih
, (DWORD
)wma
->outbih
) != ICERR_OK
) {
468 WARN("Can't begin decompression\n");
472 MCIAVI_DrawFrame(wma
);
477 static void CALLBACK
MCIAVI_waveCallback(HWAVEOUT hwo
, UINT uMsg
, DWORD_PTR dwInstance
,
478 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
480 WINE_MCIAVI
*wma
= (WINE_MCIAVI
*)MCIAVI_mciGetOpenDev(dwInstance
);
484 EnterCriticalSection(&wma
->cs
);
491 InterlockedIncrement(&wma
->dwEventCount
);
492 TRACE("Returning waveHdr=%lx\n", dwParam1
);
493 SetEvent(wma
->hEvent
);
496 ERR("Unknown uMsg=%d\n", uMsg
);
499 LeaveCriticalSection(&wma
->cs
);
502 DWORD
MCIAVI_OpenAudio(WINE_MCIAVI
* wma
, unsigned* nHdr
, LPWAVEHDR
* pWaveHdr
)
508 dwRet
= waveOutOpen((HWAVEOUT
*)&wma
->hWave
, WAVE_MAPPER
, wma
->lpWaveFormat
,
509 (DWORD_PTR
)MCIAVI_waveCallback
, wma
->wDevID
, CALLBACK_FUNCTION
);
511 TRACE("Can't open low level audio device %ld\n", dwRet
);
512 dwRet
= MCIERR_DEVICE_OPEN
;
517 /* FIXME: should set up a heuristic to compute the number of wave headers
521 waveHdr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
522 *nHdr
* (sizeof(WAVEHDR
) + wma
->ash_audio
.dwSuggestedBufferSize
));
524 TRACE("Can't alloc wave headers\n");
525 dwRet
= MCIERR_DEVICE_OPEN
;
529 for (i
= 0; i
< *nHdr
; i
++) {
530 /* other fields are zero:ed on allocation */
531 waveHdr
[i
].lpData
= (char*)waveHdr
+
532 *nHdr
* sizeof(WAVEHDR
) + i
* wma
->ash_audio
.dwSuggestedBufferSize
;
533 waveHdr
[i
].dwBufferLength
= wma
->ash_audio
.dwSuggestedBufferSize
;
534 if (waveOutPrepareHeader(wma
->hWave
, &waveHdr
[i
], sizeof(WAVEHDR
))) {
535 dwRet
= MCIERR_INTERNAL
;
540 if (wma
->dwCurrVideoFrame
!= 0 && wma
->lpWaveFormat
) {
541 FIXME("Should recompute dwCurrAudioBlock, except unsynchronized sound & video\n");
543 wma
->dwCurrAudioBlock
= 0;
545 wma
->hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
546 wma
->dwEventCount
= *nHdr
- 1;
552 void MCIAVI_PlayAudioBlocks(WINE_MCIAVI
* wma
, unsigned nHdr
, LPWAVEHDR waveHdr
)
554 if (!wma
->lpAudioIndex
)
556 TRACE("%ld (ec=%lu)\n", wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwOffset
, wma
->dwEventCount
);
558 /* push as many blocks as possible => audio gets priority */
559 while (wma
->dwStatus
!= MCI_MODE_STOP
&& wma
->dwStatus
!= MCI_MODE_NOT_READY
&&
560 wma
->dwCurrAudioBlock
< wma
->dwPlayableAudioBlocks
) {
561 unsigned whidx
= wma
->dwCurrAudioBlock
% nHdr
;
563 ResetEvent(wma
->hEvent
);
564 if (InterlockedDecrement(&wma
->dwEventCount
) < 0 ||
565 !wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwOffset
)
567 InterlockedIncrement(&wma
->dwEventCount
);
571 mmioSeek(wma
->hFile
, wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwOffset
, SEEK_SET
);
572 mmioRead(wma
->hFile
, waveHdr
[whidx
].lpData
, wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwSize
);
574 waveHdr
[whidx
].dwFlags
&= ~WHDR_DONE
;
575 waveHdr
[whidx
].dwBufferLength
= wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwSize
;
576 waveOutWrite(wma
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
577 wma
->dwCurrAudioBlock
++;
581 LRESULT
MCIAVI_PaintFrame(WINE_MCIAVI
* wma
, HDC hDC
)
583 void* pBitmapData
= NULL
;
584 LPBITMAPINFO pBitmapInfo
= NULL
;
590 if (!hDC
|| !wma
->inbih
)
593 TRACE("Painting frame %lu\n", wma
->dwCurrVideoFrame
);
596 pBitmapData
= wma
->outdata
;
597 pBitmapInfo
= (LPBITMAPINFO
)wma
->outbih
;
599 nWidth
= wma
->outbih
->biWidth
;
600 nHeight
= wma
->outbih
->biHeight
;
602 pBitmapData
= wma
->indata
;
603 pBitmapInfo
= (LPBITMAPINFO
)wma
->inbih
;
605 nWidth
= wma
->inbih
->biWidth
;
606 nHeight
= wma
->inbih
->biHeight
;
610 wma
->hbmFrame
= CreateCompatibleBitmap(hDC
, nWidth
, nHeight
);
612 SetDIBits(hDC
, wma
->hbmFrame
, 0, nHeight
, pBitmapData
, pBitmapInfo
, DIB_RGB_COLORS
);
614 hdcMem
= CreateCompatibleDC(hDC
);
615 hbmOld
= SelectObject(hdcMem
, wma
->hbmFrame
);
618 wma
->dest
.left
, wma
->dest
.top
, wma
->dest
.right
, wma
->dest
.bottom
,
620 wma
->source
.left
, wma
->source
.top
, wma
->source
.right
, wma
->source
.bottom
,
623 SelectObject(hdcMem
, hbmOld
);
628 LRESULT
MCIAVI_DrawFrame(WINE_MCIAVI
* wma
)
632 TRACE("Drawing frame %lu\n", wma
->dwCurrVideoFrame
);
634 if (!wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwOffset
||
635 !wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwSize
)
638 mmioSeek(wma
->hFile
, wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwOffset
, SEEK_SET
);
639 mmioRead(wma
->hFile
, wma
->indata
, wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwSize
);
642 wma
->inbih
->biSizeImage
= wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwSize
;
645 ICDecompress(wma
->hic
, 0, wma
->inbih
, wma
->indata
,
646 wma
->outbih
, wma
->outdata
) != ICERR_OK
) {
647 WARN("Decompression error\n");
651 if (IsWindowVisible(wma
->hWndPaint
) && (hDC
= GetDC(wma
->hWndPaint
)) != 0) {
652 MCIAVI_PaintFrame(wma
, hDC
);
653 ReleaseDC(wma
->hWndPaint
, hDC
);