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
)
31 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma
->ash_audio
.fccType
)),
32 HIBYTE(LOWORD(wma
->ash_audio
.fccType
)),
33 LOBYTE(HIWORD(wma
->ash_audio
.fccType
)),
34 HIBYTE(HIWORD(wma
->ash_audio
.fccType
)));
35 if (wma
->ash_audio
.fccHandler
) /* not all streams specify a handler */
36 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma
->ash_audio
.fccHandler
)),
37 HIBYTE(LOWORD(wma
->ash_audio
.fccHandler
)),
38 LOBYTE(HIWORD(wma
->ash_audio
.fccHandler
)),
39 HIBYTE(HIWORD(wma
->ash_audio
.fccHandler
)));
41 TRACE("ash.fccHandler=0, no handler specified\n");
42 TRACE("ash.dwFlags=%d\n", wma
->ash_audio
.dwFlags
);
43 TRACE("ash.wPriority=%d\n", wma
->ash_audio
.wPriority
);
44 TRACE("ash.wLanguage=%d\n", wma
->ash_audio
.wLanguage
);
45 TRACE("ash.dwInitialFrames=%d\n", wma
->ash_audio
.dwInitialFrames
);
46 TRACE("ash.dwScale=%d\n", wma
->ash_audio
.dwScale
);
47 TRACE("ash.dwRate=%d\n", wma
->ash_audio
.dwRate
);
48 TRACE("ash.dwStart=%d\n", wma
->ash_audio
.dwStart
);
49 TRACE("ash.dwLength=%d\n", wma
->ash_audio
.dwLength
);
50 TRACE("ash.dwSuggestedBufferSize=%d\n", wma
->ash_audio
.dwSuggestedBufferSize
);
51 TRACE("ash.dwQuality=%d\n", wma
->ash_audio
.dwQuality
);
52 TRACE("ash.dwSampleSize=%d\n", wma
->ash_audio
.dwSampleSize
);
53 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma
->ash_audio
.rcFrame
.top
, wma
->ash_audio
.rcFrame
.left
,
54 wma
->ash_audio
.rcFrame
.bottom
, wma
->ash_audio
.rcFrame
.right
);
56 /* rewind to the start of the stream */
57 mmioAscend(wma
->hFile
, mmckStream
, 0);
59 mmckInfo
.ckid
= ckidSTREAMFORMAT
;
60 if (mmioDescend(wma
->hFile
, &mmckInfo
, mmckList
, MMIO_FINDCHUNK
) != 0) {
61 WARN("Can't find 'strf' chunk\n");
64 if (mmckInfo
.cksize
< sizeof(WAVEFORMAT
)) {
65 WARN("Size of strf chunk (%d) < audio format struct\n", mmckInfo
.cksize
);
68 wma
->lpWaveFormat
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
69 if (!wma
->lpWaveFormat
) {
70 WARN("Can't alloc WaveFormat\n");
74 mmioRead(wma
->hFile
, (LPSTR
)wma
->lpWaveFormat
, mmckInfo
.cksize
);
76 TRACE("waveFormat.wFormatTag=%d\n", wma
->lpWaveFormat
->wFormatTag
);
77 TRACE("waveFormat.nChannels=%d\n", wma
->lpWaveFormat
->nChannels
);
78 TRACE("waveFormat.nSamplesPerSec=%d\n", wma
->lpWaveFormat
->nSamplesPerSec
);
79 TRACE("waveFormat.nAvgBytesPerSec=%d\n", wma
->lpWaveFormat
->nAvgBytesPerSec
);
80 TRACE("waveFormat.nBlockAlign=%d\n", wma
->lpWaveFormat
->nBlockAlign
);
81 TRACE("waveFormat.wBitsPerSample=%d\n", wma
->lpWaveFormat
->wBitsPerSample
);
82 if (mmckInfo
.cksize
>= sizeof(WAVEFORMATEX
))
83 TRACE("waveFormat.cbSize=%d\n", wma
->lpWaveFormat
->cbSize
);
88 static BOOL
MCIAVI_GetInfoVideo(WINE_MCIAVI
* wma
, const MMCKINFO
* mmckList
, MMCKINFO
* mmckStream
)
92 TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma
->ash_video
.fccType
)),
93 HIBYTE(LOWORD(wma
->ash_video
.fccType
)),
94 LOBYTE(HIWORD(wma
->ash_video
.fccType
)),
95 HIBYTE(HIWORD(wma
->ash_video
.fccType
)));
96 TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma
->ash_video
.fccHandler
)),
97 HIBYTE(LOWORD(wma
->ash_video
.fccHandler
)),
98 LOBYTE(HIWORD(wma
->ash_video
.fccHandler
)),
99 HIBYTE(HIWORD(wma
->ash_video
.fccHandler
)));
100 TRACE("ash.dwFlags=%d\n", wma
->ash_video
.dwFlags
);
101 TRACE("ash.wPriority=%d\n", wma
->ash_video
.wPriority
);
102 TRACE("ash.wLanguage=%d\n", wma
->ash_video
.wLanguage
);
103 TRACE("ash.dwInitialFrames=%d\n", wma
->ash_video
.dwInitialFrames
);
104 TRACE("ash.dwScale=%d\n", wma
->ash_video
.dwScale
);
105 TRACE("ash.dwRate=%d\n", wma
->ash_video
.dwRate
);
106 TRACE("ash.dwStart=%d\n", wma
->ash_video
.dwStart
);
107 TRACE("ash.dwLength=%d\n", wma
->ash_video
.dwLength
);
108 TRACE("ash.dwSuggestedBufferSize=%d\n", wma
->ash_video
.dwSuggestedBufferSize
);
109 TRACE("ash.dwQuality=%d\n", wma
->ash_video
.dwQuality
);
110 TRACE("ash.dwSampleSize=%d\n", wma
->ash_video
.dwSampleSize
);
111 TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma
->ash_video
.rcFrame
.top
, wma
->ash_video
.rcFrame
.left
,
112 wma
->ash_video
.rcFrame
.bottom
, wma
->ash_video
.rcFrame
.right
);
114 /* rewind to the start of the stream */
115 mmioAscend(wma
->hFile
, mmckStream
, 0);
117 mmckInfo
.ckid
= ckidSTREAMFORMAT
;
118 if (mmioDescend(wma
->hFile
, &mmckInfo
, mmckList
, MMIO_FINDCHUNK
) != 0) {
119 WARN("Can't find 'strf' chunk\n");
123 wma
->inbih
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
125 WARN("Can't alloc input BIH\n");
129 mmioRead(wma
->hFile
, (LPSTR
)wma
->inbih
, mmckInfo
.cksize
);
131 TRACE("bih.biSize=%d\n", wma
->inbih
->biSize
);
132 TRACE("bih.biWidth=%d\n", wma
->inbih
->biWidth
);
133 TRACE("bih.biHeight=%d\n", wma
->inbih
->biHeight
);
134 TRACE("bih.biPlanes=%d\n", wma
->inbih
->biPlanes
);
135 TRACE("bih.biBitCount=%d\n", wma
->inbih
->biBitCount
);
136 TRACE("bih.biCompression=%x\n", wma
->inbih
->biCompression
);
137 TRACE("bih.biSizeImage=%d\n", wma
->inbih
->biSizeImage
);
138 TRACE("bih.biXPelsPerMeter=%d\n", wma
->inbih
->biXPelsPerMeter
);
139 TRACE("bih.biYPelsPerMeter=%d\n", wma
->inbih
->biYPelsPerMeter
);
140 TRACE("bih.biClrUsed=%d\n", wma
->inbih
->biClrUsed
);
141 TRACE("bih.biClrImportant=%d\n", wma
->inbih
->biClrImportant
);
143 wma
->source
.left
= 0;
145 wma
->source
.right
= wma
->inbih
->biWidth
;
146 wma
->source
.bottom
= wma
->inbih
->biHeight
;
148 wma
->dest
= wma
->source
;
153 struct AviListBuild
{
154 DWORD numVideoFrames
;
155 DWORD numAudioAllocated
;
156 DWORD numAudioBlocks
;
161 static BOOL
MCIAVI_AddFrame(WINE_MCIAVI
* wma
, LPMMCKINFO mmck
,
162 struct AviListBuild
* alb
)
168 if (mmck
->ckid
== ckidAVIPADDING
) return TRUE
;
170 p
= (const BYTE
*)&mmck
->ckid
;
172 if (!isxdigit(p
[0]) || !isxdigit(p
[1]))
174 WARN("wrongly encoded stream #\n");
178 stream_n
= (p
[0] <= '9') ? (p
[0] - '0') : (tolower(p
[0]) - 'a' + 10);
180 stream_n
|= (p
[1] <= '9') ? (p
[1] - '0') : (tolower(p
[1]) - 'a' + 10);
182 TRACE("ckid %4.4s (stream #%d)\n", (LPSTR
)&mmck
->ckid
, stream_n
);
184 /* Some (rare?) AVI files have video streams name XXYY where XX = stream number and YY = TWOCC
185 * of the last 2 characters of the biCompression member of the BITMAPINFOHEADER structure.
186 * Ex: fccHandler = IV32 & biCompression = IV32 => stream name = XX32
187 * fccHandler = MSVC & biCompression = CRAM => stream name = XXAM
188 * Another possibility is that these TWOCC are simply ignored.
189 * Default to cktypeDIBcompressed when this case happens.
191 twocc
= TWOCCFromFOURCC(mmck
->ckid
);
192 if (twocc
== TWOCCFromFOURCC(wma
->inbih
->biCompression
))
193 twocc
= cktypeDIBcompressed
;
194 /* Also detect some chunks that seem to be used by Indeo videos where the chunk is named
195 * after the codec. */
196 else if (twocc
== LOWORD(wma
->ash_video
.fccHandler
))
197 twocc
= cktypeDIBcompressed
;
200 case cktypeDIBcompressed
:
201 case cktypePALchange
:
202 if (stream_n
!= wma
->video_stream_n
)
204 TRACE("data belongs to another video stream #%d\n", stream_n
);
208 TRACE("Adding video frame[%d]: %d bytes\n",
209 alb
->numVideoFrames
, mmck
->cksize
);
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
++;
218 WARN("Too many video frames\n");
221 case cktypeWAVEbytes
:
222 if (stream_n
!= wma
->audio_stream_n
)
224 TRACE("data belongs to another audio stream #%d\n", stream_n
);
228 TRACE("Adding audio frame[%d]: %d 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
));
237 wma
->lpAudioIndex
= HeapReAlloc(GetProcessHeap(), 0, wma
->lpAudioIndex
,
238 alb
->numAudioAllocated
* sizeof(struct MMIOPos
));
239 if (!wma
->lpAudioIndex
) return FALSE
;
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
++;
247 WARN("Wave chunk without wave format... discarding\n");
251 WARN("Unknown frame type %4.4s\n", (LPSTR
)&mmck
->ckid
);
257 BOOL
MCIAVI_GetInfo(WINE_MCIAVI
* wma
)
263 AVIStreamHeader strh
;
264 struct AviListBuild alb
;
267 if (mmioDescend(wma
->hFile
, &ckMainRIFF
, NULL
, 0) != 0) {
268 WARN("Can't find 'RIFF' chunk\n");
272 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) || (ckMainRIFF
.fccType
!= formtypeAVI
)) {
273 WARN("Can't find 'AVI ' chunk\n");
277 mmckHead
.fccType
= listtypeAVIHEADER
;
278 if (mmioDescend(wma
->hFile
, &mmckHead
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
279 WARN("Can't find 'hdrl' list\n");
283 mmckInfo
.ckid
= ckidAVIMAINHDR
;
284 if (mmioDescend(wma
->hFile
, &mmckInfo
, &mmckHead
, MMIO_FINDCHUNK
) != 0) {
285 WARN("Can't find 'avih' chunk\n");
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
++)
312 mmckList
.fccType
= listtypeSTREAMHEADER
;
313 if (mmioDescend(wma
->hFile
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) != 0)
316 mmckStream
.ckid
= ckidSTREAMHEADER
;
317 if (mmioDescend(wma
->hFile
, &mmckStream
, &mmckList
, MMIO_FINDCHUNK
) != 0)
319 WARN("Can't find 'strh' chunk\n");
323 mmioRead(wma
->hFile
, (LPSTR
)&strh
, sizeof(strh
));
325 TRACE("Stream #%d fccType %4.4s\n", stream_n
, (LPSTR
)&strh
.fccType
);
327 if (strh
.fccType
== streamtypeVIDEO
)
329 TRACE("found video stream\n");
331 WARN("ignoring another video stream\n");
334 wma
->ash_video
= strh
;
336 if (!MCIAVI_GetInfoVideo(wma
, &mmckList
, &mmckStream
))
338 wma
->video_stream_n
= stream_n
;
342 else if (strh
.fccType
== streamtypeAUDIO
)
344 TRACE("found audio stream\n");
345 if (wma
->lpWaveFormat
)
346 WARN("ignoring another audio stream\n");
349 wma
->ash_audio
= strh
;
351 if (!MCIAVI_GetInfoAudio(wma
, &mmckList
, &mmckStream
))
353 wma
->audio_stream_n
= stream_n
;
358 TRACE("Unsupported stream type %4.4s\n", (LPSTR
)&strh
.fccType
);
360 mmioAscend(wma
->hFile
, &mmckList
, 0);
363 TRACE("End of streams\n");
365 mmioAscend(wma
->hFile
, &mmckHead
, 0);
367 /* no need to read optional JUNK chunk */
369 mmckList
.fccType
= listtypeAVIMOVIE
;
370 if (mmioDescend(wma
->hFile
, &mmckList
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
371 WARN("Can't find 'movi' list\n");
375 wma
->dwPlayableVideoFrames
= wma
->mah
.dwTotalFrames
;
376 wma
->lpVideoIndex
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
377 wma
->dwPlayableVideoFrames
* sizeof(struct MMIOPos
));
378 if (!wma
->lpVideoIndex
) {
379 WARN("Can't alloc video index array\n");
382 wma
->dwPlayableAudioBlocks
= 0;
383 wma
->lpAudioIndex
= NULL
;
385 alb
.numAudioBlocks
= alb
.numVideoFrames
= 0;
386 alb
.inVideoSize
= alb
.inAudioSize
= 0;
387 alb
.numAudioAllocated
= 0;
389 while (mmioDescend(wma
->hFile
, &mmckInfo
, &mmckList
, 0) == 0) {
390 if (mmckInfo
.fccType
== listtypeAVIRECORD
) {
393 while (mmioDescend(wma
->hFile
, &tmp
, &mmckInfo
, 0) == 0) {
394 MCIAVI_AddFrame(wma
, &tmp
, &alb
);
395 mmioAscend(wma
->hFile
, &tmp
, 0);
398 MCIAVI_AddFrame(wma
, &mmckInfo
, &alb
);
401 mmioAscend(wma
->hFile
, &mmckInfo
, 0);
403 if (alb
.numVideoFrames
!= wma
->dwPlayableVideoFrames
) {
404 WARN("AVI header says %d frames, we found %d video frames, reducing playable frames\n",
405 wma
->dwPlayableVideoFrames
, alb
.numVideoFrames
);
406 wma
->dwPlayableVideoFrames
= alb
.numVideoFrames
;
408 wma
->dwPlayableAudioBlocks
= alb
.numAudioBlocks
;
410 if (alb
.inVideoSize
> wma
->ash_video
.dwSuggestedBufferSize
) {
411 WARN("inVideoSize=%d suggestedSize=%d\n", alb
.inVideoSize
, wma
->ash_video
.dwSuggestedBufferSize
);
412 wma
->ash_video
.dwSuggestedBufferSize
= alb
.inVideoSize
;
414 if (alb
.inAudioSize
> wma
->ash_audio
.dwSuggestedBufferSize
) {
415 WARN("inAudioSize=%d suggestedSize=%d\n", alb
.inAudioSize
, wma
->ash_audio
.dwSuggestedBufferSize
);
416 wma
->ash_audio
.dwSuggestedBufferSize
= alb
.inAudioSize
;
419 wma
->indata
= HeapAlloc(GetProcessHeap(), 0, wma
->ash_video
.dwSuggestedBufferSize
);
421 WARN("Can't alloc input buffer\n");
428 BOOL
MCIAVI_OpenVideo(WINE_MCIAVI
* wma
)
432 FOURCC fcc
= wma
->ash_video
.fccHandler
;
434 TRACE("fcc %4.4s\n", (LPSTR
)&fcc
);
436 wma
->dwCachedFrame
= -1;
438 /* get the right handle */
439 if (fcc
== mmioFOURCC('C','R','A','M')) fcc
= mmioFOURCC('M','S','V','C');
441 /* try to get a decompressor for that type */
442 wma
->hic
= ICLocate(ICTYPE_VIDEO
, fcc
, wma
->inbih
, NULL
, ICMODE_DECOMPRESS
);
444 /* check for builtin DIB compressions */
445 fcc
= wma
->inbih
->biCompression
;
446 if ((fcc
== mmioFOURCC('D','I','B',' ')) ||
447 (fcc
== mmioFOURCC('R','L','E',' ')) ||
448 (fcc
== BI_RGB
) || (fcc
== BI_RLE8
) ||
449 (fcc
== BI_RLE4
) || (fcc
== BI_BITFIELDS
))
452 WARN("Can't locate codec for the file\n");
456 outSize
= sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
);
458 wma
->outbih
= HeapAlloc(GetProcessHeap(), 0, outSize
);
460 WARN("Can't alloc output BIH\n");
463 if (!ICGetDisplayFormat(wma
->hic
, wma
->inbih
, wma
->outbih
, 0, 0, 0)) {
464 WARN("Can't open decompressor\n");
468 TRACE("bih.biSize=%d\n", wma
->outbih
->biSize
);
469 TRACE("bih.biWidth=%d\n", wma
->outbih
->biWidth
);
470 TRACE("bih.biHeight=%d\n", wma
->outbih
->biHeight
);
471 TRACE("bih.biPlanes=%d\n", wma
->outbih
->biPlanes
);
472 TRACE("bih.biBitCount=%d\n", wma
->outbih
->biBitCount
);
473 TRACE("bih.biCompression=%x\n", wma
->outbih
->biCompression
);
474 TRACE("bih.biSizeImage=%d\n", wma
->outbih
->biSizeImage
);
475 TRACE("bih.biXPelsPerMeter=%d\n", wma
->outbih
->biXPelsPerMeter
);
476 TRACE("bih.biYPelsPerMeter=%d\n", wma
->outbih
->biYPelsPerMeter
);
477 TRACE("bih.biClrUsed=%d\n", wma
->outbih
->biClrUsed
);
478 TRACE("bih.biClrImportant=%d\n", wma
->outbih
->biClrImportant
);
480 wma
->outdata
= HeapAlloc(GetProcessHeap(), 0, wma
->outbih
->biSizeImage
);
482 WARN("Can't alloc output buffer\n");
486 if (ICSendMessage(wma
->hic
, ICM_DECOMPRESS_BEGIN
,
487 (DWORD_PTR
)wma
->inbih
, (DWORD_PTR
)wma
->outbih
) != ICERR_OK
) {
488 WARN("Can't begin decompression\n");
493 hDC
= wma
->hWndPaint
? GetDC(wma
->hWndPaint
) : 0;
496 MCIAVI_PaintFrame(wma
, hDC
);
497 ReleaseDC(wma
->hWndPaint
, hDC
);
502 static void CALLBACK
MCIAVI_waveCallback(HWAVEOUT hwo
, UINT uMsg
, DWORD_PTR dwInstance
,
503 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
505 WINE_MCIAVI
*wma
= MCIAVI_mciGetOpenDev(dwInstance
);
509 EnterCriticalSection(&wma
->cs
);
516 InterlockedIncrement(&wma
->dwEventCount
);
517 TRACE("Returning waveHdr=%lx\n", dwParam1
);
518 SetEvent(wma
->hEvent
);
521 ERR("Unknown uMsg=%d\n", uMsg
);
524 LeaveCriticalSection(&wma
->cs
);
527 DWORD
MCIAVI_OpenAudio(WINE_MCIAVI
* wma
, unsigned* nHdr
, LPWAVEHDR
* pWaveHdr
)
533 dwRet
= waveOutOpen((HWAVEOUT
*)&wma
->hWave
, WAVE_MAPPER
, wma
->lpWaveFormat
,
534 (DWORD_PTR
)MCIAVI_waveCallback
, wma
->wDevID
, CALLBACK_FUNCTION
);
536 TRACE("Can't open low level audio device %d\n", dwRet
);
537 dwRet
= MCIERR_DEVICE_OPEN
;
542 /* FIXME: should set up a heuristic to compute the number of wave headers
546 waveHdr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
547 *nHdr
* (sizeof(WAVEHDR
) + wma
->ash_audio
.dwSuggestedBufferSize
));
549 TRACE("Can't alloc wave headers\n");
550 dwRet
= MCIERR_DEVICE_OPEN
;
554 for (i
= 0; i
< *nHdr
; i
++) {
555 /* other fields are zero:ed on allocation */
556 waveHdr
[i
].lpData
= (char*)waveHdr
+
557 *nHdr
* sizeof(WAVEHDR
) + i
* wma
->ash_audio
.dwSuggestedBufferSize
;
558 waveHdr
[i
].dwBufferLength
= wma
->ash_audio
.dwSuggestedBufferSize
;
559 if (waveOutPrepareHeader(wma
->hWave
, &waveHdr
[i
], sizeof(WAVEHDR
))) {
560 dwRet
= MCIERR_INTERNAL
;
565 if (wma
->dwCurrVideoFrame
!= 0 && wma
->lpWaveFormat
) {
566 FIXME("Should recompute dwCurrAudioBlock, except unsynchronized sound & video\n");
568 wma
->dwCurrAudioBlock
= 0;
570 wma
->hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
571 wma
->dwEventCount
= *nHdr
- 1;
577 void MCIAVI_PlayAudioBlocks(WINE_MCIAVI
* wma
, unsigned nHdr
, LPWAVEHDR waveHdr
)
579 if (!wma
->lpAudioIndex
)
581 TRACE("%d (ec=%u)\n", wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwOffset
, wma
->dwEventCount
);
583 /* push as many blocks as possible => audio gets priority */
584 while (wma
->dwStatus
!= MCI_MODE_STOP
&& wma
->dwStatus
!= MCI_MODE_NOT_READY
&&
585 wma
->dwCurrAudioBlock
< wma
->dwPlayableAudioBlocks
) {
586 unsigned whidx
= wma
->dwCurrAudioBlock
% nHdr
;
588 ResetEvent(wma
->hEvent
);
589 if (InterlockedDecrement(&wma
->dwEventCount
) < 0 ||
590 !wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwOffset
)
592 InterlockedIncrement(&wma
->dwEventCount
);
596 mmioSeek(wma
->hFile
, wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwOffset
, SEEK_SET
);
597 mmioRead(wma
->hFile
, waveHdr
[whidx
].lpData
, wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwSize
);
599 waveHdr
[whidx
].dwFlags
&= ~WHDR_DONE
;
600 waveHdr
[whidx
].dwBufferLength
= wma
->lpAudioIndex
[wma
->dwCurrAudioBlock
].dwSize
;
601 waveOutWrite(wma
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
602 wma
->dwCurrAudioBlock
++;
606 double MCIAVI_PaintFrame(WINE_MCIAVI
* wma
, HDC hDC
)
609 LPBITMAPINFO pBitmapInfo
;
611 if (!hDC
|| !wma
->inbih
)
614 TRACE("Painting frame %u (cached %u)\n", wma
->dwCurrVideoFrame
, wma
->dwCachedFrame
);
616 if (wma
->dwCurrVideoFrame
!= wma
->dwCachedFrame
)
618 if (!wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwOffset
)
621 if (wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwSize
)
623 mmioSeek(wma
->hFile
, wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwOffset
, SEEK_SET
);
624 mmioRead(wma
->hFile
, wma
->indata
, wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwSize
);
626 wma
->inbih
->biSizeImage
= wma
->lpVideoIndex
[wma
->dwCurrVideoFrame
].dwSize
;
628 if (wma
->hic
&& ICDecompress(wma
->hic
, 0, wma
->inbih
, wma
->indata
,
629 wma
->outbih
, wma
->outdata
) != ICERR_OK
)
631 WARN("Decompression error\n");
636 wma
->dwCachedFrame
= wma
->dwCurrVideoFrame
;
640 pBitmapData
= wma
->outdata
;
641 pBitmapInfo
= (LPBITMAPINFO
)wma
->outbih
;
643 pBitmapData
= wma
->indata
;
644 pBitmapInfo
= (LPBITMAPINFO
)wma
->inbih
;
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 (wma
->ash_video
.dwScale
/ (double)wma
->ash_video
.dwRate
) * 1000000;