Moved queue paint count to the server. Removed a few no longer used
[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  */
8
9 /* TODO list :
10  *      - handling of palettes
11  *      - recording (which input devices ?), a cam recorder ?
12  *      - lots of messages still need to be handled (cf FIXME)
13  *      - synchronization between audio and video (especially for interleaved
14  *        files)
15  *      - synchronization (as in all the Wine MCI drivers (MCI_WAIT) messages)
16  *      - robustness when reading file can be enhanced
17  *      - better move the AVI handling part to avifile DLL and make use of it
18  *      - some files appear to have more than one audio stream (we only play the
19  *        first one)
20  *      - some files contain an index of audio/video frame. Better use it, 
21  *        instead of rebuilding it
22  *      - mciWindow (for setting the hWnd) is broken with media player
23  *      - stopping while playing a file with sound blocks until all buffered
24  *        audio is played... still should be stopped ASAP
25  */
26
27 #include <string.h>
28 #include "private_mciavi.h"
29 #include "debugtools.h"
30
31 DEFAULT_DEBUG_CHANNEL(mciavi);
32
33 /* ===================================================================
34  * ===================================================================
35  * FIXME: should be using the new mmThreadXXXX functions from WINMM
36  * instead of those
37  * it would require to add a wine internal flag to mmThreadCreate
38  * in order to pass a 32 bit function instead of a 16 bit one
39  * ===================================================================
40  * =================================================================== */
41
42 struct SCA {
43     UINT        wDevID;
44     UINT        wMsg;
45     DWORD       dwParam1;
46     DWORD       dwParam2;
47 };
48
49 /**************************************************************************
50  *                              MCI_SCAStarter                  [internal]
51  */
52 static DWORD CALLBACK   MCI_SCAStarter(LPVOID arg)
53 {
54     struct SCA* sca = (struct SCA*)arg;
55     DWORD       ret;
56     
57     TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
58           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
59     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
60     TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
61           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
62     HeapFree(GetProcessHeap(), 0, sca);
63     ExitThread(ret);
64     WARN("Should not happen ? what's wrong \n");
65     /* should not go after this point */
66     return ret;
67 }
68
69 /**************************************************************************
70  *                              MCI_SendCommandAsync            [internal]
71  */
72 static  DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1, 
73                                    DWORD dwParam2, UINT size)
74 {
75     struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
76     
77     if (sca == 0)
78         return MCIERR_OUT_OF_MEMORY;
79     
80     sca->wDevID   = wDevID;
81     sca->wMsg     = wMsg;
82     sca->dwParam1 = dwParam1;
83     
84     if (size && dwParam2) {
85         sca->dwParam2 = (DWORD)sca + sizeof(struct SCA);
86         /* copy structure passed by program in dwParam2 to be sure 
87          * we can still use it whatever the program does 
88          */
89         memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
90     } else {
91         sca->dwParam2 = dwParam2;
92     }
93     
94     if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
95         WARN("Couldn't allocate thread for async command handling, sending synchronously\n");
96         return MCI_SCAStarter(&sca);
97     }
98     return 0;
99 }
100
101 /*======================================================================*
102  *                          MCI AVI implemantation                      *
103  *======================================================================*/
104
105 HINSTANCE MCIAVI_hInstance = 0;
106
107 BOOL WINAPI MCIAVI_LibMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
108 {
109     switch (fdwReason) {
110     case DLL_PROCESS_ATTACH:
111         MCIAVI_hInstance = hInstDLL;
112         break;
113     }
114     return TRUE;
115 }
116
117 /**************************************************************************
118  *                              MCIAVI_drvOpen                  [internal]      
119  */
120 static  DWORD   MCIAVI_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
121 {
122     WINE_MCIAVI*        wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIAVI));
123     static WCHAR        mciAviWStr[] = {'M','C','I','A','V','I',0};
124
125     if (!wma)
126         return 0;
127     
128     wma->wDevID = modp->wDeviceID;
129     mciSetDriverData(wma->wDevID, (DWORD)wma);
130     wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
131     modp->wCustomCommandTable = wma->wCommandTable;
132     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
133     return modp->wDeviceID;
134 }
135
136 /**************************************************************************
137  *                              MCIAVI_drvClose         [internal]      
138  */
139 static  DWORD   MCIAVI_drvClose(DWORD dwDevID)
140 {
141     WINE_MCIAVI*  wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
142     
143     if (wma) {
144         mciSetDriverData(dwDevID, 0);
145         mciFreeCommandResource(wma->wCommandTable);
146         HeapFree(GetProcessHeap(), 0, wma);     
147         return 1;
148     }
149     return 0;
150 }
151
152 /**************************************************************************
153  *                              MCIAVI_drvConfigure             [internal]      
154  */
155 static  DWORD   MCIAVI_drvConfigure(DWORD dwDevID)
156 {
157     WINE_MCIAVI*  wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
158
159     if (wma) {
160         MessageBoxA(0, "Sample AVI Wine Driver !", "MM-Wine Driver", MB_OK); 
161         return 1;
162     }
163     return 0;
164 }
165
166 /**************************************************************************
167  *                              MCIAVI_mciGetOpenDev            [internal]      
168  */
169 WINE_MCIAVI*  MCIAVI_mciGetOpenDev(UINT wDevID)
170 {
171     WINE_MCIAVI*        wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
172     
173     if (wma == NULL || wma->nUseCount == 0) {
174         WARN("Invalid wDevID=%u\n", wDevID);
175         return 0;
176     }
177     return wma;
178 }
179
180 static void MCIAVI_CleanUp(WINE_MCIAVI* wma)
181 {
182     /* to prevent handling in WindowProc */
183     wma->dwStatus = MCI_MODE_NOT_READY;
184     if (wma->hFile) {
185         mmioClose(wma->hFile, 0);
186         wma->hFile = 0;
187         if (wma->lpVideoIndex)  HeapFree(GetProcessHeap(), 0, wma->lpVideoIndex);
188         wma->lpVideoIndex = NULL;
189         if (wma->lpAudioIndex)  HeapFree(GetProcessHeap(), 0, wma->lpAudioIndex);
190         wma->lpAudioIndex = NULL;
191         if (wma->hic)           ICClose(wma->hic);
192         wma->hic = 0;
193         if (wma->inbih)         HeapFree(GetProcessHeap(), 0, wma->inbih);
194         wma->inbih = NULL;
195         if (wma->outbih)        HeapFree(GetProcessHeap(), 0, wma->outbih);
196         wma->outbih = NULL;
197         if (wma->indata)        HeapFree(GetProcessHeap(), 0, wma->indata);
198         wma->indata = NULL;
199         if (wma->outdata)       HeapFree(GetProcessHeap(), 0, wma->outdata);
200         wma->outdata = NULL;
201         if (wma->hbmFrame)      DeleteObject(wma->hbmFrame);
202         wma->hbmFrame = 0;
203         if (wma->hWnd)          DestroyWindow(wma->hWnd);
204         wma->hWnd = 0;
205         
206         if (wma->lpWaveFormat)  HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
207         wma->lpWaveFormat = 0;
208
209         memset(&wma->mah, 0, sizeof(wma->mah));
210         memset(&wma->ash_video, 0, sizeof(wma->ash_video));
211         memset(&wma->ash_audio, 0, sizeof(wma->ash_audio));
212         wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
213     }
214 }
215
216 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
217
218 /***************************************************************************
219  *                              MCIAVI_mciOpen                  [internal]
220  */
221 static  DWORD   MCIAVI_mciOpen(UINT wDevID, DWORD dwFlags, 
222                             LPMCI_DGV_OPEN_PARMSA lpOpenParms)
223 {
224     WINE_MCIAVI*        wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
225     LRESULT             dwRet = 0;
226     
227     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
228     
229     if (lpOpenParms == NULL)            return MCIERR_NULL_PARAMETER_BLOCK;
230     if (wma == NULL)                    return MCIERR_INVALID_DEVICE_ID;
231     
232     if (wma->nUseCount > 0) {
233         /* The driver is already open on this channel */
234         /* If the driver was opened shareable before and this open specifies */
235         /* shareable then increment the use count */
236         if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
237             ++wma->nUseCount;
238         else
239             return MCIERR_MUST_USE_SHAREABLE;
240     } else {
241         wma->nUseCount = 1;
242         wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
243     }
244     
245     wma->dwStatus = MCI_MODE_NOT_READY; 
246     InitializeCriticalSection(&wma->cs);
247     
248     if (dwFlags & MCI_OPEN_ELEMENT) {
249         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
250             /* could it be that (DWORD)lpOpenParms->lpstrElementName 
251              * contains the hFile value ? 
252              */
253             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
254         } else if (strlen(lpOpenParms->lpstrElementName) > 0) {
255             /* FIXME : what should be done id wma->hFile is already != 0, or the driver is playin' */
256             TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
257             
258             if (lpOpenParms->lpstrElementName && (strlen(lpOpenParms->lpstrElementName) > 0)) {
259                 wma->hFile = mmioOpenA(lpOpenParms->lpstrElementName, NULL, 
260                                        MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE);
261                 
262                 if (wma->hFile == 0) {
263                     WARN("can't find file='%s' !\n", lpOpenParms->lpstrElementName);
264                     dwRet = MCIERR_FILE_NOT_FOUND;
265                 } else {
266                     if (!MCIAVI_GetInfo(wma)) 
267                         dwRet = MCIERR_INVALID_FILE;
268                     else if (!MCIAVI_OpenVideo(wma))
269                         dwRet = MCIERR_CANNOT_LOAD_DRIVER;
270                     else if (!MCIAVI_CreateWindow(wma, dwFlags, lpOpenParms))
271                         dwRet = MCIERR_CREATEWINDOW;
272                 } 
273             }
274         } else {
275             FIXME("Don't record yet\n");
276             dwRet = MCIERR_UNSUPPORTED_FUNCTION;
277         }
278     }
279     
280     memcpy(&wma->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
281     
282     if (dwRet == 0) {
283         wma->dwStatus = MCI_MODE_STOP;
284         wma->dwMciTimeFormat = MCI_FORMAT_FRAMES;
285     } else {
286         MCIAVI_CleanUp(wma);
287     }
288     return dwRet;
289     
290 }
291
292 /***************************************************************************
293  *                              MCIAVI_mciClose                 [internal]
294  */
295 static  DWORD   MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
296 {
297     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
298     DWORD               dwRet = 0;
299     
300     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);    
301     
302     if (wma == NULL)    return MCIERR_INVALID_DEVICE_ID;
303     
304     if (wma->nUseCount == 1) {
305         if (wma->dwStatus != MCI_MODE_STOP)
306             dwRet = MCIAVI_mciStop(wDevID, MCI_WAIT, lpParms);
307         MCIAVI_CleanUp(wma);
308         
309         if ((dwFlags & MCI_NOTIFY) && lpParms) {
310             mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
311                             wma->openParms.wDeviceID,
312                             MCI_NOTIFY_SUCCESSFUL);
313         }
314         HeapFree(GetProcessHeap(), 0, wma);
315         return dwRet;
316     }
317     wma->nUseCount--;
318     return dwRet;
319 }
320
321 /***************************************************************************
322  *                              MCIAVI_mciPlay                  [internal]
323  */
324 static  DWORD   MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
325 {
326     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
327     DWORD               tc;
328     DWORD               frameTime;
329     DWORD               delta;
330     DWORD               dwRet;
331     LPWAVEHDR           waveHdr = NULL;
332     unsigned            i, nHdr = 0;
333     DWORD               dwFromFrame, dwToFrame;
334
335     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
336     
337     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
338     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
339     
340     if (!wma->hFile)            return MCIERR_FILE_NOT_FOUND;
341     if (!wma->hWnd)             return MCIERR_NO_WINDOW;
342     
343     wma->dwStatus = MCI_MODE_PLAY;
344     
345     if (!(dwFlags & MCI_WAIT)) {
346         return MCI_SendCommandAsync(wma->openParms.wDeviceID, MCI_PLAY, dwFlags, 
347                                     (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
348     }
349     
350     ShowWindow(wma->hWnd, SW_SHOW);
351     
352     dwFromFrame = wma->dwCurrVideoFrame;
353     dwToFrame = wma->dwPlayableVideoFrames - 1;
354     
355     if (lpParms && (dwFlags & MCI_FROM)) {
356         dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom); 
357     }
358     if (lpParms && (dwFlags & MCI_TO)) {
359         dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
360     }
361     if (dwToFrame >= wma->dwPlayableVideoFrames)
362         dwToFrame = wma->dwPlayableVideoFrames - 1;
363
364     TRACE("Playing from frame=%lu to frame=%lu\n", dwFromFrame, dwToFrame);
365     
366     if (dwToFrame <= wma->dwCurrVideoFrame)
367         return TRUE;
368     wma->dwCurrVideoFrame = dwFromFrame;
369
370     if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_DGV_PLAY_REVERSE|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
371         FIXME("Unsupported flag %08lx\n", dwFlags);
372     
373     /* time is in microseconds, we should convert it to milliseconds */
374     frameTime = (wma->mah.dwMicroSecPerFrame + 500) / 1000;
375
376     if (wma->lpWaveFormat) {
377         if ((dwRet = MCIAVI_OpenAudio(wma, &nHdr, &waveHdr)) != 0)
378             goto cleanUp;
379         /* fill the queue with as many wave headers as possible */
380         MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
381     }
382
383     while (wma->dwStatus != MCI_MODE_STOP && wma->dwStatus != MCI_MODE_NOT_READY) {
384         tc = GetTickCount();
385         
386         MCIAVI_DrawFrame(wma);
387
388         if (wma->lpWaveFormat) {
389             MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
390             delta = GetTickCount() - tc;
391             WaitForSingleObject(wma->hEvent, (delta >= frameTime) ? 0 : frameTime - delta);
392         }
393
394         delta = GetTickCount() - tc;
395         if (delta < frameTime)
396             Sleep(frameTime - delta);
397
398         if (wma->dwCurrVideoFrame++ >= dwToFrame) {
399             wma->dwCurrVideoFrame--;
400             wma->dwStatus = MCI_MODE_STOP;
401         }
402     }
403
404     if (wma->lpWaveFormat) {
405         while (*(volatile DWORD*)&wma->dwEventCount != nHdr - 1) {
406             Sleep(100);
407         }
408         
409         /* just to get rid of some race conditions between play, stop and pause */
410         waveOutReset(wma->hWave);
411
412         for (i = 0; i < nHdr; i++)
413             waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
414     }
415
416     dwRet = 0;
417 cleanUp:
418     if (wma->lpWaveFormat) {
419         HeapFree(GetProcessHeap(), 0, waveHdr);
420
421         if (wma->hWave) {
422             waveOutClose(wma->hWave);
423             wma->hWave = 0;
424         }
425         CloseHandle(wma->hEvent);
426     }
427
428     if (lpParms && (dwFlags & MCI_NOTIFY)) {
429         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
430         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
431                         wma->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
432     }
433     
434     wma->dwStatus = MCI_MODE_STOP;
435     
436     return dwRet;
437 }
438
439 /***************************************************************************
440  *                              MCIAVI_mciRecord                        [internal]
441  */
442 static  DWORD   MCIAVI_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECORD_PARMS lpParms)
443 {
444     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
445     
446     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
447     
448     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
449     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
450     
451     wma->dwStatus = MCI_MODE_RECORD;
452     return 0;
453 }
454
455 /***************************************************************************
456  *                              MCIAVI_mciStop                  [internal]
457  */
458 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
459 {
460     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
461     DWORD               dwRet = 0;
462
463     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
464     
465     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
466     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
467     
468     switch (wma->dwStatus) {
469     case MCI_MODE_PAUSE:
470     case MCI_MODE_PLAY:
471     case MCI_MODE_RECORD:
472         {
473             int oldStat = wma->dwStatus;
474             wma->dwStatus = MCI_MODE_NOT_READY;
475             if (oldStat == MCI_MODE_PAUSE)
476                 dwRet = waveOutReset(wma->hWave);
477         }
478         while (wma->dwStatus != MCI_MODE_STOP)
479             Sleep(10);
480         break;
481     default:
482         wma->dwStatus = MCI_MODE_STOP;
483         break;
484     }
485     
486     if ((dwFlags & MCI_NOTIFY) && lpParms) {
487         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
488                         wma->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
489     }
490     
491     return dwRet;
492 }
493
494 /***************************************************************************
495  *                              MCIAVI_mciPause                 [internal]
496  */
497 static  DWORD   MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
498 {
499     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
500     
501     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
502     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
503     
504     if (wma->dwStatus == MCI_MODE_PLAY)
505         wma->dwStatus = MCI_MODE_PAUSE;
506
507     return (wma->lpWaveFormat) ? waveOutPause(wma->hWave) : 0;
508 }
509
510 /***************************************************************************
511  *                              MCIAVI_mciResume                        [internal]
512  */
513 static  DWORD   MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
514 {
515     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
516     
517     FIXME("(%04x, %08lX, %p) : stub\n", wDevID, dwFlags, lpParms);
518     
519     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
520     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
521     
522     if (wma->dwStatus == MCI_MODE_PAUSE)
523         wma->dwStatus = MCI_MODE_PLAY;
524
525     return (wma->lpWaveFormat) ? waveOutRestart(wma->hWave) : 0;
526 }
527
528 /***************************************************************************
529  *                              MCIAVI_mciSeek                  [internal]
530  */
531 static  DWORD   MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
532 {
533     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
534     
535     TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
536     
537     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
538     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
539     
540     EnterCriticalSection(&wma->cs);
541     
542     MCIAVI_mciStop(wDevID, MCI_WAIT, 0);
543         
544     if (dwFlags & MCI_SEEK_TO_START) {
545         wma->dwCurrVideoFrame = 0;
546     } else if (dwFlags & MCI_SEEK_TO_END) {
547         wma->dwCurrVideoFrame = wma->dwPlayableVideoFrames - 1;
548     } else if (dwFlags & MCI_TO) {
549         wma->dwCurrVideoFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
550     } else {
551         WARN("dwFlag doesn't tell where to seek to...\n");
552         return MCIERR_MISSING_PARAMETER;
553     }
554         
555     TRACE("Seeking to frame=%lu bytes\n", wma->dwCurrVideoFrame);
556         
557     if (dwFlags & MCI_NOTIFY) {
558         mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
559                         wma->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
560     }
561
562     LeaveCriticalSection(&wma->cs);
563
564     return 0;
565 }
566
567 /*****************************************************************************
568  *                              MCIAVI_mciLoad                  [internal]
569  */
570 static DWORD    MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSA lpParms)
571 {
572     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
573     
574     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
575     
576     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
577     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
578     
579     return 0;
580 }
581
582 /******************************************************************************
583  *                              MCIAVI_mciSave                  [internal]
584  */
585 static  DWORD   MCIAVI_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SAVE_PARMSA lpParms)
586 {
587     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
588     
589     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
590     
591     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
592     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
593     
594     return 0;
595 }
596
597 /******************************************************************************
598  *                              MCIAVI_mciFreeze                        [internal]
599  */
600 static  DWORD   MCIAVI_mciFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
601 {
602     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
603     
604     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
605     
606     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
607     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
608     
609     return 0;
610 }
611
612 /******************************************************************************
613  *                              MCIAVI_mciRealize                       [internal]
614  */
615 static  DWORD   MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
616 {
617     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
618     
619     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
620     
621     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
622     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
623     
624     return 0;
625 }
626
627 /******************************************************************************
628  *                              MCIAVI_mciUnFreeze                      [internal]
629  */
630 static  DWORD   MCIAVI_mciUnFreeze(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
631 {
632     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
633     
634     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
635     
636     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
637     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
638     
639     return 0;
640 }
641
642 /******************************************************************************
643  *                              MCIAVI_mciUpdate                        [internal]
644  */
645 static  DWORD   MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
646 {
647     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
648
649     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
650     
651     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
652     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
653     
654     return 0;
655 }
656
657 /******************************************************************************
658  *                              MCIAVI_mciStep                  [internal]
659  */
660 static  DWORD   MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
661 {
662     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
663     
664     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
665     
666     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
667     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
668     
669     return 0;
670 }
671
672 /******************************************************************************
673  *                              MCIAVI_mciCopy                  [internal]
674  */
675 static  DWORD   MCIAVI_mciCopy(UINT wDevID, DWORD dwFlags, LPMCI_DGV_COPY_PARMS lpParms)
676 {
677     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
678     
679     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
680     
681     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
682     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
683     
684     return 0;
685 }
686
687 /******************************************************************************
688  *                              MCIAVI_mciCut                   [internal]
689  */
690 static  DWORD   MCIAVI_mciCut(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUT_PARMS lpParms)
691 {
692     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
693     
694     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
695     
696     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
697     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
698     
699     return 0;
700 }
701
702 /******************************************************************************
703  *                              MCIAVI_mciDelete                        [internal]
704  */
705 static  DWORD   MCIAVI_mciDelete(UINT wDevID, DWORD dwFlags, LPMCI_DGV_DELETE_PARMS lpParms)
706 {
707     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
708     
709     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
710     
711     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
712     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
713     
714     return 0;
715 }
716
717 /******************************************************************************
718  *                              MCIAVI_mciPaste                 [internal]
719  */
720 static  DWORD   MCIAVI_mciPaste(UINT wDevID, DWORD dwFlags, LPMCI_DGV_PASTE_PARMS lpParms)
721 {
722     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
723     
724     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
725     
726     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
727     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
728     
729     return 0;
730 }
731
732 /******************************************************************************
733  *                              MCIAVI_mciCue                   [internal]
734  */
735 static  DWORD   MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
736 {
737     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
738     
739     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
740     
741     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
742     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
743     
744     return 0;
745 }
746
747 /******************************************************************************
748  *                              MCIAVI_mciCapture                       [internal]
749  */
750 static  DWORD   MCIAVI_mciCapture(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CAPTURE_PARMSA lpParms)
751 {
752     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
753     
754     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
755     
756     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
757     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
758     
759     return 0;
760 }
761
762 /******************************************************************************
763  *                              MCIAVI_mciMonitor                       [internal]
764  */
765 static  DWORD   MCIAVI_mciMonitor(UINT wDevID, DWORD dwFlags, LPMCI_DGV_MONITOR_PARMS lpParms)
766 {
767     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
768     
769     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
770     
771     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
772     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
773     
774     return 0;
775 }
776
777 /******************************************************************************
778  *                              MCIAVI_mciReserve                       [internal]
779  */
780 static  DWORD   MCIAVI_mciReserve(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESERVE_PARMSA lpParms)
781 {
782     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
783     
784     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
785     
786     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
787     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
788     
789     return 0;
790 }
791
792 /******************************************************************************
793  *                              MCIAVI_mciSetAudio                      [internal]
794  */
795 static  DWORD   MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSA lpParms)
796 {
797     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
798     
799     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
800     
801     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
802     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
803     
804     return 0;
805 }
806
807 /******************************************************************************
808  *                              MCIAVI_mciSignal                        [internal]
809  */
810 static  DWORD   MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
811 {
812     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
813     
814     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
815     
816     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
817     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
818     
819     return 0;
820 }
821
822 /******************************************************************************
823  *                              MCIAVI_mciSetVideo                      [internal]
824  */
825 static  DWORD   MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSA lpParms)
826 {
827     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
828     
829     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
830     
831     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
832     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
833     
834     return 0;
835 }
836
837 /******************************************************************************
838  *                              MCIAVI_mciQuality                       [internal]
839  */
840 static  DWORD   MCIAVI_mciQuality(UINT wDevID, DWORD dwFlags, LPMCI_DGV_QUALITY_PARMSA lpParms)
841 {
842     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
843     
844     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
845     
846     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
847     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
848     
849     return 0;
850 }
851
852 /******************************************************************************
853  *                              MCIAVI_mciList                  [internal]
854  */
855 static  DWORD   MCIAVI_mciList(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LIST_PARMSA lpParms)
856 {
857     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
858     
859     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
860     
861     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
862     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
863     
864     return 0;
865 }
866
867 /******************************************************************************
868  *                              MCIAVI_mciUndo                  [internal]
869  */
870 static  DWORD   MCIAVI_mciUndo(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
871 {
872     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
873     
874     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
875     
876     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
877     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
878     
879     return 0;
880 }
881
882 /******************************************************************************
883  *                              MCIAVI_mciConfigure                     [internal]
884  */
885 static  DWORD   MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
886 {
887     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
888     
889     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
890     
891     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
892     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
893     
894     return 0;
895 }
896
897 /******************************************************************************
898  *                              MCIAVI_mciRestore                       [internal]
899  */
900 static  DWORD   MCIAVI_mciRestore(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RESTORE_PARMSA lpParms)
901 {
902     WINE_MCIAVI*        wma = MCIAVI_mciGetOpenDev(wDevID);
903     
904     FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
905     
906     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
907     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
908     
909     return 0;
910 }
911
912 /*======================================================================*
913  *                          MCI AVI entry points                        *
914  *======================================================================*/
915
916 /**************************************************************************
917  *                              MCIAVI_DriverProc       [sample driver]
918  */
919 LONG CALLBACK   MCIAVI_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
920                                   DWORD dwParam1, DWORD dwParam2)
921 {
922     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", 
923           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
924     
925     switch (wMsg) {
926     case DRV_LOAD:              return 1;
927     case DRV_FREE:              return 1;
928     case DRV_OPEN:              return MCIAVI_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
929     case DRV_CLOSE:             return MCIAVI_drvClose(dwDevID);
930     case DRV_ENABLE:            return 1;
931     case DRV_DISABLE:           return 1;
932     case DRV_QUERYCONFIGURE:    return 1;
933     case DRV_CONFIGURE:         return MCIAVI_drvConfigure(dwDevID);
934     case DRV_INSTALL:           return DRVCNF_RESTART;
935     case DRV_REMOVE:            return DRVCNF_RESTART;
936         
937     case MCI_OPEN_DRIVER:       return MCIAVI_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSA)     dwParam2);
938     case MCI_CLOSE_DRIVER:      return MCIAVI_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
939     case MCI_PLAY:              return MCIAVI_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
940     case MCI_RECORD:            return MCIAVI_mciRecord    (dwDevID, dwParam1, (LPMCI_DGV_RECORD_PARMS)    dwParam2);
941     case MCI_STOP:              return MCIAVI_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
942     case MCI_SET:               return MCIAVI_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
943     case MCI_PAUSE:             return MCIAVI_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
944     case MCI_RESUME:            return MCIAVI_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
945     case MCI_STATUS:            return MCIAVI_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSA)   dwParam2);
946     case MCI_GETDEVCAPS:        return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
947     case MCI_INFO:              return MCIAVI_mciInfo      (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSA)     dwParam2);
948     case MCI_SEEK:              return MCIAVI_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
949     case MCI_PUT:               return MCIAVI_mciPut       (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS)       dwParam2);           
950     case MCI_WINDOW:            return MCIAVI_mciWindow    (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSA)   dwParam2);           
951     case MCI_LOAD:              return MCIAVI_mciLoad      (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSA)     dwParam2);           
952     case MCI_SAVE:              return MCIAVI_mciSave      (dwDevID, dwParam1, (LPMCI_DGV_SAVE_PARMSA)     dwParam2);           
953     case MCI_FREEZE:            return MCIAVI_mciFreeze    (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
954     case MCI_REALIZE:           return MCIAVI_mciRealize   (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
955     case MCI_UNFREEZE:          return MCIAVI_mciUnFreeze  (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
956     case MCI_UPDATE:            return MCIAVI_mciUpdate    (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)    dwParam2);
957     case MCI_WHERE:             return MCIAVI_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
958     case MCI_STEP:              return MCIAVI_mciStep      (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS)      dwParam2);
959     case MCI_COPY:              return MCIAVI_mciCopy      (dwDevID, dwParam1, (LPMCI_DGV_COPY_PARMS)      dwParam2);           
960     case MCI_CUT:               return MCIAVI_mciCut       (dwDevID, dwParam1, (LPMCI_DGV_CUT_PARMS)       dwParam2);           
961     case MCI_DELETE:            return MCIAVI_mciDelete    (dwDevID, dwParam1, (LPMCI_DGV_DELETE_PARMS)    dwParam2);                           
962     case MCI_PASTE:             return MCIAVI_mciPaste     (dwDevID, dwParam1, (LPMCI_DGV_PASTE_PARMS)     dwParam2);                           
963     case MCI_CUE:               return MCIAVI_mciCue       (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS)       dwParam2);
964         /* Digital Video specific */    
965     case MCI_CAPTURE:           return MCIAVI_mciCapture   (dwDevID, dwParam1, (LPMCI_DGV_CAPTURE_PARMSA)  dwParam2);
966     case MCI_MONITOR:           return MCIAVI_mciMonitor   (dwDevID, dwParam1, (LPMCI_DGV_MONITOR_PARMS)   dwParam2);
967     case MCI_RESERVE:           return MCIAVI_mciReserve   (dwDevID, dwParam1, (LPMCI_DGV_RESERVE_PARMSA)  dwParam2);
968     case MCI_SETAUDIO:          return MCIAVI_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSA) dwParam2);
969     case MCI_SIGNAL:            return MCIAVI_mciSignal    (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS)    dwParam2);
970     case MCI_SETVIDEO:          return MCIAVI_mciSetVideo  (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSA) dwParam2);
971     case MCI_QUALITY:           return MCIAVI_mciQuality   (dwDevID, dwParam1, (LPMCI_DGV_QUALITY_PARMSA)  dwParam2);
972     case MCI_LIST:              return MCIAVI_mciList      (dwDevID, dwParam1, (LPMCI_DGV_LIST_PARMSA)     dwParam2);
973     case MCI_UNDO:              return MCIAVI_mciUndo      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
974     case MCI_CONFIGURE:         return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
975     case MCI_RESTORE:           return MCIAVI_mciRestore   (dwDevID, dwParam1, (LPMCI_DGV_RESTORE_PARMSA)  dwParam2);
976         
977     case MCI_SPIN:
978     case MCI_ESCAPE:            
979         WARN("Unsupported command [%lu]\n", wMsg);
980         break;
981     case MCI_OPEN:
982     case MCI_CLOSE:
983         FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
984         break;
985     default:                    
986         TRACE("Sending msg [%lu] to default driver proc\n", wMsg);
987         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
988     }
989     return MCIERR_UNRECOGNIZED_COMMAND;
990 }
991
992