Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
May 2019
- 96 participants
- 789 discussions
[PATCH v2 08/10] gdi32/tests: Add D3DKMTCheckVidPnExclusiveOwnership tests.
by Zhiyi Zhang 20 May '19
by Zhiyi Zhang 20 May '19
20 May '19
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/driver.c | 347 ++++++++++++++++++++++++++++++++++++++
1 file changed, 347 insertions(+)
diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index 2fda28138d..aa404954ce 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -33,11 +33,13 @@
static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
+static NTSTATUS (WINAPI *pD3DKMTCheckVidPnExclusiveOwnership)(const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *);
static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *);
static NTSTATUS (WINAPI *pD3DKMTCreateDevice)(D3DKMT_CREATEDEVICE *);
static NTSTATUS (WINAPI *pD3DKMTDestroyDevice)(const D3DKMT_DESTROYDEVICE *);
static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *);
static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC *);
+static NTSTATUS (WINAPI *pD3DKMTSetVidPnSourceOwner)(const D3DKMT_SETVIDPNSOURCEOWNER *);
static void test_D3DKMTOpenAdapterFromGdiDisplayName(void)
{
@@ -248,16 +250,361 @@ static void test_D3DKMTDestroyDevice(void)
todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
}
+static void test_D3DKMTCheckVidPnExclusiveOwnership(void)
+{
+ static const DWORD timeout = 1000;
+ static const DWORD wait_step = 100;
+ D3DKMT_CREATEDEVICE create_device_desc, create_device_desc2;
+ D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+ D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_owner_desc;
+ D3DKMT_DESTROYDEVICE destroy_device_desc;
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ D3DKMT_VIDPNSOURCEOWNER_TYPE owner_type;
+ D3DKMT_SETVIDPNSOURCEOWNER set_owner_desc;
+ DWORD total_time;
+ NTSTATUS status;
+ INT i;
+
+ /* Test cases using single device */
+ static const struct test_data1
+ {
+ D3DKMT_VIDPNSOURCEOWNER_TYPE owner_type;
+ NTSTATUS expected_set_status;
+ NTSTATUS expected_check_status;
+ } tests1[] = {
+ /* 0 */
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVEGDI, STATUS_INVALID_PARAMETER, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ /* 10 */
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ /* 20 */
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ /* 30 */
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_INVALID_PARAMETER, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ /* 40 */
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_INVALID_PARAMETER, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ /* 50 */
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_INVALID_PARAMETER, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS},
+ {-1, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED + 1, STATUS_INVALID_PARAMETER, STATUS_SUCCESS},
+ };
+
+ /* Test cases using two devices consecutively */
+ static const struct test_data2
+ {
+ D3DKMT_VIDPNSOURCEOWNER_TYPE set_owner_type1;
+ D3DKMT_VIDPNSOURCEOWNER_TYPE set_owner_type2;
+ NTSTATUS expected_set_status1;
+ NTSTATUS expected_set_status2;
+ NTSTATUS expected_check_status;
+ } tests2[] = {
+ /* 0 */
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_UNOWNED, D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_SHARED, D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ /* 10 */
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, D3DKMT_VIDPNSOURCEOWNER_UNOWNED, STATUS_SUCCESS, STATUS_SUCCESS, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, D3DKMT_VIDPNSOURCEOWNER_SHARED, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {D3DKMT_VIDPNSOURCEOWNER_EMULATED, D3DKMT_VIDPNSOURCEOWNER_EMULATED, STATUS_SUCCESS, STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, STATUS_SUCCESS},
+ {-1, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, -1, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ {D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE, -1, STATUS_SUCCESS, STATUS_SUCCESS, STATUS_GRAPHICS_PRESENT_OCCLUDED},
+ };
+
+ if (!pD3DKMTCheckVidPnExclusiveOwnership || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND
+ || !pD3DKMTOpenAdapterFromGdiDisplayName || !pD3DKMTCloseAdapter || !pD3DKMTCreateDevice
+ || !pD3DKMTDestroyDevice || !pD3DKMTSetVidPnSourceOwner)
+ {
+ skip("Required functions are unavailable.\n");
+ return;
+ }
+
+ /* Invalid parameters */
+ status = pD3DKMTCheckVidPnExclusiveOwnership(NULL);
+ ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ memset(&check_owner_desc, 0, sizeof(check_owner_desc));
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ /* Test cases */
+ lstrcpyW(open_adapter_gdi_desc.DeviceName, display1W);
+ status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ memset(&create_device_desc, 0, sizeof(create_device_desc));
+ create_device_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCreateDevice(&create_device_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ check_owner_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ check_owner_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
+ for (i = 0; i < ARRAY_SIZE(tests1); ++i)
+ {
+ set_owner_desc.hDevice = create_device_desc.hDevice;
+ if (tests1[i].owner_type != -1)
+ {
+ owner_type = tests1[i].owner_type;
+ set_owner_desc.pType = &owner_type;
+ set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+ set_owner_desc.VidPnSourceCount = 1;
+ }
+ else
+ {
+ set_owner_desc.pType = NULL;
+ set_owner_desc.pVidPnSourceId = NULL;
+ set_owner_desc.VidPnSourceCount = 0;
+ }
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == tests1[i].expected_set_status ||
+ /* win8 doesn't support D3DKMT_VIDPNSOURCEOWNER_EMULATED */
+ (status == STATUS_INVALID_PARAMETER && tests1[i].owner_type == D3DKMT_VIDPNSOURCEOWNER_EMULATED)
+ || (status == STATUS_SUCCESS && tests1[i].owner_type == D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE
+ && tests1[i - 1].owner_type == D3DKMT_VIDPNSOURCEOWNER_EMULATED),
+ "Got unexpected return code %#x at test %d.\n", status, i);
+
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ /* If don't sleep, D3DKMTCheckVidPnExclusiveOwnership may get STATUS_GRAPHICS_PRESENT_UNOCCLUDED instead
+ * of STATUS_SUCCESS */
+ if ((tests1[i].expected_check_status == STATUS_SUCCESS && status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED))
+ {
+ total_time = 0;
+ do
+ {
+ Sleep(wait_step);
+ total_time += wait_step;
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ } while (status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED && total_time < timeout);
+ }
+ ok(status == tests1[i].expected_check_status
+ || (status == STATUS_GRAPHICS_PRESENT_OCCLUDED /* win8 */
+ && tests1[i].owner_type == D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE
+ && tests1[i - 1].owner_type == D3DKMT_VIDPNSOURCEOWNER_EMULATED),
+ "Got unexpected return code %#x at test %d.\n", status, i);
+ }
+
+ /* Set owner and unset owner using different devices */
+ memset(&create_device_desc2, 0, sizeof(create_device_desc2));
+ create_device_desc2.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCreateDevice(&create_device_desc2);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ /* Set owner with the first device */
+ set_owner_desc.hDevice = create_device_desc.hDevice;
+ owner_type = D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE;
+ set_owner_desc.pType = &owner_type;
+ set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+ set_owner_desc.VidPnSourceCount = 1;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED, "Got unexpected return code %#x.\n", status);
+
+ /* Unset owner with the second device */
+ set_owner_desc.hDevice = create_device_desc2.hDevice;
+ set_owner_desc.pType = NULL;
+ set_owner_desc.pVidPnSourceId = NULL;
+ set_owner_desc.VidPnSourceCount = 0;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ /* No effect */
+ ok(status == STATUS_GRAPHICS_PRESENT_OCCLUDED, "Got unexpected return code %#x.\n", status);
+
+ /* Unset owner with the first device */
+ set_owner_desc.hDevice = create_device_desc.hDevice;
+ set_owner_desc.pType = NULL;
+ set_owner_desc.pVidPnSourceId = NULL;
+ set_owner_desc.VidPnSourceCount = 0;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ /* Proves that the correct device is needed to unset owner */
+ ok(status == STATUS_SUCCESS || status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED, "Got unexpected return code %#x.\n",
+ status);
+
+ /* Set owner with the first device, set owner again with the second device */
+ for (i = 0; i < ARRAY_SIZE(tests2); ++i)
+ {
+ if (tests2[i].set_owner_type1 != -1)
+ {
+ set_owner_desc.hDevice = create_device_desc.hDevice;
+ owner_type = tests2[i].set_owner_type1;
+ set_owner_desc.pType = &owner_type;
+ set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+ set_owner_desc.VidPnSourceCount = 1;
+ /* If don't sleep, D3DKMTSetVidPnSourceOwner may return STATUS_OK for D3DKMT_VIDPNSOURCEOWNER_SHARED.
+ * Other owner type doesn't seems to be affected. */
+ if (tests2[i].set_owner_type1 == D3DKMT_VIDPNSOURCEOWNER_SHARED)
+ Sleep(timeout);
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == tests2[i].expected_set_status1
+ || (status == STATUS_INVALID_PARAMETER /* win8 */
+ && tests2[i].set_owner_type1 == D3DKMT_VIDPNSOURCEOWNER_EMULATED),
+ "Got unexpected return code %#x at test %d.\n", status, i);
+ }
+
+ if (tests2[i].set_owner_type2 != -1)
+ {
+ set_owner_desc.hDevice = create_device_desc2.hDevice;
+ owner_type = tests2[i].set_owner_type2;
+ set_owner_desc.pType = &owner_type;
+ set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+ set_owner_desc.VidPnSourceCount = 1;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == tests2[i].expected_set_status2
+ || (status == STATUS_INVALID_PARAMETER /* win8 */
+ && tests2[i].set_owner_type2 == D3DKMT_VIDPNSOURCEOWNER_EMULATED)
+ || (status == STATUS_SUCCESS && tests2[i].set_owner_type1 == D3DKMT_VIDPNSOURCEOWNER_EMULATED
+ && tests2[i].set_owner_type2 == D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE),
+ "Got unexpected return code %#x at test %d.\n", status, i);
+ }
+
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ if ((tests2[i].expected_check_status == STATUS_SUCCESS && status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED))
+ {
+ total_time = 0;
+ do
+ {
+ Sleep(wait_step);
+ total_time += wait_step;
+ status = pD3DKMTCheckVidPnExclusiveOwnership(&check_owner_desc);
+ } while (status == STATUS_GRAPHICS_PRESENT_UNOCCLUDED && total_time < timeout);
+ }
+ ok(status == tests2[i].expected_check_status
+ || (status == STATUS_GRAPHICS_PRESENT_OCCLUDED /* win8 */
+ && tests2[i].set_owner_type2 == D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE
+ && tests2[i].set_owner_type1 == D3DKMT_VIDPNSOURCEOWNER_EMULATED),
+ "Got unexpected return code %#x at test %d.\n", status, i);
+
+ /* Unset owner with first device */
+ if (tests2[i].set_owner_type1 != -1)
+ {
+ set_owner_desc.hDevice = create_device_desc.hDevice;
+ set_owner_desc.pType = NULL;
+ set_owner_desc.pVidPnSourceId = NULL;
+ set_owner_desc.VidPnSourceCount = 0;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x at test %d.\n", status, i);
+ }
+
+ /* Unset owner with second device */
+ if (tests2[i].set_owner_type2 != -1)
+ {
+ set_owner_desc.hDevice = create_device_desc2.hDevice;
+ set_owner_desc.pType = NULL;
+ set_owner_desc.pVidPnSourceId = NULL;
+ set_owner_desc.VidPnSourceCount = 0;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x at test %d.\n", status, i);
+ }
+ }
+
+ /* Destroy devices holding ownership */
+ set_owner_desc.hDevice = create_device_desc.hDevice;
+ owner_type = D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE;
+ set_owner_desc.pType = &owner_type;
+ set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+ set_owner_desc.VidPnSourceCount = 1;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ destroy_device_desc.hDevice = create_device_desc.hDevice;
+ status = pD3DKMTDestroyDevice(&destroy_device_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ set_owner_desc.hDevice = create_device_desc2.hDevice;
+ owner_type = D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE;
+ set_owner_desc.pType = &owner_type;
+ set_owner_desc.pVidPnSourceId = &open_adapter_gdi_desc.VidPnSourceId;
+ set_owner_desc.VidPnSourceCount = 1;
+ status = pD3DKMTSetVidPnSourceOwner(&set_owner_desc);
+ /* So ownership is released when device is destroyed. otherwise the return code should be
+ * STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE */
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ destroy_device_desc.hDevice = create_device_desc2.hDevice;
+ status = pD3DKMTDestroyDevice(&destroy_device_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+}
+
START_TEST(driver)
{
HMODULE gdi32 = LoadLibraryA("gdi32.dll");
+ pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32, "D3DKMTCheckVidPnExclusiveOwnership");
pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32, "D3DKMTCloseAdapter");
pD3DKMTCreateDevice = (void *)GetProcAddress(gdi32, "D3DKMTCreateDevice");
pD3DKMTDestroyDevice = (void *)GetProcAddress(gdi32, "D3DKMTDestroyDevice");
pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
pD3DKMTOpenAdapterFromHdc = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc");
+ pD3DKMTSetVidPnSourceOwner = (void *)GetProcAddress(gdi32, "D3DKMTSetVidPnSourceOwner");
+ test_D3DKMTCheckVidPnExclusiveOwnership();
test_D3DKMTCloseAdapter();
test_D3DKMTCreateDevice();
test_D3DKMTDestroyDevice();
--
2.20.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/driver.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index be5d4202d3..2fda28138d 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -228,6 +228,26 @@ static void test_D3DKMTCreateDevice(void)
ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
}
+static void test_D3DKMTDestroyDevice(void)
+{
+ D3DKMT_DESTROYDEVICE destroy_device_desc;
+ NTSTATUS status;
+
+ if (!pD3DKMTDestroyDevice || pD3DKMTDestroyDevice(NULL) == STATUS_PROCEDURE_NOT_FOUND)
+ {
+ skip("D3DKMTDestroyDevice() is unavailable.\n");
+ return;
+ }
+
+ /* Invalid parameters */
+ status = pD3DKMTDestroyDevice(NULL);
+ todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ memset(&destroy_device_desc, 0, sizeof(destroy_device_desc));
+ status = pD3DKMTDestroyDevice(&destroy_device_desc);
+ todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+}
+
START_TEST(driver)
{
HMODULE gdi32 = LoadLibraryA("gdi32.dll");
@@ -240,6 +260,7 @@ START_TEST(driver)
test_D3DKMTCloseAdapter();
test_D3DKMTCreateDevice();
+ test_D3DKMTDestroyDevice();
test_D3DKMTOpenAdapterFromGdiDisplayName();
test_D3DKMTOpenAdapterFromHdc();
--
2.20.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/driver.c | 53 +++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index 5d87bbf6b9..be5d4202d3 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -34,6 +34,8 @@
static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *);
+static NTSTATUS (WINAPI *pD3DKMTCreateDevice)(D3DKMT_CREATEDEVICE *);
+static NTSTATUS (WINAPI *pD3DKMTDestroyDevice)(const D3DKMT_DESTROYDEVICE *);
static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *);
static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC *);
@@ -178,15 +180,66 @@ static void test_D3DKMTCloseAdapter(void)
todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
}
+static void test_D3DKMTCreateDevice(void)
+{
+ D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+ D3DKMT_CREATEDEVICE create_device_desc;
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ D3DKMT_DESTROYDEVICE destroy_device_desc;
+ NTSTATUS status;
+
+ if (!pD3DKMTCreateDevice || pD3DKMTCreateDevice(NULL) == STATUS_PROCEDURE_NOT_FOUND
+ || !pD3DKMTOpenAdapterFromGdiDisplayName || !pD3DKMTCloseAdapter || !pD3DKMTDestroyDevice)
+ {
+ skip("Required functions are unavailable.\n");
+ return;
+ }
+
+ /* Invalid parameters */
+ status = pD3DKMTCreateDevice(NULL);
+ ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ memset(&create_device_desc, 0, sizeof(create_device_desc));
+ status = pD3DKMTCreateDevice(&create_device_desc);
+ ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ lstrcpyW(open_adapter_gdi_desc.DeviceName, display1W);
+ status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ /* Create device */
+ create_device_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCreateDevice(&create_device_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ ok(create_device_desc.hDevice, "Expect not null.\n");
+ ok(create_device_desc.pCommandBuffer == NULL, "Expect null.\n");
+ ok(create_device_desc.CommandBufferSize == 0, "Got wrong value %#x.\n", create_device_desc.CommandBufferSize);
+ ok(create_device_desc.pAllocationList == NULL, "Expect null.\n");
+ ok(create_device_desc.AllocationListSize == 0, "Got wrong value %#x.\n", create_device_desc.AllocationListSize);
+ ok(create_device_desc.pPatchLocationList == NULL, "Expect null.\n");
+ ok(create_device_desc.PatchLocationListSize == 0, "Got wrong value %#x.\n", create_device_desc.PatchLocationListSize);
+
+ destroy_device_desc.hDevice = create_device_desc.hDevice;
+ status = pD3DKMTDestroyDevice(&destroy_device_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+
+ close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+}
+
START_TEST(driver)
{
HMODULE gdi32 = LoadLibraryA("gdi32.dll");
pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32, "D3DKMTCloseAdapter");
+ pD3DKMTCreateDevice = (void *)GetProcAddress(gdi32, "D3DKMTCreateDevice");
+ pD3DKMTDestroyDevice = (void *)GetProcAddress(gdi32, "D3DKMTDestroyDevice");
pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
pD3DKMTOpenAdapterFromHdc = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc");
test_D3DKMTCloseAdapter();
+ test_D3DKMTCreateDevice();
test_D3DKMTOpenAdapterFromGdiDisplayName();
test_D3DKMTOpenAdapterFromHdc();
--
2.20.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/driver.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index c1abe72217..5d87bbf6b9 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -158,6 +158,26 @@ static void test_D3DKMTOpenAdapterFromHdc(void)
}
}
+static void test_D3DKMTCloseAdapter(void)
+{
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ NTSTATUS status;
+
+ if (!pD3DKMTCloseAdapter || pD3DKMTCloseAdapter(NULL) == STATUS_PROCEDURE_NOT_FOUND)
+ {
+ skip("D3DKMTCloseAdapter() is unavailable.\n");
+ return;
+ }
+
+ /* Invalid parameters */
+ status = pD3DKMTCloseAdapter(NULL);
+ todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ memset(&close_adapter_desc, 0, sizeof(close_adapter_desc));
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+}
+
START_TEST(driver)
{
HMODULE gdi32 = LoadLibraryA("gdi32.dll");
@@ -166,6 +186,7 @@ START_TEST(driver)
pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
pD3DKMTOpenAdapterFromHdc = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc");
+ test_D3DKMTCloseAdapter();
test_D3DKMTOpenAdapterFromGdiDisplayName();
test_D3DKMTOpenAdapterFromHdc();
--
2.20.1
1
0
20 May '19
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/driver.c | 72 +++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c
index 57b158f16b..c1abe72217 100644
--- a/dlls/gdi32/tests/driver.c
+++ b/dlls/gdi32/tests/driver.c
@@ -35,6 +35,7 @@ static const WCHAR display1W[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'
static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *);
static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *);
+static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC *);
static void test_D3DKMTOpenAdapterFromGdiDisplayName(void)
{
@@ -88,14 +89,85 @@ static void test_D3DKMTOpenAdapterFromGdiDisplayName(void)
}
}
+static void test_D3DKMTOpenAdapterFromHdc(void)
+{
+ DISPLAY_DEVICEW display_device = {sizeof(display_device)};
+ D3DKMT_OPENADAPTERFROMHDC open_adapter_hdc_desc;
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ INT adapter_count = 0;
+ NTSTATUS status;
+ HDC hdc;
+ DWORD i;
+
+ if (!pD3DKMTOpenAdapterFromHdc || pD3DKMTOpenAdapterFromHdc(NULL) == STATUS_PROCEDURE_NOT_FOUND
+ || !pD3DKMTCloseAdapter)
+ {
+ skip("Required functions are unavailable.\n");
+ return;
+ }
+
+ /* Invalid parameters */
+ status = pD3DKMTOpenAdapterFromHdc(NULL);
+ todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ memset(&open_adapter_hdc_desc, 0, sizeof(open_adapter_hdc_desc));
+ status = pD3DKMTOpenAdapterFromHdc(&open_adapter_hdc_desc);
+ todo_wine ok(status == STATUS_INVALID_PARAMETER, "Got unexpected return code %#x.\n", status);
+
+ /* Open adapter */
+ for (i = 0; EnumDisplayDevicesW(NULL, i, &display_device, 0); ++i)
+ {
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ adapter_count++;
+
+ hdc = CreateDCW(0, display_device.DeviceName, 0, NULL);
+ open_adapter_hdc_desc.hDc = hdc;
+ status = pD3DKMTOpenAdapterFromHdc(&open_adapter_hdc_desc);
+ todo_wine ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ todo_wine ok(open_adapter_hdc_desc.hAdapter, "Expect not null.\n");
+ if (display_device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
+ ok(open_adapter_hdc_desc.VidPnSourceId == 0, "Got unexpected value %#x.\n",
+ open_adapter_hdc_desc.VidPnSourceId);
+ else
+ todo_wine ok(open_adapter_hdc_desc.VidPnSourceId, "Got unexpected value %#x.\n",
+ open_adapter_hdc_desc.VidPnSourceId);
+ DeleteDC(hdc);
+
+ if (status == STATUS_SUCCESS)
+ {
+ close_adapter_desc.hAdapter = open_adapter_hdc_desc.hAdapter;
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ }
+ }
+
+ /* HDC covering more than two adapters is invalid for D3DKMTOpenAdapterFromHdc */
+ hdc = GetDC(0);
+ open_adapter_hdc_desc.hDc = hdc;
+ status = pD3DKMTOpenAdapterFromHdc(&open_adapter_hdc_desc);
+ ReleaseDC(0, hdc);
+ todo_wine ok(status == (adapter_count > 1 ? STATUS_INVALID_PARAMETER : STATUS_SUCCESS),
+ "Got unexpected return code %#x.\n", status);
+ if (status == STATUS_SUCCESS)
+ {
+ close_adapter_desc.hAdapter = open_adapter_hdc_desc.hAdapter;
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+ }
+}
+
START_TEST(driver)
{
HMODULE gdi32 = LoadLibraryA("gdi32.dll");
pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32, "D3DKMTCloseAdapter");
pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
+ pD3DKMTOpenAdapterFromHdc = (void *)GetProcAddress(gdi32, "D3DKMTOpenAdapterFromHdc");
test_D3DKMTOpenAdapterFromGdiDisplayName();
+ test_D3DKMTOpenAdapterFromHdc();
FreeLibrary(gdi32);
}
--
2.20.1
1
0
20 May '19
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/dxgi/tests/dxgi.c | 167 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 167 insertions(+)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index b8ab0763dd..317cf31533 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -3990,9 +3990,13 @@ static void test_swapchain_parameters(void)
static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
{
+ static const DWORD flags[] = {0, DXGI_PRESENT_TEST};
+ static const DWORD timeout = 2000;
DXGI_SWAP_CHAIN_DESC swapchain_desc;
IDXGISwapChain *swapchain;
IDXGIFactory *factory;
+ IDXGIOutput *output;
+ BOOL fullscreen;
unsigned int i;
ULONG refcount;
HRESULT hr;
@@ -4027,6 +4031,169 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
hr = IDXGISwapChain_Present(swapchain, 0, 0);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ for (i = 0; i < ARRAY_SIZE(flags); ++i)
+ {
+ HWND occluding_hwnd = CreateWindowA("static", "occluding_window", WS_POPUP | WS_VISIBLE, 0, 0, 400, 200, 0, 0, 0, 0);
+
+ /* Another window covers the swapchain window, doesn't report as occluded */
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* Minimized window */
+ ShowWindow(swapchain_desc.OutputWindow, SW_MINIMIZE);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ todo_wine_if(!is_d3d12) ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Got unexpected hr %#x.\n", hr);
+ ShowWindow(swapchain_desc.OutputWindow, SW_NORMAL);
+
+ /* Hidden window */
+ ShowWindow(swapchain_desc.OutputWindow, SW_HIDE);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ShowWindow(swapchain_desc.OutputWindow, SW_SHOW);
+ DestroyWindow(occluding_hwnd);
+
+ /* Test IDXGIOutput_ReleaseOwnership makes the swapchain exit fullscreen */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines. DXGI_ERROR_UNSUPPORTED on Win 7 testbot. */
+ if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
+ {
+ skip("Could not change fullscreen state.\n");
+ continue;
+ }
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ output = NULL;
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ todo_wine_if(is_d3d12) ok(output != NULL, "Expect output not null.\n");
+
+ if (output) IDXGIOutput_ReleaseOwnership(output);
+ /* Still in fullscreen */
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ /* Now calling IDXGISwapChain_Present will exit the fullscreen */
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ /* Now fullscreen mode is exited */
+ if (flags[i] == 0 && !is_d3d12)
+ {
+ /* Still on fullscreen on vista and 2008 */
+ todo_wine ok(!fullscreen || broken(fullscreen), "Unexpected fullscreen status.\n");
+ }
+ else
+ ok(fullscreen, "Unexpected fullscreen status.\n");
+ if (output) IDXGIOutput_Release(output);
+
+
+ /* Test creating a window when swapchain is in fullscreen.
+ * The window should break the swapchain out of fullscreen mode on d3d10/11.
+ * d3d12 is different, new occluding window doesn't break swapchain out of fullscreen because d3d12 swapchain
+ * fullscreen mode doesn't take exclusive ownership over output, nor does it disable compositing.
+ * d3d12 fullscreen mode acts just like borderless fullscreen window mode */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ occluding_hwnd = CreateWindowA("static", "occluding_window", WS_POPUP, 0, 0, 400, 200, 0, 0, 0, 0);
+ /* Invisible window doesn't cause fullscreen mode to exit */
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ /* Visible but with bottom z-order window still cause fullscreen mode to exit */
+ SetWindowPos(occluding_hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ ShowWindow(occluding_hwnd, SW_SHOW);
+ /* Fullscreen mode takes a while to exit */
+ Sleep(timeout);
+
+ /* No longer fullscreen before calling IDXGISwapChain_Present except for d3d12 */
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen, "Unexpected fullscreen status.\n");
+
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK), "Got unexpected hr %#x.\n", hr);
+
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ if (flags[i] == DXGI_PRESENT_TEST)
+ todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen, "Unexpected fullscreen status.\n");
+ else
+ todo_wine ok(!fullscreen, "Unexpected fullscreen status.\n");
+
+ /* Even though d3d12 doesn't exit fullscreen, a IDXGISwapChain_ResizeBuffers is still needed for subsequent
+ * IDXGISwapChain_Present calls to work, otherwise they will return DXGI_ERROR_INVALID_CALL */
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ if (flags[i] == DXGI_PRESENT_TEST)
+ todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK), "Got unexpected hr %#x.\n", hr);
+ else
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+
+ /* Trying break out of fullscreen mode again. This time, don't call IDXGISwapChain_GetFullscreenState before
+ * IDXGISwapChain_Present */
+ ShowWindow(occluding_hwnd, SW_HIDE);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ShowWindow(occluding_hwnd, SW_SHOW);
+
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ /* hr == S_OK on vista and 2008 */
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK), "Got unexpected hr %#x.\n", hr);
+
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ if (flags[i] == DXGI_PRESENT_TEST)
+ {
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK), "Got unexpected hr %#x.\n", hr);
+ /* IDXGISwapChain_Present without flags refresh the occlusion state */
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK), "Got unexpected hr %#x.\n", hr);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+ else
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!fullscreen, "Unexpected fullscreen status.\n");
+
+ DestroyWindow(occluding_hwnd);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ }
+
wait_device_idle(device);
IDXGISwapChain_Release(swapchain);
--
2.20.1
1
0
Mostly to show that TakeOwnership and ReleaseOwnership
are based on VidPN ownership.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v2: Poll results instead of using Sleep() whenever possible.
D3DKMTOpenAdapterFromGdiDisplayName opens the adapter used
by the swapchain. D3DKMTOpenAdapterFromLuid could not be
used here because we need to know VidPnSourceId as well,
which D3DKMTOpenAdapterFromLuid doesn't offer.
dlls/dxgi/tests/dxgi.c | 224 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 223 insertions(+), 1 deletion(-)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 79e4bc0c15..b8ab0763dd 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -17,11 +17,15 @@
*/
#include <assert.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
#define COBJMACROS
#include "initguid.h"
#include "dxgi1_6.h"
#include "d3d11.h"
#include "d3d12.h"
+#include "winternl.h"
+#include "ddk/d3dkmthk.h"
#include "wine/heap.h"
#include "wine/test.h"
@@ -36,6 +40,10 @@ static DEVMODEW registry_mode;
static HRESULT (WINAPI *pCreateDXGIFactory1)(REFIID iid, void **factory);
static HRESULT (WINAPI *pCreateDXGIFactory2)(UINT flags, REFIID iid, void **factory);
+static NTSTATUS (WINAPI *pD3DKMTCheckVidPnExclusiveOwnership)(const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *);
+static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER *);
+static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *);
+
static PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
static PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface;
@@ -43,6 +51,9 @@ static unsigned int use_adapter_idx;
static BOOL use_warp_adapter;
static BOOL use_mt = TRUE;
+static const DWORD wait_timeout = 1000;
+static const DWORD wait_step = 100;
+
static struct test_entry
{
void (*test)(void);
@@ -113,6 +124,22 @@ static ULONG get_refcount(void *iface)
return IUnknown_Release(unknown);
}
+#define wait_result1(func, arg1, expected, todo) \
+ do \
+ { \
+ DWORD total_time = 0; \
+ typeof(expected) got; \
+ do \
+ { \
+ got = func(arg1); \
+ if (got == expected) \
+ break; \
+ Sleep(wait_step); \
+ total_time += wait_step; \
+ } while (total_time < wait_timeout); \
+ todo_wine_if(todo) ok(got == expected, "Expect %#x, got unexpected result %#x.\n", expected, got); \
+ } while (0)
+
#define check_interface(a, b, c, d) check_interface_(__LINE__, a, b, c, d)
static HRESULT check_interface_(unsigned int line, void *iface, REFIID iid,
BOOL supported, BOOL is_broken)
@@ -4985,6 +5012,194 @@ done:
ok(!refcount, "Factory has %u references left.\n", refcount);
}
+static void test_output_ownership(IUnknown *device, BOOL is_d3d12)
+{
+ D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+ D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP check_ownership_desc;
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ DXGI_SWAP_CHAIN_DESC swapchain_desc;
+ DXGI_OUTPUT_DESC output_desc;
+ ID3D12Device *d3d12_device;
+ IDXGISwapChain *swapchain;
+ IDXGIFactory4 *factory4;
+ IDXGIFactory *factory;
+ IDXGIAdapter *adapter;
+ IDXGIOutput *output;
+ BOOL fullscreen;
+ NTSTATUS status;
+ ULONG refcount;
+ LUID luid;
+ HRESULT hr;
+
+ if (!pD3DKMTCheckVidPnExclusiveOwnership || pD3DKMTCheckVidPnExclusiveOwnership(NULL) == STATUS_PROCEDURE_NOT_FOUND
+ || !pD3DKMTCloseAdapter || !pD3DKMTOpenAdapterFromGdiDisplayName)
+ {
+ skip("Required functions are unavailable.\n");
+ return;
+ }
+
+ get_factory(device, is_d3d12, &factory);
+
+ if (is_d3d12)
+ {
+ hr = ID3D12CommandQueue_GetDevice((ID3D12CommandQueue *)device, &IID_ID3D12Device, (void **)&d3d12_device);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ luid = ID3D12Device_GetAdapterLuid(d3d12_device);
+ ID3D12Device_Release(d3d12_device);
+ hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void **)&factory4);
+ if (hr == E_NOINTERFACE)
+ {
+ skip("DXGI 1.4 unsupported.\n");
+ IDXGIFactory_Release(factory);
+ return;
+ }
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGIFactory4_EnumAdapterByLuid(factory4, luid, &IID_IDXGIAdapter, (void **)&adapter);
+ IDXGIFactory4_Release(factory4);
+ if (hr == DXGI_ERROR_NOT_FOUND)
+ {
+ skip("Wine doesn't support IDXGIFactory4_EnumAdapterByLuid.\n");
+ IDXGIFactory_Release(factory);
+ return;
+ }
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+ else
+ {
+ hr = IDXGIDevice_GetAdapter((IDXGIDevice *)device, &adapter);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+
+ hr = IDXGIAdapter_EnumOutputs(adapter, 0, &output);
+ IDXGIAdapter_Release(adapter);
+ if (hr == DXGI_ERROR_NOT_FOUND)
+ {
+ skip("Adapter doesn't have any outputs.\n");
+ IDXGIFactory_Release(factory);
+ return;
+ }
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGIOutput_GetDesc(output, &output_desc);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ lstrcpyW(open_adapter_gdi_desc.DeviceName, output_desc.DeviceName);
+ status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+
+ check_ownership_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ check_ownership_desc.VidPnSourceId = open_adapter_gdi_desc.VidPnSourceId;
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+ swapchain_desc.BufferDesc.Width = 800;
+ swapchain_desc.BufferDesc.Height = 600;
+ swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
+ swapchain_desc.BufferDesc.RefreshRate.Denominator = 60;
+ swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+ swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+ swapchain_desc.SampleDesc.Count = 1;
+ swapchain_desc.SampleDesc.Quality = 0;
+ swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
+ swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+ swapchain_desc.Windowed = TRUE;
+ swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
+ swapchain_desc.Flags = 0;
+
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "Failed to create swapchain, hr %#x.\n", hr);
+
+ /* Swapchain in fullscreen mode */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, output);
+ /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines. DXGI_ERROR_UNSUPPORTED on Win 7 testbot. */
+ if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
+ {
+ skip("Failed to change fullscreen state.\n");
+ goto done;
+ }
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen state.\n");
+ if (is_d3d12)
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+ else
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_GRAPHICS_PRESENT_OCCLUDED, TRUE);
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : E_INVALIDARG), "Got unexpected hr %#x.\n", hr);
+ hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : S_OK), "Got unexpected hr %#x.\n", hr);
+ /* Calling IDXGIOutput_ReleaseOwnership makes it unoccluded. So we can be confident about IDXGIOutput_TakeOwnership
+ * was called in IDXGISwapChain_SetFullscreenState */
+ IDXGIOutput_ReleaseOwnership(output);
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), "Got unexpected hr %#x.\n", hr);
+ IDXGIOutput_ReleaseOwnership(output);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : S_OK), "Got unexpected hr %#x.\n", hr);
+ /* So the following results shows that IDXGIOutput_TakeOwnership(output, device, TRUE) is used in
+ * SetFullscreenState(swapchain, TRUE, NULL)
+ *
+ * This make me believe the MSDN documentation is saying the opposite about the last parameter,
+ * "HRESULT TakeOwnership(IUnknown *pDevice, BOOL Exclusive);
+ * Name: Exclusive Type: BOOL
+ * Set to TRUE to enable other threads or applications to take ownership of the device; otherwise, set to FALSE."
+ *
+ * Reasons:
+ * 1. The parameter name is called 'Exclusive'
+ * 2. D3DKMTSetVidPnSourceOwner(D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE) makes D3DKMTCheckVidPnExclusiveOwnership return
+ * STATUS_GRAPHICS_PRESENT_OCCLUDED. And D3DKMTSetVidPnSourceOwner(D3DKMT_VIDPNSOURCEOWNER_SHARED) makes
+ * D3DKMTCheckVidPnExclusiveOwnership return STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE. So the opposite mapping of
+ * what MSDN is saying is consistent with the tests.
+ */
+ if (is_d3d12)
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+ else
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_GRAPHICS_PRESENT_OCCLUDED, TRUE);
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : E_INVALIDARG), "Got unexpected hr %#x.\n", hr);
+ IDXGIOutput_ReleaseOwnership(output);
+
+ /* Swapchain in windowed mode */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(!fullscreen, "Unexpected fullscreen state.\n");
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, FALSE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE), "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGIOutput_TakeOwnership(output, device, TRUE);
+ todo_wine ok(hr == (is_d3d12 ? E_NOINTERFACE : S_OK), "Got unexpected hr %#x.\n", hr);
+ if (is_d3d12)
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+ else
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_GRAPHICS_PRESENT_OCCLUDED, TRUE);
+ IDXGIOutput_ReleaseOwnership(output);
+ wait_result1(pD3DKMTCheckVidPnExclusiveOwnership, &check_ownership_desc, STATUS_SUCCESS, FALSE);
+
+done:
+ wait_device_idle(device);
+
+ IDXGIOutput_Release(output);
+ IDXGISwapChain_Release(swapchain);
+ DestroyWindow(swapchain_desc.OutputWindow);
+ refcount = IDXGIFactory_Release(factory);
+ ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
+
+ close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status);
+}
+
static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
{
IDXGIDevice *device;
@@ -5028,7 +5243,7 @@ static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
START_TEST(dxgi)
{
- HMODULE dxgi_module, d3d12_module;
+ HMODULE dxgi_module, d3d12_module, gdi32_module;
BOOL enable_debug_layer = FALSE;
unsigned int argc, i;
ID3D12Debug *debug;
@@ -5038,6 +5253,11 @@ START_TEST(dxgi)
pCreateDXGIFactory1 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
pCreateDXGIFactory2 = (void *)GetProcAddress(dxgi_module, "CreateDXGIFactory2");
+ gdi32_module = GetModuleHandleA("gdi32.dll");
+ pD3DKMTCheckVidPnExclusiveOwnership = (void *)GetProcAddress(gdi32_module, "D3DKMTCheckVidPnExclusiveOwnership");
+ pD3DKMTCloseAdapter = (void *)GetProcAddress(gdi32_module, "D3DKMTCloseAdapter");
+ pD3DKMTOpenAdapterFromGdiDisplayName = (void *)GetProcAddress(gdi32_module, "D3DKMTOpenAdapterFromGdiDisplayName");
+
registry_mode.dmSize = sizeof(registry_mode);
ok(EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, ®istry_mode), "Failed to get display mode.\n");
@@ -5088,6 +5308,7 @@ START_TEST(dxgi)
run_on_d3d10(test_swapchain_present);
run_on_d3d10(test_swapchain_backbuffer_index);
run_on_d3d10(test_swapchain_formats);
+ run_on_d3d10(test_output_ownership);
if (!(d3d12_module = LoadLibraryA("d3d12.dll")))
{
@@ -5108,6 +5329,7 @@ START_TEST(dxgi)
run_on_d3d12(test_swapchain_present);
run_on_d3d12(test_swapchain_backbuffer_index);
run_on_d3d12(test_swapchain_formats);
+ run_on_d3d12(test_output_ownership);
FreeLibrary(d3d12_module);
}
--
2.20.1
1
0
20 May '19
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/main.c | 12 ++++++++++--
dlls/mfplat/tests/mfplat.c | 17 +++++++++++++++++
include/mfidl.idl | 6 ++++++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index e80408d2b2..77edabec2c 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -6633,9 +6633,17 @@ static HRESULT WINAPI system_time_source_GetState(IMFPresentationTimeSource *ifa
static HRESULT WINAPI system_time_source_GetProperties(IMFPresentationTimeSource *iface, MFCLOCK_PROPERTIES *props)
{
- FIXME("%p, %p.\n", iface, props);
+ TRACE("%p, %p.\n", iface, props);
- return E_NOTIMPL;
+ if (!props)
+ return E_POINTER;
+
+ memset(props, 0, sizeof(*props));
+ props->qwClockFrequency = MFCLOCK_FREQUENCY_HNS;
+ props->dwClockTolerance = MFCLOCK_TOLERANCE_UNKNOWN;
+ props->dwClockJitter = 1;
+
+ return S_OK;
}
static HRESULT WINAPI system_time_source_GetUnderlyingClock(IMFPresentationTimeSource *iface, IMFClock **clock)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 7fa3ddd876..4adfb1b8ad 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -2542,6 +2542,7 @@ static void test_system_time_source(void)
};
IMFPresentationTimeSource *time_source;
IMFClockStateSink *statesink;
+ MFCLOCK_PROPERTIES props;
MFCLOCK_STATE state;
unsigned int i;
DWORD value;
@@ -2595,6 +2596,22 @@ static void test_system_time_source(void)
IMFClockStateSink_Release(statesink);
+ /* Properties. */
+ hr = IMFPresentationTimeSource_GetProperties(time_source, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFPresentationTimeSource_GetProperties(time_source, &props);
+ ok(hr == S_OK, "Failed to get clock properties, hr %#x.\n", hr);
+
+ ok(props.qwCorrelationRate == 0, "Unexpected correlation rate %s.\n",
+ wine_dbgstr_longlong(props.qwCorrelationRate));
+ ok(IsEqualGUID(&props.guidClockId, &GUID_NULL), "Unexpected clock id %s.\n", wine_dbgstr_guid(&props.guidClockId));
+ ok(props.dwClockFlags == 0, "Unexpected flags %#x.\n", props.dwClockFlags);
+ ok(props.qwClockFrequency == MFCLOCK_FREQUENCY_HNS, "Unexpected frequency %s.\n",
+ wine_dbgstr_longlong(props.qwClockFrequency));
+ ok(props.dwClockTolerance == MFCLOCK_TOLERANCE_UNKNOWN, "Unexpected tolerance %u.\n", props.dwClockTolerance);
+ ok(props.dwClockJitter == 1, "Unexpected jitter %u.\n", props.dwClockJitter);
+
IMFPresentationTimeSource_Release(time_source);
}
diff --git a/include/mfidl.idl b/include/mfidl.idl
index a5882e98e5..2421c06f50 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -47,6 +47,12 @@ typedef enum MF_OBJECT_TYPE
MF_OBJECT_INVALID
} MF_OBJECT_TYPE;
+cpp_quote("#define MFCLOCK_FREQUENCY_HNS 10000000")
+cpp_quote("#define MFCLOCK_TOLERANCE_UNKNOWN 50000")
+cpp_quote("#define MFCLOCK_JITTER_ISR 1000")
+cpp_quote("#define MFCLOCK_JITTER_DPC 4000")
+cpp_quote("#define MFCLOCK_JITTER_PASSIVE 10000")
+
typedef struct _MFCLOCK_PROPERTIES
{
unsigned __int64 qwCorrelationRate;
--
2.20.1
1
1
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/main.c | 2 +-
dlls/mf/samplegrabber.c | 422 +++++++++++++++++++++++++++++++++++++++-
dlls/mf/tests/mf.c | 139 ++++++++++++-
include/mferror.h | 14 ++
include/mfidl.idl | 32 +++
5 files changed, 602 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/main.c b/dlls/mf/main.c
index b5b4b0e7c8..6db13f19db 100644
--- a/dlls/mf/main.c
+++ b/dlls/mf/main.c
@@ -395,7 +395,7 @@ static HRESULT WINAPI activate_object_ActivateObject(IMFActivate *iface, REFIID
if (FAILED(hr = activate->funcs->create_object((IMFAttributes *)iface, activate->context, &object)))
return hr;
- if (!InterlockedCompareExchangePointer((void **)&activate->object, object, NULL))
+ if (InterlockedCompareExchangePointer((void **)&activate->object, object, NULL))
IUnknown_Release(object);
}
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c
index 7b3536467c..997c9db539 100644
--- a/dlls/mf/samplegrabber.c
+++ b/dlls/mf/samplegrabber.c
@@ -19,6 +19,7 @@
#define COBJMACROS
#include "mfidl.h"
+#include "mferror.h"
#include "mf_private.h"
#include "wine/debug.h"
@@ -26,6 +27,24 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct sample_grabber_stream
+{
+ IMFStreamSink IMFStreamSink_iface;
+ LONG refcount;
+ IMFMediaSink *sink;
+};
+
+struct sample_grabber
+{
+ IMFMediaSink IMFMediaSink_iface;
+ LONG refcount;
+ IMFSampleGrabberSinkCallback *callback;
+ IMFMediaType *media_type;
+ BOOL is_shut_down;
+ IMFStreamSink *stream;
+ CRITICAL_SECTION cs;
+};
+
struct sample_grabber_activate_context
{
IMFMediaType *media_type;
@@ -40,13 +59,412 @@ static void sample_grabber_free_private(void *user_context)
heap_free(context);
}
-static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
+static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface)
+{
+ return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface);
+}
+
+static struct sample_grabber_stream *impl_from_IMFStreamSink(IMFStreamSink *iface)
{
- FIXME("%p, %p, %p.\n", attributes, user_context, obj);
+ return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFStreamSink_iface);
+}
+
+static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFStreamSink) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = &stream->IMFStreamSink_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*obj);
+
+ return S_OK;
+}
+
+static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedIncrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFMediaSink_Release(stream->sink);
+ heap_free(stream);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
+{
+ FIXME("%p, %#x, %p.\n", iface, flags, event);
return E_NOTIMPL;
}
+static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
+ IUnknown *state)
+{
+ FIXME("%p, %p, %p.\n", iface, callback, state);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
+ IMFMediaEvent **event)
+{
+ FIXME("%p, %p, %p.\n", iface, result, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
+ REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
+{
+ FIXME("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %p.\n", iface, sink);
+
+ *sink = stream->sink;
+ IMFMediaSink_AddRef(*sink);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
+{
+ TRACE("%p, %p.\n", iface, identifier);
+
+ *identifier = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
+{
+ FIXME("%p, %p.\n", iface, handler);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
+{
+ FIXME("%p, %p.\n", iface, sample);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
+ const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
+{
+ FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static const IMFStreamSinkVtbl sample_grabber_stream_vtbl =
+{
+ sample_grabber_stream_QueryInterface,
+ sample_grabber_stream_AddRef,
+ sample_grabber_stream_Release,
+ sample_grabber_stream_GetEvent,
+ sample_grabber_stream_BeginGetEvent,
+ sample_grabber_stream_EndGetEvent,
+ sample_grabber_stream_QueueEvent,
+ sample_grabber_stream_GetMediaSink,
+ sample_grabber_stream_GetIdentifier,
+ sample_grabber_stream_GetMediaTypeHandler,
+ sample_grabber_stream_ProcessSample,
+ sample_grabber_stream_PlaceMarker,
+ sample_grabber_stream_Flush,
+};
+
+static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFMediaSink) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = &grabber->IMFMediaSink_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*obj);
+
+ return S_OK;
+}
+
+static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ ULONG refcount = InterlockedIncrement(&grabber->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ ULONG refcount = InterlockedDecrement(&grabber->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFSampleGrabberSinkCallback_Release(grabber->callback);
+ IMFMediaType_Release(grabber->media_type);
+ DeleteCriticalSection(&grabber->cs);
+ heap_free(grabber);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %p.\n", iface, flags);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ *flags = MEDIASINK_FIXED_STREAMS;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
+ IMFMediaType *media_type, IMFStreamSink **stream_sink)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
+
+ return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
+}
+
+static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %#x.\n", iface, stream_sink_id);
+
+ return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %p.\n", iface, count);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ *count = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
+ IMFStreamSink **stream)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %u, %p.\n", iface, index, stream);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ EnterCriticalSection(&grabber->cs);
+
+ if (grabber->is_shut_down)
+ hr = MF_E_SHUTDOWN;
+ else if (index > 0)
+ hr = MF_E_INVALIDINDEX;
+ else
+ {
+ *stream = grabber->stream;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ LeaveCriticalSection(&grabber->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
+ IMFStreamSink **stream)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
+
+ EnterCriticalSection(&grabber->cs);
+
+ if (grabber->is_shut_down)
+ hr = MF_E_SHUTDOWN;
+ else if (stream_sink_id > 0)
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ else
+ {
+ *stream = grabber->stream;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ LeaveCriticalSection(&grabber->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
+{
+ FIXME("%p, %p.\n", iface, clock);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
+{
+ FIXME("%p, %p.\n", iface, clock);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p.\n", iface);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ EnterCriticalSection(&grabber->cs);
+ grabber->is_shut_down = TRUE;
+ IMFStreamSink_Release(grabber->stream);
+ grabber->stream = NULL;
+ EnterCriticalSection(&grabber->cs);
+
+ return E_NOTIMPL;
+}
+
+static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
+{
+ sample_grabber_sink_QueryInterface,
+ sample_grabber_sink_AddRef,
+ sample_grabber_sink_Release,
+ sample_grabber_sink_GetCharacteristics,
+ sample_grabber_sink_AddStreamSink,
+ sample_grabber_sink_RemoveStreamSink,
+ sample_grabber_sink_GetStreamSinkCount,
+ sample_grabber_sink_GetStreamSinkByIndex,
+ sample_grabber_sink_GetStreamSinkById,
+ sample_grabber_sink_SetPresentationClock,
+ sample_grabber_sink_GetPresentationClock,
+ sample_grabber_sink_Shutdown,
+};
+
+static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink **stream)
+{
+ struct sample_grabber_stream *object;
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
+ object->refcount = 1;
+ object->sink = sink;
+ IMFMediaSink_AddRef(object->sink);
+
+ *stream = &object->IMFStreamSink_iface;
+
+ return S_OK;
+}
+
+static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
+{
+ struct sample_grabber_activate_context *context = user_context;
+ struct sample_grabber *object;
+ HRESULT hr;
+
+ TRACE("%p, %p, %p.\n", attributes, user_context, obj);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
+ object->refcount = 1;
+ object->callback = context->callback;
+ IMFSampleGrabberSinkCallback_AddRef(object->callback);
+ object->media_type = context->media_type;
+ IMFMediaType_AddRef(object->media_type);
+ InitializeCriticalSection(&object->cs);
+ if (FAILED(hr = sample_grabber_create_stream(&object->IMFMediaSink_iface, &object->stream)))
+ {
+ IMFMediaSink_Release(&object->IMFMediaSink_iface);
+ return hr;
+ }
+
+ *obj = (IUnknown *)&object->IMFMediaSink_iface;
+
+ TRACE("Created %p.\n", *obj);
+
+ return S_OK;
+}
+
static const struct activate_funcs sample_grabber_activate_funcs =
{
sample_grabber_create_object,
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 37bcb8d029..2987e86f4b 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1230,7 +1230,6 @@ todo_wine
ok(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
-todo_wine
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
@@ -1639,9 +1638,16 @@ static IMFSampleGrabberSinkCallback grabber_callback = { &grabber_callback_vtbl
static void test_sample_grabber(void)
{
+ IMFMediaTypeHandler *handler, *handler2;
+ IMFStreamSink *stream, *stream2;
+ IMFClockStateSink *clocksink;
+ IMFMediaEventGenerator *eg;
+ IMFMediaSink *sink, *sink2;
IMFMediaType *media_type;
+ DWORD flags, count, id;
IMFActivate *activate;
ULONG refcount;
+ IUnknown *unk;
HRESULT hr;
hr = MFCreateMediaType(&media_type);
@@ -1656,10 +1662,135 @@ static void test_sample_grabber(void)
hr = MFCreateSampleGrabberSinkActivate(media_type, &grabber_callback, &activate);
ok(hr == S_OK, "Failed to create grabber activate, hr %#x.\n", hr);
- refcount = IMFMediaType_Release(media_type);
- ok(refcount == 1, "Unexpected refcount %u.\n", refcount);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+
+ hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink);
+ ok(hr == S_OK, "Failed to activate object, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetCharacteristics(sink, &flags);
+ ok(hr == S_OK, "Failed to get sink flags, hr %#x.\n", hr);
+ ok(flags & MEDIASINK_FIXED_STREAMS, "Unexpected flags %#x.\n", flags);
+
+ hr = IMFMediaSink_GetStreamSinkCount(sink, &count);
+ ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr);
+ ok(count == 1, "Unexpected stream count %u.\n", count);
+
+ EXPECT_REF(sink, 3);
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream);
+ ok(hr == S_OK, "Failed to get sink stream, hr %#x.\n", hr);
+ EXPECT_REF(sink, 3);
+ EXPECT_REF(stream, 2);
+
+ hr = IMFStreamSink_GetIdentifier(stream, &id);
+ ok(hr == S_OK, "Failed to get stream id, hr %#x.\n", hr);
+ ok(id == 0, "Unexpected id %#x.\n", id);
+
+ hr = IMFStreamSink_GetMediaSink(stream, &sink2);
+ ok(hr == S_OK, "Failed to get media sink, hr %x.\n", hr);
+ ok(sink2 == sink, "Unexpected sink.\n");
+ IMFMediaSink_Release(sink2);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 1, &stream2);
+ ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkById(sink, 1, &stream2);
+ ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream2);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_RemoveStreamSink(sink, 0);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
- IMFActivate_Release(activate);
+ hr = IMFMediaSink_RemoveStreamSink(sink, 1);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&clocksink);
+todo_wine
+ ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ IMFClockStateSink_Release(clocksink);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFMediaEventGenerator, (void **)&eg);
+todo_wine
+ ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ IMFMediaEventGenerator_Release(eg);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamSink_QueryInterface(stream, &IID_IMFMediaTypeHandler, (void **)&handler2);
+todo_wine
+ ok(hr == S_OK, "Failed to get handler interface, hr %#x.\n", hr);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler);
+ ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
+ ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr);
+ ok(count == 0, "Unexpected count %u.\n", count);
+
+ ok(handler == handler2, "Unexpected handler.\n");
+
+ IMFMediaTypeHandler_Release(handler);
+ IMFMediaTypeHandler_Release(handler2);
+ }
+
+ hr = IMFActivate_ShutdownObject(activate);
+todo_wine
+ ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_Shutdown(sink);
+ ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_Shutdown(sink);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetCharacteristics(sink, &flags);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream2);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkCount(sink, &count);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream2);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamSink_GetMediaSink(stream, &sink2);
+ ok(hr == S_OK, "Failed to get media sink, hr %x.\n", hr);
+ ok(sink2 == sink, "Unexpected sink.\n");
+ IMFMediaSink_Release(sink2);
+
+ hr = IMFStreamSink_GetIdentifier(stream, &id);
+ ok(hr == S_OK, "Failed to get stream id, hr %#x.\n", hr);
+ ok(id == 0, "Unexpected id %#x.\n", id);
+
+ hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler);
+todo_wine
+ ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
+ ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr);
+ ok(count == 0, "Unexpected count %u.\n", count);
+
+ IMFMediaTypeHandler_Release(handler);
+ }
+
+ IMFMediaSink_Release(sink);
+ IMFStreamSink_Release(stream);
+
+ refcount = IMFActivate_Release(activate);
+ ok(!refcount, "Unexpected refcount %u.\n", refcount);
+
+ IMFMediaType_Release(media_type);
}
START_TEST(mf)
diff --git a/include/mferror.h b/include/mferror.h
index a0acf90f8b..4d3a530734 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -94,6 +94,20 @@
#define MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED _HRESULT_TYPEDEF_(0xc00d3e9c)
#define MF_E_UNSUPPORTED_CHARACTERISTICS _HRESULT_TYPEDEF_(0xc00d3e9e)
+#define MF_E_STREAMSINK_REMOVED _HRESULT_TYPEDEF_(0xc00d4a38)
+#define MF_E_STREAMSINKS_OUT_OF_SYNC _HRESULT_TYPEDEF_(0xc00d4a3a)
+#define MF_E_STREAMSINKS_FIXED _HRESULT_TYPEDEF_(0xc00d4a3b)
+#define MF_E_STREAMSINK_EXISTS _HRESULT_TYPEDEF_(0xc00d4a3c)
+#define MF_E_SAMPLEALLOCATOR_CANCELED _HRESULT_TYPEDEF_(0xc00d4a3d)
+#define MF_E_SAMPLEALLOCATOR_EMPTY _HRESULT_TYPEDEF_(0xc00d4a3e)
+#define MF_E_SINK_ALREADYSTOPPED _HRESULT_TYPEDEF_(0xc00d4a3f)
+#define MF_E_ASF_FILESINK_BITRATE_UNKNOWN _HRESULT_TYPEDEF_(0xc00d4a40)
+#define MF_E_SINK_NO_STREAMS _HRESULT_TYPEDEF_(0xc00d4a41)
+#define MF_S_SINK_NOT_FINALIZED _HRESULT_TYPEDEF_(0x000d4a42)
+#define MF_E_METADATA_TOO_LONG _HRESULT_TYPEDEF_(0xc00d4a43)
+#define MF_E_SINK_NO_SAMPLES_PROCESSED _HRESULT_TYPEDEF_(0xc00d4a44)
+#define MF_E_SINK_HEADERS_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d4a45)
+
#define MF_E_TOPO_INVALID_OPTIONAL_NODE _HRESULT_TYPEDEF_(0xc00d520e)
#define MF_E_TOPO_CANNOT_FIND_DECRYPTOR _HRESULT_TYPEDEF_(0xc00d5211)
#define MF_E_TOPO_CODEC_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d5212)
diff --git a/include/mfidl.idl b/include/mfidl.idl
index c024e67378..a5882e98e5 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -83,6 +83,14 @@ typedef enum _MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS
MF_OPTIONAL_NODE_REJECTED_PROTECTED_PROCESS = 0x00000002,
} MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS;
+typedef enum _MFSTREAMSINK_MARKER_TYPE
+{
+ MFSTREAMSINK_MARKER_DEFAULT,
+ MFSTREAMSINK_MARKER_ENDOFSEGMENT,
+ MFSTREAMSINK_MARKER_TICK,
+ MFSTREAMSINK_MARKER_EVENT,
+} MFSTREAMSINK_MARKER_TYPE;
+
[
object,
uuid(2eb1e945-18b8-4139-9b1a-d5d584818530),
@@ -646,6 +654,13 @@ interface IMFPresentationClock : IMFClock
HRESULT Pause();
}
+cpp_quote("#define MEDIASINK_FIXED_STREAMS 0x00000001")
+cpp_quote("#define MEDIASINK_CANNOT_MATCH_CLOCK 0x00000002")
+cpp_quote("#define MEDIASINK_RATELESS 0x00000004")
+cpp_quote("#define MEDIASINK_CLOCK_REQUIRED 0x00000008")
+cpp_quote("#define MEDIASINK_CAN_PREROLL 0x00000010")
+cpp_quote("#define MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE 0x00000020")
+
[
object,
uuid(6ef2a660-47c0-4666-b13d-cbb717f2fa2c)
@@ -666,6 +681,23 @@ interface IMFMediaSink : IUnknown
HRESULT Shutdown();
}
+[
+ object,
+ uuid(0a97b3cf-8e7c-4a3d-8f8c-0c843dc247fb),
+]
+interface IMFStreamSink : IMFMediaEventGenerator
+{
+ HRESULT GetMediaSink([out] IMFMediaSink **sink);
+ HRESULT GetIdentifier([out] DWORD *identifier);
+ HRESULT GetMediaTypeHandler([out] IMFMediaTypeHandler **handler);
+ HRESULT ProcessSample([in] IMFSample *sample);
+ HRESULT PlaceMarker(
+ [in] MFSTREAMSINK_MARKER_TYPE marker_type,
+ [in] const PROPVARIANT *marker_value,
+ [in] const PROPVARIANT *context_value);
+ HRESULT Flush();
+}
+
typedef enum _MFSHUTDOWN_STATUS
{
MFSHUTDOWN_INITIATED,
--
2.20.1
1
4
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/main.c | 2 +-
dlls/mf/samplegrabber.c | 422 +++++++++++++++++++++++++++++++++++++++-
dlls/mf/tests/mf.c | 143 +++++++++++++-
include/mferror.h | 14 ++
include/mfidl.idl | 32 +++
5 files changed, 606 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/main.c b/dlls/mf/main.c
index b5b4b0e7c8..6db13f19db 100644
--- a/dlls/mf/main.c
+++ b/dlls/mf/main.c
@@ -395,7 +395,7 @@ static HRESULT WINAPI activate_object_ActivateObject(IMFActivate *iface, REFIID
if (FAILED(hr = activate->funcs->create_object((IMFAttributes *)iface, activate->context, &object)))
return hr;
- if (!InterlockedCompareExchangePointer((void **)&activate->object, object, NULL))
+ if (InterlockedCompareExchangePointer((void **)&activate->object, object, NULL))
IUnknown_Release(object);
}
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c
index 7b3536467c..997c9db539 100644
--- a/dlls/mf/samplegrabber.c
+++ b/dlls/mf/samplegrabber.c
@@ -19,6 +19,7 @@
#define COBJMACROS
#include "mfidl.h"
+#include "mferror.h"
#include "mf_private.h"
#include "wine/debug.h"
@@ -26,6 +27,24 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct sample_grabber_stream
+{
+ IMFStreamSink IMFStreamSink_iface;
+ LONG refcount;
+ IMFMediaSink *sink;
+};
+
+struct sample_grabber
+{
+ IMFMediaSink IMFMediaSink_iface;
+ LONG refcount;
+ IMFSampleGrabberSinkCallback *callback;
+ IMFMediaType *media_type;
+ BOOL is_shut_down;
+ IMFStreamSink *stream;
+ CRITICAL_SECTION cs;
+};
+
struct sample_grabber_activate_context
{
IMFMediaType *media_type;
@@ -40,13 +59,412 @@ static void sample_grabber_free_private(void *user_context)
heap_free(context);
}
-static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
+static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface)
+{
+ return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface);
+}
+
+static struct sample_grabber_stream *impl_from_IMFStreamSink(IMFStreamSink *iface)
{
- FIXME("%p, %p, %p.\n", attributes, user_context, obj);
+ return CONTAINING_RECORD(iface, struct sample_grabber_stream, IMFStreamSink_iface);
+}
+
+static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFStreamSink) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = &stream->IMFStreamSink_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*obj);
+
+ return S_OK;
+}
+
+static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedIncrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFMediaSink_Release(stream->sink);
+ heap_free(stream);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
+{
+ FIXME("%p, %#x, %p.\n", iface, flags, event);
return E_NOTIMPL;
}
+static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
+ IUnknown *state)
+{
+ FIXME("%p, %p, %p.\n", iface, callback, state);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
+ IMFMediaEvent **event)
+{
+ FIXME("%p, %p, %p.\n", iface, result, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
+ REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
+{
+ FIXME("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
+{
+ struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
+
+ TRACE("%p, %p.\n", iface, sink);
+
+ *sink = stream->sink;
+ IMFMediaSink_AddRef(*sink);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
+{
+ TRACE("%p, %p.\n", iface, identifier);
+
+ *identifier = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
+{
+ FIXME("%p, %p.\n", iface, handler);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
+{
+ FIXME("%p, %p.\n", iface, sample);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
+ const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
+{
+ FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static const IMFStreamSinkVtbl sample_grabber_stream_vtbl =
+{
+ sample_grabber_stream_QueryInterface,
+ sample_grabber_stream_AddRef,
+ sample_grabber_stream_Release,
+ sample_grabber_stream_GetEvent,
+ sample_grabber_stream_BeginGetEvent,
+ sample_grabber_stream_EndGetEvent,
+ sample_grabber_stream_QueueEvent,
+ sample_grabber_stream_GetMediaSink,
+ sample_grabber_stream_GetIdentifier,
+ sample_grabber_stream_GetMediaTypeHandler,
+ sample_grabber_stream_ProcessSample,
+ sample_grabber_stream_PlaceMarker,
+ sample_grabber_stream_Flush,
+};
+
+static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFMediaSink) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = &grabber->IMFMediaSink_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*obj);
+
+ return S_OK;
+}
+
+static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ ULONG refcount = InterlockedIncrement(&grabber->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ ULONG refcount = InterlockedDecrement(&grabber->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFSampleGrabberSinkCallback_Release(grabber->callback);
+ IMFMediaType_Release(grabber->media_type);
+ DeleteCriticalSection(&grabber->cs);
+ heap_free(grabber);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %p.\n", iface, flags);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ *flags = MEDIASINK_FIXED_STREAMS;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
+ IMFMediaType *media_type, IMFStreamSink **stream_sink)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
+
+ return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
+}
+
+static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %#x.\n", iface, stream_sink_id);
+
+ return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p, %p.\n", iface, count);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ *count = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
+ IMFStreamSink **stream)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %u, %p.\n", iface, index, stream);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ EnterCriticalSection(&grabber->cs);
+
+ if (grabber->is_shut_down)
+ hr = MF_E_SHUTDOWN;
+ else if (index > 0)
+ hr = MF_E_INVALIDINDEX;
+ else
+ {
+ *stream = grabber->stream;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ LeaveCriticalSection(&grabber->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
+ IMFStreamSink **stream)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
+
+ EnterCriticalSection(&grabber->cs);
+
+ if (grabber->is_shut_down)
+ hr = MF_E_SHUTDOWN;
+ else if (stream_sink_id > 0)
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ else
+ {
+ *stream = grabber->stream;
+ IMFStreamSink_AddRef(*stream);
+ }
+
+ LeaveCriticalSection(&grabber->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
+{
+ FIXME("%p, %p.\n", iface, clock);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
+{
+ FIXME("%p, %p.\n", iface, clock);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
+{
+ struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
+
+ TRACE("%p.\n", iface);
+
+ if (grabber->is_shut_down)
+ return MF_E_SHUTDOWN;
+
+ EnterCriticalSection(&grabber->cs);
+ grabber->is_shut_down = TRUE;
+ IMFStreamSink_Release(grabber->stream);
+ grabber->stream = NULL;
+ EnterCriticalSection(&grabber->cs);
+
+ return E_NOTIMPL;
+}
+
+static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
+{
+ sample_grabber_sink_QueryInterface,
+ sample_grabber_sink_AddRef,
+ sample_grabber_sink_Release,
+ sample_grabber_sink_GetCharacteristics,
+ sample_grabber_sink_AddStreamSink,
+ sample_grabber_sink_RemoveStreamSink,
+ sample_grabber_sink_GetStreamSinkCount,
+ sample_grabber_sink_GetStreamSinkByIndex,
+ sample_grabber_sink_GetStreamSinkById,
+ sample_grabber_sink_SetPresentationClock,
+ sample_grabber_sink_GetPresentationClock,
+ sample_grabber_sink_Shutdown,
+};
+
+static HRESULT sample_grabber_create_stream(IMFMediaSink *sink, IMFStreamSink **stream)
+{
+ struct sample_grabber_stream *object;
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
+ object->refcount = 1;
+ object->sink = sink;
+ IMFMediaSink_AddRef(object->sink);
+
+ *stream = &object->IMFStreamSink_iface;
+
+ return S_OK;
+}
+
+static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
+{
+ struct sample_grabber_activate_context *context = user_context;
+ struct sample_grabber *object;
+ HRESULT hr;
+
+ TRACE("%p, %p, %p.\n", attributes, user_context, obj);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
+ object->refcount = 1;
+ object->callback = context->callback;
+ IMFSampleGrabberSinkCallback_AddRef(object->callback);
+ object->media_type = context->media_type;
+ IMFMediaType_AddRef(object->media_type);
+ InitializeCriticalSection(&object->cs);
+ if (FAILED(hr = sample_grabber_create_stream(&object->IMFMediaSink_iface, &object->stream)))
+ {
+ IMFMediaSink_Release(&object->IMFMediaSink_iface);
+ return hr;
+ }
+
+ *obj = (IUnknown *)&object->IMFMediaSink_iface;
+
+ TRACE("Created %p.\n", *obj);
+
+ return S_OK;
+}
+
static const struct activate_funcs sample_grabber_activate_funcs =
{
sample_grabber_create_object,
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 37bcb8d029..f2895d5bd3 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1230,7 +1230,6 @@ todo_wine
ok(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
-todo_wine
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
@@ -1639,9 +1638,16 @@ static IMFSampleGrabberSinkCallback grabber_callback = { &grabber_callback_vtbl
static void test_sample_grabber(void)
{
+ IMFMediaTypeHandler *handler, *handler2;
+ IMFStreamSink *stream, *stream2;
+ IMFClockStateSink *clocksink;
+ IMFMediaEventGenerator *eg;
+ IMFMediaSink *sink, *sink2;
IMFMediaType *media_type;
+ DWORD flags, count, id;
IMFActivate *activate;
ULONG refcount;
+ IUnknown *unk;
HRESULT hr;
hr = MFCreateMediaType(&media_type);
@@ -1656,10 +1662,139 @@ static void test_sample_grabber(void)
hr = MFCreateSampleGrabberSinkActivate(media_type, &grabber_callback, &activate);
ok(hr == S_OK, "Failed to create grabber activate, hr %#x.\n", hr);
- refcount = IMFMediaType_Release(media_type);
- ok(refcount == 1, "Unexpected refcount %u.\n", refcount);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+
+ hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink);
+ ok(hr == S_OK, "Failed to activate object, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetCharacteristics(sink, &flags);
+ ok(hr == S_OK, "Failed to get sink flags, hr %#x.\n", hr);
+ ok(flags & MEDIASINK_FIXED_STREAMS, "Unexpected flags %#x.\n", flags);
+
+ hr = IMFMediaSink_GetStreamSinkCount(sink, &count);
+ ok(hr == S_OK, "Failed to get stream count, hr %#x.\n", hr);
+ ok(count == 1, "Unexpected stream count %u.\n", count);
+
+ EXPECT_REF(sink, 3);
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream);
+ ok(hr == S_OK, "Failed to get sink stream, hr %#x.\n", hr);
+ EXPECT_REF(sink, 3);
+ EXPECT_REF(stream, 2);
+
+ hr = IMFStreamSink_GetIdentifier(stream, &id);
+ ok(hr == S_OK, "Failed to get stream id, hr %#x.\n", hr);
+ ok(id == 0, "Unexpected id %#x.\n", id);
+
+ hr = IMFStreamSink_GetMediaSink(stream, &sink2);
+ ok(hr == S_OK, "Failed to get media sink, hr %x.\n", hr);
+ ok(sink2 == sink, "Unexpected sink.\n");
+ IMFMediaSink_Release(sink2);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 1, &stream2);
+ ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkById(sink, 1, &stream2);
+ ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream2);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_RemoveStreamSink(sink, 0);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_RemoveStreamSink(sink, 1);
+ ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&clocksink);
+todo_wine
+ ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ IMFClockStateSink_Release(clocksink);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFMediaEventGenerator, (void **)&eg);
+todo_wine
+ ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ IMFMediaEventGenerator_Release(eg);
+
+ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamSink_QueryInterface(stream, &IID_IMFMediaTypeHandler, (void **)&handler2);
+todo_wine
+ ok(hr == S_OK, "Failed to get handler interface, hr %#x.\n", hr);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler);
+ ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
+ ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr);
+ ok(count == 0, "Unexpected count %u.\n", count);
- IMFActivate_Release(activate);
+ ok(handler == handler2, "Unexpected handler.\n");
+
+ IMFMediaTypeHandler_Release(handler);
+ IMFMediaTypeHandler_Release(handler2);
+ }
+
+ hr = IMFActivate_ShutdownObject(activate);
+todo_wine
+ ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_Shutdown(sink);
+ ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_Shutdown(sink);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetCharacteristics(sink, &flags);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream2);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkCount(sink, &count);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream2);
+ ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFStreamSink_GetMediaSink(stream, &sink2);
+ ok(hr == S_OK, "Failed to get media sink, hr %x.\n", hr);
+ ok(sink2 == sink, "Unexpected sink.\n");
+ IMFMediaSink_Release(sink2);
+
+ hr = IMFStreamSink_GetIdentifier(stream, &id);
+ ok(hr == S_OK, "Failed to get stream id, hr %#x.\n", hr);
+ ok(id == 0, "Unexpected id %#x.\n", id);
+
+ hr = IMFStreamSink_GetMediaTypeHandler(stream, &handler);
+todo_wine
+ ok(hr == S_OK, "Failed to get type handler, hr %#x.\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count);
+ ok(hr == S_OK, "Failed to get media type count, hr %#x.\n", hr);
+ ok(count == 0, "Unexpected count %u.\n", count);
+
+ IMFMediaTypeHandler_Release(handler);
+ }
+
+ hr = IMFStreamSink_Flush(stream);
+todo_wine
+ ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr);
+
+ IMFMediaSink_Release(sink);
+ IMFStreamSink_Release(stream);
+
+ refcount = IMFActivate_Release(activate);
+ ok(!refcount, "Unexpected refcount %u.\n", refcount);
+
+ IMFMediaType_Release(media_type);
}
START_TEST(mf)
diff --git a/include/mferror.h b/include/mferror.h
index a0acf90f8b..4d3a530734 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -94,6 +94,20 @@
#define MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED _HRESULT_TYPEDEF_(0xc00d3e9c)
#define MF_E_UNSUPPORTED_CHARACTERISTICS _HRESULT_TYPEDEF_(0xc00d3e9e)
+#define MF_E_STREAMSINK_REMOVED _HRESULT_TYPEDEF_(0xc00d4a38)
+#define MF_E_STREAMSINKS_OUT_OF_SYNC _HRESULT_TYPEDEF_(0xc00d4a3a)
+#define MF_E_STREAMSINKS_FIXED _HRESULT_TYPEDEF_(0xc00d4a3b)
+#define MF_E_STREAMSINK_EXISTS _HRESULT_TYPEDEF_(0xc00d4a3c)
+#define MF_E_SAMPLEALLOCATOR_CANCELED _HRESULT_TYPEDEF_(0xc00d4a3d)
+#define MF_E_SAMPLEALLOCATOR_EMPTY _HRESULT_TYPEDEF_(0xc00d4a3e)
+#define MF_E_SINK_ALREADYSTOPPED _HRESULT_TYPEDEF_(0xc00d4a3f)
+#define MF_E_ASF_FILESINK_BITRATE_UNKNOWN _HRESULT_TYPEDEF_(0xc00d4a40)
+#define MF_E_SINK_NO_STREAMS _HRESULT_TYPEDEF_(0xc00d4a41)
+#define MF_S_SINK_NOT_FINALIZED _HRESULT_TYPEDEF_(0x000d4a42)
+#define MF_E_METADATA_TOO_LONG _HRESULT_TYPEDEF_(0xc00d4a43)
+#define MF_E_SINK_NO_SAMPLES_PROCESSED _HRESULT_TYPEDEF_(0xc00d4a44)
+#define MF_E_SINK_HEADERS_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d4a45)
+
#define MF_E_TOPO_INVALID_OPTIONAL_NODE _HRESULT_TYPEDEF_(0xc00d520e)
#define MF_E_TOPO_CANNOT_FIND_DECRYPTOR _HRESULT_TYPEDEF_(0xc00d5211)
#define MF_E_TOPO_CODEC_NOT_FOUND _HRESULT_TYPEDEF_(0xc00d5212)
diff --git a/include/mfidl.idl b/include/mfidl.idl
index c024e67378..a5882e98e5 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -83,6 +83,14 @@ typedef enum _MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS
MF_OPTIONAL_NODE_REJECTED_PROTECTED_PROCESS = 0x00000002,
} MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS;
+typedef enum _MFSTREAMSINK_MARKER_TYPE
+{
+ MFSTREAMSINK_MARKER_DEFAULT,
+ MFSTREAMSINK_MARKER_ENDOFSEGMENT,
+ MFSTREAMSINK_MARKER_TICK,
+ MFSTREAMSINK_MARKER_EVENT,
+} MFSTREAMSINK_MARKER_TYPE;
+
[
object,
uuid(2eb1e945-18b8-4139-9b1a-d5d584818530),
@@ -646,6 +654,13 @@ interface IMFPresentationClock : IMFClock
HRESULT Pause();
}
+cpp_quote("#define MEDIASINK_FIXED_STREAMS 0x00000001")
+cpp_quote("#define MEDIASINK_CANNOT_MATCH_CLOCK 0x00000002")
+cpp_quote("#define MEDIASINK_RATELESS 0x00000004")
+cpp_quote("#define MEDIASINK_CLOCK_REQUIRED 0x00000008")
+cpp_quote("#define MEDIASINK_CAN_PREROLL 0x00000010")
+cpp_quote("#define MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE 0x00000020")
+
[
object,
uuid(6ef2a660-47c0-4666-b13d-cbb717f2fa2c)
@@ -666,6 +681,23 @@ interface IMFMediaSink : IUnknown
HRESULT Shutdown();
}
+[
+ object,
+ uuid(0a97b3cf-8e7c-4a3d-8f8c-0c843dc247fb),
+]
+interface IMFStreamSink : IMFMediaEventGenerator
+{
+ HRESULT GetMediaSink([out] IMFMediaSink **sink);
+ HRESULT GetIdentifier([out] DWORD *identifier);
+ HRESULT GetMediaTypeHandler([out] IMFMediaTypeHandler **handler);
+ HRESULT ProcessSample([in] IMFSample *sample);
+ HRESULT PlaceMarker(
+ [in] MFSTREAMSINK_MARKER_TYPE marker_type,
+ [in] const PROPVARIANT *marker_value,
+ [in] const PROPVARIANT *context_value);
+ HRESULT Flush();
+}
+
typedef enum _MFSHUTDOWN_STATUS
{
MFSHUTDOWN_INITIATED,
--
2.20.1
2
8