dxgi: Add IDXGISwapChain2 stubs for D3D11.
[wine.git] / dlls / mciavi32 / mciavi.c
bloba62c791cc9cbe474e3a68545535e28abeba57509
1 /*
2 * Digital video MCI Wine Driver
4 * Copyright 1999, 2000 Eric POUECH
5 * Copyright 2003 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 /* 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 * - reimplement the AVI handling part with avifile DLL because
30 * "open @1122334 type avivideo alias a" expects an AVIFile/Stream
31 * and MCI_DGV_SET|STATUS_SPEED maps to Rate/Scale
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 (AVIFile does that already)
36 * - stopping while playing a file with sound blocks until all buffered
37 * audio is played... still should be stopped ASAP
40 #include <string.h>
41 #include "private_mciavi.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
46 static DWORD MCIAVI_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
48 /*======================================================================*
49 * MCI AVI implementation *
50 *======================================================================*/
52 HINSTANCE MCIAVI_hInstance = 0;
54 /***********************************************************************
55 * DllMain (MCIAVI.0)
57 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
59 switch (fdwReason) {
60 case DLL_PROCESS_ATTACH:
61 DisableThreadLibraryCalls(hInstDLL);
62 MCIAVI_hInstance = hInstDLL;
63 break;
65 return TRUE;
68 /**************************************************************************
69 * MCIAVI_drvOpen [internal]
71 static DWORD MCIAVI_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
73 WINE_MCIAVI* wma;
75 TRACE("%s, %p\n", debugstr_w(str), modp);
77 /* session instance */
78 if (!modp) return 0xFFFFFFFF;
80 if (!MCIAVI_RegisterClass()) return 0;
82 wma = calloc(1, sizeof(WINE_MCIAVI));
83 if (!wma)
84 return 0;
86 InitializeCriticalSectionEx(&wma->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
87 wma->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINE_MCIAVI.cs");
88 wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
89 wma->wDevID = modp->wDeviceID;
90 wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, L"MCIAVI", 0);
91 wma->dwStatus = MCI_MODE_NOT_READY;
92 modp->wCustomCommandTable = wma->wCommandTable;
93 modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
94 mciSetDriverData(wma->wDevID, (DWORD_PTR)wma);
96 return modp->wDeviceID;
99 /**************************************************************************
100 * MCIAVI_drvClose [internal]
102 static DWORD MCIAVI_drvClose(DWORD dwDevID)
104 WINE_MCIAVI *wma;
106 TRACE("%04lx\n", dwDevID);
108 /* finish all outstanding things */
109 MCIAVI_mciClose(dwDevID, MCI_WAIT, NULL);
111 wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
113 if (wma) {
114 MCIAVI_UnregisterClass();
116 EnterCriticalSection(&wma->cs);
118 mciSetDriverData(dwDevID, 0);
119 mciFreeCommandResource(wma->wCommandTable);
121 CloseHandle(wma->hStopEvent);
123 LeaveCriticalSection(&wma->cs);
124 wma->cs.DebugInfo->Spare[0] = 0;
125 DeleteCriticalSection(&wma->cs);
127 free(wma);
128 return 1;
130 return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
133 /**************************************************************************
134 * MCIAVI_drvConfigure [internal]
136 static DWORD MCIAVI_drvConfigure(DWORD dwDevID)
138 WINE_MCIAVI *wma;
140 TRACE("%04lx\n", dwDevID);
142 MCIAVI_mciStop(dwDevID, MCI_WAIT, NULL);
144 wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
146 if (wma) {
147 MessageBoxA(0, "Sample AVI Wine Driver !", "MM-Wine Driver", MB_OK);
148 return 1;
150 return 0;
153 /**************************************************************************
154 * MCIAVI_mciGetOpenDev [internal]
156 WINE_MCIAVI* MCIAVI_mciGetOpenDev(UINT wDevID)
158 WINE_MCIAVI* wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
160 if (wma == NULL || wma->nUseCount == 0) {
161 WARN("Invalid wDevID=%u\n", wDevID);
162 return 0;
164 return wma;
167 static void MCIAVI_CleanUp(WINE_MCIAVI* wma)
169 /* to prevent handling in WindowProc */
170 wma->dwStatus = MCI_MODE_NOT_READY;
171 if (wma->hFile) {
172 mmioClose(wma->hFile, 0);
173 wma->hFile = 0;
175 free(wma->lpFileName);
176 wma->lpFileName = NULL;
178 free(wma->lpVideoIndex);
179 wma->lpVideoIndex = NULL;
180 free(wma->lpAudioIndex);
181 wma->lpAudioIndex = NULL;
182 if (wma->hic) ICClose(wma->hic);
183 wma->hic = 0;
184 free(wma->inbih);
185 wma->inbih = NULL;
186 free(wma->outbih);
187 wma->outbih = NULL;
188 free(wma->indata);
189 wma->indata = NULL;
190 free(wma->outdata);
191 wma->outdata = NULL;
192 if (wma->hbmFrame) DeleteObject(wma->hbmFrame);
193 wma->hbmFrame = 0;
194 if (wma->hWnd) DestroyWindow(wma->hWnd);
195 wma->hWnd = 0;
197 free(wma->lpWaveFormat);
198 wma->lpWaveFormat = 0;
200 memset(&wma->mah, 0, sizeof(wma->mah));
201 memset(&wma->ash_video, 0, sizeof(wma->ash_video));
202 memset(&wma->ash_audio, 0, sizeof(wma->ash_audio));
203 wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
204 wma->dwCachedFrame = -1;
208 /***************************************************************************
209 * MCIAVI_mciOpen [internal]
211 static DWORD MCIAVI_mciOpen(UINT wDevID, DWORD dwFlags,
212 LPMCI_DGV_OPEN_PARMSW lpOpenParms)
214 WINE_MCIAVI *wma;
215 LRESULT dwRet = 0;
217 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
219 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
221 wma = (WINE_MCIAVI *)mciGetDriverData(wDevID);
222 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
224 EnterCriticalSection(&wma->cs);
226 if (wma->nUseCount > 0) {
227 /* The driver is already open on this channel */
228 /* If the driver was opened shareable before and this open specifies */
229 /* shareable then increment the use count */
230 if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
231 ++wma->nUseCount;
232 else
234 LeaveCriticalSection(&wma->cs);
235 return MCIERR_MUST_USE_SHAREABLE;
237 } else {
238 wma->nUseCount = 1;
239 wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
242 wma->dwStatus = MCI_MODE_NOT_READY;
244 if (dwFlags & MCI_OPEN_ELEMENT) {
245 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
246 /* could it be that (DWORD)lpOpenParms->lpstrElementName
247 * contains the hFile value ?
249 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
250 } else if (lpOpenParms->lpstrElementName && lpOpenParms->lpstrElementName[0]) {
251 /* FIXME : what should be done id wma->hFile is already != 0, or the driver is playin' */
252 TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(lpOpenParms->lpstrElementName));
254 wma->lpFileName = wcsdup(lpOpenParms->lpstrElementName);
256 if (lpOpenParms->lpstrElementName[0] == '@') {
257 /* The file name @11223344 encodes an AVIFile handle in decimal notation
258 * in Win3.1 and w2k/NT, but this feature is absent in win95 (KB140750).
259 * wma->hFile = LongToHandle(wcstol(lpOpenParms->lpstrElementName+1, NULL, 10)); */
260 FIXME("Using AVIFile/Stream %s NIY\n", debugstr_w(lpOpenParms->lpstrElementName));
262 wma->hFile = mmioOpenW(lpOpenParms->lpstrElementName, NULL,
263 MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
265 if (wma->hFile == 0) {
266 WARN("can't find file=%s!\n", debugstr_w(lpOpenParms->lpstrElementName));
267 dwRet = MCIERR_FILE_NOT_FOUND;
268 } else {
269 if (!MCIAVI_GetInfo(wma))
270 dwRet = MCIERR_INVALID_FILE;
271 else if (!MCIAVI_OpenVideo(wma))
272 dwRet = MCIERR_CANNOT_LOAD_DRIVER;
273 else if (!MCIAVI_CreateWindow(wma, dwFlags, lpOpenParms))
274 dwRet = MCIERR_CREATEWINDOW;
276 } else {
277 FIXME("Don't record yet\n");
278 dwRet = MCIERR_UNSUPPORTED_FUNCTION;
282 if (dwRet == 0) {
283 TRACE("lpOpenParms->wDeviceID = %04x\n", lpOpenParms->wDeviceID);
285 wma->dwStatus = MCI_MODE_STOP;
286 wma->dwMciTimeFormat = MCI_FORMAT_FRAMES;
287 } else {
288 MCIAVI_CleanUp(wma);
291 LeaveCriticalSection(&wma->cs);
293 if (!dwRet && (dwFlags & MCI_NOTIFY)) {
294 mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)),
295 wDevID, MCI_NOTIFY_SUCCESSFUL);
297 return dwRet;
300 /***************************************************************************
301 * MCIAVI_mciClose [internal]
303 DWORD MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
305 WINE_MCIAVI *wma;
306 DWORD dwRet = 0;
308 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
310 wma = MCIAVI_mciGetOpenDev(wDevID);
311 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
313 MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
315 EnterCriticalSection(&wma->cs);
317 if (wma->nUseCount == 1) {
318 MCIAVI_CleanUp(wma);
320 if ((dwFlags & MCI_NOTIFY) && lpParms) {
321 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
322 wDevID,
323 MCI_NOTIFY_SUCCESSFUL);
325 LeaveCriticalSection(&wma->cs);
326 return dwRet;
328 wma->nUseCount--;
330 LeaveCriticalSection(&wma->cs);
331 return dwRet;
334 static double currenttime_us(void)
336 LARGE_INTEGER lc, lf;
337 QueryPerformanceCounter(&lc);
338 QueryPerformanceFrequency(&lf);
339 return (lc.QuadPart * 1000000) / lf.QuadPart;
342 /***************************************************************************
343 * MCIAVI_player [internal]
345 static DWORD MCIAVI_player(WINE_MCIAVI *wma, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
347 DWORD dwRet;
348 LPWAVEHDR waveHdr = NULL;
349 unsigned i, nHdr = 0;
350 DWORD numEvents = 1;
351 HANDLE events[2];
352 double next_frame_us;
353 BOOL wait_audio = TRUE;
355 EnterCriticalSection(&wma->cs);
357 if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
359 dwRet = 0;
360 goto mci_play_done;
363 events[0] = wma->hStopEvent;
364 if (wma->lpWaveFormat) {
365 if (MCIAVI_OpenAudio(wma, &nHdr, &waveHdr) != 0)
367 /* can't play audio */
368 free(wma->lpWaveFormat);
369 wma->lpWaveFormat = NULL;
371 else
373 /* fill the queue with as many wave headers as possible */
374 MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
375 events[1] = wma->hEvent;
376 numEvents = 2;
380 next_frame_us = currenttime_us();
381 while (wma->dwStatus == MCI_MODE_PLAY)
383 HDC hDC;
384 double tc, delta;
385 DWORD ret;
387 tc = currenttime_us();
389 hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
390 if (hDC)
392 while(next_frame_us <= tc && wma->dwCurrVideoFrame < wma->dwToVideoFrame){
393 double dur;
394 dur = MCIAVI_PaintFrame(wma, hDC);
395 ++wma->dwCurrVideoFrame;
396 if(!dur)
397 break;
398 next_frame_us += dur;
399 TRACE("next_frame: %f\n", next_frame_us);
401 ReleaseDC(wma->hWndPaint, hDC);
403 if (wma->dwCurrVideoFrame >= wma->dwToVideoFrame)
405 if (!(dwFlags & MCI_DGV_PLAY_REPEAT))
406 break;
407 TRACE("repeat media as requested\n");
408 wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
411 if (wma->lpWaveFormat)
412 MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
414 tc = currenttime_us();
415 if (tc < next_frame_us)
416 delta = next_frame_us - tc;
417 else
418 delta = 0;
420 /* check if the playback was cancelled */
421 if ((wma->mci_break.flags & MCI_BREAK_KEY) &&
422 (GetAsyncKeyState(wma->mci_break.parms.nVirtKey) & 0x8000))
424 if (!(wma->mci_break.flags & MCI_BREAK_HWND) ||
425 GetForegroundWindow() == wma->mci_break.parms.hwndBreak)
427 /* we queue audio blocks ahead so ignore them otherwise the audio
428 * will keep playing until the buffer is empty */
429 wait_audio = FALSE;
431 TRACE("playback cancelled using break key\n");
432 break;
436 LeaveCriticalSection(&wma->cs);
437 ret = WaitForMultipleObjects(numEvents, events, FALSE, delta / 1000);
438 EnterCriticalSection(&wma->cs);
439 if (ret == WAIT_OBJECT_0 || wma->dwStatus != MCI_MODE_PLAY) break;
442 if (wma->lpWaveFormat)
444 if (wait_audio)
445 while (wma->dwEventCount != nHdr - 1)
447 LeaveCriticalSection(&wma->cs);
448 Sleep(100);
449 EnterCriticalSection(&wma->cs);
452 /* just to get rid of some race conditions between play, stop and pause */
453 LeaveCriticalSection(&wma->cs);
454 waveOutReset(wma->hWave);
455 EnterCriticalSection(&wma->cs);
457 for (i = 0; i < nHdr; i++)
458 waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
461 dwRet = 0;
463 if (wma->lpWaveFormat) {
464 free(waveHdr);
466 if (wma->hWave) {
467 LeaveCriticalSection(&wma->cs);
468 waveOutClose(wma->hWave);
469 EnterCriticalSection(&wma->cs);
470 wma->hWave = 0;
472 CloseHandle(wma->hEvent);
475 mci_play_done:
476 wma->dwStatus = MCI_MODE_STOP;
478 if (dwFlags & MCI_NOTIFY) {
479 TRACE("MCI_NOTIFY_SUCCESSFUL %08IX !\n", lpParms->dwCallback);
480 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
481 wma->wDevID, MCI_NOTIFY_SUCCESSFUL);
483 LeaveCriticalSection(&wma->cs);
484 return dwRet;
487 struct MCIAVI_play_data
489 WINE_MCIAVI *wma;
490 DWORD flags;
491 MCI_PLAY_PARMS params; /* FIXME: notify via wma->hCallback like the other MCI drivers */
495 * MCIAVI_mciPlay_thread
497 * FIXME: probably should use a common worker thread created at the driver
498 * load time and queue all async commands to it.
500 static DWORD WINAPI MCIAVI_mciPlay_thread(LPVOID arg)
502 struct MCIAVI_play_data *data = (struct MCIAVI_play_data *)arg;
503 DWORD ret;
505 TRACE("In thread before async play command (id %u, flags %08lx)\n", data->wma->wDevID, data->flags);
506 ret = MCIAVI_player(data->wma, data->flags, &data->params);
507 TRACE("In thread after async play command (id %u, flags %08lx)\n", data->wma->wDevID, data->flags);
509 free(data);
510 return ret;
514 * MCIAVI_mciPlay_async
516 static DWORD MCIAVI_mciPlay_async(WINE_MCIAVI *wma, DWORD dwFlags, LPMCI_PLAY_PARMS lpParams)
518 HANDLE handle;
519 struct MCIAVI_play_data *data = malloc(sizeof(struct MCIAVI_play_data));
521 if (!data) return MCIERR_OUT_OF_MEMORY;
523 data->wma = wma;
524 data->flags = dwFlags;
525 if (dwFlags & MCI_NOTIFY)
526 data->params.dwCallback = lpParams->dwCallback;
528 if (!(handle = CreateThread(NULL, 0, MCIAVI_mciPlay_thread, data, 0, NULL)))
530 WARN("Couldn't create thread for async play, playing synchronously\n");
531 return MCIAVI_mciPlay_thread(data);
533 SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
534 CloseHandle(handle);
535 return 0;
538 /***************************************************************************
539 * MCIAVI_mciPlay [internal]
541 static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
543 WINE_MCIAVI *wma;
544 DWORD dwRet;
545 DWORD dwFromFrame, dwToFrame;
547 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
549 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
551 wma = MCIAVI_mciGetOpenDev(wDevID);
552 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
553 if (dwFlags & MCI_DGV_PLAY_REVERSE) return MCIERR_UNSUPPORTED_FUNCTION;
554 if (dwFlags & MCI_TEST) return 0;
556 if (dwFlags & (MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLBY2))
557 FIXME("Unsupported flag %08lx\n", dwFlags);
559 EnterCriticalSection(&wma->cs);
561 if (!wma->hFile)
563 LeaveCriticalSection(&wma->cs);
564 return MCIERR_FILE_NOT_FOUND;
566 if (!wma->hWndPaint)
568 LeaveCriticalSection(&wma->cs);
569 return MCIERR_NO_WINDOW;
572 dwFromFrame = wma->dwCurrVideoFrame;
573 dwToFrame = wma->dwPlayableVideoFrames - 1;
575 if (dwFlags & MCI_FROM) {
576 dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
578 if (dwFlags & MCI_TO) {
579 dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
581 if (dwToFrame >= wma->dwPlayableVideoFrames)
582 dwToFrame = wma->dwPlayableVideoFrames - 1;
584 TRACE("Playing from frame=%lu to frame=%lu\n", dwFromFrame, dwToFrame);
586 wma->dwCurrVideoFrame = dwFromFrame;
587 wma->dwToVideoFrame = dwToFrame;
589 LeaveCriticalSection(&wma->cs);
591 if (dwFlags & MCI_MCIAVI_PLAY_FULLSCREEN)
593 HMONITOR mon = MonitorFromWindow(wma->hWndPaint, MONITOR_DEFAULTTONEAREST);
594 MONITORINFO mi;
595 mi.cbSize = sizeof(mi);
596 GetMonitorInfoA(mon, &mi);
597 wma->hWndPaint = CreateWindowA("STATIC", NULL, WS_POPUP | WS_VISIBLE, mi.rcMonitor.left,
598 mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top,
599 NULL, NULL, NULL, 0);
601 /* if not fullscreen ensure the window is visible */
602 else if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
603 ShowWindow(wma->hWndPaint, SW_SHOWNA);
605 EnterCriticalSection(&wma->cs);
607 /* if already playing exit */
608 if (wma->dwStatus == MCI_MODE_PLAY)
610 LeaveCriticalSection(&wma->cs);
611 return 0;
614 wma->dwStatus = MCI_MODE_PLAY;
616 LeaveCriticalSection(&wma->cs);
618 if (dwFlags & MCI_WAIT)
619 return MCIAVI_player(wma, dwFlags, lpParms);
621 dwRet = MCIAVI_mciPlay_async(wma, dwFlags, lpParms);
623 if (dwRet) {
624 EnterCriticalSection(&wma->cs);
625 wma->dwStatus = MCI_MODE_STOP;
626 LeaveCriticalSection(&wma->cs);
628 return dwRet;
631 /***************************************************************************
632 * MCIAVI_mciStop [internal]
634 static DWORD MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
636 WINE_MCIAVI *wma;
637 DWORD dwRet = 0;
639 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
641 wma = MCIAVI_mciGetOpenDev(wDevID);
642 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
643 if (dwFlags & MCI_TEST) return 0;
645 EnterCriticalSection(&wma->cs);
647 TRACE("current status %04lx\n", wma->dwStatus);
649 switch (wma->dwStatus) {
650 case MCI_MODE_PLAY:
651 case MCI_MODE_RECORD:
652 LeaveCriticalSection(&wma->cs);
653 SetEvent(wma->hStopEvent);
654 EnterCriticalSection(&wma->cs);
655 /* fall through */
656 case MCI_MODE_PAUSE:
657 /* Since our wave notification callback takes the lock,
658 * we must release it before resetting the device */
659 LeaveCriticalSection(&wma->cs);
660 dwRet = waveOutReset(wma->hWave);
661 EnterCriticalSection(&wma->cs);
662 /* fall through */
663 default:
664 do /* one more chance for an async thread to finish */
666 LeaveCriticalSection(&wma->cs);
667 Sleep(10);
668 EnterCriticalSection(&wma->cs);
669 } while (wma->dwStatus != MCI_MODE_STOP);
671 break;
673 case MCI_MODE_NOT_READY:
674 break;
677 if ((dwFlags & MCI_NOTIFY) && lpParms) {
678 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
679 wDevID, MCI_NOTIFY_SUCCESSFUL);
681 LeaveCriticalSection(&wma->cs);
682 return dwRet;
685 /***************************************************************************
686 * MCIAVI_mciPause [internal]
688 static DWORD MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
690 WINE_MCIAVI *wma;
692 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
694 wma = MCIAVI_mciGetOpenDev(wDevID);
695 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
696 if (dwFlags & MCI_TEST) return 0;
698 EnterCriticalSection(&wma->cs);
700 if (wma->dwStatus == MCI_MODE_PLAY)
701 wma->dwStatus = MCI_MODE_PAUSE;
703 if (wma->lpWaveFormat) {
704 LeaveCriticalSection(&wma->cs);
705 return waveOutPause(wma->hWave);
708 LeaveCriticalSection(&wma->cs);
709 return 0;
712 /***************************************************************************
713 * MCIAVI_mciResume [internal]
715 static DWORD MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
717 WINE_MCIAVI *wma;
719 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
721 wma = MCIAVI_mciGetOpenDev(wDevID);
722 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
723 if (dwFlags & MCI_TEST) return 0;
725 EnterCriticalSection(&wma->cs);
727 if (wma->dwStatus == MCI_MODE_PAUSE)
728 wma->dwStatus = MCI_MODE_PLAY;
730 if (wma->lpWaveFormat) {
731 LeaveCriticalSection(&wma->cs);
732 return waveOutRestart(wma->hWave);
735 LeaveCriticalSection(&wma->cs);
736 return 0;
739 /***************************************************************************
740 * MCIAVI_mciSeek [internal]
742 static DWORD MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
744 WINE_MCIAVI *wma;
745 DWORD position;
747 TRACE("(%04x, %08lX, %p)\n", wDevID, dwFlags, lpParms);
749 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
751 wma = MCIAVI_mciGetOpenDev(wDevID);
752 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
754 position = dwFlags & (MCI_SEEK_TO_START|MCI_SEEK_TO_END|MCI_TO);
755 if (!position) return MCIERR_MISSING_PARAMETER;
756 if (position&(position-1)) return MCIERR_FLAGS_NOT_COMPATIBLE;
758 if (dwFlags & MCI_TO) {
759 position = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
760 if (position >= wma->dwPlayableVideoFrames)
761 return MCIERR_OUTOFRANGE;
762 } else if (dwFlags & MCI_SEEK_TO_START) {
763 position = 0;
764 } else {
765 position = wma->dwPlayableVideoFrames - 1;
767 if (dwFlags & MCI_TEST) return 0;
769 MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
771 EnterCriticalSection(&wma->cs);
773 wma->dwCurrVideoFrame = position;
774 TRACE("Seeking to frame=%lu\n", wma->dwCurrVideoFrame);
776 if (dwFlags & MCI_NOTIFY) {
777 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
778 wDevID, MCI_NOTIFY_SUCCESSFUL);
780 LeaveCriticalSection(&wma->cs);
781 return 0;
784 /*****************************************************************************
785 * MCIAVI_mciLoad [internal]
787 static DWORD MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSW lpParms)
789 WINE_MCIAVI *wma;
791 FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
793 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
795 wma = MCIAVI_mciGetOpenDev(wDevID);
796 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
798 return MCIERR_UNSUPPORTED_FUNCTION; /* like w2k */
801 /******************************************************************************
802 * MCIAVI_mciRealize [internal]
804 static DWORD MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
806 WINE_MCIAVI *wma;
808 FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
810 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
812 wma = MCIAVI_mciGetOpenDev(wDevID);
813 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
814 if (dwFlags & MCI_TEST) return 0;
816 return 0;
819 /******************************************************************************
820 * MCIAVI_mciUpdate [internal]
822 static DWORD MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
824 WINE_MCIAVI *wma;
826 TRACE("%04x, %08lx, %p\n", wDevID, dwFlags, lpParms);
828 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
830 wma = MCIAVI_mciGetOpenDev(wDevID);
831 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
832 /* Ignore MCI_TEST flag. */
834 EnterCriticalSection(&wma->cs);
836 if (dwFlags & MCI_DGV_UPDATE_HDC)
837 MCIAVI_PaintFrame(wma, lpParms->hDC);
839 LeaveCriticalSection(&wma->cs);
841 return 0;
844 /******************************************************************************
845 * MCIAVI_mciStep [internal]
847 static DWORD MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
849 WINE_MCIAVI *wma;
850 DWORD position;
851 int delta = 1;
853 TRACE("(%04x, %08lx, %p)\n", wDevID, dwFlags, lpParms);
855 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
857 wma = MCIAVI_mciGetOpenDev(wDevID);
858 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
860 if (dwFlags & MCI_DGV_STEP_FRAMES) delta = lpParms->dwFrames;
861 if (dwFlags & MCI_DGV_STEP_REVERSE) delta = -delta;
862 position = wma->dwCurrVideoFrame + delta;
863 if (position >= wma->dwPlayableVideoFrames) return MCIERR_OUTOFRANGE;
864 if (dwFlags & MCI_TEST) return 0;
866 MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
868 EnterCriticalSection(&wma->cs);
870 wma->dwCurrVideoFrame = position;
871 TRACE("Stepping to frame=%lu\n", wma->dwCurrVideoFrame);
873 if (dwFlags & MCI_NOTIFY) {
874 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
875 wDevID, MCI_NOTIFY_SUCCESSFUL);
877 LeaveCriticalSection(&wma->cs);
878 return 0;
881 /******************************************************************************
882 * MCIAVI_mciCue [internal]
884 static DWORD MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
886 WINE_MCIAVI *wma;
888 FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
890 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
892 wma = MCIAVI_mciGetOpenDev(wDevID);
893 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
894 if (dwFlags & MCI_DGV_CUE_INPUT) return MCIERR_UNSUPPORTED_FUNCTION;
895 if (dwFlags & MCI_TEST) return 0;
897 return 0;
900 /******************************************************************************
901 * MCIAVI_mciBreak [internal]
903 static DWORD MCIAVI_mciBreak(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms)
905 WINE_MCIAVI *wma;
907 TRACE("(%04x, %08lx, %p)\n", wDevID, dwFlags, lpParms);
909 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
911 wma = MCIAVI_mciGetOpenDev(wDevID);
912 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
914 EnterCriticalSection(&wma->cs);
916 wma->mci_break.flags = dwFlags;
917 wma->mci_break.parms = *lpParms;
919 LeaveCriticalSection(&wma->cs);
921 return 0;
924 /******************************************************************************
925 * MCIAVI_mciSetAudio [internal]
927 static DWORD MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
929 WINE_MCIAVI *wma;
931 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
933 FIXME("(%04x, %08lx, %p) Item %04lx: stub\n", wDevID, dwFlags, lpParms, dwFlags & MCI_DGV_SETAUDIO_ITEM ? lpParms->dwItem : 0);
935 wma = MCIAVI_mciGetOpenDev(wDevID);
936 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
938 return 0;
941 /******************************************************************************
942 * MCIAVI_mciSignal [internal]
944 static DWORD MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
946 WINE_MCIAVI *wma;
948 FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
950 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
952 wma = MCIAVI_mciGetOpenDev(wDevID);
953 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
955 return 0;
958 /******************************************************************************
959 * MCIAVI_mciSetVideo [internal]
961 static DWORD MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSW lpParms)
963 WINE_MCIAVI *wma;
965 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
967 FIXME("(%04x, %08lx, %p) Item %04lx: stub\n", wDevID, dwFlags, lpParms, dwFlags & MCI_DGV_SETVIDEO_ITEM ? lpParms->dwItem : 0);
969 wma = MCIAVI_mciGetOpenDev(wDevID);
970 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
972 return 0;
975 /******************************************************************************
976 * MCIAVI_mciConfigure [internal]
978 static DWORD MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
980 WINE_MCIAVI *wma;
982 FIXME("(%04x, %08lx, %p) : stub\n", wDevID, dwFlags, lpParms);
984 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
986 wma = MCIAVI_mciGetOpenDev(wDevID);
987 if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
988 if (dwFlags & MCI_TEST) return 0;
990 return 0;
993 /*======================================================================*
994 * MCI AVI entry points *
995 *======================================================================*/
997 /**************************************************************************
998 * DriverProc (MCIAVI.@)
1000 LRESULT CALLBACK MCIAVI_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1001 LPARAM dwParam1, LPARAM dwParam2)
1003 TRACE("(%08IX, %p, %08X, %08IX, %08IX)\n",
1004 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1006 switch (wMsg) {
1007 case DRV_LOAD: return 1;
1008 case DRV_FREE: return 1;
1009 case DRV_OPEN: return MCIAVI_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1010 case DRV_CLOSE: return MCIAVI_drvClose(dwDevID);
1011 case DRV_ENABLE: return 1;
1012 case DRV_DISABLE: return 1;
1013 case DRV_QUERYCONFIGURE: return 1;
1014 case DRV_CONFIGURE: return MCIAVI_drvConfigure(dwDevID);
1015 case DRV_INSTALL: return DRVCNF_RESTART;
1016 case DRV_REMOVE: return DRVCNF_RESTART;
1019 /* session instance */
1020 if (dwDevID == 0xFFFFFFFF) return 1;
1022 switch (wMsg) {
1023 case MCI_OPEN_DRIVER: return MCIAVI_mciOpen (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW) dwParam2);
1024 case MCI_CLOSE_DRIVER: return MCIAVI_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1025 case MCI_PLAY: return MCIAVI_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1026 case MCI_STOP: return MCIAVI_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1027 case MCI_SET: return MCIAVI_mciSet (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS) dwParam2);
1028 case MCI_PAUSE: return MCIAVI_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1029 case MCI_RESUME: return MCIAVI_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1030 case MCI_STATUS: return MCIAVI_mciStatus (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW) dwParam2);
1031 case MCI_GETDEVCAPS: return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1032 case MCI_INFO: return MCIAVI_mciInfo (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSW) dwParam2);
1033 case MCI_SEEK: return MCIAVI_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1034 case MCI_PUT: return MCIAVI_mciPut (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS) dwParam2);
1035 case MCI_WINDOW: return MCIAVI_mciWindow (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW) dwParam2);
1036 case MCI_LOAD: return MCIAVI_mciLoad (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSW) dwParam2);
1037 case MCI_REALIZE: return MCIAVI_mciRealize (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1038 case MCI_UPDATE: return MCIAVI_mciUpdate (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS) dwParam2);
1039 case MCI_WHERE: return MCIAVI_mciWhere (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS) dwParam2);
1040 case MCI_STEP: return MCIAVI_mciStep (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS) dwParam2);
1041 case MCI_CUE: return MCIAVI_mciCue (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS) dwParam2);
1042 case MCI_BREAK: return MCIAVI_mciBreak (dwDevID, dwParam1, (LPMCI_BREAK_PARMS) dwParam2);
1043 /* Digital Video specific */
1044 case MCI_SETAUDIO: return MCIAVI_mciSetAudio (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
1045 case MCI_SIGNAL: return MCIAVI_mciSignal (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS) dwParam2);
1046 case MCI_SETVIDEO: return MCIAVI_mciSetVideo (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSW) dwParam2);
1047 case MCI_CONFIGURE: return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1049 /* no editing, recording, saving, locking without inputs */
1050 case MCI_CAPTURE:
1051 case MCI_COPY:
1052 case MCI_CUT:
1053 case MCI_DELETE:
1054 case MCI_FREEZE:
1055 case MCI_LIST:
1056 case MCI_MONITOR:
1057 case MCI_PASTE:
1058 case MCI_QUALITY:
1059 case MCI_RECORD:
1060 case MCI_RESERVE:
1061 case MCI_RESTORE:
1062 case MCI_SAVE:
1063 case MCI_UNDO:
1064 case MCI_UNFREEZE:
1065 TRACE("Unsupported function [0x%x] flags=%08Ix\n", wMsg, dwParam1);
1066 return MCIERR_UNSUPPORTED_FUNCTION;
1067 case MCI_SPIN:
1068 case MCI_ESCAPE:
1069 WARN("Unsupported command [0x%x] %08Ix\n", wMsg, dwParam1);
1070 break;
1071 case MCI_OPEN:
1072 case MCI_CLOSE:
1073 FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1074 break;
1075 default:
1076 TRACE("Sending msg [%u] to default driver proc\n", wMsg);
1077 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1079 return MCIERR_UNRECOGNIZED_COMMAND;