Fix direct sound capabilities to match hardware.
[wine] / dlls / winmm / mciavi / mciavi.c
1
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 /* TODO list :
25  *      - handling of palettes
26  *      - recording (which input devices ?), a cam recorder ?
27  *      - lots of messages still need to be handled (cf FIXME)
28  *      - synchronization between audio and video (especially for interleaved
29  *        files)
30  *      - robustness when reading file can be enhanced
31  *      - better move the AVI handling part to avifile DLL and make use of it
32  *      - some files appear to have more than one audio stream (we only play the
33  *        first one)
34  *      - some files contain an index of audio/video frame. Better use it,
35  *        instead of rebuilding it
36  *      - stopping while playing a file with sound blocks until all buffered
37  *        audio is played... still should be stopped ASAP
38  */
39
40 #include <string.h>
41 #include "private_mciavi.h"
42 #include "wine/debug.h"
43 #include "wine/unicode.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
46
47 static DWORD MCIAVI_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
48
49 /* ===================================================================
50  * ===================================================================
51  * FIXME: should be using the new mmThreadXXXX functions from WINMM
52  * instead of those
53  * it would require to add a wine internal flag to mmThreadCreate
54  * in order to pass a 32 bit function instead of a 16 bit one
55  * ===================================================================
56  * =================================================================== */
57
58 struct SCA {
59     MCIDEVICEID wDevID;
60     UINT        wMsg;
61     DWORD_PTR   dwParam1;
62     DWORD_PTR   dwParam2;
63 };
64
65 /**************************************************************************
66  *                              MCI_SCAStarter                  [internal]
67  */
68 static DWORD CALLBACK   MCI_SCAStarter(LPVOID arg)
69 {
70     struct SCA* sca = (struct SCA*)arg;
71     DWORD       ret;
72
73     TRACE("In thread before async command (%08x,%04x,%08lx,%08lx)\n",
74           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
75     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
76     TRACE("In thread after async command (%08x,%04x,%08lx,%08lx)\n",
77           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
78     HeapFree(GetProcessHeap(), 0, sca);
79     return ret;
80 }
81
82 /**************************************************************************
83  *                              MCI_SendCommandAsync            [internal]
84  */
85 static  DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
86                                   DWORD_PTR dwParam2, UINT size)
87 {
88     HANDLE handle;
89     struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
90
91     if (sca == 0)
92         return MCIERR_OUT_OF_MEMORY;
93
94     sca->wDevID   = wDevID;
95     sca->wMsg     = wMsg;
96     sca->dwParam1 = dwParam1;
97
98     if (size && dwParam2) {
99        sca->dwParam2 = (DWORD_PTR)sca + sizeof(struct SCA);
100         /* copy structure passed by program in dwParam2 to be sure
101          * we can still use it whatever the program does
102          */
103         memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
104     } else {
105         sca->dwParam2 = dwParam2;
106     }
107
108     if ((handle = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
109         WARN("Couldn't allocate thread for async command handling, sending synchronously\n");
110         return MCI_SCAStarter(&sca);
111     }
112     CloseHandle(handle);
113     return 0;
114 }
115
116 /*======================================================================*
117  *                          MCI AVI implemantation                      *
118  *======================================================================*/
119
120 HINSTANCE MCIAVI_hInstance = 0;
121
122 /***********************************************************************
123  *              DllMain (MCIAVI.0)
124  */
125 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
126 {
127     switch (fdwReason) {
128     case DLL_PROCESS_ATTACH:
129         DisableThreadLibraryCalls(hInstDLL);
130         MCIAVI_hInstance = hInstDLL;
131         break;
132     }
133     return TRUE;
134 }
135
136 /**************************************************************************
137  *                              MCIAVI_drvOpen                  [internal]
138  */
139 static  DWORD   MCIAVI_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
140 {
141     WINE_MCIAVI*        wma;
142     static const WCHAR mciAviWStr[] = {'M','C','I','A','V','I',0};
143
144     TRACE("%s, %p\n", debugstr_w(str), modp);
145
146     /* session instance */
147     if (!modp) return 0xFFFFFFFF;
148
149     if (!MCIAVI_RegisterClass()) return 0;
150
151     wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIAVI));
152     if (!wma)
153         return 0;
154
155     InitializeCriticalSection(&wma->cs);
156     wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
157     wma->wDevID = modp->wDeviceID;
158     wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
159     modp->wCustomCommandTable = wma->wCommandTable;
160     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
161     mciSetDriverData(wma->wDevID, (DWORD)wma);
162
163     return modp->wDeviceID;
164 }
165
166 /**************************************************************************
167  *                              MCIAVI_drvClose         [internal]
168  */
169 static  DWORD   MCIAVI_drvClose(DWORD dwDevID)
170 {
171     WINE_MCIAVI *wma;
172
173     TRACE("%04lx\n", dwDevID);
174
175     /* finish all outstanding things */
176     MCIAVI_mciClose(dwDevID, MCI_WAIT, NULL);
177
178     wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
179
180     if (wma) {
181         MCIAVI_UnregisterClass();
182
183         EnterCriticalSection(&wma->cs);
184
185         mciSetDriverData(dwDevID, 0);
186         mciFreeCommandResource(wma->wCommandTable);
187
188         CloseHandle(wma->hStopEvent);
189
190         LeaveCriticalSection(&wma->cs);
191         DeleteCriticalSection(&wma->cs);
192
193         HeapFree(GetProcessHeap(), 0, wma);
194         return 1;
195     }
196     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
197 }
198
199 /**************************************************************************
200  *                              MCIAVI_drvConfigure             [internal]
201  */
202 static  DWORD   MCIAVI_drvConfigure(DWORD dwDevID)
203 {
204     WINE_MCIAVI *wma;
205
206     TRACE("%04lx\n", dwDevID);
207
208     MCIAVI_mciStop(dwDevID, MCI_WAIT, NULL);
209
210     wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
211
212     if (wma) {
213         MessageBoxA(0, "Sample AVI Wine Driver !", "MM-Wine Driver", MB_OK);
214         return 1;
215     }
216     return 0;
217 }
218
219 /**************************************************************************
220  *                              MCIAVI_mciGetOpenDev            [internal]
221  */
222 WINE_MCIAVI*  MCIAVI_mciGetOpenDev(UINT wDevID)
223 {
224     WINE_MCIAVI*        wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
225
226     if (wma == NULL || wma->nUseCount == 0) {
227         WARN("Invalid wDevID=%u\n", wDevID);
228         return 0;
229     }
230     return wma;
231 }
232
233 static void MCIAVI_CleanUp(WINE_MCIAVI* wma)
234 {
235     /* to prevent handling in WindowProc */
236     wma->dwStatus = MCI_MODE_NOT_READY;
237     if (wma->hFile) {
238         mmioClose(wma->hFile, 0);
239         wma->hFile = 0;
240
241         HeapFree(GetProcessHeap(), 0, wma->lpFileName);
242         wma->lpFileName = NULL;
243
244         HeapFree(GetProcessHeap(), 0, wma->lpVideoIndex);
245         wma->lpVideoIndex = NULL;
246         HeapFree(GetProcessHeap(), 0, wma->lpAudioIndex);
247         wma->lpAudioIndex = NULL;
248         if (wma->hic)           ICClose(wma->hic);
249         wma->hic = 0;
250         HeapFree(GetProcessHeap(), 0, wma->inbih);
251         wma->inbih = NULL;
252         HeapFree(GetProcessHeap(), 0, wma->outbih);
253         wma->outbih = NULL;
254         HeapFree(GetProcessHeap(), 0, wma->indata);
255         wma->indata = NULL;
256         HeapFree(GetProcessHeap(), 0, wma->outdata);
257         wma->outdata = NULL;
258         if (wma->hbmFrame)      DeleteObject(wma->hbmFrame);
259         wma->hbmFrame = 0;
260         if (wma->hWnd)          DestroyWindow(wma->hWnd);
261         wma->hWnd = 0;
262
263         HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
264         wma->lpWaveFormat = 0;
265
266         memset(&wma->mah, 0, sizeof(wma->mah));
267         memset(&wma->ash_video, 0, sizeof(wma->ash_video));
268         memset(&wma->ash_audio, 0, sizeof(wma->ash_audio));
269         wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
270         wma->dwCachedFrame = -1;
271     }
272 }
273
274 /***************************************************************************
275  *                              MCIAVI_mciOpen                  [internal]
276  */
277 static  DWORD   MCIAVI_mciOpen(UINT wDevID, DWORD dwFlags,
278                                LPMCI_DGV_OPEN_PARMSW lpOpenParms)
279 {
280     WINE_MCIAVI *wma;
281     LRESULT             dwRet = 0;
282
283     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
284
285     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
286
287     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
288
289     wma = (WINE_MCIAVI *)mciGetDriverData(wDevID);
290     if (wma == NULL)                    return MCIERR_INVALID_DEVICE_ID;
291
292     EnterCriticalSection(&wma->cs);
293
294     if (wma->nUseCount > 0) {
295         /* The driver is already open on this channel */
296         /* If the driver was opened shareable before and this open specifies */
297         /* shareable then increment the use count */
298         if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
299             ++wma->nUseCount;
300         else
301         {
302             LeaveCriticalSection(&wma->cs);
303             return MCIERR_MUST_USE_SHAREABLE;
304         }
305     } else {
306         wma->nUseCount = 1;
307         wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
308     }
309
310     wma->dwStatus = MCI_MODE_NOT_READY;
311
312     if (dwFlags & MCI_OPEN_ELEMENT) {
313         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
314             /* could it be that (DWORD)lpOpenParms->lpstrElementName
315              * contains the hFile value ?
316              */
317             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
318         } else if (strlenW(lpOpenParms->lpstrElementName) > 0) {
319             /* FIXME : what should be done id wma->hFile is already != 0, or the driver is playin' */
320             TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(lpOpenParms->lpstrElementName));
321
322             if (lpOpenParms->lpstrElementName && (strlenW(lpOpenParms->lpstrElementName) > 0))
323             {
324                 wma->lpFileName = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpOpenParms->lpstrElementName) + 1) * sizeof(WCHAR));
325                 strcpyW(wma->lpFileName, lpOpenParms->lpstrElementName);
326
327                 wma->hFile = mmioOpenW(lpOpenParms->lpstrElementName, NULL,
328                                        MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
329
330                 if (wma->hFile == 0) {
331                     WARN("can't find file=%s!\n", debugstr_w(lpOpenParms->lpstrElementName));
332                     dwRet = MCIERR_FILE_NOT_FOUND;
333                 } else {
334                     if (!MCIAVI_GetInfo(wma))
335                         dwRet = MCIERR_INVALID_FILE;
336                     else if (!MCIAVI_OpenVideo(wma))
337                         dwRet = MCIERR_CANNOT_LOAD_DRIVER;
338                     else if (!MCIAVI_CreateWindow(wma, dwFlags, lpOpenParms))
339                         dwRet = MCIERR_CREATEWINDOW;
340                 }
341             }
342         } else {
343             FIXME("Don't record yet\n");
344             dwRet = MCIERR_UNSUPPORTED_FUNCTION;
345         }
346     }
347
348     if (dwRet == 0) {
349         TRACE("lpOpenParms->wDeviceID = %04x\n", lpOpenParms->wDeviceID);
350
351         wma->dwStatus = MCI_MODE_STOP;
352         wma->dwMciTimeFormat = MCI_FORMAT_FRAMES;
353     } else {
354         MCIAVI_CleanUp(wma);
355     }
356
357     LeaveCriticalSection(&wma->cs);
358     return dwRet;
359 }
360
361 /***************************************************************************
362  *                              MCIAVI_mciClose                 [internal]
363  */
364 DWORD MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
365 {
366     WINE_MCIAVI *wma;
367     DWORD               dwRet = 0;
368
369     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
370
371     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
372
373     wma = (WINE_MCIAVI *)MCIAVI_mciGetOpenDev(wDevID);
374     if (wma == NULL)    return MCIERR_INVALID_DEVICE_ID;
375
376     EnterCriticalSection(&wma->cs);
377
378     if (wma->nUseCount == 1) {
379         if (wma->dwStatus != MCI_MODE_STOP)
380            dwRet = MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
381         MCIAVI_CleanUp(wma);
382
383         if ((dwFlags & MCI_NOTIFY) && lpParms) {
384             mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
385                            wDevID,
386                             MCI_NOTIFY_SUCCESSFUL);
387         }
388         LeaveCriticalSection(&wma->cs);
389         return dwRet;
390     }
391     wma->nUseCount--;
392
393     LeaveCriticalSection(&wma->cs);
394     return dwRet;
395 }
396
397 /***************************************************************************
398  *                              MCIAVI_mciPlay                  [internal]
399  */
400 static  DWORD   MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
401 {
402     WINE_MCIAVI *wma;
403     DWORD               tc;
404     DWORD               frameTime;
405     DWORD               delta;
406     DWORD               dwRet;
407     LPWAVEHDR           waveHdr = NULL;
408     unsigned            i, nHdr = 0;
409     DWORD               dwFromFrame, dwToFrame;
410
411     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
412
413     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
414
415     wma = (WINE_MCIAVI *)MCIAVI_mciGetOpenDev(wDevID);
416     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
417
418     EnterCriticalSection(&wma->cs);
419
420     if (!wma->hFile)
421     {
422         LeaveCriticalSection(&wma->cs);
423         return MCIERR_FILE_NOT_FOUND;
424     }
425     if (!wma->hWndPaint)
426     {
427         LeaveCriticalSection(&wma->cs);
428         return MCIERR_NO_WINDOW;
429     }
430
431     LeaveCriticalSection(&wma->cs);
432
433     if (!(dwFlags & MCI_WAIT)) {
434        return MCI_SendCommandAsync(wDevID, MCI_PLAY, dwFlags,
435                                    (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS));
436     }
437
438     if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
439         ShowWindow(wma->hWndPaint, SW_SHOWNA);
440
441     EnterCriticalSection(&wma->cs);
442
443     dwFromFrame = wma->dwCurrVideoFrame;
444     dwToFrame = wma->dwPlayableVideoFrames - 1;
445
446     if (lpParms && (dwFlags & MCI_FROM)) {
447         dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
448     }
449     if (lpParms && (dwFlags & MCI_TO)) {
450         dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
451     }
452     if (dwToFrame >= wma->dwPlayableVideoFrames)
453         dwToFrame = wma->dwPlayableVideoFrames - 1;
454
455     TRACE("Playing from frame=%lu to frame=%lu\n", dwFromFrame, dwToFrame);
456
457     wma->dwCurrVideoFrame = dwFromFrame;
458     wma->dwToVideoFrame = dwToFrame;
459
460     /* if already playing exit */
461     if (wma->dwStatus == MCI_MODE_PLAY)
462     {
463         LeaveCriticalSection(&wma->cs);
464         return 0;
465     }
466
467     if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
468     {
469         dwRet = 0;
470         goto mci_play_done;
471     }
472
473     wma->dwStatus = MCI_MODE_PLAY;
474
475     if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_DGV_PLAY_REVERSE|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
476         FIXME("Unsupported flag %08lx\n", dwFlags);
477
478     /* time is in microseconds, we should convert it to milliseconds */
479     frameTime = (wma->mah.dwMicroSecPerFrame + 500) / 1000;
480
481     if (wma->lpWaveFormat) {
482        if (MCIAVI_OpenAudio(wma, &nHdr, &waveHdr) != 0)
483         {
484             /* can't play audio */
485             HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
486             wma->lpWaveFormat = NULL;
487         }
488         else
489         /* fill the queue with as many wave headers as possible */
490         MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
491     }
492
493     while (wma->dwStatus == MCI_MODE_PLAY)
494     {
495         HDC hDC;
496
497         tc = GetTickCount();
498
499         hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
500         if (hDC)
501         {
502             MCIAVI_PaintFrame(wma, hDC);
503             ReleaseDC(wma->hWndPaint, hDC);
504         }
505
506         if (wma->lpWaveFormat) {
507             HANDLE events[2];
508             DWORD ret;
509
510             events[0] = wma->hStopEvent;
511             events[1] = wma->hEvent;
512
513             MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
514             delta = GetTickCount() - tc;
515
516             LeaveCriticalSection(&wma->cs);
517             ret = MsgWaitForMultipleObjectsEx(2, events,
518                 (delta >= frameTime) ? 0 : frameTime - delta, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
519             EnterCriticalSection(&wma->cs);
520
521             if (ret == WAIT_OBJECT_0 || wma->dwStatus != MCI_MODE_PLAY) break;
522         }
523
524         delta = GetTickCount() - tc;
525         if (delta < frameTime)
526         {
527             DWORD ret;
528
529             LeaveCriticalSection(&wma->cs);
530             ret = MsgWaitForMultipleObjectsEx(1, &wma->hStopEvent, frameTime - delta,
531                                               QS_ALLINPUT, MWMO_INPUTAVAILABLE);
532             EnterCriticalSection(&wma->cs);
533             if (ret == WAIT_OBJECT_0) break;
534         }
535
536        if (wma->dwCurrVideoFrame < dwToFrame)
537            wma->dwCurrVideoFrame++;
538         else
539             break;
540     }
541
542     if (wma->lpWaveFormat) {
543        while (wma->dwEventCount != nHdr - 1)
544         {
545             LeaveCriticalSection(&wma->cs);
546             Sleep(100);
547             EnterCriticalSection(&wma->cs);
548         }
549
550         /* just to get rid of some race conditions between play, stop and pause */
551         LeaveCriticalSection(&wma->cs);
552         waveOutReset(wma->hWave);
553         EnterCriticalSection(&wma->cs);
554
555         for (i = 0; i < nHdr; i++)
556             waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
557     }
558
559     dwRet = 0;
560
561     if (wma->lpWaveFormat) {
562         HeapFree(GetProcessHeap(), 0, waveHdr);
563
564         if (wma->hWave) {
565             LeaveCriticalSection(&wma->cs);
566             waveOutClose(wma->hWave);
567             EnterCriticalSection(&wma->cs);
568             wma->hWave = 0;
569         }
570         CloseHandle(wma->hEvent);
571     }
572
573 mci_play_done:
574     wma->dwStatus = MCI_MODE_STOP;
575
576     if (lpParms && (dwFlags & MCI_NOTIFY)) {
577         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
578         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
579                        wDevID, MCI_NOTIFY_SUCCESSFUL);
580     }
581     LeaveCriticalSection(&wma->cs);
582     return dwRet;
583 }
584
585 /***************************************************************************
586  *                              MCIAVI_mciRecord                        [internal]
587  */
588 static  DWORD   MCIAVI_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECORD_PARMS lpParms)
589 {
590     WINE_MCIAVI *wma;
591
592     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
593
594     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
595
596     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
597
598     wma = MCIAVI_mciGetOpenDev(wDevID);
599     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
600
601     EnterCriticalSection(&wma->cs);
602     wma->dwStatus = MCI_MODE_RECORD;
603     LeaveCriticalSection(&wma->cs);
604     return 0;
605 }
606
607 /***************************************************************************
608  *                              MCIAVI_mciStop                  [internal]
609  */
610 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
611 {
612     WINE_MCIAVI *wma;
613     DWORD               dwRet = 0;
614
615     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
616
617     wma = MCIAVI_mciGetOpenDev(wDevID);
618     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
619
620     EnterCriticalSection(&wma->cs);
621
622     switch (wma->dwStatus) {
623     case MCI_MODE_PLAY:
624     case MCI_MODE_RECORD:
625         LeaveCriticalSection(&wma->cs);
626         SetEvent(wma->hStopEvent);
627         EnterCriticalSection(&wma->cs);
628         /* fall through */
629     case MCI_MODE_PAUSE:
630         /* Since our wave notification callback takes the lock,
631          * we must release it before resetting the device */
632         LeaveCriticalSection(&wma->cs);
633         dwRet = waveOutReset(wma->hWave);
634         EnterCriticalSection(&wma->cs);
635         /* fall through */
636     default:
637         do /* one more chance for an async thread to finish */
638         {
639             LeaveCriticalSection(&wma->cs);
640             Sleep(10);
641             EnterCriticalSection(&wma->cs);
642         } while (wma->dwStatus != MCI_MODE_STOP);
643
644         break;
645
646     case MCI_MODE_NOT_READY:
647         break;        
648     }
649
650     if ((dwFlags & MCI_NOTIFY) && lpParms) {
651         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
652                        wDevID, MCI_NOTIFY_SUCCESSFUL);
653     }
654     LeaveCriticalSection(&wma->cs);
655     return dwRet;
656 }
657
658 /***************************************************************************
659  *                              MCIAVI_mciPause                 [internal]
660  */
661 static  DWORD   MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
662 {
663     WINE_MCIAVI *wma;
664
665     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
666
667     wma = MCIAVI_mciGetOpenDev(wDevID);
668     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
669
670     EnterCriticalSection(&wma->cs);
671
672     if (wma->dwStatus == MCI_MODE_PLAY)
673         wma->dwStatus = MCI_MODE_PAUSE;
674
675     if (wma->lpWaveFormat) {
676         LeaveCriticalSection(&wma->cs);
677         return waveOutPause(wma->hWave);
678     }
679
680     LeaveCriticalSection(&wma->cs);
681     return 0;
682 }
683
684 /***************************************************************************
685  *                              MCIAVI_mciResume                        [internal]
686  */
687 static  DWORD   MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
688 {
689     WINE_MCIAVI *wma;
690
691     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
692
693     wma = MCIAVI_mciGetOpenDev(wDevID);
694     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
695
696     EnterCriticalSection(&wma->cs);
697
698     if (wma->dwStatus == MCI_MODE_PAUSE)
699         wma->dwStatus = MCI_MODE_PLAY;
700
701     if (wma->lpWaveFormat) {
702         LeaveCriticalSection(&wma->cs);
703         return waveOutRestart(wma->hWave);
704     }
705
706     LeaveCriticalSection(&wma->cs);
707     return 0;
708 }
709
710 /***************************************************************************
711  *                              MCIAVI_mciSeek                  [internal]
712  */
713 static  DWORD   MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
714 {
715     WINE_MCIAVI *wma;
716
717     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
718
719     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
720
721     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
722
723     wma = MCIAVI_mciGetOpenDev(wDevID);
724     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
725
726     EnterCriticalSection(&wma->cs);
727
728     if (dwFlags & MCI_SEEK_TO_START) {
729         wma->dwCurrVideoFrame = 0;
730     } else if (dwFlags & MCI_SEEK_TO_END) {
731         wma->dwCurrVideoFrame = wma->dwPlayableVideoFrames - 1;
732     } else if (dwFlags & MCI_TO) {
733         if (lpParms->dwTo > wma->dwPlayableVideoFrames - 1)
734             lpParms->dwTo = wma->dwPlayableVideoFrames - 1;
735         wma->dwCurrVideoFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
736     } else {
737         WARN("dwFlag doesn't tell where to seek to...\n");
738         LeaveCriticalSection(&wma->cs);
739         return MCIERR_MISSING_PARAMETER;
740     }
741
742     TRACE("Seeking to frame=%lu bytes\n", wma->dwCurrVideoFrame);
743
744     if (dwFlags & MCI_NOTIFY) {
745         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
746                        wDevID, MCI_NOTIFY_SUCCESSFUL);
747     }
748     LeaveCriticalSection(&wma->cs);
749     return 0;
750 }
751
752 /*****************************************************************************
753  *                              MCIAVI_mciLoad                  [internal]
754  */
755 static DWORD    MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSW lpParms)
756 {
757     WINE_MCIAVI *wma;
758
759     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
760
761     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
762
763     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
764
765     wma = MCIAVI_mciGetOpenDev(wDevID);
766     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
767
768     return 0;
769 }
770
771 /******************************************************************************
772  *                              MCIAVI_mciSave                  [internal]
773  */
774 static  DWORD   MCIAVI_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SAVE_PARMSW lpParms)
775 {
776     WINE_MCIAVI *wma;
777
778     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
779
780     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
781
782     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
783
784     wma = MCIAVI_mciGetOpenDev(wDevID);
785     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
786
787     return 0;
788 }
789
790 /******************************************************************************
791  *                              MCIAVI_mciFreeze                        [internal]
792  */
793 static  DWORD   MCIAVI_mciFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
794 {
795     WINE_MCIAVI *wma;
796
797     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
798
799     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
800
801     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
802
803     wma = MCIAVI_mciGetOpenDev(wDevID);
804     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
805
806     return 0;
807 }
808
809 /******************************************************************************
810  *                              MCIAVI_mciRealize                       [internal]
811  */
812 static  DWORD   MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
813 {
814     WINE_MCIAVI *wma;
815
816     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
817
818     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
819
820     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
821
822     wma = MCIAVI_mciGetOpenDev(wDevID);
823     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
824
825     return 0;
826 }
827
828 /******************************************************************************
829  *                              MCIAVI_mciUnFreeze                      [internal]
830  */
831 static  DWORD   MCIAVI_mciUnFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
832 {
833     WINE_MCIAVI *wma;
834
835     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
836
837     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
838
839     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
840
841     wma = MCIAVI_mciGetOpenDev(wDevID);
842     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
843
844     return 0;
845 }
846
847 /******************************************************************************
848  *                              MCIAVI_mciUpdate                        [internal]
849  */
850 static  DWORD   MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
851 {
852     WINE_MCIAVI *wma;
853
854     TRACE("%04x, %08lx, %p\n", wDevID, dwFlags, lpParms);
855
856     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
857
858     wma = MCIAVI_mciGetOpenDev(wDevID);
859     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
860
861     EnterCriticalSection(&wma->cs);
862
863     if (dwFlags & MCI_DGV_UPDATE_HDC)
864         MCIAVI_PaintFrame(wma, lpParms->hDC);
865
866     LeaveCriticalSection(&wma->cs);
867
868     return 0;
869 }
870
871 /******************************************************************************
872  *                              MCIAVI_mciStep                  [internal]
873  */
874 static  DWORD   MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
875 {
876     WINE_MCIAVI *wma;
877
878     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
879
880     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
881
882     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
883
884     wma = MCIAVI_mciGetOpenDev(wDevID);
885     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
886
887     return 0;
888 }
889
890 /******************************************************************************
891  *                              MCIAVI_mciCopy                  [internal]
892  */
893 static  DWORD   MCIAVI_mciCopy(UINT wDevID, DWORD dwFlags, LPMCI_DGV_COPY_PARMS lpParms)
894 {
895     WINE_MCIAVI *wma;
896
897     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
898
899     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
900
901     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
902
903     wma = MCIAVI_mciGetOpenDev(wDevID);
904     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
905
906     return 0;
907 }
908
909 /******************************************************************************
910  *                              MCIAVI_mciCut                   [internal]
911  */
912 static  DWORD   MCIAVI_mciCut(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUT_PARMS lpParms)
913 {
914     WINE_MCIAVI *wma;
915
916     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
917
918     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
919
920     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
921
922     wma = MCIAVI_mciGetOpenDev(wDevID);
923     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
924
925     return 0;
926 }
927
928 /******************************************************************************
929  *                              MCIAVI_mciDelete                        [internal]
930  */
931 static  DWORD   MCIAVI_mciDelete(UINT wDevID, DWORD dwFlags, LPMCI_DGV_DELETE_PARMS lpParms)
932 {
933     WINE_MCIAVI *wma;
934
935     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
936
937     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
938
939     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
940
941     wma = MCIAVI_mciGetOpenDev(wDevID);
942     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
943
944     return 0;
945 }
946
947 /******************************************************************************
948  *                              MCIAVI_mciPaste                 [internal]
949  */
950 static  DWORD   MCIAVI_mciPaste(UINT wDevID, DWORD dwFlags, LPMCI_DGV_PASTE_PARMS lpParms)
951 {
952     WINE_MCIAVI *wma;
953
954     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
955
956     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
957
958     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
959
960     wma = MCIAVI_mciGetOpenDev(wDevID);
961     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
962
963     return 0;
964 }
965
966 /******************************************************************************
967  *                              MCIAVI_mciCue                   [internal]
968  */
969 static  DWORD   MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
970 {
971     WINE_MCIAVI *wma;
972
973     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
974
975     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
976
977     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
978
979     wma = MCIAVI_mciGetOpenDev(wDevID);
980     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
981
982     return 0;
983 }
984
985 /******************************************************************************
986  *                              MCIAVI_mciCapture                       [internal]
987  */
988 static  DWORD   MCIAVI_mciCapture(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CAPTURE_PARMSW lpParms)
989 {
990     WINE_MCIAVI *wma;
991
992     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
993
994     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
995
996     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
997
998     wma = MCIAVI_mciGetOpenDev(wDevID);
999     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1000
1001     return 0;
1002 }
1003
1004 /******************************************************************************
1005  *                              MCIAVI_mciMonitor                       [internal]
1006  */
1007 static  DWORD   MCIAVI_mciMonitor(UINT wDevID, DWORD dwFlags, LPMCI_DGV_MONITOR_PARMS lpParms)
1008 {
1009     WINE_MCIAVI *wma;
1010
1011     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1012
1013     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1014
1015     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1016
1017     wma = MCIAVI_mciGetOpenDev(wDevID);
1018     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1019
1020     return 0;
1021 }
1022
1023 /******************************************************************************
1024  *                              MCIAVI_mciReserve                       [internal]
1025  */
1026 static  DWORD   MCIAVI_mciReserve(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESERVE_PARMSW lpParms)
1027 {
1028     WINE_MCIAVI *wma;
1029
1030     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1031
1032     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1033
1034     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1035
1036     wma = MCIAVI_mciGetOpenDev(wDevID);
1037     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1038
1039     return 0;
1040 }
1041
1042 /******************************************************************************
1043  *                              MCIAVI_mciSetAudio                      [internal]
1044  */
1045 static  DWORD   MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
1046 {
1047     WINE_MCIAVI *wma;
1048
1049     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1050
1051     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1052
1053     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1054
1055     wma = MCIAVI_mciGetOpenDev(wDevID);
1056     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1057
1058     return 0;
1059 }
1060
1061 /******************************************************************************
1062  *                              MCIAVI_mciSignal                        [internal]
1063  */
1064 static  DWORD   MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
1065 {
1066     WINE_MCIAVI *wma;
1067
1068     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1069
1070     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1071
1072     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1073
1074     wma = MCIAVI_mciGetOpenDev(wDevID);
1075     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1076
1077     return 0;
1078 }
1079
1080 /******************************************************************************
1081  *                              MCIAVI_mciSetVideo                      [internal]
1082  */
1083 static  DWORD   MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSW lpParms)
1084 {
1085     WINE_MCIAVI *wma;
1086
1087     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1088
1089     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1090
1091     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1092
1093     wma = MCIAVI_mciGetOpenDev(wDevID);
1094     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1095
1096     return 0;
1097 }
1098
1099 /******************************************************************************
1100  *                              MCIAVI_mciQuality                       [internal]
1101  */
1102 static  DWORD   MCIAVI_mciQuality(UINT wDevID, DWORD dwFlags, LPMCI_DGV_QUALITY_PARMSW lpParms)
1103 {
1104     WINE_MCIAVI *wma;
1105
1106     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1107
1108     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1109
1110     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1111
1112     wma = MCIAVI_mciGetOpenDev(wDevID);
1113     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1114
1115     return 0;
1116 }
1117
1118 /******************************************************************************
1119  *                              MCIAVI_mciList                  [internal]
1120  */
1121 static  DWORD   MCIAVI_mciList(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LIST_PARMSW lpParms)
1122 {
1123     WINE_MCIAVI *wma;
1124
1125     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1126
1127     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1128
1129     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1130
1131     wma = MCIAVI_mciGetOpenDev(wDevID);
1132     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1133
1134     return 0;
1135 }
1136
1137 /******************************************************************************
1138  *                              MCIAVI_mciUndo                  [internal]
1139  */
1140 static  DWORD   MCIAVI_mciUndo(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1141 {
1142     WINE_MCIAVI *wma;
1143
1144     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1145
1146     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1147
1148     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1149
1150     wma = MCIAVI_mciGetOpenDev(wDevID);
1151     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1152
1153     return 0;
1154 }
1155
1156 /******************************************************************************
1157  *                              MCIAVI_mciConfigure                     [internal]
1158  */
1159 static  DWORD   MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1160 {
1161     WINE_MCIAVI *wma;
1162
1163     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1164
1165     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1166
1167     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1168
1169     wma = MCIAVI_mciGetOpenDev(wDevID);
1170     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1171
1172     return 0;
1173 }
1174
1175 /******************************************************************************
1176  *                              MCIAVI_mciRestore                       [internal]
1177  */
1178 static  DWORD   MCIAVI_mciRestore(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESTORE_PARMSW lpParms)
1179 {
1180     WINE_MCIAVI *wma;
1181
1182     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1183
1184     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1185
1186     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1187
1188     wma = MCIAVI_mciGetOpenDev(wDevID);
1189     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1190
1191     return 0;
1192 }
1193
1194 /*======================================================================*
1195  *                          MCI AVI entry points                        *
1196  *======================================================================*/
1197
1198 /**************************************************************************
1199  *                              DriverProc (MCIAVI.@)
1200  */
1201 LONG CALLBACK   MCIAVI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1202                                   DWORD dwParam1, DWORD dwParam2)
1203 {
1204     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1205           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1206
1207     switch (wMsg) {
1208     case DRV_LOAD:              return 1;
1209     case DRV_FREE:              return 1;
1210     case DRV_OPEN:              return MCIAVI_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1211     case DRV_CLOSE:             return MCIAVI_drvClose(dwDevID);
1212     case DRV_ENABLE:            return 1;
1213     case DRV_DISABLE:           return 1;
1214     case DRV_QUERYCONFIGURE:    return 1;
1215     case DRV_CONFIGURE:         return MCIAVI_drvConfigure(dwDevID);
1216     case DRV_INSTALL:           return DRVCNF_RESTART;
1217     case DRV_REMOVE:            return DRVCNF_RESTART;
1218     }
1219
1220     /* session instance */
1221     if (dwDevID == 0xFFFFFFFF) return 1;
1222
1223     switch (wMsg) {
1224     case MCI_OPEN_DRIVER:       return MCIAVI_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW)     dwParam2);
1225     case MCI_CLOSE_DRIVER:      return MCIAVI_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1226     case MCI_PLAY:              return MCIAVI_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
1227     case MCI_RECORD:            return MCIAVI_mciRecord    (dwDevID, dwParam1, (LPMCI_DGV_RECORD_PARMS)    dwParam2);
1228     case MCI_STOP:              return MCIAVI_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1229     case MCI_SET:               return MCIAVI_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
1230     case MCI_PAUSE:             return MCIAVI_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1231     case MCI_RESUME:            return MCIAVI_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1232     case MCI_STATUS:            return MCIAVI_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
1233     case MCI_GETDEVCAPS:        return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
1234     case MCI_INFO:              return MCIAVI_mciInfo      (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSW)     dwParam2);
1235     case MCI_SEEK:              return MCIAVI_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
1236     case MCI_PUT:               return MCIAVI_mciPut       (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS)       dwParam2);
1237     case MCI_WINDOW:            return MCIAVI_mciWindow    (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)   dwParam2);
1238     case MCI_LOAD:              return MCIAVI_mciLoad      (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSW)     dwParam2);
1239     case MCI_SAVE:              return MCIAVI_mciSave      (dwDevID, dwParam1, (LPMCI_DGV_SAVE_PARMSW)     dwParam2);
1240     case MCI_FREEZE:            return MCIAVI_mciFreeze    (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1241     case MCI_REALIZE:           return MCIAVI_mciRealize   (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1242     case MCI_UNFREEZE:          return MCIAVI_mciUnFreeze  (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1243     case MCI_UPDATE:            return MCIAVI_mciUpdate    (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)    dwParam2);
1244     case MCI_WHERE:             return MCIAVI_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1245     case MCI_STEP:              return MCIAVI_mciStep      (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS)      dwParam2);
1246     case MCI_COPY:              return MCIAVI_mciCopy      (dwDevID, dwParam1, (LPMCI_DGV_COPY_PARMS)      dwParam2);
1247     case MCI_CUT:               return MCIAVI_mciCut       (dwDevID, dwParam1, (LPMCI_DGV_CUT_PARMS)       dwParam2);
1248     case MCI_DELETE:            return MCIAVI_mciDelete    (dwDevID, dwParam1, (LPMCI_DGV_DELETE_PARMS)    dwParam2);
1249     case MCI_PASTE:             return MCIAVI_mciPaste     (dwDevID, dwParam1, (LPMCI_DGV_PASTE_PARMS)     dwParam2);
1250     case MCI_CUE:               return MCIAVI_mciCue       (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS)       dwParam2);
1251         /* Digital Video specific */
1252     case MCI_CAPTURE:           return MCIAVI_mciCapture   (dwDevID, dwParam1, (LPMCI_DGV_CAPTURE_PARMSW)  dwParam2);
1253     case MCI_MONITOR:           return MCIAVI_mciMonitor   (dwDevID, dwParam1, (LPMCI_DGV_MONITOR_PARMS)   dwParam2);
1254     case MCI_RESERVE:           return MCIAVI_mciReserve   (dwDevID, dwParam1, (LPMCI_DGV_RESERVE_PARMSW)  dwParam2);
1255     case MCI_SETAUDIO:          return MCIAVI_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
1256     case MCI_SIGNAL:            return MCIAVI_mciSignal    (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS)    dwParam2);
1257     case MCI_SETVIDEO:          return MCIAVI_mciSetVideo  (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSW) dwParam2);
1258     case MCI_QUALITY:           return MCIAVI_mciQuality   (dwDevID, dwParam1, (LPMCI_DGV_QUALITY_PARMSW)  dwParam2);
1259     case MCI_LIST:              return MCIAVI_mciList      (dwDevID, dwParam1, (LPMCI_DGV_LIST_PARMSW)     dwParam2);
1260     case MCI_UNDO:              return MCIAVI_mciUndo      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1261     case MCI_CONFIGURE:         return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1262     case MCI_RESTORE:           return MCIAVI_mciRestore   (dwDevID, dwParam1, (LPMCI_DGV_RESTORE_PARMSW)  dwParam2);
1263
1264     case MCI_SPIN:
1265     case MCI_ESCAPE:
1266         WARN("Unsupported command [%lu]\n", wMsg);
1267         break;
1268     case MCI_OPEN:
1269     case MCI_CLOSE:
1270         FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1271         break;
1272     default:
1273         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
1274         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1275     }
1276     return MCIERR_UNRECOGNIZED_COMMAND;
1277 }