Dmitry Timoshkov : mciavi32: Rewrite asynchronous MCI_PLAY command handling.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Dec 22 11:11:24 CST 2005


Module: wine
Branch: refs/heads/master
Commit: 43cbb44f4fe9ebd68cf86d8dec5a70df6c5e92ba
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=43cbb44f4fe9ebd68cf86d8dec5a70df6c5e92ba

Author: Dmitry Timoshkov <dmitry at codeweavers.com>
Date:   Thu Dec 22 17:15:33 2005 +0100

mciavi32: Rewrite asynchronous MCI_PLAY command handling.
Rewrite asynchronous MCI_PLAY command handling in MCIAVI driver, make
it more responsive to commands in the MCI_MODE_PLAY state by checking
hStopEvent even if the time frame between frames has expired.

---

 dlls/mciavi32/mciavi.c         |  155 +++++++++++++++++++---------------------
 dlls/mciavi32/private_mciavi.h |    1 
 2 files changed, 75 insertions(+), 81 deletions(-)

diff --git a/dlls/mciavi32/mciavi.c b/dlls/mciavi32/mciavi.c
index 8f1074c..a1f04f9 100644
--- a/dlls/mciavi32/mciavi.c
+++ b/dlls/mciavi32/mciavi.c
@@ -44,74 +44,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mciavi);
 
 static DWORD MCIAVI_mciStop(UINT, DWORD, LPMCI_GENERIC_PARMS);
 
