static DWORD MCIQTZ_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
{
WINE_MCIQTZ* wma;
+ static const WCHAR mciAviWStr[] = {'M','C','I','A','V','I',0};
TRACE("(%s, %p)\n", debugstr_w(str), modp);
if (!wma)
return 0;
+ modp->wType = MCI_DEVTYPE_DIGITAL_VIDEO;
wma->wDevID = modp->wDeviceID;
+ modp->wCustomCommandTable = wma->command_table = mciLoadCommandResource(MCIQTZ_hInstance, mciAviWStr, 0);
mciSetDriverData(wma->wDevID, (DWORD_PTR)wma);
return modp->wDeviceID;
/* finish all outstanding things */
MCIQTZ_mciClose(dwDevID, MCI_WAIT, NULL);
+ mciFreeCommandResource(wma->command_table);
+ mciSetDriverData(dwDevID, 0);
HeapFree(GetProcessHeap(), 0, wma);
return 1;
}
{
WINE_MCIQTZ* wma;
HRESULT hr;
+ IBasicVideo *vidbasic;
+ IVideoWindow *vidwin;
TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpOpenParms);
MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
- CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ wma->uninit = SUCCEEDED(hr);
hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&wma->pgraph);
if (FAILED(hr)) {
goto err;
}
- if (!((dwFlags & MCI_OPEN_ELEMENT) && (dwFlags & MCI_OPEN_ELEMENT))) {
+ if (!(dwFlags & MCI_OPEN_ELEMENT) || (dwFlags & MCI_OPEN_ELEMENT_ID)) {
TRACE("Wrong dwFlags %x\n", dwFlags);
goto err;
}
goto err;
}
+ hr = IFilterGraph2_QueryInterface(wma->pgraph, &IID_IVideoWindow, (void**)&vidwin);
+ if (SUCCEEDED(hr))
+ hr = IFilterGraph2_QueryInterface(wma->pgraph, &IID_IBasicVideo, (void**)&vidbasic);
+ if (SUCCEEDED(hr)) {
+ DWORD style;
+ RECT rc = { 0, 0, 0, 0 };
+ IVideoWindow_put_AutoShow(vidwin, OAFALSE);
+ IVideoWindow_put_Visible(vidwin, OAFALSE);
+ style = 0;
+ if (dwFlags & MCI_DGV_OPEN_WS)
+ style |= lpOpenParms->dwStyle;
+ if (dwFlags & MCI_DGV_OPEN_PARENT) {
+ IVideoWindow_put_MessageDrain(vidwin, (OAHWND)lpOpenParms->hWndParent);
+ IVideoWindow_put_WindowState(vidwin, SW_HIDE);
+ IVideoWindow_put_WindowStyle(vidwin, WS_CHILD);
+ IVideoWindow_put_Owner(vidwin, (OAHWND)lpOpenParms->hWndParent);
+ wma->parent = (HWND)lpOpenParms->hWndParent;
+ }
+ else if (style)
+ IVideoWindow_put_WindowStyle(vidwin, style);
+ IBasicVideo_GetVideoSize(vidbasic, &rc.right, &rc.bottom);
+ IVideoWindow_SetWindowPosition(vidwin, rc.left, rc.top, rc.right, rc.bottom);
+ IBasicVideo_Release(vidbasic);
+ }
+ if (vidwin)
+ IVideoWindow_Release(vidwin);
+
wma->opened = TRUE;
+ if (dwFlags & MCI_NOTIFY)
+ mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)), wDevID, MCI_NOTIFY_SUCCESSFUL);
+
return 0;
err:
IMediaControl_Release(wma->pmctrl);
wma->pmctrl = NULL;
- CoUninitialize();
+ if (wma->uninit)
+ CoUninitialize();
return MCIERR_INTERNAL;
}
if (wma->opened) {
IGraphBuilder_Release(wma->pgraph);
IMediaControl_Release(wma->pmctrl);
- CoUninitialize();
+ if (wma->uninit)
+ CoUninitialize();
wma->opened = FALSE;
}
return MCIERR_INTERNAL;
}
- wma->started = TRUE;
+ if (!wma->parent) {
+ IVideoWindow *vidwin;
+ IFilterGraph2_QueryInterface(wma->pgraph, &IID_IVideoWindow, (void**)&vidwin);
+ if (vidwin) {
+ IVideoWindow_put_Visible(vidwin, OATRUE);
+ IVideoWindow_Release(vidwin);
+ }
+ }
return 0;
}
if (!wma)
return MCIERR_INVALID_DEVICE_ID;
- if (!wma->started)
+ if (!wma->opened)
return 0;
hr = IMediaControl_Stop(wma->pmctrl);
return MCIERR_INTERNAL;
}
- wma->started = FALSE;
+ if (!wma->parent) {
+ IVideoWindow *vidwin;
+ IFilterGraph2_QueryInterface(wma->pgraph, &IID_IVideoWindow, (void**)&vidwin);
+ if (vidwin) {
+ IVideoWindow_put_Visible(vidwin, OAFALSE);
+ IVideoWindow_Release(vidwin);
+ }
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * MCIQTZ_mciPause [internal]
+ */
+static DWORD MCIQTZ_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
+{
+ WINE_MCIQTZ* wma;
+ HRESULT hr;
+
+ TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
+
+ wma = MCIQTZ_mciGetOpenDev(wDevID);
+ if (!wma)
+ return MCIERR_INVALID_DEVICE_ID;
+
+ hr = IMediaControl_Pause(wma->pmctrl);
+ if (FAILED(hr)) {
+ TRACE("Cannot pause filtergraph (hr = %x)\n", hr);
+ return MCIERR_INTERNAL;
+ }
return 0;
}
if (!wma)
return MCIERR_INVALID_DEVICE_ID;
- if (!(dwFlags & MCI_STATUS_ITEM)) {
- WARN("No capability item specified\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
- }
+ if (!(dwFlags & MCI_GETDEVCAPS_ITEM))
+ return MCIERR_MISSING_PARAMETER;
switch (lpParms->dwItem) {
case MCI_GETDEVCAPS_CAN_RECORD:
lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
TRACE("MCI_GETDEVCAPS_CAN_SAVE = %08x\n", lpParms->dwReturn);
break;
+ case MCI_DGV_GETDEVCAPS_CAN_REVERSE:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+ TRACE("MCI_DGV_GETDEVCAPS_CAN_REVERSE = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_CAN_STRETCH:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); /* FIXME */
+ TRACE("MCI_DGV_GETDEVCAPS_CAN_STRETCH = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_CAN_LOCK:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+ TRACE("MCI_DGV_GETDEVCAPS_CAN_LOCK = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_CAN_FREEZE:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+ TRACE("MCI_DGV_GETDEVCAPS_CAN_FREEZE = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_CAN_STR_IN:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+ TRACE("MCI_DGV_GETDEVCAPS_CAN_STRETCH_INPUT = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_HAS_STILL:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+ TRACE("MCI_DGV_GETDEVCAPS_HAS_STILL = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_CAN_TEST:
+ lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE); /* FIXME */
+ TRACE("MCI_DGV_GETDEVCAPS_CAN_TEST = %08x\n", lpParms->dwReturn);
+ break;
+ case MCI_DGV_GETDEVCAPS_MAX_WINDOWS:
+ lpParms->dwReturn = 1;
+ TRACE("MCI_DGV_GETDEVCAPS_MAX_WINDOWS = %u\n", lpParms->dwReturn);
+ return 0;
default:
- ERR("Unknown capability %08x\n", lpParms->dwItem);
- return MCIERR_UNRECOGNIZED_COMMAND;
+ WARN("Unknown capability %08x\n", lpParms->dwItem);
+ /* Fall through */
+ case MCI_DGV_GETDEVCAPS_MAXIMUM_RATE: /* unknown to w2k */
+ case MCI_DGV_GETDEVCAPS_MINIMUM_RATE: /* unknown to w2k */
+ return MCIERR_UNSUPPORTED_FUNCTION;
}
return MCI_RESOURCE_RETURNED;
}
}
- if (dwFlags & ~MCI_SET_TIME_FORMAT)
- FIXME("Flags not supported yet %08lX\n", dwFlags & ~MCI_SET_TIME_FORMAT);
+ if (dwFlags & MCI_SET_DOOR_OPEN)
+ FIXME("MCI_SET_DOOR_OPEN not implemented yet\n");
+ if (dwFlags & MCI_SET_DOOR_CLOSED)
+ FIXME("MCI_SET_DOOR_CLOSED not implemented yet\n");
+ if (dwFlags & MCI_SET_AUDIO)
+ FIXME("MCI_SET_AUDIO not implemented yet\n");
+ if (dwFlags & MCI_SET_VIDEO)
+ FIXME("MCI_SET_VIDEO not implemented yet\n");
+ if (dwFlags & MCI_SET_ON)
+ FIXME("MCI_SET_ON not implemented yet\n");
+ if (dwFlags & MCI_SET_OFF)
+ FIXME("MCI_SET_OFF not implemented yet\n");
+ if (dwFlags & MCI_SET_AUDIO_LEFT)
+ FIXME("MCI_SET_AUDIO_LEFT not implemented yet\n");
+ if (dwFlags & MCI_SET_AUDIO_RIGHT)
+ FIXME("MCI_SET_AUDIO_RIGHT not implemented yet\n");
+
+ if (dwFlags & ~0x7f03 /* All MCI_SET flags mask */)
+ ERR("Unknown flags %08x\n", dwFlags & ~0x7f03);
return 0;
}
static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMSW lpParms)
{
WINE_MCIQTZ* wma;
+ HRESULT hr;
TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
}
switch (lpParms->dwItem) {
- case MCI_STATUS_LENGTH:
- FIXME("MCI_STATUS_LENGTH not implemented yet\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
- case MCI_STATUS_POSITION:
- {
- HRESULT hr;
- REFTIME curpos;
+ case MCI_STATUS_LENGTH: {
+ IMediaSeeking *seek;
+ LONGLONG duration = -1;
+ GUID format;
+ switch (wma->time_format) {
+ case MCI_FORMAT_MILLISECONDS: format = TIME_FORMAT_MEDIA_TIME; break;
+ case MCI_FORMAT_FRAMES: format = TIME_FORMAT_FRAME; break;
+ default: ERR("Unhandled format %x\n", wma->time_format); break;
+ }
+ hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaSeeking, (void**)&seek);
+ if (FAILED(hr)) {
+ FIXME("Cannot get IMediaPostion interface (hr = %x)\n", hr);
+ return MCIERR_INTERNAL;
+ }
+ hr = IMediaSeeking_SetTimeFormat(seek, &format);
+ if (FAILED(hr)) {
+ IMediaSeeking_Release(seek);
+ FIXME("Cannot set time format (hr = %x)\n", hr);
+ lpParms->dwReturn = 0;
+ break;
+ }
+ hr = IMediaSeeking_GetDuration(seek, &duration);
+ IMediaSeeking_Release(seek);
+ if (FAILED(hr) || duration < 0) {
+ FIXME("Cannot read duration (hr = %x)\n", hr);
+ lpParms->dwReturn = 0;
+ } else if (wma->time_format != MCI_FORMAT_MILLISECONDS)
+ lpParms->dwReturn = duration;
+ else
+ lpParms->dwReturn = duration / 10000;
+ break;
+ }
+ case MCI_STATUS_POSITION: {
IMediaPosition* pmpos;
+ REFTIME curpos;
hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IMediaPosition, (LPVOID*)&pmpos);
if (FAILED(hr)) {
FIXME("MCI_STATUS_MEDIA_PRESENT not implemented yet\n");
return MCIERR_UNRECOGNIZED_COMMAND;
case MCI_STATUS_TIME_FORMAT:
- FIXME("MCI_STATUS_TIME_FORMAT not implemented yet\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
+ lpParms->dwReturn = wma->time_format;
+ break;
case MCI_STATUS_READY:
FIXME("MCI_STATUS_READY not implemented yet\n");
return MCIERR_UNRECOGNIZED_COMMAND;
{
WINE_MCIQTZ* wma;
IVideoWindow* pVideoWindow;
+ IBasicVideo *pBasicVideo;
HRESULT hr;
HWND hWnd;
RECT rc;
+ DWORD ret = MCIERR_UNRECOGNIZED_COMMAND;
TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
return MCIERR_INTERNAL;
}
+ hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
+ if (FAILED(hr)) {
+ ERR("Cannot get IBasicVideo interface (hr = %x)\n", hr);
+ IUnknown_Release(pVideoWindow);
+ return MCIERR_INTERNAL;
+ }
+
hr = IVideoWindow_get_Owner(pVideoWindow, (OAHWND*)&hWnd);
- IVideoWindow_Release(pVideoWindow);
if (FAILED(hr)) {
TRACE("No video stream, returning no window error\n");
+ IUnknown_Release(pVideoWindow);
return MCIERR_NO_WINDOW;
}
if (dwFlags & MCI_DGV_WHERE_SOURCE) {
if (dwFlags & MCI_DGV_WHERE_MAX)
- FIXME("MCI_DGV_WHERE_SOURCE_MAX not supported yet\n");
- else
- FIXME("MCI_DGV_WHERE_SOURCE not supported yet\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
+ FIXME("MCI_DGV_WHERE_SOURCE_MAX stub %s\n", wine_dbgstr_rect(&rc));
+ IBasicVideo_get_SourceLeft(pBasicVideo, &rc.left);
+ IBasicVideo_get_SourceTop(pBasicVideo, &rc.top);
+ IBasicVideo_get_SourceWidth(pBasicVideo, &rc.right);
+ IBasicVideo_get_SourceHeight(pBasicVideo, &rc.bottom);
+ /* Undo conversion done below */
+ rc.right += rc.left;
+ rc.bottom += rc.top;
+ TRACE("MCI_DGV_WHERE_SOURCE %s\n", wine_dbgstr_rect(&rc));
}
if (dwFlags & MCI_DGV_WHERE_DESTINATION) {
if (dwFlags & MCI_DGV_WHERE_MAX) {
TRACE("MCI_DGV_WHERE_DESTINATION_MAX %s\n", wine_dbgstr_rect(&rc));
} else {
FIXME("MCI_DGV_WHERE_DESTINATION not supported yet\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
+ goto out;
}
}
if (dwFlags & MCI_DGV_WHERE_FRAME) {
FIXME("MCI_DGV_WHERE_FRAME_MAX not supported yet\n");
else
FIXME("MCI_DGV_WHERE_FRAME not supported yet\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
+ goto out;
}
if (dwFlags & MCI_DGV_WHERE_VIDEO) {
if (dwFlags & MCI_DGV_WHERE_MAX)
FIXME("MCI_DGV_WHERE_VIDEO_MAX not supported yet\n");
else
FIXME("MCI_DGV_WHERE_VIDEO not supported yet\n");
- return MCIERR_UNRECOGNIZED_COMMAND;
+ goto out;
}
if (dwFlags & MCI_DGV_WHERE_WINDOW) {
if (dwFlags & MCI_DGV_WHERE_MAX) {
TRACE("MCI_DGV_WHERE_WINDOW %s\n", wine_dbgstr_rect(&rc));
}
}
+ ret = 0;
+out:
/* In MCI, RECT structure is used differently: rc.right = width & rc.bottom = height
* So convert the normal RECT into a MCI RECT before returning */
+ IVideoWindow_Release(pVideoWindow);
+ IBasicVideo_Release(pBasicVideo);
lpParms->rc.left = rc.left;
- lpParms->rc.top = rc.right;
+ lpParms->rc.top = rc.top;
lpParms->rc.right = rc.right - rc.left;
lpParms->rc.bottom = rc.bottom - rc.top;
+ return ret;
+}
+
+/******************************************************************************
+ * MCIAVI_mciUpdate [internal]
+ */
+static DWORD MCIQTZ_mciUpdate(UINT wDevID, DWORD dwFlags, LPMCI_DGV_UPDATE_PARMS lpParms)
+{
+ WINE_MCIQTZ *wma;
+ DWORD res = 0;
+
+ TRACE("%04x, %08x, %p\n", wDevID, dwFlags, lpParms);
+
+ if (!lpParms)
+ return MCIERR_NULL_PARAMETER_BLOCK;
+
+ wma = MCIQTZ_mciGetOpenDev(wDevID);
+ if (!wma)
+ return MCIERR_INVALID_DEVICE_ID;
+
+ if (dwFlags & MCI_DGV_UPDATE_HDC) {
+ IBasicVideo *vidbasic;
+ IVideoWindow *vidwin;
+ res = MCIERR_INTERNAL;
+ IFilterGraph2_QueryInterface(wma->pgraph, &IID_IVideoWindow, (void**)&vidwin);
+ IFilterGraph2_QueryInterface(wma->pgraph, &IID_IBasicVideo, (void**)&vidbasic);
+ if (vidbasic && vidwin) {
+ LONG state, size;
+ BYTE *data;
+ BITMAPINFO *info;
+ HRESULT hr;
+ RECT src, dest;
+
+ /* If in stopped state, nothing has been drawn to screen
+ * moving to pause, which is needed for the old dib renderer, will result
+ * in a single frame drawn, so hide the window here */
+ IVideoWindow_put_Visible(vidwin, OAFALSE);
+ /* FIXME: Should we check the original state and restore it? */
+ IMediaControl_Pause(wma->pmctrl);
+ IMediaControl_GetState(wma->pmctrl, -1, &state);
+ if (FAILED(hr = IBasicVideo_GetCurrentImage(vidbasic, &size, NULL))) {
+ WARN("Could not get image size (hr = %x)\n", hr);
+ goto out;
+ }
+ data = HeapAlloc(GetProcessHeap(), 0, size);
+ info = (BITMAPINFO*)data;
+ IBasicVideo_GetCurrentImage(vidbasic, &size, (LONG*)data);
+ data += info->bmiHeader.biSize;
+
+ IBasicVideo_GetSourcePosition(vidbasic, &src.left, &src.top, &src.right, &src.bottom);
+ IBasicVideo_GetDestinationPosition(vidbasic, &dest.left, &dest.top, &dest.right, &dest.bottom);
+ StretchDIBits(lpParms->hDC,
+ dest.left, dest.top, dest.right + dest.left, dest.bottom + dest.top,
+ src.left, src.top, src.right + src.left, src.bottom + src.top,
+ data, info, DIB_RGB_COLORS, SRCCOPY);
+ HeapFree(GetProcessHeap(), 0, data);
+ }
+ res = 0;
+out:
+ if (vidbasic)
+ IBasicVideo_Release(vidbasic);
+ if (vidwin) {
+ if (wma->parent)
+ IVideoWindow_put_Visible(vidwin, OATRUE);
+ IVideoWindow_Release(vidwin);
+ }
+ }
+ else if (dwFlags)
+ FIXME("Unhandled flags %x\n", dwFlags);
+ return res;
+}
+
+/***************************************************************************
+ * MCIQTZ_mciSetAudio [internal]
+ */
+static DWORD MCIQTZ_mciSetAudio(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SETAUDIO_PARMSW lpParms)
+{
+ WINE_MCIQTZ *wma;
+
+ FIXME("(%04x, %08x, %p) : stub\n", wDevID, dwFlags, lpParms);
+
+ if (!lpParms)
+ return MCIERR_NULL_PARAMETER_BLOCK;
+
+ wma = MCIQTZ_mciGetOpenDev(wDevID);
+ if (!wma)
+ return MCIERR_INVALID_DEVICE_ID;
+
+ MCIQTZ_mciStop(wDevID, MCI_WAIT, NULL);
+
return 0;
}
case MCI_PLAY: return MCIQTZ_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
case MCI_SEEK: return MCIQTZ_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
case MCI_STOP: return MCIQTZ_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
+ case MCI_PAUSE: return MCIQTZ_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
case MCI_GETDEVCAPS: return MCIQTZ_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
case MCI_SET: return MCIQTZ_mciSet (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS) dwParam2);
case MCI_STATUS: return MCIQTZ_mciStatus (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW) dwParam2);
case MCI_WHERE: return MCIQTZ_mciWhere (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS) dwParam2);
+ /* Digital Video specific */
+ case MCI_SETAUDIO: return MCIQTZ_mciSetAudio (dwDevID, dwParam1, (LPMCI_DGV_SETAUDIO_PARMSW) dwParam2);
+ case MCI_UPDATE:
+ return MCIQTZ_mciUpdate(dwDevID, dwParam1, (LPMCI_DGV_UPDATE_PARMS)dwParam2);
case MCI_RECORD:
- case MCI_PAUSE:
case MCI_RESUME:
case MCI_INFO:
case MCI_PUT:
case MCI_FREEZE:
case MCI_REALIZE:
case MCI_UNFREEZE:
- case MCI_UPDATE:
case MCI_STEP:
case MCI_COPY:
case MCI_CUT:
case MCI_CAPTURE:
case MCI_MONITOR:
case MCI_RESERVE:
- case MCI_SETAUDIO:
case MCI_SIGNAL:
case MCI_SETVIDEO:
case MCI_QUALITY: