ReactOS Fundraising Campaign 2012
 
€ 3,873 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

mciavi.c
Go to the documentation of this file.
00001 /*
00002  * Digital video MCI Wine Driver
00003  *
00004  * Copyright 1999, 2000 Eric POUECH
00005  * Copyright 2003 Dmitry Timoshkov
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 /* TODO list :
00023  *  - handling of palettes
00024  *  - recording (which input devices ?), a cam recorder ?
00025  *  - lots of messages still need to be handled (cf FIXME)
00026  *  - synchronization between audio and video (especially for interleaved
00027  *    files)
00028  *  - robustness when reading file can be enhanced
00029  *  - reimplement the AVI handling part with avifile DLL because
00030  *    "open @1122334 type avivideo alias a" expects an AVIFile/Stream
00031  *    and MCI_DGV_SET|STATUS_SPEED maps to Rate/Scale
00032  *  - some files appear to have more than one audio stream (we only play the
00033  *    first one)
00034  *  - some files contain an index of audio/video frame. Better use it,
00035  *    instead of rebuilding it (AVIFile does that already)
00036  *  - stopping while playing a file with sound blocks until all buffered
00037  *        audio is played... still should be stopped ASAP
00038  */
00039 
00040 #include <string.h>
00041 #include "private_mciavi.h"
00042 #include "wine/debug.h"
00043 #include "wine/unicode.h"
00044 
00045 WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
00046 
00047 static DWORD MCIAVI_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
00048 
00049 /*======================================================================*
00050  *                          MCI AVI implementation          *
00051  *======================================================================*/
00052 
00053 HINSTANCE MCIAVI_hInstance = 0;
00054 
00055 /***********************************************************************
00056  *      DllMain (MCIAVI.0)
00057  */
00058 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
00059 {
00060     switch (fdwReason) {
00061     case DLL_PROCESS_ATTACH:
00062         DisableThreadLibraryCalls(hInstDLL);
00063     MCIAVI_hInstance = hInstDLL;
00064     break;
00065     }
00066     return TRUE;
00067 }
00068 
00069 /**************************************************************************
00070  *              MCIAVI_drvOpen          [internal]
00071  */
00072 static  DWORD   MCIAVI_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
00073 {
00074     WINE_MCIAVI*    wma;
00075     static const WCHAR mciAviWStr[] = {'M','C','I','A','V','I',0};
00076 
00077     TRACE("%s, %p\n", debugstr_w(str), modp);
00078 
00079     /* session instance */
00080     if (!modp) return 0xFFFFFFFF;
00081 
00082     if (!MCIAVI_RegisterClass()) return 0;
00083 
00084     wma = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIAVI));
00085     if (!wma)
00086     return 0;
00087 
00088     InitializeCriticalSection(&wma->cs);
00089     wma->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINE_MCIAVI.cs");
00090     wma->ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
00091     wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
00092     wma->wDevID = modp->wDeviceID;
00093     wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
00094     wma->dwStatus = MCI_MODE_NOT_READY;
00095     modp->wCustomCommandTable = wma->wCommandTable;
00096     modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
00097     mciSetDriverData(wma->wDevID, (DWORD_PTR)wma);
00098 
00099     return modp->wDeviceID;
00100 }
00101 
00102 /**************************************************************************
00103  *              MCIAVI_drvClose     [internal]
00104  */
00105 static  DWORD   MCIAVI_drvClose(DWORD dwDevID)
00106 {
00107     WINE_MCIAVI *wma;
00108 
00109     TRACE("%04x\n", dwDevID);
00110 
00111     /* finish all outstanding things */
00112     MCIAVI_mciClose(dwDevID, MCI_WAIT, NULL);
00113 
00114     wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
00115 
00116     if (wma) {
00117         MCIAVI_UnregisterClass();
00118 
00119         EnterCriticalSection(&wma->cs);
00120 
00121     mciSetDriverData(dwDevID, 0);
00122     mciFreeCommandResource(wma->wCommandTable);
00123 
00124         CloseHandle(wma->ack_event);
00125         CloseHandle(wma->hStopEvent);
00126 
00127         LeaveCriticalSection(&wma->cs);
00128         wma->cs.DebugInfo->Spare[0] = 0;
00129         DeleteCriticalSection(&wma->cs);
00130 
00131     HeapFree(GetProcessHeap(), 0, wma);
00132     return 1;
00133     }
00134     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
00135 }
00136 
00137 /**************************************************************************
00138  *              MCIAVI_drvConfigure     [internal]
00139  */
00140 static  DWORD   MCIAVI_drvConfigure(DWORD dwDevID)
00141 {
00142     WINE_MCIAVI *wma;
00143 
00144     TRACE("%04x\n", dwDevID);
00145 
00146     MCIAVI_mciStop(dwDevID, MCI_WAIT, NULL);
00147 
00148     wma = (WINE_MCIAVI*)mciGetDriverData(dwDevID);
00149 
00150     if (wma) {
00151     MessageBoxA(0, "Sample AVI Wine Driver !", "MM-Wine Driver", MB_OK);
00152     return 1;
00153     }
00154     return 0;
00155 }
00156 
00157 /**************************************************************************
00158  *              MCIAVI_mciGetOpenDev        [internal]
00159  */
00160 WINE_MCIAVI*  MCIAVI_mciGetOpenDev(UINT wDevID)
00161 {
00162     WINE_MCIAVI*    wma = (WINE_MCIAVI*)mciGetDriverData(wDevID);
00163 
00164     if (wma == NULL || wma->nUseCount == 0) {
00165     WARN("Invalid wDevID=%u\n", wDevID);
00166     return 0;
00167     }
00168     return wma;
00169 }
00170 
00171 static void MCIAVI_CleanUp(WINE_MCIAVI* wma)
00172 {
00173     /* to prevent handling in WindowProc */
00174     wma->dwStatus = MCI_MODE_NOT_READY;
00175     if (wma->hFile) {
00176     mmioClose(wma->hFile, 0);
00177     wma->hFile = 0;
00178 
00179         HeapFree(GetProcessHeap(), 0, wma->lpFileName);
00180         wma->lpFileName = NULL;
00181 
00182         HeapFree(GetProcessHeap(), 0, wma->lpVideoIndex);
00183     wma->lpVideoIndex = NULL;
00184         HeapFree(GetProcessHeap(), 0, wma->lpAudioIndex);
00185     wma->lpAudioIndex = NULL;
00186     if (wma->hic)       ICClose(wma->hic);
00187     wma->hic = 0;
00188         HeapFree(GetProcessHeap(), 0, wma->inbih);
00189     wma->inbih = NULL;
00190         HeapFree(GetProcessHeap(), 0, wma->outbih);
00191     wma->outbih = NULL;
00192         HeapFree(GetProcessHeap(), 0, wma->indata);
00193     wma->indata = NULL;
00194         HeapFree(GetProcessHeap(), 0, wma->outdata);
00195     wma->outdata = NULL;
00196         if (wma->hbmFrame)  DeleteObject(wma->hbmFrame);
00197     wma->hbmFrame = 0;
00198     if (wma->hWnd)      DestroyWindow(wma->hWnd);
00199     wma->hWnd = 0;
00200 
00201         HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
00202     wma->lpWaveFormat = 0;
00203 
00204     memset(&wma->mah, 0, sizeof(wma->mah));
00205     memset(&wma->ash_video, 0, sizeof(wma->ash_video));
00206     memset(&wma->ash_audio, 0, sizeof(wma->ash_audio));
00207     wma->dwCurrVideoFrame = wma->dwCurrAudioBlock = 0;
00208         wma->dwCachedFrame = -1;
00209     }
00210 }
00211 
00212 /***************************************************************************
00213  *              MCIAVI_mciOpen          [internal]
00214  */
00215 static  DWORD   MCIAVI_mciOpen(UINT wDevID, DWORD dwFlags,
00216                                LPMCI_DGV_OPEN_PARMSW lpOpenParms)
00217 {
00218     WINE_MCIAVI *wma;
00219     LRESULT     dwRet = 0;
00220 
00221     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpOpenParms);
00222 
00223     if (lpOpenParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
00224 
00225     wma = (WINE_MCIAVI *)mciGetDriverData(wDevID);
00226     if (wma == NULL)            return MCIERR_INVALID_DEVICE_ID;
00227 
00228     EnterCriticalSection(&wma->cs);
00229 
00230     if (wma->nUseCount > 0) {
00231     /* The driver is already open on this channel */
00232     /* If the driver was opened shareable before and this open specifies */
00233     /* shareable then increment the use count */
00234     if (wma->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
00235         ++wma->nUseCount;
00236     else
00237         {
00238             LeaveCriticalSection(&wma->cs);
00239         return MCIERR_MUST_USE_SHAREABLE;
00240         }
00241     } else {
00242     wma->nUseCount = 1;
00243     wma->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
00244     }
00245 
00246     wma->dwStatus = MCI_MODE_NOT_READY;
00247 
00248     if (dwFlags & MCI_OPEN_ELEMENT) {
00249     if (dwFlags & MCI_OPEN_ELEMENT_ID) {
00250         /* could it be that (DWORD)lpOpenParms->lpstrElementName
00251          * contains the hFile value ?
00252          */
00253         dwRet = MCIERR_UNRECOGNIZED_COMMAND;
00254     } else if (lpOpenParms->lpstrElementName && lpOpenParms->lpstrElementName[0]) {
00255         /* FIXME : what should be done id wma->hFile is already != 0, or the driver is playin' */
00256         TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(lpOpenParms->lpstrElementName));
00257 
00258             wma->lpFileName = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpOpenParms->lpstrElementName) + 1) * sizeof(WCHAR));
00259             strcpyW(wma->lpFileName, lpOpenParms->lpstrElementName);
00260 
00261         if (lpOpenParms->lpstrElementName[0] == '@') {
00262         /* The file name @11223344 encodes an AVIFile handle in decimal notation
00263          * in Win3.1 and w2k/NT, but this feature is absent in win95 (KB140750).
00264          * wma->hFile = LongToHandle(strtolW(lpOpenParms->lpstrElementName+1, NULL, 10)); */
00265         FIXME("Using AVIFile/Stream %s NIY\n", debugstr_w(lpOpenParms->lpstrElementName));
00266         }
00267         wma->hFile = mmioOpenW(lpOpenParms->lpstrElementName, NULL,
00268                    MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
00269 
00270         if (wma->hFile == 0) {
00271         WARN("can't find file=%s!\n", debugstr_w(lpOpenParms->lpstrElementName));
00272         dwRet = MCIERR_FILE_NOT_FOUND;
00273         } else {
00274         if (!MCIAVI_GetInfo(wma))
00275             dwRet = MCIERR_INVALID_FILE;
00276         else if (!MCIAVI_OpenVideo(wma))
00277             dwRet = MCIERR_CANNOT_LOAD_DRIVER;
00278         else if (!MCIAVI_CreateWindow(wma, dwFlags, lpOpenParms))
00279             dwRet = MCIERR_CREATEWINDOW;
00280         }
00281     } else {
00282         FIXME("Don't record yet\n");
00283         dwRet = MCIERR_UNSUPPORTED_FUNCTION;
00284     }
00285     }
00286 
00287     if (dwRet == 0) {
00288         TRACE("lpOpenParms->wDeviceID = %04x\n", lpOpenParms->wDeviceID);
00289 
00290     wma->dwStatus = MCI_MODE_STOP;
00291     wma->dwMciTimeFormat = MCI_FORMAT_FRAMES;
00292     } else {
00293     MCIAVI_CleanUp(wma);
00294     }
00295 
00296     LeaveCriticalSection(&wma->cs);
00297 
00298     if (!dwRet && (dwFlags & MCI_NOTIFY)) {
00299     mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)),
00300                        wDevID, MCI_NOTIFY_SUCCESSFUL);
00301     }
00302     return dwRet;
00303 }
00304 
00305 /***************************************************************************
00306  *              MCIAVI_mciClose         [internal]
00307  */
00308 DWORD MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
00309 {
00310     WINE_MCIAVI *wma;
00311     DWORD       dwRet = 0;
00312 
00313     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
00314 
00315     wma = MCIAVI_mciGetOpenDev(wDevID);
00316     if (wma == NULL)    return MCIERR_INVALID_DEVICE_ID;
00317 
00318     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
00319 
00320     EnterCriticalSection(&wma->cs);
00321 
00322     if (wma->nUseCount == 1) {
00323         MCIAVI_CleanUp(wma);
00324 
00325     if ((dwFlags & MCI_NOTIFY) && lpParms) {
00326         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
00327                            wDevID,
00328                 MCI_NOTIFY_SUCCESSFUL);
00329     }
00330         LeaveCriticalSection(&wma->cs);
00331     return dwRet;
00332     }
00333     wma->nUseCount--;
00334 
00335     LeaveCriticalSection(&wma->cs);
00336     return dwRet;
00337 }
00338 
00339 static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms);
00340 
00341 struct MCIAVI_play_data
00342 {
00343     MCIDEVICEID wDevID;
00344     DWORD flags;
00345     MCI_PLAY_PARMS params;
00346 };
00347 
00348 /*
00349  * MCIAVI_mciPlay_thread
00350  *
00351  * FIXME: probably should use a common worker thread created at the driver
00352  * load time and queue all async commands to it.
00353  */
00354 static DWORD WINAPI MCIAVI_mciPlay_thread(LPVOID arg)
00355 {
00356     struct MCIAVI_play_data *data = (struct MCIAVI_play_data *)arg;
00357     DWORD ret;
00358 
00359     TRACE("In thread before async play command (id %08x, flags %08x)\n", data->wDevID, data->flags);
00360     ret = MCIAVI_mciPlay(data->wDevID, data->flags | MCI_WAIT, &data->params);
00361     TRACE("In thread after async play command (id %08x, flags %08x)\n", data->wDevID, data->flags);
00362 
00363     HeapFree(GetProcessHeap(), 0, data);
00364     return ret;
00365 }
00366 
00367 /*
00368  * MCIAVI_mciPlay_async
00369  */
00370 static DWORD MCIAVI_mciPlay_async(WINE_MCIAVI *wma, DWORD dwFlags, LPMCI_PLAY_PARMS lpParams)
00371 {
00372     HANDLE handle, ack_event = wma->ack_event;
00373     struct MCIAVI_play_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct MCIAVI_play_data));
00374 
00375     if (!data) return MCIERR_OUT_OF_MEMORY;
00376 
00377     data->wDevID = wma->wDevID;
00378     data->flags = dwFlags;
00379     data->params = *lpParams;
00380 
00381     if (!(handle = CreateThread(NULL, 0, MCIAVI_mciPlay_thread, data, 0, NULL)))
00382     {
00383         WARN("Couldn't create thread for async play, playing synchronously\n");
00384         return MCIAVI_mciPlay_thread(data);
00385     }
00386     SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
00387     CloseHandle(handle);
00388     /* wait until the thread starts up, so the app could see a changed status */
00389     WaitForSingleObject(ack_event, INFINITE);
00390     TRACE("Async play has started\n");
00391     return 0;
00392 }
00393 
00394 /***************************************************************************
00395  *              MCIAVI_mciPlay          [internal]
00396  */
00397 static  DWORD   MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
00398 {
00399     WINE_MCIAVI *wma;
00400     DWORD       frameTime;
00401     DWORD       dwRet;
00402     LPWAVEHDR       waveHdr = NULL;
00403     unsigned        i, nHdr = 0;
00404     DWORD       dwFromFrame, dwToFrame;
00405     DWORD       numEvents = 1;
00406     HANDLE      events[2];
00407 
00408     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
00409 
00410     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00411 
00412     wma = MCIAVI_mciGetOpenDev(wDevID);
00413     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00414     if (dwFlags & MCI_DGV_PLAY_REVERSE) return MCIERR_UNSUPPORTED_FUNCTION;
00415     if (dwFlags & MCI_TEST) return 0;
00416 
00417     EnterCriticalSection(&wma->cs);
00418 
00419     if (!wma->hFile)
00420     {
00421         LeaveCriticalSection(&wma->cs);
00422         return MCIERR_FILE_NOT_FOUND;
00423     }
00424     if (!wma->hWndPaint)
00425     {
00426         LeaveCriticalSection(&wma->cs);
00427         return MCIERR_NO_WINDOW;
00428     }
00429 
00430     LeaveCriticalSection(&wma->cs);
00431 
00432     if (!(dwFlags & MCI_WAIT))
00433         return MCIAVI_mciPlay_async(wma, dwFlags, lpParms);
00434 
00435     if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
00436         ShowWindow(wma->hWndPaint, SW_SHOWNA);
00437 
00438     EnterCriticalSection(&wma->cs);
00439 
00440     dwFromFrame = wma->dwCurrVideoFrame;
00441     dwToFrame = wma->dwPlayableVideoFrames - 1;
00442 
00443     if (dwFlags & MCI_FROM) {
00444     dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
00445     }
00446     if (dwFlags & MCI_TO) {
00447     dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
00448     }
00449     if (dwToFrame >= wma->dwPlayableVideoFrames)
00450     dwToFrame = wma->dwPlayableVideoFrames - 1;
00451 
00452     TRACE("Playing from frame=%u to frame=%u\n", dwFromFrame, dwToFrame);
00453 
00454     wma->dwCurrVideoFrame = dwFromFrame;
00455     wma->dwToVideoFrame = dwToFrame;
00456 
00457     /* if already playing exit */
00458     if (wma->dwStatus == MCI_MODE_PLAY)
00459     {
00460         LeaveCriticalSection(&wma->cs);
00461         SetEvent(wma->ack_event);
00462         return 0;
00463     }
00464 
00465     if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
00466     {
00467         dwRet = 0;
00468         SetEvent(wma->ack_event);
00469         goto mci_play_done;
00470     }
00471 
00472     wma->dwStatus = MCI_MODE_PLAY;
00473     /* signal the state change */
00474     SetEvent(wma->ack_event);
00475 
00476     if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
00477     FIXME("Unsupported flag %08x\n", dwFlags);
00478 
00479     /* time is in microseconds, we should convert it to milliseconds */
00480     frameTime = (wma->mah.dwMicroSecPerFrame + 500) / 1000;
00481 
00482     events[0] = wma->hStopEvent;
00483     if (wma->lpWaveFormat) {
00484        if (MCIAVI_OpenAudio(wma, &nHdr, &waveHdr) != 0)
00485         {
00486             /* can't play audio */
00487             HeapFree(GetProcessHeap(), 0, wma->lpWaveFormat);
00488             wma->lpWaveFormat = NULL;
00489         }
00490        else
00491        {
00492             /* fill the queue with as many wave headers as possible */
00493             MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
00494             events[1] = wma->hEvent;
00495             numEvents = 2;
00496        }
00497     }
00498 
00499     while (wma->dwStatus == MCI_MODE_PLAY)
00500     {
00501         HDC hDC;
00502         DWORD tc, delta;
00503         DWORD ret;
00504 
00505     tc = GetTickCount();
00506 
00507         hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
00508         if (hDC)
00509         {
00510             MCIAVI_PaintFrame(wma, hDC);
00511             ReleaseDC(wma->hWndPaint, hDC);
00512         }
00513 
00514         if (wma->lpWaveFormat)
00515         MCIAVI_PlayAudioBlocks(wma, nHdr, waveHdr);
00516 
00517     delta = GetTickCount() - tc;
00518     if (delta < frameTime)
00519             delta = frameTime - delta;
00520         else
00521             delta = 0;
00522 
00523         LeaveCriticalSection(&wma->cs);
00524         ret = WaitForMultipleObjects(numEvents, events, FALSE, delta);
00525         EnterCriticalSection(&wma->cs);
00526         if (ret == WAIT_OBJECT_0 || wma->dwStatus != MCI_MODE_PLAY) break;
00527 
00528        if (wma->dwCurrVideoFrame < dwToFrame)
00529            wma->dwCurrVideoFrame++;
00530         else
00531             break;
00532     }
00533 
00534     if (wma->lpWaveFormat) {
00535        while (wma->dwEventCount != nHdr - 1)
00536         {
00537             LeaveCriticalSection(&wma->cs);
00538             Sleep(100);
00539             EnterCriticalSection(&wma->cs);
00540         }
00541 
00542     /* just to get rid of some race conditions between play, stop and pause */
00543     LeaveCriticalSection(&wma->cs);
00544     waveOutReset(wma->hWave);
00545     EnterCriticalSection(&wma->cs);
00546 
00547     for (i = 0; i < nHdr; i++)
00548         waveOutUnprepareHeader(wma->hWave, &waveHdr[i], sizeof(WAVEHDR));
00549     }
00550 
00551     dwRet = 0;
00552 
00553     if (wma->lpWaveFormat) {
00554     HeapFree(GetProcessHeap(), 0, waveHdr);
00555 
00556     if (wma->hWave) {
00557         LeaveCriticalSection(&wma->cs);
00558         waveOutClose(wma->hWave);
00559         EnterCriticalSection(&wma->cs);
00560         wma->hWave = 0;
00561     }
00562     CloseHandle(wma->hEvent);
00563     }
00564 
00565 mci_play_done:
00566     wma->dwStatus = MCI_MODE_STOP;
00567 
00568     if (dwFlags & MCI_NOTIFY) {
00569     TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
00570     mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
00571                        wDevID, MCI_NOTIFY_SUCCESSFUL);
00572     }
00573     LeaveCriticalSection(&wma->cs);
00574     return dwRet;
00575 }
00576 
00577 /***************************************************************************
00578  *              MCIAVI_mciStop          [internal]
00579  */
00580 static  DWORD   MCIAVI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
00581 {
00582     WINE_MCIAVI *wma;
00583     DWORD       dwRet = 0;
00584 
00585     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
00586 
00587     wma = MCIAVI_mciGetOpenDev(wDevID);
00588     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00589     if (dwFlags & MCI_TEST) return 0;
00590 
00591     EnterCriticalSection(&wma->cs);
00592 
00593     TRACE("current status %04x\n", wma->dwStatus);
00594 
00595     switch (wma->dwStatus) {
00596     case MCI_MODE_PLAY:
00597     case MCI_MODE_RECORD:
00598         LeaveCriticalSection(&wma->cs);
00599         SetEvent(wma->hStopEvent);
00600         EnterCriticalSection(&wma->cs);
00601         /* fall through */
00602     case MCI_MODE_PAUSE:
00603     /* Since our wave notification callback takes the lock,
00604      * we must release it before resetting the device */
00605         LeaveCriticalSection(&wma->cs);
00606         dwRet = waveOutReset(wma->hWave);
00607         EnterCriticalSection(&wma->cs);
00608         /* fall through */
00609     default:
00610         do /* one more chance for an async thread to finish */
00611         {
00612             LeaveCriticalSection(&wma->cs);
00613             Sleep(10);
00614             EnterCriticalSection(&wma->cs);
00615         } while (wma->dwStatus != MCI_MODE_STOP);
00616 
00617     break;
00618 
00619     case MCI_MODE_NOT_READY:
00620         break;        
00621     }
00622 
00623     if ((dwFlags & MCI_NOTIFY) && lpParms) {
00624     mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
00625                        wDevID, MCI_NOTIFY_SUCCESSFUL);
00626     }
00627     LeaveCriticalSection(&wma->cs);
00628     return dwRet;
00629 }
00630 
00631 /***************************************************************************
00632  *              MCIAVI_mciPause         [internal]
00633  */
00634 static  DWORD   MCIAVI_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
00635 {
00636     WINE_MCIAVI *wma;
00637 
00638     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
00639 
00640     wma = MCIAVI_mciGetOpenDev(wDevID);
00641     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00642     if (dwFlags & MCI_TEST) return 0;
00643 
00644     EnterCriticalSection(&wma->cs);
00645 
00646     if (wma->dwStatus == MCI_MODE_PLAY)
00647     wma->dwStatus = MCI_MODE_PAUSE;
00648 
00649     if (wma->lpWaveFormat) {
00650         LeaveCriticalSection(&wma->cs);
00651     return waveOutPause(wma->hWave);
00652     }
00653 
00654     LeaveCriticalSection(&wma->cs);
00655     return 0;
00656 }
00657 
00658 /***************************************************************************
00659  *              MCIAVI_mciResume            [internal]
00660  */
00661 static  DWORD   MCIAVI_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
00662 {
00663     WINE_MCIAVI *wma;
00664 
00665     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
00666 
00667     wma = MCIAVI_mciGetOpenDev(wDevID);
00668     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00669     if (dwFlags & MCI_TEST) return 0;
00670 
00671     EnterCriticalSection(&wma->cs);
00672 
00673     if (wma->dwStatus == MCI_MODE_PAUSE)
00674     wma->dwStatus = MCI_MODE_PLAY;
00675 
00676     if (wma->lpWaveFormat) {
00677         LeaveCriticalSection(&wma->cs);
00678     return waveOutRestart(wma->hWave);
00679     }
00680 
00681     LeaveCriticalSection(&wma->cs);
00682     return 0;
00683 }
00684 
00685 /***************************************************************************
00686  *              MCIAVI_mciSeek          [internal]
00687  */
00688 static  DWORD   MCIAVI_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
00689 {
00690     WINE_MCIAVI *wma;
00691     DWORD position;
00692 
00693     TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
00694 
00695     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00696 
00697     wma = MCIAVI_mciGetOpenDev(wDevID);
00698     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00699 
00700     position = dwFlags & (MCI_SEEK_TO_START|MCI_SEEK_TO_END|MCI_TO);
00701     if (!position)      return MCIERR_MISSING_PARAMETER;
00702     if (position&(position-1))  return MCIERR_FLAGS_NOT_COMPATIBLE;
00703 
00704     if (dwFlags & MCI_TO) {
00705     position = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
00706     if (position >= wma->dwPlayableVideoFrames)
00707         return MCIERR_OUTOFRANGE;
00708     } else if (dwFlags & MCI_SEEK_TO_START) {
00709     position = 0;
00710     } else {
00711     position = wma->dwPlayableVideoFrames - 1;
00712     }
00713     if (dwFlags & MCI_TEST) return 0;
00714 
00715     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
00716 
00717     EnterCriticalSection(&wma->cs);
00718 
00719     wma->dwCurrVideoFrame = position;
00720     TRACE("Seeking to frame=%u\n", wma->dwCurrVideoFrame);
00721 
00722     if (dwFlags & MCI_NOTIFY) {
00723     mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
00724                        wDevID, MCI_NOTIFY_SUCCESSFUL);
00725     }
00726     LeaveCriticalSection(&wma->cs);
00727     return 0;
00728 }
00729 
00730 /*****************************************************************************
00731  *              MCIAVI_mciLoad          [internal]
00732  */
00733 static DWORD    MCIAVI_mciLoad(UINT wDevID, DWORD dwFlags, LPMCI_DGV_LOAD_PARMSW lpParms)
00734 {
00735     WINE_MCIAVI *wma;
00736 
00737     FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
00738 
00739     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00740 
00741     wma = MCIAVI_mciGetOpenDev(wDevID);
00742     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00743 
00744     return MCIERR_UNSUPPORTED_FUNCTION; /* like w2k */
00745 }
00746 
00747 /******************************************************************************
00748  *              MCIAVI_mciRealize           [internal]
00749  */
00750 static  DWORD   MCIAVI_mciRealize(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
00751 {
00752     WINE_MCIAVI *wma;
00753 
00754     FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
00755 
00756     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00757 
00758     wma = MCIAVI_mciGetOpenDev(wDevID);
00759     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00760     if (dwFlags & MCI_TEST) return 0;
00761 
00762     return 0;
00763 }
00764 
00765 /******************************************************************************
00766  *              MCIAVI_mciUpdate            [internal]
00767  */
00768 static  DWORD   MCIAVI_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
00769 {
00770     WINE_MCIAVI *wma;
00771 
00772     TRACE("%04x, %08x, %p\n", wDevID, dwFlags, lpParms);
00773 
00774     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00775 
00776     wma = MCIAVI_mciGetOpenDev(wDevID);
00777     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00778     /* Ignore MCI_TEST flag. */
00779 
00780     EnterCriticalSection(&wma->cs);
00781 
00782     if (dwFlags & MCI_DGV_UPDATE_HDC)
00783         MCIAVI_PaintFrame(wma, lpParms->hDC);
00784 
00785     LeaveCriticalSection(&wma->cs);
00786 
00787     return 0;
00788 }
00789 
00790 /******************************************************************************
00791  *              MCIAVI_mciStep          [internal]
00792  */
00793 static  DWORD   MCIAVI_mciStep(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STEP_PARMS lpParms)
00794 {
00795     WINE_MCIAVI *wma;
00796     DWORD position;
00797     int delta = 1;
00798 
00799     TRACE("(%04x, %08x, %p)\n", wDevID, dwFlags, lpParms);
00800 
00801     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00802 
00803     wma = MCIAVI_mciGetOpenDev(wDevID);
00804     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00805 
00806     if (dwFlags & MCI_DGV_STEP_FRAMES)  delta = lpParms->dwFrames;
00807     if (dwFlags & MCI_DGV_STEP_REVERSE) delta = -delta;
00808     position = wma->dwCurrVideoFrame + delta;
00809     if (position >= wma->dwPlayableVideoFrames) return MCIERR_OUTOFRANGE;
00810     if (dwFlags & MCI_TEST) return 0;
00811 
00812     MCIAVI_mciStop(wDevID, MCI_WAIT, NULL);
00813 
00814     EnterCriticalSection(&wma->cs);
00815 
00816     wma->dwCurrVideoFrame = position;
00817     TRACE("Stepping to frame=%u\n", wma->dwCurrVideoFrame);
00818 
00819     if (dwFlags & MCI_NOTIFY) {
00820     mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
00821                        wDevID, MCI_NOTIFY_SUCCESSFUL);
00822     }
00823     LeaveCriticalSection(&wma->cs);
00824     return 0;
00825 }
00826 
00827 /******************************************************************************
00828  *              MCIAVI_mciCue           [internal]
00829  */
00830 static  DWORD   MCIAVI_mciCue(UINT wDevID, DWORD dwFlags, LPMCI_DGV_CUE_PARMS lpParms)
00831 {
00832     WINE_MCIAVI *wma;
00833 
00834     FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
00835 
00836     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00837 
00838     wma = MCIAVI_mciGetOpenDev(wDevID);
00839     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00840     if (dwFlags & MCI_DGV_CUE_INPUT) return MCIERR_UNSUPPORTED_FUNCTION;
00841     if (dwFlags & MCI_TEST) return 0;
00842 
00843     return 0;
00844 }
00845 
00846 /******************************************************************************
00847  *              MCIAVI_mciSetAudio          [internal]
00848  */
00849 static  DWORD   MCIAVI_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
00850 {
00851     WINE_MCIAVI *wma;
00852 
00853     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00854 
00855     FIXME("(%04x, %08x, %p) Item %04x: stub\n", wDevID, dwFlags, lpParms, dwFlags & MCI_DGV_SETAUDIO_ITEM ? lpParms->dwItem : 0);
00856 
00857     wma = MCIAVI_mciGetOpenDev(wDevID);
00858     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00859 
00860     return 0;
00861 }
00862 
00863 /******************************************************************************
00864  *              MCIAVI_mciSignal            [internal]
00865  */
00866 static  DWORD   MCIAVI_mciSignal(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SIGNAL_PARMS lpParms)
00867 {
00868     WINE_MCIAVI *wma;
00869 
00870     FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
00871 
00872     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00873 
00874     wma = MCIAVI_mciGetOpenDev(wDevID);
00875     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00876 
00877     return 0;
00878 }
00879 
00880 /******************************************************************************
00881  *              MCIAVI_mciSetVideo          [internal]
00882  */
00883 static  DWORD   MCIAVI_mciSetVideo(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETVIDEO_PARMSW lpParms)
00884 {
00885     WINE_MCIAVI *wma;
00886 
00887     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00888 
00889     FIXME("(%04x, %08x, %p) Item %04x: stub\n", wDevID, dwFlags, lpParms, dwFlags & MCI_DGV_SETVIDEO_ITEM ? lpParms->dwItem : 0);
00890 
00891     wma = MCIAVI_mciGetOpenDev(wDevID);
00892     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00893 
00894     return 0;
00895 }
00896 
00897 /******************************************************************************
00898  *              MCIAVI_mciConfigure         [internal]
00899  */
00900 static  DWORD   MCIAVI_mciConfigure(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
00901 {
00902     WINE_MCIAVI *wma;
00903 
00904     FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
00905 
00906     if (lpParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
00907 
00908     wma = MCIAVI_mciGetOpenDev(wDevID);
00909     if (wma == NULL)        return MCIERR_INVALID_DEVICE_ID;
00910     if (dwFlags & MCI_TEST) return 0;
00911 
00912     return 0;
00913 }
00914 
00915 /*======================================================================*
00916  *                          MCI AVI entry points            *
00917  *======================================================================*/
00918 
00919 /**************************************************************************
00920  *              DriverProc (MCIAVI.@)
00921  */
00922 LRESULT CALLBACK MCIAVI_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
00923                                    LPARAM dwParam1, LPARAM dwParam2)
00924 {
00925     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
00926       dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00927 
00928     switch (wMsg) {
00929     case DRV_LOAD:      return 1;
00930     case DRV_FREE:      return 1;
00931     case DRV_OPEN:      return MCIAVI_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
00932     case DRV_CLOSE:     return MCIAVI_drvClose(dwDevID);
00933     case DRV_ENABLE:        return 1;
00934     case DRV_DISABLE:       return 1;
00935     case DRV_QUERYCONFIGURE:    return 1;
00936     case DRV_CONFIGURE:     return MCIAVI_drvConfigure(dwDevID);
00937     case DRV_INSTALL:       return DRVCNF_RESTART;
00938     case DRV_REMOVE:        return DRVCNF_RESTART;
00939     }
00940 
00941     /* session instance */
00942     if (dwDevID == 0xFFFFFFFF) return 1;
00943 
00944     switch (wMsg) {
00945     case MCI_OPEN_DRIVER:   return MCIAVI_mciOpen      (dwDevID, dwParam1, (LPMCI_DGV_OPEN_PARMSW)     dwParam2);
00946     case MCI_CLOSE_DRIVER:  return MCIAVI_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
00947     case MCI_PLAY:      return MCIAVI_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
00948     case MCI_STOP:      return MCIAVI_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
00949     case MCI_SET:       return MCIAVI_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
00950     case MCI_PAUSE:     return MCIAVI_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
00951     case MCI_RESUME:        return MCIAVI_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
00952     case MCI_STATUS:        return MCIAVI_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
00953     case MCI_GETDEVCAPS:    return MCIAVI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
00954     case MCI_INFO:      return MCIAVI_mciInfo      (dwDevID, dwParam1, (LPMCI_DGV_INFO_PARMSW)     dwParam2);
00955     case MCI_SEEK:      return MCIAVI_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
00956     case MCI_PUT:       return MCIAVI_mciPut       (dwDevID, dwParam1, (LPMCI_DGV_PUT_PARMS)       dwParam2);
00957     case MCI_WINDOW:        return MCIAVI_mciWindow    (dwDevID, dwParam1, (LPMCI_DGV_WINDOW_PARMSW)   dwParam2);
00958     case MCI_LOAD:      return MCIAVI_mciLoad      (dwDevID, dwParam1, (LPMCI_DGV_LOAD_PARMSW)     dwParam2);
00959     case MCI_REALIZE:       return MCIAVI_mciRealize   (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
00960     case MCI_UPDATE:        return MCIAVI_mciUpdate    (dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)    dwParam2);
00961     case MCI_WHERE:     return MCIAVI_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
00962     case MCI_STEP:      return MCIAVI_mciStep      (dwDevID, dwParam1, (LPMCI_DGV_STEP_PARMS)      dwParam2);
00963     case MCI_CUE:       return MCIAVI_mciCue       (dwDevID, dwParam1, (LPMCI_DGV_CUE_PARMS)       dwParam2);
00964     /* Digital Video specific */
00965     case MCI_SETAUDIO:      return MCIAVI_mciSetAudio  (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
00966     case MCI_SIGNAL:        return MCIAVI_mciSignal    (dwDevID, dwParam1, (LPMCI_DGV_SIGNAL_PARMS)    dwParam2);
00967     case MCI_SETVIDEO:      return MCIAVI_mciSetVideo  (dwDevID, dwParam1, (LPMCI_DGV_SETVIDEO_PARMSW) dwParam2);
00968     case MCI_CONFIGURE:     return MCIAVI_mciConfigure (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
00969 
00970     /* no editing, recording, saving, locking without inputs */
00971     case MCI_CAPTURE:
00972     case MCI_COPY:
00973     case MCI_CUT:
00974     case MCI_DELETE:
00975     case MCI_FREEZE:
00976     case MCI_LIST:
00977     case MCI_MONITOR:
00978     case MCI_PASTE:
00979     case MCI_QUALITY:
00980     case MCI_RECORD:
00981     case MCI_RESERVE:
00982     case MCI_RESTORE:
00983     case MCI_SAVE:
00984     case MCI_UNDO:
00985     case MCI_UNFREEZE:
00986     TRACE("Unsupported function [0x%x] flags=%08x\n", wMsg, (DWORD)dwParam1);
00987     return MCIERR_UNSUPPORTED_FUNCTION;
00988     case MCI_SPIN:
00989     case MCI_ESCAPE:
00990     WARN("Unsupported command [0x%x] %08x\n", wMsg, (DWORD)dwParam1);
00991     break;
00992     case MCI_OPEN:
00993     case MCI_CLOSE:
00994     FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
00995     break;
00996     default:
00997     TRACE("Sending msg [%u] to default driver proc\n", wMsg);
00998     return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00999     }
01000     return MCIERR_UNRECOGNIZED_COMMAND;
01001 }

Generated on Sat May 19 2012 04:22:21 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.