-/* ===================================================================
- * ===================================================================
- * FIXME: should be using the new mmThreadXXXX functions from WINMM
- * instead of those
- * it would require to add a wine internal flag to mmThreadCreate
- * in order to pass a 32 bit function instead of a 16 bit one
- * ===================================================================
- * =================================================================== */
-
-struct SCA {
-    MCIDEVICEID wDevID;
-    UINT        wMsg;
-    DWORD_PTR   dwParam1;
-    DWORD_PTR   dwParam2;
-};
-
-/**************************************************************************
- * 				MCI_SCAStarter			[internal]
- */
-static DWORD CALLBACK	MCI_SCAStarter(LPVOID arg)
-{
-    struct SCA*	sca = (struct SCA*)arg;
-    DWORD	ret;
-
-    TRACE("In thread before async command (%08x,%04x,%08lx,%08lx)\n",
-	  sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
-    ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
-    TRACE("In thread after async command (%08x,%04x,%08lx,%08lx)\n",
-	  sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
-    HeapFree(GetProcessHeap(), 0, sca);
-    return ret;
-}
-
-/**************************************************************************
- * 				MCI_SendCommandAsync		[internal]
- */
-static	DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
-                                  DWORD_PTR dwParam2, UINT size)
-{
-    HANDLE handle;
-    struct SCA*	sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
-
-    if (sca == 0)
-	return MCIERR_OUT_OF_MEMORY;
-
-    sca->wDevID   = wDevID;
-    sca->wMsg     = wMsg;
-    sca->dwParam1 = dwParam1;
-
-    if (size && dwParam2) {
-       sca->dwParam2 = (DWORD_PTR)sca + sizeof(struct SCA);
-	/* copy structure passed by program in dwParam2 to be sure
-	 * we can still use it whatever the program does
-	 */
-	memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
-    } else {
-	sca->dwParam2 = dwParam2;
-    }
-
-    if ((handle = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
-	WARN("Couldn't allocate thread for async command handling, sending synchronously\n");
-	return MCI_SCAStarter(&sca);
-    }
-    SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
-    CloseHandle(handle);
-    return 0;
-}
-
 /*======================================================================*
  *                  	    MCI AVI implemantation			*
  *======================================================================*/
@@ -152,6 +84,7 @@ static	DWORD	MCIAVI_drvOpen(LPCWSTR str,
 	return 0;
 
     InitializeCriticalSection(&wma->cs);
+    wma->ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
     wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
     wma->wDevID = modp->wDeviceID;
     wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
@@ -184,6 +117,7 @@ static	DWORD	MCIAVI_drvClose(DWORD dwDev
 	mciSetDriverData(dwDevID, 0);
 	mciFreeCommandResource(wma->wCommandTable);
 
+        CloseHandle(wma->ack_event);
         CloseHandle(wma->hStopEvent);
 
         LeaveCriticalSection(&wma->cs);
@@ -393,6 +327,61 @@ DWORD MCIAVI_mciClose(UINT wDevID, DWORD
     return dwRet;
 }
 
+static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms);
+
+struct MCIAVI_play_data
+{
+    MCIDEVICEID wDevID;
+    DWORD flags;
+    MCI_PLAY_PARMS params;
+};
+
+/*
+ * MCIAVI_mciPlay_thread
+ *
+ * FIXME: probably should use a common worker thread created at the driver
+ * load time and queue all async commands to it.
+ */
+static DWORD WINAPI MCIAVI_mciPlay_thread(LPVOID arg)
+{
+    struct MCIAVI_play_data *data = (struct MCIAVI_play_data *)arg;
+    DWORD ret;
+
+    TRACE("In thread before async play command (id %08x, flags %08lx)\n", data->wDevID, data->flags);
+    ret = MCIAVI_mciPlay(data->wDevID, data->flags | MCI_WAIT, &data->params);
+    TRACE("In thread after async play command (id %08x, flags %08lx)\n", data->wDevID, data->flags);
+
+    HeapFree(GetProcessHeap(), 0, data);
+    return ret;
+}
+
+/*
+ * MCIAVI_mciPlay_async
+ */
+static DWORD MCIAVI_mciPlay_async(WINE_MCIAVI *wma, DWORD dwFlags, LPMCI_PLAY_PARMS lpParams)
+{
+    HANDLE handle, ack_event = wma->ack_event;
+    struct MCIAVI_play_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct MCIAVI_play_data));
+
+    if (!data) return MCIERR_OUT_OF_MEMORY;
+
+    data->wDevID = wma->wDevID;
+    data->flags = dwFlags;
+    memcpy(&data->params, lpParams, sizeof(MCI_PLAY_PARMS));
+
+    if (!(handle = CreateThread(NULL, 0, MCIAVI_mciPlay_thread, data, 0, NULL)))
+    {
+        WARN("Couldn't create thread for async play, playing synchronously\n");
+        return MCIAVI_mciPlay_thread(data);
+    }
+    SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
+    CloseHandle(handle);
+    /* wait until the thread starts up, so the app could see a changed status */
+    WaitForSingleObject(ack_event, INFINITE);
+    TRACE("Async play has started\n");
+    return 0;
+}
+
 /***************************************************************************
  * 				MCIAVI_mciPlay			[internal]
  */
@@ -429,10 +418,8 @@ static	DWORD	MCIAVI_mciPlay(UINT wDevID,
 
     LeaveCriticalSection(&wma->cs);
 
-    if (!(dwFlags & MCI_WAIT)) {
-       return MCI_SendCommandAsync(wDevID, MCI_PLAY, dwFlags,
-                                   (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS));
-    }
+    if (!(dwFlags & MCI_WAIT))
+        return MCIAVI_mciPlay_async(wma, dwFlags, lpParms);
 
     if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
         ShowWindow(wma->hWndPaint, SW_SHOWNA);
@@ -460,16 +447,20 @@ static	DWORD	MCIAVI_mciPlay(UINT wDevID,
     if (wma->dwStatus == MCI_MODE_PLAY)
     {
         LeaveCriticalSection(&wma->cs);
+        SetEvent(wma->ack_event);
         return 0;
     }
 
     if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
     {
         dwRet = 0;
+        SetEvent(wma->ack_event);
         goto mci_play_done;
     }
 
     wma->dwStatus = MCI_MODE_PLAY;
+    /* signal the state change */
+    SetEvent(wma->ack_event);
 
     if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_DGV_PLAY_REVERSE|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
 	FIXME("Unsupported flag %08lx\n", dwFlags);
@@ -492,6 +483,7 @@ static	DWORD	MCIAVI_mciPlay(UINT wDevID,
     while (wma->dwStatus == MCI_MODE_PLAY)
     {
         HDC hDC;
+        DWORD ret;
 
 	tc = GetTickCount();
 
@@ -504,7 +496,6 @@ static	DWORD	MCIAVI_mciPlay(UINT wDevID,
 
 	if (wma->lpWaveFormat) {
             HANDLE events[2];
-            DWORD ret;
 
             events[0] = wma->hStopEvent;
             events[1] = wma->hEvent;
@@ -522,15 +513,15 @@ static	DWORD	MCIAVI_mciPlay(UINT wDevID,
 
 	delta = GetTickCount() - tc;
 	if (delta < frameTime)
-        {
-            DWORD ret;
+            delta = frameTime - delta;
+        else
+            delta = 0;
 
-            LeaveCriticalSection(&wma->cs);
-            ret = MsgWaitForMultipleObjectsEx(1, &wma->hStopEvent, frameTime - delta,
-                                              QS_ALLINPUT, MWMO_INPUTAVAILABLE);
-            EnterCriticalSection(&wma->cs);
-            if (ret == WAIT_OBJECT_0) break;
-        }
+        LeaveCriticalSection(&wma->cs);
+        ret = MsgWaitForMultipleObjectsEx(1, &wma->hStopEvent, delta,
+                                          QS_ALLINPUT, MWMO_INPUTAVAILABLE);
+        EnterCriticalSection(&wma->cs);
+        if (ret == WAIT_OBJECT_0) break;
 
        if (wma->dwCurrVideoFrame < dwToFrame)
            wma->dwCurrVideoFrame++;
@@ -618,6 +609,8 @@ static	DWORD	MCIAVI_mciStop(UINT wDevID,
 
     EnterCriticalSection(&wma->cs);
 
+    TRACE("current status %04lx\n", wma->dwStatus);
+
     switch (wma->dwStatus) {
     case MCI_MODE_PLAY:
     case MCI_MODE_RECORD:
diff --git a/dlls/mciavi32/private_mciavi.h b/dlls/mciavi32/private_mciavi.h
index 2cbed11..cd11f76 100644
--- a/dlls/mciavi32/private_mciavi.h
+++ b/dlls/mciavi32/private_mciavi.h
@@ -80,6 +80,7 @@ typedef struct {
     /* data for the background mechanism */
     CRITICAL_SECTION	cs;
     HANDLE              hStopEvent;
+    HANDLE              ack_event; /* acknowledge that an async command has started */
 } WINE_MCIAVI;
 
 extern HINSTANCE MCIAVI_hInstance;




More information about the wine-cvs mailing list