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=%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
));
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");
58 if (mmckInfo
.cksize
< sizeof(WAVEFORMAT
)) {
59 WARN("Size of strf chunk (%ld) < audio format struct\n", mmckInfo
.cksize
);
62 wma
->lpWaveFormat
= malloc(mmckInfo
.cksize
);
63 if (!wma
->lpWaveFormat
) {
64 WARN("Can't alloc WaveFormat\n");
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
);
82 static BOOL
MCIAVI_GetInfoVideo(WINE_MCIAVI
* wma
, const MMCKINFO
* mmckList
, MMCKINFO
* mmckStream
)
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");
111 wma
->inbih
= malloc(mmckInfo
.cksize
);
113 WARN("Can't alloc input BIH\n");
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
;
137 struct AviListBuild
{
138 DWORD numVideoFrames
;
139 DWORD numAudioAllocated
;
140 DWORD numAudioBlocks
;
145 static BOOL
MCIAVI_AddFrame(WINE_MCIAVI
* wma
, LPMMCKINFO mmck
,
146 struct AviListBuild
* alb
)
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");
162 stream_n
= (p
[0] <= '9') ? (p
[0] - '0') : (tolower(p
[0]) - 'a' + 10);
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
;
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
);
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
++;
202 WARN("Too many video frames\n");
205 case cktypeWAVEbytes
:
206 if (stream_n
!= wma
->audio_stream_n
)
208 TRACE("data belongs to another audio stream #%ld\n", stream_n
);
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
++;
230 WARN("Wave chunk without wave format... discarding\n");
234 WARN("Unknown frame type %4.4s\n", (LPSTR
)&mmck
->ckid
);
240 BOOL
MCIAVI_GetInfo(WINE_MCIAVI
* wma
)
246 AVIStreamHeader strh
;
247 struct AviListBuild alb
;
250 if (mmioDescend(wma
->hFile
, &ckMainRIFF
, NULL
, 0) != 0) {
251 WARN("Can't find 'RIFF' chunk\n");
255 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) || (ckMainRIFF
.fccType
!= formtypeAVI
)) {
256 WARN("Can't find 'AVI ' chunk\n");
260 mmckHead
.fccType
= listtypeAVIHEADER
;
261 if (mmioDescend(wma
->hFile
, &mmckHead
, &ckMainRIFF
, MMIO_FINDLIST
) != 0) {
262 WARN("Can't find 'hdrl' list\n");
266 mmckInfo
.ckid
= ckidAVIMAINHDR
;
267 if (mmioDescend(wma
->hFile
, &mmckInfo
, &mmckHead
, MMIO_FINDCHUNK
) != 0) {
268 WARN("Can't find 'avih' chunk\n");
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
++)
295 mmckList
.fccType
= listtypeSTREAMHEADER
;
296 if (mmioDescend(wma
->hFile
, &mmckList
, &mmckHead
, MMIO_FINDLIST
) != 0)
299 mmckStream
.ckid
= ckidSTREAMHEADER
;
300 if (mmioDescend(wma
->hFile
, &mmckStream
, &mmckList
, MMIO_FINDCHUNK
) != 0)
302 WARN("Can't find 'strh' chunk\n");
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");
314 WARN("ignoring another video stream\n");
317 wma
->ash_video
= strh
;
319 if (!MCIAVI_GetInfoVideo(wma
, &mmckList
, &mmckStream
))
321 wma
->video_stream_n
= stream_n
;
325 else if (strh
.fccType
== streamtypeAUDIO
)
327 TRACE("found audio stream\n");
328 if (wma
->lpWaveFormat
)
329 WARN("ignoring another audio stream\n");
332 wma
->ash_audio
= strh
;
334 if (!MCIAVI_GetInfoAudio(wma
, &mmckList
, &mmckStream
))
336 wma
->audio_stream_n
= stream_n
;
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");
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");
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
) {
375 while (mmioDescend(wma
->hFile
, &tmp
, &mmckInfo
, 0) == 0) {
376 MCIAVI_AddFrame(wma
, &tmp
, &alb
);
377 mmioAscend(wma
->hFile
, &tmp
, 0);
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
);
403 WARN("Can't alloc input buffer\n");
410 BOOL
MCIAVI_OpenVideo(WINE_MCIAVI
* wma
)
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
);
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
))
434 WARN("Can't locate codec for the file\n");
438 outSize
= sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
);
440 wma
->outbih
= malloc(outSize
);
442 WARN("Can't alloc output BIH\n");
445 if (!ICGetDisplayFormat(wma
->hic
, wma
->inbih
, wma
->outbih
, 0, 0, 0)) {
446 WARN("Can't open decompressor\n");
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
);
464 WARN("Can't alloc output buffer\n");
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");
475 hDC
= wma
->hWndPaint
? GetDC(wma
->hWndPaint
) : 0;
478 MCIAVI_PaintFrame(wma
, hDC
);
479 ReleaseDC(wma
->hWndPaint
, hDC
);
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
);
491 EnterCriticalSection(&wma
->cs
);
498 InterlockedIncrement(&wma
->dwEventCount
);
499 TRACE("Returning waveHdr=%Ix\n", dwParam1
);
500 SetEvent(wma
->hEvent
);
503 ERR("Unknown uMsg=%d\n", uMsg
);
506 LeaveCriticalSection(&wma
->cs
);
509 DWORD
MCIAVI_OpenAudio(WINE_MCIAVI
* wma
, unsigned* nHdr
, LPWAVEHDR
* pWaveHdr
)
515 dwRet
= waveOutOpen((HWAVEOUT
*)&wma
->hWave
, WAVE_MAPPER
, wma
->lpWaveFormat
,
516 (DWORD_PTR
)MCIAVI_waveCallback
, wma
->wDevID
, CALLBACK_FUNCTION
);
518 TRACE("Can't open low level audio device %ld\n", dwRet
);
519 dwRet
= MCIERR_DEVICE_OPEN
;
524 /* FIXME: should set up a heuristic to compute the number of wave headers
528 waveHdr
= calloc(*nHdr
, sizeof(WAVEHDR
) + wma
->ash_audio
.dwSuggestedBufferSize
);
530 TRACE("Can't alloc wave headers\n");
531 dwRet
= MCIERR_DEVICE_OPEN
;
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
;
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;
558 void MCIAVI_PlayAudioBlocks(WINE_MCIAVI
* wma
, unsigned nHdr
, LPWAVEHDR waveHdr
)
560 if (!wma
->lpAudioIndex
)
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
);
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
)
590 LPBITMAPINFO pBitmapInfo
;
592 if (!hDC
|| !wma
->inbih
)
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
)
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");
617 wma
->dwCachedFrame
= wma
->dwCurrVideoFrame
;
621 pBitmapData
= wma
->outdata
;
622 pBitmapInfo
= (LPBITMAPINFO
)wma
->outbih
;
624 pBitmapData
= wma
->indata
;
625 pBitmapInfo
= (LPBITMAPINFO
)wma
->inbih
;
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;