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