Generate 16-bit spec files as assembly code too.
[wine] / dlls / mciavi32 / mciavi.c
1 /*
2  * Digital video MCI Wine Driver
3  *
4  * Copyright 1999, 2000 Eric POUECH
5  * Copyright 2003 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* TODO list :
23  *      - handling of palettes
24  *      - recording (which input devices ?), a cam recorder ?
25  *      - lots of messages still need to be handled (cf FIXME)
26  *      - synchronization between audio and video (especially for interleaved
27  *        files)
28  *      - robustness when reading file can be enhanced
29  *      - better move the AVI handling part to avifile DLL and make use of it
30  *      - some files appear to have more than one audio stream (we only play the
31  *        first one)
32  *      - some files contain an index of audio/video frame. Better use it,
33  *        instead of rebuilding it
34  *      - stopping while playing a file with sound blocks until all buffered
35  *        audio is played... still should be stopped ASAP
36  */
37
38 #include <string.h>
39 #include "private_mciavi.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
44
45 static DWORD MCIAVI_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
46
47 /* ===================================================================
48  * ===================================================================
49  * FIXME: should be using the new mmThreadXXXX functions from WINMM
50  * instead of those
51  * it would require to add a wine internal flag to mmThreadCreate
52  * in order to pass a 32 bit function instead of a 16 bit one
53  * ===================================================================
54  * =================================================================== */
55
56 struct SCA {
57     MCIDEVICEID wDevID;
58     UINT        wMsg;
59     DWORD_PTR   dwParam1;
60     DWORD_PTR   dwParam2;
61 };
62
63 /**************************************************************************
64  *                              MCI_SCAStarter                  [internal]
65  */
66 static DWORD CALLBACK   MCI_SCAStarter(LPVOID arg)
67 {
68     struct SCA* sca = (struct SCA*)arg;
69     DWORD       ret;
70
71     TRACE("In thread before async command (%08x,%04x,%08lx,%08lx)\n",
72           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
73     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
74     TRACE("In thread after async command (%08x,%04x,%08lx,%08lx)\n",
75           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
76     HeapFree(GetProcessHeap(), 0, sca);
77     return ret;
78 }
79
80 /**************************************************************************
81  *                              MCI_SendCommandAsync            [internal]
82  */
83 static  DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
84                                   DWORD_PTR dwParam2, UINT size)
85 {
86     HANDLE handle;
87     struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
88
89     if (sca == 0)
90         return MCIERR_OUT_OF_MEMORY;
91
92     sca->wDevID   = wDevID;
93     sca->wMsg     = wMsg;
94     sca->dwParam1 = dwParam1;
95
96     if (size && dwParam2) {
97        sca->dwParam2 = (DWORD_PTR)sca + sizeof(struct SCA);
98         /* copy structure passed by program in dwParam2 to be sure
99          * we can still use it whatever the program does
100          */
101         memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
102     } else {
103         sca->dwParam2 = dwParam2;
104     }
105
106     if ((handle = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
107         WARN("Couldn't allocate thread for async command handling, sending synchronously\n");
108         return MCI_SCAStarter(&sca);
109     }
110     SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
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(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW 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_w(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 = CreateEventW(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         HeapFree(GetProcessHeap(), 0, wma->lpFileName);
241         wma->lpFileName = NULL;
242
243         HeapFree(GetProcessHeap(), 0, wma->lpVideoIndex);
244         wma->lpVideoIndex = NULL;
245         HeapFree(GetProcessHeap(), 0, wma->lpAudioIndex);
246         wma->lpAudioIndex = NULL;
247         if (wma->hic)           ICClose(wma->hic);
248         wma->hic = 0;
249         HeapFree(GetProcessHeap(), 0, wma->inbih);
250         wma->inbih = NULL;
251         HeapFree(GetProcessHeap(), 0, wma->outbih);
252         wma->outbih = NULL;
253         HeapFree(GetProcessHeap(), 0, wma->indata);
254         wma->indata = NULL;
255         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         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_PARMSW 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 (strlenW(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", debugstr_w(lpOpenParms->lpstrElementName));
320
321             if (lpOpenParms->lpstrElementName && (strlenW(lpOpenParms->lpstrElementName) > 0))
322             {
323                 wma->lpFileName = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpOpenParms->lpstrElementName) + 1) * sizeof(WCHAR));
324                 strcpyW(wma->lpFileName, lpOpenParms->lpstrElementName);
325
326                 wma->hFile = mmioOpenW(lpOpenParms->lpstrElementName, NULL,
327                                        MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
328
329                 if (wma->hFile == 0) {
330                     WARN("can't find file=%s!\n", debugstr_w(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 = MsgWaitForMultipleObjectsEx(2, events,
517                 (delta >= frameTime) ? 0 : frameTime - delta, QS_ALLINPUT, 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 = MsgWaitForMultipleObjectsEx(1, &wma->hStopEvent, frameTime - delta,
530                                               QS_ALLINPUT, MWMO_INPUTAVAILABLE);
531             EnterCriticalSection(&wma->cs);
532             if (ret == WAIT_OBJECT_0) break;
533         }
534
535        if (wma->dwCurrVideoFrame < dwToFrame)
536            wma->dwCurrVideoFrame++;
537         else
538             break;
539     }
540
541     if (wma->lpWaveFormat) {
542        while (wma->dwEventCount != nHdr - 1)
543         {
544             LeaveCriticalSection(&wma->cs);
545             Sleep(100);
546             EnterCriticalSection(&wma->cs);
547         }
548
549         /* just to get rid of some race conditions between play, stop and pause */
550         LeaveCriticalSection(&wma->cs);
551         waveOutReset(wma->hWave);
552         EnterCriticalSection(&wma->cs);
553
554         for (i = 0; i < nHdr; i++)
555             waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
556     }
557
558     dwRet = 0;
559
560     if (wma->lpWaveFormat) {
561         HeapFree(GetProcessHeap(), 0, waveHdr);
562
563         if (wma->hWave) {
564             LeaveCriticalSection(&wma->cs);
565             waveOutClose(wma->hWave);
566             EnterCriticalSection(&wma->cs);
567             wma->hWave = 0;
568         }
569         CloseHandle(wma->hEvent);
570     }
571
572 mci_play_done:
573     wma->dwStatus = MCI_MODE_STOP;
574
575     if (lpParms && (dwFlags & MCI_NOTIFY)) {
576         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
577         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
578                        wDevID, MCI_NOTIFY_SUCCESSFUL);
579     }
580     LeaveCriticalSection(&wma->cs);
581     return dwRet;
582 }
583
584 /***************************************************************************
585  *                              MCIAVI_mciRecord                        [internal]
586  */
587 static  DWORD   MCIAVI_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECORD_PARMS lpParms)
588 {
589     WINE_MCIAVI *wma;
590
591     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
592
593     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
594
595     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
596
597     wma = MCIAVI_mciGetOpenDev(wDevID);
598     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
599
600     EnterCriticalSection(&wma->cs);
601     wma->dwStatus = MCI_MODE_RECORD;
602     LeaveCriticalSection(&wma->cs);
603     return 0;
604 }
605
606 /***************************************************************************
607  *                              MCIAVI_mciStop                  [internal]
608  */
609 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
610 {
611     WINE_MCIAVI *wma;
612     DWORD               dwRet = 0;
613
614     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
615
616     wma = MCIAVI_mciGetOpenDev(wDevID);
617     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
618
619     EnterCriticalSection(&wma->cs);
620
621     switch (wma->dwStatus) {
622     case MCI_MODE_PLAY:
623     case MCI_MODE_RECORD:
624         LeaveCriticalSection(&wma->cs);
625         SetEvent(wma->hStopEvent);
626         EnterCriticalSection(&wma->cs);
627         /* fall through */
628     case MCI_MODE_PAUSE:
629         /* Since our wave notification callback takes the lock,
630          * we must release it before resetting the device */
631         LeaveCriticalSection(&wma->cs);
632         dwRet = waveOutReset(wma->hWave);
633         EnterCriticalSection(&wma->cs);
634         /* fall through */
635     default:
636         do /* one more chance for an async thread to finish */
637         {
638             LeaveCriticalSection(&wma->cs);
639             Sleep(10);
640             EnterCriticalSection(&wma->cs);
641         } while (wma->dwStatus != MCI_MODE_STOP);
642
643         break;
644
645     case MCI_MODE_NOT_READY:
646         break;        
647     }
648
649     if ((dwFlags & MCI_NOTIFY) && lpParms) {
650         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
651                        wDevID, MCI_NOTIFY_SUCCESSFUL);
652     }
653     LeaveCriticalSection(&wma->cs);
654     return dwRet;
655 }
656
657 /***************************************************************************
658  *                              MCIAVI_mciPause                 [internal]
659  */
660 static  DWORD   MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
661 {
662     WINE_MCIAVI *wma;
663
664     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
665
666     wma = MCIAVI_mciGetOpenDev(wDevID);
667     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
668
669     EnterCriticalSection(&wma->cs);
670
671     if (wma->dwStatus == MCI_MODE_PLAY)
672         wma->dwStatus = MCI_MODE_PAUSE;
673
674     if (wma->lpWaveFormat) {
675         LeaveCriticalSection(&wma->cs);
676         return waveOutPause(wma->hWave);
677     }
678
679     LeaveCriticalSection(&wma->cs);
680     return 0;
681 }
682
683 /***************************************************************************
684  *                              MCIAVI_mciResume                        [internal]
685  */
686 static  DWORD   MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
687 {
688     WINE_MCIAVI *wma;
689
690     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
691
692     wma = MCIAVI_mciGetOpenDev(wDevID);
693     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
694
695     EnterCriticalSection(&wma->cs);
696
697     if (wma->dwStatus == MCI_MODE_PAUSE)
698         wma->dwStatus = MCI_MODE_PLAY;
699
700     if (wma->lpWaveFormat) {
701         LeaveCriticalSection(&wma->cs);
702         return waveOutRestart(wma->hWave);
703     }
704
705     LeaveCriticalSection(&wma->cs);
706     return 0;
707 }
708
709 /***************************************************************************
710  *                              MCIAVI_mciSeek                  [internal]
711  */
712 static  DWORD   MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
713 {
714     WINE_MCIAVI *wma;
715
716     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
717
718     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
719
720     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
721
722     wma = MCIAVI_mciGetOpenDev(wDevID);
723     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
724
725     EnterCriticalSection(&wma->cs);
726
727     if (dwFlags & MCI_SEEK_TO_START) {
728         wma->dwCurrVideoFrame = 0;
729     } else if (dwFlags & MCI_SEEK_TO_END) {
730         wma->dwCurrVideoFrame = wma->dwPlayableVideoFrames - 1;
731     } else if (dwFlags & MCI_TO) {
732         if (lpParms->dwTo > wma->dwPlayableVideoFrames - 1)
733             lpParms->dwTo = wma->dwPlayableVideoFrames - 1;
734         wma->dwCurrVideoFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
735     } else {
736         WARN("dwFlag doesn't tell where to seek to...\n");
737         LeaveCriticalSection(&wma->cs);
738         return MCIERR_MISSING_PARAMETER;
739     }
740
741     TRACE("Seeking to frame=%lu bytes\n", wma->dwCurrVideoFrame);
742
743     if (dwFlags & MCI_NOTIFY) {
744         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
745                        wDevID, MCI_NOTIFY_SUCCESSFUL);
746     }
747     LeaveCriticalSection(&wma->cs);
748     return 0;
749 }
750
751 /*****************************************************************************
752  *                              MCIAVI_mciLoad                  [internal]
753  */
754 static DWORD    MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSW lpParms)
755 {
756     WINE_MCIAVI *wma;
757
758     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
759
760     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
761
762     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
763
764     wma = MCIAVI_mciGetOpenDev(wDevID);
765     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
766
767     return 0;
768 }
769
770 /******************************************************************************
771  *                              MCIAVI_mciSave                  [internal]
772  */
773 static  DWORD   MCIAVI_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SAVE_PARMSW lpParms)
774 {
775     WINE_MCIAVI *wma;
776
777     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
778
779     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
780
781     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
782
783     wma = MCIAVI_mciGetOpenDev(wDevID);
784     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
785
786     return 0;
787 }
788
789 /******************************************************************************
790  *                              MCIAVI_mciFreeze                        [internal]
791  */
792 static  DWORD   MCIAVI_mciFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
793 {
794     WINE_MCIAVI *wma;
795
796     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
797
798     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
799
800     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
801
802     wma = MCIAVI_mciGetOpenDev(wDevID);
803     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
804
805     return 0;
806 }
807
808 /******************************************************************************
809  *                              MCIAVI_mciRealize                       [internal]
810  */
811 static  DWORD   MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
812 {
813     WINE_MCIAVI *wma;
814
815     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
816
817     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
818
819     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
820
821     wma = MCIAVI_mciGetOpenDev(wDevID);
822     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
823
824     return 0;
825 }
826
827 /******************************************************************************
828  *                              MCIAVI_mciUnFreeze                      [internal]
829  */
830 static  DWORD   MCIAVI_mciUnFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
831 {
832     WINE_MCIAVI *wma;
833
834     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
835
836     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
837
838     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
839
840     wma = MCIAVI_mciGetOpenDev(wDevID);
841     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
842
843     return 0;
844 }
845
846 /******************************************************************************
847  *                              MCIAVI_mciUpdate                        [internal]
848  */
849 static  DWORD   MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
850 {
851     WINE_MCIAVI *wma;
852
853     TRACE("%04x, %08lx, %p\n", wDevID, dwFlags, lpParms);
854
855     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
856
857     wma = MCIAVI_mciGetOpenDev(wDevID);
858     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
859
860     EnterCriticalSection(&wma->cs);
861
862     if (dwFlags & MCI_DGV_UPDATE_HDC)
863         MCIAVI_PaintFrame(wma, lpParms->hDC);
864
865     LeaveCriticalSection(&wma->cs);
866
867     return 0;
868 }
869
870 /******************************************************************************
871  *                              MCIAVI_mciStep                  [internal]
872  */
873 static  DWORD   MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
874 {
875     WINE_MCIAVI *wma;
876
877     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
878
879     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
880
881     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
882
883     wma = MCIAVI_mciGetOpenDev(wDevID);
884     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
885
886     return 0;
887 }
888
889 /******************************************************************************
890  *                              MCIAVI_mciCopy                  [internal]
891  */
892 static  DWORD   MCIAVI_mciCopy(UINT wDevID, DWORD dwFlags, LPMCI_DGV_COPY_PARMS lpParms)
893 {
894     WINE_MCIAVI *wma;
895
896     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
897
898     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
899
900     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
901
902     wma = MCIAVI_mciGetOpenDev(wDevID);
903     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
904
905     return 0;
906 }
907
908 /******************************************************************************
909  *                              MCIAVI_mciCut                   [internal]
910  */
911 static  DWORD   MCIAVI_mciCut(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUT_PARMS lpParms)
912 {
913     WINE_MCIAVI *wma;
914
915     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
916
917     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
918
919     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
920
921     wma = MCIAVI_mciGetOpenDev(wDevID);
922     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
923
924     return 0;
925 }
926
927 /******************************************************************************
928  *                              MCIAVI_mciDelete                        [internal]
929  */
930 static  DWORD   MCIAVI_mciDelete(UINT wDevID, DWORD dwFlags, LPMCI_DGV_DELETE_PARMS lpParms)
931 {
932     WINE_MCIAVI *wma;
933
934     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
935
936     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
937
938     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
939
940     wma = MCIAVI_mciGetOpenDev(wDevID);
941     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
942
943     return 0;
944 }
945
946 /******************************************************************************
947  *                              MCIAVI_mciPaste                 [internal]
948  */
949 static  DWORD   MCIAVI_mciPaste(UINT wDevID, DWORD dwFlags, LPMCI_DGV_PASTE_PARMS lpParms)
950 {
951     WINE_MCIAVI *wma;
952
953     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
954
955     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
956
957     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
958
959     wma = MCIAVI_mciGetOpenDev(wDevID);
960     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
961
962     return 0;
963 }
964
965 /******************************************************************************
966  *                              MCIAVI_mciCue                   [internal]
967  */
968 static  DWORD   MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
969 {
970     WINE_MCIAVI *wma;
971
972     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
973
974     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
975
976     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
977
978     wma = MCIAVI_mciGetOpenDev(wDevID);
979     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
980
981     return 0;
982 }
983
984 /******************************************************************************
985  *                              MCIAVI_mciCapture                       [internal]
986  */
987 static  DWORD   MCIAVI_mciCapture(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CAPTURE_PARMSW lpParms)
988 {
989     WINE_MCIAVI *wma;
990
991     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
992
993     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
994
995     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
996
997     wma = MCIAVI_mciGetOpenDev(wDevID);
998     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
999
1000     return 0;
1001 }
1002
1003 /******************************************************************************
1004  *                              MCIAVI_mciMonitor                       [internal]
1005  */
1006 static  DWORD   MCIAVI_mciMonitor(UINT wDevID, DWORD dwFlags, LPMCI_DGV_MONITOR_PARMS lpParms)
1007 {
1008     WINE_MCIAVI *wma;
1009
1010     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1011
1012     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1013
1014     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1015
1016     wma = MCIAVI_mciGetOpenDev(wDevID);
1017     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1018
1019     return 0;
1020 }
1021
1022 /******************************************************************************
1023  *                              MCIAVI_mciReserve                       [internal]
1024  */
1025 static  DWORD   MCIAVI_mciReserve(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESERVE_PARMSW lpParms)
1026 {
1027     WINE_MCIAVI *wma;
1028
1029     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1030
1031     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1032
1033     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1034
1035     wma = MCIAVI_mciGetOpenDev(wDevID);
1036     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1037
1038     return 0;
1039 }
1040
1041 /******************************************************************************
1042  *                              MCIAVI_mciSetAudio                      [internal]
1043  */
1044 static  DWORD   MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
1045 {
1046     WINE_MCIAVI *wma;
1047
1048     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1049
1050     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1051
1052     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1053
1054     wma = MCIAVI_mciGetOpenDev(wDevID);
1055     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1056
1057     return 0;
1058 }
1059
1060 /******************************************************************************
1061  *                              MCIAVI_mciSignal                        [internal]
1062  */
1063 static  DWORD   MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
1064 {
1065     WINE_MCIAVI *wma;
1066
1067     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1068
1069     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1070
1071     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1072
1073     wma = MCIAVI_mciGetOpenDev(wDevID);
1074     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1075
1076     return 0;
1077 }
1078
1079 /******************************************************************************
1080  *                              MCIAVI_mciSetVideo                      [internal]
1081  */
1082 static  DWORD   MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSW lpParms)
1083 {
1084     WINE_MCIAVI *wma;
1085
1086     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1087
1088     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1089
1090     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1091
1092     wma = MCIAVI_mciGetOpenDev(wDevID);
1093     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1094
1095     return 0;
1096 }
1097
1098 /******************************************************************************
1099  *                              MCIAVI_mciQuality                       [internal]
1100  */
1101 static  DWORD   MCIAVI_mciQuality(UINT wDevID, DWORD dwFlags, LPMCI_DGV_QUALITY_PARMSW lpParms)
1102 {
1103     WINE_MCIAVI *wma;
1104
1105     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1106
1107     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1108
1109     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1110
1111     wma = MCIAVI_mciGetOpenDev(wDevID);
1112     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1113
1114     return 0;
1115 }
1116
1117 /******************************************************************************
1118  *                              MCIAVI_mciList                  [internal]
1119  */
1120 static  DWORD   MCIAVI_mciList(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LIST_PARMSW lpParms)
1121 {
1122     WINE_MCIAVI *wma;
1123
1124     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1125
1126     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1127
1128     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1129
1130     wma = MCIAVI_mciGetOpenDev(wDevID);
1131     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1132
1133     return 0;
1134 }
1135
1136 /******************************************************************************
1137  *                              MCIAVI_mciUndo                  [internal]
1138  */
1139 static  DWORD   MCIAVI_mciUndo(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1140 {
1141     WINE_MCIAVI *wma;
1142
1143     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1144
1145     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1146
1147     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1148
1149     wma = MCIAVI_mciGetOpenDev(wDevID);
1150     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1151
1152     return 0;
1153 }
1154
1155 /******************************************************************************
1156  *                              MCIAVI_mciConfigure                     [internal]
1157  */
1158 static  DWORD   MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1159 {
1160     WINE_MCIAVI *wma;
1161
1162     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1163
1164     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1165
1166     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1167
1168     wma = MCIAVI_mciGetOpenDev(wDevID);
1169     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1170
1171     return 0;
1172 }
1173
1174 /******************************************************************************
1175  *                              MCIAVI_mciRestore                       [internal]
1176  */
1177 static  DWORD   MCIAVI_mciRestore(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESTORE_PARMSW lpParms)
1178 {
1179     WINE_MCIAVI *wma;
1180
1181     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
1182
1183     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
1184
1185     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1186
1187     wma = MCIAVI_mciGetOpenDev(wDevID);
1188     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
1189
1190     return 0;
1191 }
1192
1193 /*======================================================================*
1194  *                          MCI AVI entry points                        *
1195  *======================================================================*/
1196
1197 /**************************************************************************
1198  *                              DriverProc (MCIAVI.@)
1199  */
1200 LONG CALLBACK   MCIAVI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1201                                   DWORD dwParam1, DWORD dwParam2)
1202 {
1203     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1204           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1205
1206     switch (wMsg) {
1207     case DRV_LOAD:              return 1;
1208     case DRV_FREE:              return 1;
1209     case DRV_OPEN:              return MCIAVI_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1210     case DRV_CLOSE:             return MCIAVI_drvClose(dwDevID);
1211     case DRV_ENABLE:            return 1;
1212     case DRV_DISABLE:           return 1;
1213     case DRV_QUERYCONFIGURE:    return 1;
1214     case DRV_CONFIGURE:         return MCIAVI_drvConfigure(dwDevID);
1215     case DRV_INSTALL:           return DRVCNF_RESTART;
1216     case DRV_REMOVE:            return DRVCNF_RESTART;
1217     }
1218
1219     /* session instance */
1220     if (dwDevID == 0xFFFFFFFF) return 1;
1221
1222     switch (wMsg) {
1223     case MCI_OPEN_DRIVER:       return MCIAVI_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW)     dwParam2);
1224     case MCI_CLOSE_DRIVER:      return MCIAVI_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1225     case MCI_PLAY:              return MCIAVI_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
1226     case MCI_RECORD:            return MCIAVI_mciRecord    (dwDevID, dwParam1, (LPMCI_DGV_RECORD_PARMS)    dwParam2);
1227     case MCI_STOP:              return MCIAVI_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1228     case MCI_SET:               return MCIAVI_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
1229     case MCI_PAUSE:             return MCIAVI_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1230     case MCI_RESUME:            return MCIAVI_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1231     case MCI_STATUS:            return MCIAVI_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
1232     case MCI_GETDEVCAPS:        return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
1233     case MCI_INFO:              return MCIAVI_mciInfo      (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSW)     dwParam2);
1234     case MCI_SEEK:              return MCIAVI_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
1235     case MCI_PUT:               return MCIAVI_mciPut       (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS)       dwParam2);
1236     case MCI_WINDOW:            return MCIAVI_mciWindow    (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)   dwParam2);
1237     case MCI_LOAD:              return MCIAVI_mciLoad      (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSW)     dwParam2);
1238     case MCI_SAVE:              return MCIAVI_mciSave      (dwDevID, dwParam1, (LPMCI_DGV_SAVE_PARMSW)     dwParam2);
1239     case MCI_FREEZE:            return MCIAVI_mciFreeze    (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1240     case MCI_REALIZE:           return MCIAVI_mciRealize   (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1241     case MCI_UNFREEZE:          return MCIAVI_mciUnFreeze  (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1242     case MCI_UPDATE:            return MCIAVI_mciUpdate    (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)    dwParam2);
1243     case MCI_WHERE:             return MCIAVI_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
1244     case MCI_STEP:              return MCIAVI_mciStep      (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS)      dwParam2);
1245     case MCI_COPY:              return MCIAVI_mciCopy      (dwDevID, dwParam1, (LPMCI_DGV_COPY_PARMS)      dwParam2);
1246     case MCI_CUT:               return MCIAVI_mciCut       (dwDevID, dwParam1, (LPMCI_DGV_CUT_PARMS)       dwParam2);
1247     case MCI_DELETE:            return MCIAVI_mciDelete    (dwDevID, dwParam1, (LPMCI_DGV_DELETE_PARMS)    dwParam2);
1248     case MCI_PASTE:             return MCIAVI_mciPaste     (dwDevID, dwParam1, (LPMCI_DGV_PASTE_PARMS)     dwParam2);
1249     case MCI_CUE:               return MCIAVI_mciCue       (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS)       dwParam2);
1250         /* Digital Video specific */
1251     case MCI_CAPTURE:           return MCIAVI_mciCapture   (dwDevID, dwParam1, (LPMCI_DGV_CAPTURE_PARMSW)  dwParam2);
1252     case MCI_MONITOR:           return MCIAVI_mciMonitor   (dwDevID, dwParam1, (LPMCI_DGV_MONITOR_PARMS)   dwParam2);
1253     case MCI_RESERVE:           return MCIAVI_mciReserve   (dwDevID, dwParam1, (LPMCI_DGV_RESERVE_PARMSW)  dwParam2);
1254     case MCI_SETAUDIO:          return MCIAVI_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
1255     case MCI_SIGNAL:            return MCIAVI_mciSignal    (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS)    dwParam2);
1256     case MCI_SETVIDEO:          return MCIAVI_mciSetVideo  (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSW) dwParam2);
1257     case MCI_QUALITY:           return MCIAVI_mciQuality   (dwDevID, dwParam1, (LPMCI_DGV_QUALITY_PARMSW)  dwParam2);
1258     case MCI_LIST:              return MCIAVI_mciList      (dwDevID, dwParam1, (LPMCI_DGV_LIST_PARMSW)     dwParam2);
1259     case MCI_UNDO:              return MCIAVI_mciUndo      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1260     case MCI_CONFIGURE:         return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
1261     case MCI_RESTORE:           return MCIAVI_mciRestore   (dwDevID, dwParam1, (LPMCI_DGV_RESTORE_PARMSW)  dwParam2);
1262
1263     case MCI_SPIN:
1264     case MCI_ESCAPE:
1265         WARN("Unsupported command [%lu]\n", wMsg);
1266         break;
1267     case MCI_OPEN:
1268     case MCI_CLOSE:
1269         FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1270         break;
1271     default:
1272         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
1273         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1274     }
1275     return MCIERR_UNRECOGNIZED_COMMAND;
1276 }