mciavi: Fix player deadlock when starting to play.
This commit is contained in:
parent
4f07c49547
commit
42bdb48c67
@ -87,7 +87,6 @@ static DWORD MCIAVI_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
|
|||||||
|
|
||||||
InitializeCriticalSection(&wma->cs);
|
InitializeCriticalSection(&wma->cs);
|
||||||
wma->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINE_MCIAVI.cs");
|
wma->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINE_MCIAVI.cs");
|
||||||
wma->ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
||||||
wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
wma->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
wma->wDevID = modp->wDeviceID;
|
wma->wDevID = modp->wDeviceID;
|
||||||
wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
|
wma->wCommandTable = mciLoadCommandResource(MCIAVI_hInstance, mciAviWStr, 0);
|
||||||
@ -121,7 +120,6 @@ static DWORD MCIAVI_drvClose(DWORD dwDevID)
|
|||||||
mciSetDriverData(dwDevID, 0);
|
mciSetDriverData(dwDevID, 0);
|
||||||
mciFreeCommandResource(wma->wCommandTable);
|
mciFreeCommandResource(wma->wCommandTable);
|
||||||
|
|
||||||
CloseHandle(wma->ack_event);
|
|
||||||
CloseHandle(wma->hStopEvent);
|
CloseHandle(wma->hStopEvent);
|
||||||
|
|
||||||
LeaveCriticalSection(&wma->cs);
|
LeaveCriticalSection(&wma->cs);
|
||||||
@ -336,61 +334,6 @@ DWORD MCIAVI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
|
|||||||
return dwRet;
|
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 %08x)\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 %08x)\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;
|
|
||||||
data->params = *lpParams;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double currenttime_us(void)
|
static double currenttime_us(void)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER lc, lf;
|
LARGE_INTEGER lc, lf;
|
||||||
@ -400,90 +343,25 @@ static double currenttime_us(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* MCIAVI_mciPlay [internal]
|
* MCIAVI_player [internal]
|
||||||
*/
|
*/
|
||||||
static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
|
static DWORD MCIAVI_player(WINE_MCIAVI *wma, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
|
||||||
{
|
{
|
||||||
WINE_MCIAVI *wma;
|
|
||||||
DWORD dwRet;
|
DWORD dwRet;
|
||||||
LPWAVEHDR waveHdr = NULL;
|
LPWAVEHDR waveHdr = NULL;
|
||||||
unsigned i, nHdr = 0;
|
unsigned i, nHdr = 0;
|
||||||
DWORD dwFromFrame, dwToFrame;
|
|
||||||
DWORD numEvents = 1;
|
DWORD numEvents = 1;
|
||||||
HANDLE events[2];
|
HANDLE events[2];
|
||||||
double next_frame_us;
|
double next_frame_us;
|
||||||
|
|
||||||
TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
|
|
||||||
|
|
||||||
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
|
|
||||||
|
|
||||||
wma = MCIAVI_mciGetOpenDev(wDevID);
|
|
||||||
if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
|
|
||||||
if (dwFlags & MCI_DGV_PLAY_REVERSE) return MCIERR_UNSUPPORTED_FUNCTION;
|
|
||||||
if (dwFlags & MCI_TEST) return 0;
|
|
||||||
|
|
||||||
EnterCriticalSection(&wma->cs);
|
EnterCriticalSection(&wma->cs);
|
||||||
|
|
||||||
if (!wma->hFile)
|
|
||||||
{
|
|
||||||
LeaveCriticalSection(&wma->cs);
|
|
||||||
return MCIERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
if (!wma->hWndPaint)
|
|
||||||
{
|
|
||||||
LeaveCriticalSection(&wma->cs);
|
|
||||||
return MCIERR_NO_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
LeaveCriticalSection(&wma->cs);
|
|
||||||
|
|
||||||
if (!(dwFlags & MCI_WAIT))
|
|
||||||
return MCIAVI_mciPlay_async(wma, dwFlags, lpParms);
|
|
||||||
|
|
||||||
if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
|
|
||||||
ShowWindow(wma->hWndPaint, SW_SHOWNA);
|
|
||||||
|
|
||||||
EnterCriticalSection(&wma->cs);
|
|
||||||
|
|
||||||
dwFromFrame = wma->dwCurrVideoFrame;
|
|
||||||
dwToFrame = wma->dwPlayableVideoFrames - 1;
|
|
||||||
|
|
||||||
if (dwFlags & MCI_FROM) {
|
|
||||||
dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
|
|
||||||
}
|
|
||||||
if (dwFlags & MCI_TO) {
|
|
||||||
dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
|
|
||||||
}
|
|
||||||
if (dwToFrame >= wma->dwPlayableVideoFrames)
|
|
||||||
dwToFrame = wma->dwPlayableVideoFrames - 1;
|
|
||||||
|
|
||||||
TRACE("Playing from frame=%u to frame=%u\n", dwFromFrame, dwToFrame);
|
|
||||||
|
|
||||||
wma->dwCurrVideoFrame = dwFromFrame;
|
|
||||||
wma->dwToVideoFrame = dwToFrame;
|
|
||||||
|
|
||||||
/* if already playing exit */
|
|
||||||
if (wma->dwStatus == MCI_MODE_PLAY)
|
|
||||||
{
|
|
||||||
LeaveCriticalSection(&wma->cs);
|
|
||||||
SetEvent(wma->ack_event);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
|
if (wma->dwToVideoFrame <= wma->dwCurrVideoFrame)
|
||||||
{
|
{
|
||||||
dwRet = 0;
|
dwRet = 0;
|
||||||
SetEvent(wma->ack_event);
|
|
||||||
goto mci_play_done;
|
goto mci_play_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
wma->dwStatus = MCI_MODE_PLAY;
|
|
||||||
/* signal the state change */
|
|
||||||
SetEvent(wma->ack_event);
|
|
||||||
|
|
||||||
if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN))
|
|
||||||
FIXME("Unsupported flag %08x\n", dwFlags);
|
|
||||||
|
|
||||||
events[0] = wma->hStopEvent;
|
events[0] = wma->hStopEvent;
|
||||||
if (wma->lpWaveFormat) {
|
if (wma->lpWaveFormat) {
|
||||||
if (MCIAVI_OpenAudio(wma, &nHdr, &waveHdr) != 0)
|
if (MCIAVI_OpenAudio(wma, &nHdr, &waveHdr) != 0)
|
||||||
@ -513,7 +391,7 @@ static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms
|
|||||||
hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
|
hDC = wma->hWndPaint ? GetDC(wma->hWndPaint) : 0;
|
||||||
if (hDC)
|
if (hDC)
|
||||||
{
|
{
|
||||||
while(next_frame_us <= tc && wma->dwCurrVideoFrame < dwToFrame){
|
while(next_frame_us <= tc && wma->dwCurrVideoFrame < wma->dwToVideoFrame){
|
||||||
double dur;
|
double dur;
|
||||||
++wma->dwCurrVideoFrame;
|
++wma->dwCurrVideoFrame;
|
||||||
dur = MCIAVI_PaintFrame(wma, hDC);
|
dur = MCIAVI_PaintFrame(wma, hDC);
|
||||||
@ -524,7 +402,7 @@ static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms
|
|||||||
}
|
}
|
||||||
ReleaseDC(wma->hWndPaint, hDC);
|
ReleaseDC(wma->hWndPaint, hDC);
|
||||||
}
|
}
|
||||||
if(wma->dwCurrVideoFrame >= dwToFrame)
|
if(wma->dwCurrVideoFrame >= wma->dwToVideoFrame)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (wma->lpWaveFormat)
|
if (wma->lpWaveFormat)
|
||||||
@ -579,12 +457,145 @@ mci_play_done:
|
|||||||
if (dwFlags & MCI_NOTIFY) {
|
if (dwFlags & MCI_NOTIFY) {
|
||||||
TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
|
TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
|
||||||
mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
|
mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
|
||||||
wDevID, MCI_NOTIFY_SUCCESSFUL);
|
wma->wDevID, MCI_NOTIFY_SUCCESSFUL);
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&wma->cs);
|
LeaveCriticalSection(&wma->cs);
|
||||||
return dwRet;
|
return dwRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MCIAVI_play_data
|
||||||
|
{
|
||||||
|
WINE_MCIAVI *wma;
|
||||||
|
DWORD flags;
|
||||||
|
MCI_PLAY_PARMS params; /* FIXME: notify via wma->hCallback like the other MCI drivers */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 %u, flags %08x)\n", data->wma->wDevID, data->flags);
|
||||||
|
ret = MCIAVI_player(data->wma, data->flags, &data->params);
|
||||||
|
TRACE("In thread after async play command (id %u, flags %08x)\n", data->wma->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;
|
||||||
|
struct MCIAVI_play_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct MCIAVI_play_data));
|
||||||
|
|
||||||
|
if (!data) return MCIERR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
data->wma = wma;
|
||||||
|
data->flags = dwFlags;
|
||||||
|
if (dwFlags & MCI_NOTIFY)
|
||||||
|
data->params.dwCallback = lpParams->dwCallback;
|
||||||
|
|
||||||
|
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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* MCIAVI_mciPlay [internal]
|
||||||
|
*/
|
||||||
|
static DWORD MCIAVI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
|
||||||
|
{
|
||||||
|
WINE_MCIAVI *wma;
|
||||||
|
DWORD dwRet;
|
||||||
|
DWORD dwFromFrame, dwToFrame;
|
||||||
|
|
||||||
|
TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
|
||||||
|
|
||||||
|
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
|
||||||
|
|
||||||
|
wma = MCIAVI_mciGetOpenDev(wDevID);
|
||||||
|
if (wma == NULL) return MCIERR_INVALID_DEVICE_ID;
|
||||||
|
if (dwFlags & MCI_DGV_PLAY_REVERSE) return MCIERR_UNSUPPORTED_FUNCTION;
|
||||||
|
if (dwFlags & MCI_TEST) return 0;
|
||||||
|
|
||||||
|
if (dwFlags & (MCI_DGV_PLAY_REPEAT|MCI_MCIAVI_PLAY_WINDOW|MCI_MCIAVI_PLAY_FULLSCREEN|MCI_MCIAVI_PLAY_FULLBY2))
|
||||||
|
FIXME("Unsupported flag %08x\n", dwFlags);
|
||||||
|
|
||||||
|
EnterCriticalSection(&wma->cs);
|
||||||
|
|
||||||
|
if (!wma->hFile)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&wma->cs);
|
||||||
|
return MCIERR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
if (!wma->hWndPaint)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&wma->cs);
|
||||||
|
return MCIERR_NO_WINDOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwFromFrame = wma->dwCurrVideoFrame;
|
||||||
|
dwToFrame = wma->dwPlayableVideoFrames - 1;
|
||||||
|
|
||||||
|
if (dwFlags & MCI_FROM) {
|
||||||
|
dwFromFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwFrom);
|
||||||
|
}
|
||||||
|
if (dwFlags & MCI_TO) {
|
||||||
|
dwToFrame = MCIAVI_ConvertTimeFormatToFrame(wma, lpParms->dwTo);
|
||||||
|
}
|
||||||
|
if (dwToFrame >= wma->dwPlayableVideoFrames)
|
||||||
|
dwToFrame = wma->dwPlayableVideoFrames - 1;
|
||||||
|
|
||||||
|
TRACE("Playing from frame=%u to frame=%u\n", dwFromFrame, dwToFrame);
|
||||||
|
|
||||||
|
wma->dwCurrVideoFrame = dwFromFrame;
|
||||||
|
wma->dwToVideoFrame = dwToFrame;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&wma->cs);
|
||||||
|
|
||||||
|
if (!(GetWindowLongW(wma->hWndPaint, GWL_STYLE) & WS_VISIBLE))
|
||||||
|
ShowWindow(wma->hWndPaint, SW_SHOWNA);
|
||||||
|
|
||||||
|
EnterCriticalSection(&wma->cs);
|
||||||
|
|
||||||
|
/* if already playing exit */
|
||||||
|
if (wma->dwStatus == MCI_MODE_PLAY)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&wma->cs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wma->dwStatus = MCI_MODE_PLAY;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&wma->cs);
|
||||||
|
|
||||||
|
if (dwFlags & MCI_WAIT)
|
||||||
|
return MCIAVI_player(wma, dwFlags, lpParms);
|
||||||
|
|
||||||
|
dwRet = MCIAVI_mciPlay_async(wma, dwFlags, lpParms);
|
||||||
|
|
||||||
|
if (dwRet) {
|
||||||
|
EnterCriticalSection(&wma->cs);
|
||||||
|
wma->dwStatus = MCI_MODE_STOP;
|
||||||
|
LeaveCriticalSection(&wma->cs);
|
||||||
|
}
|
||||||
|
return dwRet;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* MCIAVI_mciStop [internal]
|
* MCIAVI_mciStop [internal]
|
||||||
*/
|
*/
|
||||||
|
@ -79,7 +79,6 @@ typedef struct {
|
|||||||
/* data for the background mechanism */
|
/* data for the background mechanism */
|
||||||
CRITICAL_SECTION cs;
|
CRITICAL_SECTION cs;
|
||||||
HANDLE hStopEvent;
|
HANDLE hStopEvent;
|
||||||
HANDLE ack_event; /* acknowledge that an async command has started */
|
|
||||||
} WINE_MCIAVI;
|
} WINE_MCIAVI;
|
||||||
|
|
||||||
extern HINSTANCE MCIAVI_hInstance DECLSPEC_HIDDEN;
|
extern HINSTANCE MCIAVI_hInstance DECLSPEC_HIDDEN;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user