You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-04-13 14:42:51 -07:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
eae4093bf8 | ||
|
621cf69c80 | ||
|
bc6c681225 | ||
|
46420edcd0 | ||
|
af56d3821a | ||
|
32082f4d6f | ||
|
59e6a606b9 | ||
|
bf043458ba | ||
|
7c1249e5c0 | ||
|
3b24c1cf1d | ||
|
eb32fd78ae | ||
|
e4a11b1663 | ||
|
90d57326b5 |
@@ -1,4 +1,4 @@
|
||||
From dd7df362ecf1c3a7483e930dd9b9c8519db47aba Mon Sep 17 00:00:00 2001
|
||||
From f058e0e1425aab869a1a7d0db0446944af9bc8d6 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 5 Aug 2017 03:39:55 +0200
|
||||
Subject: [PATCH] ntdll: Implement process token elevation through manifests.
|
||||
@@ -74,7 +74,7 @@ index 6290cbcb4e6..9a8f13901b2 100644
|
||||
RemoveEntryList( &wm->ldr.InLoadOrderLinks );
|
||||
InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderLinks );
|
||||
diff --git a/server/process.c b/server/process.c
|
||||
index 406167e825b..5d1248d7c4d 100644
|
||||
index 7875db09801..d7334ffc959 100644
|
||||
--- a/server/process.c
|
||||
+++ b/server/process.c
|
||||
@@ -1086,6 +1086,14 @@ int set_process_debug_flag( struct process *process, int flag )
|
||||
@@ -93,7 +93,7 @@ index 406167e825b..5d1248d7c4d 100644
|
||||
DECL_HANDLER(new_process)
|
||||
{
|
||||
diff --git a/server/process.h b/server/process.h
|
||||
index fb29f21cb12..d0b7ec4987b 100644
|
||||
index 3944a67d571..3cbf70fda21 100644
|
||||
--- a/server/process.h
|
||||
+++ b/server/process.h
|
||||
@@ -129,6 +129,7 @@ extern void kill_console_processes( struct thread *renderer, int exit_code );
|
||||
@@ -103,12 +103,12 @@ index fb29f21cb12..d0b7ec4987b 100644
|
||||
+extern void replace_process_token( struct process *process, struct token *token );
|
||||
|
||||
/* console functions */
|
||||
extern void inherit_console( struct thread *parent_thread, struct process *parent,
|
||||
extern obj_handle_t inherit_console( struct thread *parent_thread, struct process *parent,
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index dbc80b2d673..ed60a8da7df 100644
|
||||
index b84d1d10004..65bcb99d486 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -3567,6 +3567,13 @@ struct handle_info
|
||||
@@ -3526,6 +3526,13 @@ struct handle_info
|
||||
@END
|
||||
|
||||
|
||||
|
@@ -1,167 +1,36 @@
|
||||
From 4a846857e57963ceac9eb7302da17060facb12e3 Mon Sep 17 00:00:00 2001
|
||||
From b9eb0aeed5bc09d8a54c383c9d5149cacf36f1c3 Mon Sep 17 00:00:00 2001
|
||||
From: Louis Lenders <xerox.xerox2000x@gmail.com>
|
||||
Date: Wed, 5 Dec 2018 13:18:26 +0100
|
||||
Subject: [PATCH] dwmapi: add initial tests
|
||||
Subject: [PATCH] dwmapi: Add tests for DwmGetTransportAttributes().
|
||||
|
||||
Signed-off-by: Louis Lenders <xerox.xerox2000x@gmail.com>
|
||||
---
|
||||
configure | 1 +
|
||||
configure.ac | 1 +
|
||||
dlls/dwmapi/tests/Makefile.in | 5 ++
|
||||
dlls/dwmapi/tests/dwmapi.c | 108 ++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 115 insertions(+)
|
||||
create mode 100644 dlls/dwmapi/tests/Makefile.in
|
||||
create mode 100644 dlls/dwmapi/tests/dwmapi.c
|
||||
dlls/dwmapi/tests/dwmapi.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index 588364f8e..ba145e3f4 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -20310,6 +20310,7 @@ wine_fn_config_makefile dlls/dssenh/tests enable_tests
|
||||
wine_fn_config_makefile dlls/dswave enable_dswave
|
||||
wine_fn_config_makefile dlls/dswave/tests enable_tests
|
||||
wine_fn_config_makefile dlls/dwmapi enable_dwmapi
|
||||
+wine_fn_config_makefile dlls/dwmapi/tests enable_tests
|
||||
wine_fn_config_makefile dlls/dwrite enable_dwrite
|
||||
wine_fn_config_makefile dlls/dwrite/tests enable_tests
|
||||
wine_fn_config_makefile dlls/dx8vb enable_dx8vb
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 0ad841773..0eb2ebbe6 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -3267,6 +3267,7 @@ WINE_CONFIG_MAKEFILE(dlls/dssenh/tests)
|
||||
WINE_CONFIG_MAKEFILE(dlls/dswave)
|
||||
WINE_CONFIG_MAKEFILE(dlls/dswave/tests)
|
||||
WINE_CONFIG_MAKEFILE(dlls/dwmapi)
|
||||
+WINE_CONFIG_MAKEFILE(dlls/dwmapi/tests)
|
||||
WINE_CONFIG_MAKEFILE(dlls/dwrite)
|
||||
WINE_CONFIG_MAKEFILE(dlls/dwrite/tests)
|
||||
WINE_CONFIG_MAKEFILE(dlls/dx8vb)
|
||||
diff --git a/dlls/dwmapi/tests/Makefile.in b/dlls/dwmapi/tests/Makefile.in
|
||||
new file mode 100644
|
||||
index 000000000..f365f96c7
|
||||
--- /dev/null
|
||||
+++ b/dlls/dwmapi/tests/Makefile.in
|
||||
@@ -0,0 +1,5 @@
|
||||
+TESTDLL = dwmapi.dll
|
||||
+IMPORTS = dwmapi
|
||||
+
|
||||
+C_SRCS = \
|
||||
+ dwmapi.c
|
||||
diff --git a/dlls/dwmapi/tests/dwmapi.c b/dlls/dwmapi/tests/dwmapi.c
|
||||
new file mode 100644
|
||||
index 000000000..7c51e77c4
|
||||
--- /dev/null
|
||||
index 1904e283bba..d79861f53ed 100644
|
||||
--- a/dlls/dwmapi/tests/dwmapi.c
|
||||
+++ b/dlls/dwmapi/tests/dwmapi.c
|
||||
@@ -0,0 +1,108 @@
|
||||
+/*
|
||||
+ * Unit tests for dwmapi
|
||||
+ *
|
||||
+ * Copyright 2018 Louis Lenders
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include "dwmapi.h"
|
||||
+
|
||||
+#include "wine/test.h"
|
||||
+
|
||||
+static HRESULT (WINAPI *pDwmIsCompositionEnabled)(BOOL*);
|
||||
+static HRESULT (WINAPI *pDwmEnableComposition)(UINT);
|
||||
+static HRESULT (WINAPI *pDwmGetTransportAttributes)(BOOL*,BOOL*,DWORD*);
|
||||
+
|
||||
+BOOL dwmenabled;
|
||||
+
|
||||
+static void test_isdwmenabled(void)
|
||||
+{
|
||||
+ HRESULT res;
|
||||
+ BOOL ret;
|
||||
+
|
||||
+ ret = -1;
|
||||
+ res = pDwmIsCompositionEnabled(&ret);
|
||||
+ ok((res == S_OK && ret == TRUE) || (res == S_OK && ret == FALSE), "got %x and %d\n", res, ret);
|
||||
+
|
||||
+ if (res == S_OK && ret == TRUE)
|
||||
+ dwmenabled = TRUE;
|
||||
+ else
|
||||
+ dwmenabled = FALSE;
|
||||
+ /*tested on win7 by enabling/disabling DWM service via services.msc*/
|
||||
+ if (dwmenabled)
|
||||
+ {
|
||||
+ res = pDwmEnableComposition(DWM_EC_DISABLECOMPOSITION); /* try disable and reenable dwm*/
|
||||
+ ok(res == S_OK, "got %x expected S_OK\n", res);
|
||||
+
|
||||
+ ret = -1;
|
||||
+ res = pDwmIsCompositionEnabled(&ret);
|
||||
+ ok((res == S_OK && ret == FALSE) /*wvista win7*/ || (res == S_OK && ret == TRUE) /*>win7*/, "got %x and %d\n", res, ret);
|
||||
+
|
||||
+ res = pDwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
|
||||
+ ok(res == S_OK, "got %x\n", res);
|
||||
+
|
||||
+ ret = -1;
|
||||
+ res = pDwmIsCompositionEnabled(&ret);
|
||||
+ todo_wine ok(res == S_OK && ret == TRUE, "got %x and %d\n", res, ret);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ res = pDwmEnableComposition(DWM_EC_ENABLECOMPOSITION); /*cannot enable DWM composition this way*/
|
||||
+ ok(res == S_OK /*win7 testbot*/ || res == DWM_E_COMPOSITIONDISABLED /*win7 laptop*/, "got %x\n", res);
|
||||
+ if (winetest_debug > 1)
|
||||
+ trace("returning %x\n", res);
|
||||
+
|
||||
+ ret = -1;
|
||||
+ res = pDwmIsCompositionEnabled(&ret);
|
||||
+ ok(res == S_OK && ret == FALSE, "got %x and %d\n", res, ret);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
@@ -33,7 +33,18 @@ static void test_DwmIsCompositionEnabled(void)
|
||||
ok(enabled == TRUE || enabled == FALSE, "Got unexpected %#x.\n", enabled);
|
||||
}
|
||||
|
||||
+static void test_dwm_get_transport_attributes(void)
|
||||
+{
|
||||
+ BOOL isremoting, isconnected;
|
||||
+ DWORD generation;
|
||||
+ HRESULT res;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ res = pDwmGetTransportAttributes(&isremoting, &isconnected, &generation);
|
||||
+ if (dwmenabled)
|
||||
+ ok(res == S_OK, "got %x\n", res);
|
||||
+ else
|
||||
+ {
|
||||
+ ok(res == S_OK /*win7 testbot*/ || res == DWM_E_COMPOSITIONDISABLED /*win7 laptop*/, "got %x\n", res);
|
||||
+ if (winetest_debug > 1)
|
||||
+ trace("returning %x\n", res);
|
||||
+ }
|
||||
+ hr = DwmGetTransportAttributes(&isremoting, &isconnected, &generation);
|
||||
+ ok(hr == S_OK || hr == DWM_E_COMPOSITIONDISABLED, "Got unexpected %#x.\n", hr);
|
||||
+}
|
||||
+
|
||||
+START_TEST(dwmapi)
|
||||
+{
|
||||
+ HMODULE hmod = LoadLibraryA("dwmapi.dll");
|
||||
+
|
||||
+ if (!hmod)
|
||||
+ {
|
||||
+ trace("dwmapi not found, skipping tests\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ pDwmIsCompositionEnabled = (void *)GetProcAddress(hmod, "DwmIsCompositionEnabled");
|
||||
+ pDwmEnableComposition = (void *)GetProcAddress(hmod, "DwmEnableComposition");
|
||||
+ pDwmGetTransportAttributes = (void *)GetProcAddress(hmod, "DwmGetTransportAttributes");
|
||||
+
|
||||
+ test_isdwmenabled();
|
||||
START_TEST(dwmapi)
|
||||
{
|
||||
test_DwmIsCompositionEnabled();
|
||||
+ test_dwm_get_transport_attributes();
|
||||
+}
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
2.27.0
|
||||
|
||||
|
@@ -1,256 +0,0 @@
|
||||
From b0eec9e5d8736bfa86096fd2d69cfb73dba7a5fe Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 1 Apr 2016 01:29:51 +0200
|
||||
Subject: [PATCH] fsutil: Add fsutil program with support for creating hard
|
||||
links.
|
||||
|
||||
---
|
||||
programs/fsutil/Makefile.in | 3 +
|
||||
programs/fsutil/fsutil.rc | 34 ++++++++++
|
||||
programs/fsutil/main.c | 130 ++++++++++++++++++++++++++++++++++--
|
||||
programs/fsutil/resources.h | 25 +++++++
|
||||
4 files changed, 186 insertions(+), 6 deletions(-)
|
||||
create mode 100644 programs/fsutil/fsutil.rc
|
||||
create mode 100644 programs/fsutil/resources.h
|
||||
|
||||
diff --git a/programs/fsutil/Makefile.in b/programs/fsutil/Makefile.in
|
||||
index 64307e83aca..e10bd433baa 100644
|
||||
--- a/programs/fsutil/Makefile.in
|
||||
+++ b/programs/fsutil/Makefile.in
|
||||
@@ -1,6 +1,9 @@
|
||||
MODULE = fsutil.exe
|
||||
|
||||
EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
|
||||
+IMPORTS = user32
|
||||
|
||||
C_SRCS = \
|
||||
main.c
|
||||
+
|
||||
+RC_SRCS = fsutil.rc
|
||||
diff --git a/programs/fsutil/fsutil.rc b/programs/fsutil/fsutil.rc
|
||||
new file mode 100644
|
||||
index 00000000000..593f8175a23
|
||||
--- /dev/null
|
||||
+++ b/programs/fsutil/fsutil.rc
|
||||
@@ -0,0 +1,34 @@
|
||||
+/*
|
||||
+ * FSUTIL.EXE - Wine-compatible fsutil program
|
||||
+ *
|
||||
+ * Copyright 2016 Michael MĂĽller
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ */
|
||||
+
|
||||
+#include "resources.h"
|
||||
+
|
||||
+#pragma makedep po
|
||||
+
|
||||
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
||||
+
|
||||
+STRINGTABLE
|
||||
+{
|
||||
+ STRING_USAGE, "---- Commands Supported ----\n\nhardlink Hardlink management\n\n"
|
||||
+ STRING_UNSUPPORTED_CMD, "%1 is an unsupported command\n"
|
||||
+ STRING_UNSUPPORTED_PARAM, "%1 is an unsupported parameter\n"
|
||||
+ STRING_HARDLINK_USAGE, "---- Hardlink - Commands Supported ----\n\ncreate Create a hardlink.\n\n"
|
||||
+ STRING_HARDLINK_CREATE_USAGE, "Syntax: fsutil hardlink create old new\n\n"
|
||||
+}
|
||||
diff --git a/programs/fsutil/main.c b/programs/fsutil/main.c
|
||||
index eb4e3412976..ffef8aecbb1 100644
|
||||
--- a/programs/fsutil/main.c
|
||||
+++ b/programs/fsutil/main.c
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2016 Austin English
|
||||
+ * Copyright 2016 Michael MĂĽller
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -16,18 +17,135 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
-#include "wine/debug.h"
|
||||
+#include <windows.h>
|
||||
+#include <wine/debug.h>
|
||||
+
|
||||
+#include "resources.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fsutil);
|
||||
|
||||
+static void output_write(const WCHAR *str, DWORD wlen)
|
||||
+{
|
||||
+ DWORD count, ret;
|
||||
+
|
||||
+ ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL);
|
||||
+ if (!ret)
|
||||
+ {
|
||||
+ DWORD len;
|
||||
+ char *msgA;
|
||||
+
|
||||
+ /* On Windows WriteConsoleW() fails if the output is redirected. So fall
|
||||
+ * back to WriteFile(), assuming the console encoding is still the right
|
||||
+ * one in that case.
|
||||
+ */
|
||||
+ len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL);
|
||||
+ msgA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
|
||||
+ if (!msgA) return;
|
||||
+
|
||||
+ WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL);
|
||||
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
|
||||
+ HeapFree(GetProcessHeap(), 0, msgA);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int output_vprintf(const WCHAR* fmt, __ms_va_list va_args)
|
||||
+{
|
||||
+ WCHAR str[8192];
|
||||
+ int len;
|
||||
+
|
||||
+ SetLastError(NO_ERROR);
|
||||
+ len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, fmt, 0, 0, str,
|
||||
+ sizeof(str)/sizeof(*str), &va_args);
|
||||
+ if (len == 0 && GetLastError() != NO_ERROR)
|
||||
+ WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
|
||||
+ else
|
||||
+ output_write(str, len);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int WINAPIV output_string(int msg, ...)
|
||||
+{
|
||||
+ WCHAR fmt[8192];
|
||||
+ __ms_va_list arguments;
|
||||
+
|
||||
+ LoadStringW(GetModuleHandleW(NULL), msg, fmt, sizeof(fmt)/sizeof(fmt[0]));
|
||||
+ __ms_va_start(arguments, msg);
|
||||
+ output_vprintf(fmt, arguments);
|
||||
+ __ms_va_end(arguments);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static BOOL output_error_string(DWORD error)
|
||||
+{
|
||||
+ LPWSTR pBuffer;
|
||||
+ if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
+ FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
+ NULL, error, 0, (LPWSTR)&pBuffer, 0, NULL))
|
||||
+ {
|
||||
+ output_write(pBuffer, lstrlenW(pBuffer));
|
||||
+ LocalFree(pBuffer);
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static int create_hardlink(int argc, WCHAR *argv[])
|
||||
+{
|
||||
+ if (argc != 5)
|
||||
+ {
|
||||
+ output_string(STRING_HARDLINK_CREATE_USAGE);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (CreateHardLinkW(argv[3], argv[4], NULL))
|
||||
+ return 0;
|
||||
+
|
||||
+ output_error_string(GetLastError());
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int hardlink(int argc, WCHAR *argv[])
|
||||
+{
|
||||
+ static const WCHAR createW[]={'c','r','e','a','t','e',0};
|
||||
+ int ret;
|
||||
+
|
||||
+ if (argc > 2)
|
||||
+ {
|
||||
+ if (!_wcsicmp(argv[2], createW))
|
||||
+ return create_hardlink(argc, argv);
|
||||
+ else
|
||||
+ {
|
||||
+ FIXME("unsupported parameter %s\n", debugstr_w(argv[2]));
|
||||
+ output_string(STRING_UNSUPPORTED_PARAM, argv[2]);
|
||||
+ ret = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ output_string(STRING_HARDLINK_USAGE);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int __cdecl wmain(int argc, WCHAR *argv[])
|
||||
{
|
||||
- int i;
|
||||
+ static const WCHAR hardlinkW[]={'h','a','r','d','l','i','n','k',0};
|
||||
+ int i, ret = 0;
|
||||
|
||||
- WINE_FIXME("stub:");
|
||||
for (i = 0; i < argc; i++)
|
||||
- WINE_FIXME(" %s", wine_dbgstr_w(argv[i]));
|
||||
- WINE_FIXME("\n");
|
||||
+ WINE_TRACE(" %s", wine_dbgstr_w(argv[i]));
|
||||
+ WINE_TRACE("\n");
|
||||
|
||||
- return 0;
|
||||
+ if (argc > 1)
|
||||
+ {
|
||||
+ if (!_wcsicmp(argv[1], hardlinkW))
|
||||
+ return hardlink(argc, argv);
|
||||
+ else
|
||||
+ {
|
||||
+ FIXME("unsupported command %s\n", debugstr_w(argv[1]));
|
||||
+ output_string(STRING_UNSUPPORTED_CMD, argv[1]);
|
||||
+ ret = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ output_string(STRING_USAGE);
|
||||
+ return ret;
|
||||
}
|
||||
diff --git a/programs/fsutil/resources.h b/programs/fsutil/resources.h
|
||||
new file mode 100644
|
||||
index 00000000000..b85826ac421
|
||||
--- /dev/null
|
||||
+++ b/programs/fsutil/resources.h
|
||||
@@ -0,0 +1,25 @@
|
||||
+/*
|
||||
+ * Copyright 2016 Michael MĂĽller
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ */
|
||||
+
|
||||
+#include <windef.h>
|
||||
+
|
||||
+#define STRING_USAGE 101
|
||||
+#define STRING_UNSUPPORTED_CMD 102
|
||||
+#define STRING_UNSUPPORTED_PARAM 103
|
||||
+#define STRING_HARDLINK_USAGE 104
|
||||
+#define STRING_HARDLINK_CREATE_USAGE 105
|
||||
--
|
||||
2.17.1
|
||||
|
@@ -1 +0,0 @@
|
||||
Fixes: [22749] Add stub for fsutil.exe hardlink command
|
@@ -1,4 +1,4 @@
|
||||
From 04aceb5470fc9ca9133f7a6269144eb7aa8d6a10 Mon Sep 17 00:00:00 2001
|
||||
From 6ecb74571f99faaaf558bf10fc7f626c0c58dc24 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sat, 13 Jun 2015 05:03:54 +0200
|
||||
Subject: [PATCH] iphlpapi: Fallback to system ping when ICMP permissions are
|
||||
@@ -6,11 +6,11 @@ Subject: [PATCH] iphlpapi: Fallback to system ping when ICMP permissions are
|
||||
|
||||
Based on an idea by Bruno Jesus.
|
||||
---
|
||||
dlls/iphlpapi/icmp.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
dlls/iphlpapi/icmp.c | 256 ++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 250 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dlls/iphlpapi/icmp.c b/dlls/iphlpapi/icmp.c
|
||||
index 0dc2f12..da3850b 100644
|
||||
index 8e425ea68ed..1f55356c047 100644
|
||||
--- a/dlls/iphlpapi/icmp.c
|
||||
+++ b/dlls/iphlpapi/icmp.c
|
||||
@@ -5,6 +5,7 @@
|
||||
@@ -49,7 +49,7 @@ index 0dc2f12..da3850b 100644
|
||||
|
||||
#define USE_WS_PREFIX
|
||||
|
||||
@@ -212,6 +219,7 @@ DWORD WINAPI Icmp6SendEcho2(
|
||||
@@ -213,6 +220,7 @@ DWORD WINAPI Icmp6SendEcho2(
|
||||
*/
|
||||
HANDLE WINAPI IcmpCreateFile(VOID)
|
||||
{
|
||||
@@ -57,8 +57,8 @@ index 0dc2f12..da3850b 100644
|
||||
icmp_t* icp;
|
||||
|
||||
int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
|
||||
@@ -220,15 +228,14 @@ HANDLE WINAPI IcmpCreateFile(VOID)
|
||||
/* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
|
||||
@@ -222,15 +230,14 @@ HANDLE WINAPI IcmpCreateFile(VOID)
|
||||
non-privileged ICMP via SOCK_DGRAM type. */
|
||||
sid=socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP);
|
||||
}
|
||||
- if (sid < 0) {
|
||||
@@ -77,7 +77,7 @@ index 0dc2f12..da3850b 100644
|
||||
SetLastError(IP_NO_RESOURCES);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
@@ -250,11 +257,242 @@ BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle)
|
||||
@@ -252,11 +259,242 @@ BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ index 0dc2f12..da3850b 100644
|
||||
|
||||
/***********************************************************************
|
||||
* IcmpSendEcho (IPHLPAPI.@)
|
||||
@@ -308,6 +546,12 @@ DWORD WINAPI IcmpSendEcho(
|
||||
@@ -310,6 +548,12 @@ DWORD WINAPI IcmpSendEcho(
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -335,5 +335,5 @@ index 0dc2f12..da3850b 100644
|
||||
id=getpid() & 0xFFFF;
|
||||
seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
|
||||
--
|
||||
1.9.1
|
||||
2.27.0
|
||||
|
||||
|
@@ -0,0 +1,246 @@
|
||||
From ac9dd9bf46de1056dd26a3230bfd885d2962c8aa Mon Sep 17 00:00:00 2001
|
||||
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
|
||||
Date: Tue, 11 Aug 2020 09:26:57 +1000
|
||||
Subject: [PATCH 01/54] Revert "mf/topoloader: Add a structure for iterative
|
||||
branch resolution."
|
||||
|
||||
This reverts commit e308d81a617632fe0fedd243952f79e8d9ec05b4.
|
||||
---
|
||||
dlls/mf/tests/mf.c | 9 +--
|
||||
dlls/mf/topology.c | 138 +--------------------------------------------
|
||||
2 files changed, 4 insertions(+), 143 deletions(-)
|
||||
|
||||
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
|
||||
index f01385cc46..aa2c5199b9 100644
|
||||
--- a/dlls/mf/tests/mf.c
|
||||
+++ b/dlls/mf/tests/mf.c
|
||||
@@ -1400,7 +1400,6 @@ static void test_topology_loader(void)
|
||||
IMFPresentationDescriptor *pd;
|
||||
IMFSourceResolver *resolver;
|
||||
IMFActivate *sink_activate;
|
||||
- IMFStreamSink *stream_sink;
|
||||
unsigned int count, value;
|
||||
IMFMediaType *media_type;
|
||||
IMFStreamDescriptor *sd;
|
||||
@@ -1513,19 +1512,15 @@ todo_wine
|
||||
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
|
||||
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
|
||||
|
||||
- hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
|
||||
- ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
-
|
||||
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
|
||||
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
|
||||
ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
|
||||
|
||||
- IMFStreamSink_Release(stream_sink);
|
||||
-
|
||||
hr = IMFTopology_GetCount(topology, &count);
|
||||
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
|
||||
ok(count == 0, "Unexpected count %u.\n", count);
|
||||
|
||||
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+todo_wine
|
||||
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
ok(full_topology != topology, "Unexpected instance.\n");
|
||||
|
||||
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
|
||||
index 8032e438b7..840f1bd25f 100644
|
||||
--- a/dlls/mf/topology.c
|
||||
+++ b/dlls/mf/topology.c
|
||||
@@ -1935,41 +1935,17 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
|
||||
|
||||
struct topoloader_context
|
||||
{
|
||||
- IMFTopology *input_topology;
|
||||
IMFTopology *output_topology;
|
||||
- unsigned int marker;
|
||||
GUID key;
|
||||
};
|
||||
|
||||
-static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id)
|
||||
-{
|
||||
- IMFTopologyNode *node;
|
||||
- unsigned short i = 0;
|
||||
- unsigned int value;
|
||||
-
|
||||
- while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node)))
|
||||
- {
|
||||
- if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker)
|
||||
- {
|
||||
- IMFTopologyNode_GetTopoNodeID(node, id);
|
||||
- return node;
|
||||
- }
|
||||
- IMFTopologyNode_Release(node);
|
||||
- }
|
||||
-
|
||||
- *id = 0;
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node,
|
||||
- IMFTopologyNode **ret, unsigned int marker)
|
||||
+ unsigned int marker)
|
||||
{
|
||||
IMFTopologyNode *cloned_node;
|
||||
MF_TOPOLOGY_TYPE node_type;
|
||||
HRESULT hr;
|
||||
|
||||
- if (ret) *ret = NULL;
|
||||
-
|
||||
IMFTopologyNode_GetNodeType(node, &node_type);
|
||||
|
||||
if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node)))
|
||||
@@ -1981,113 +1957,17 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM
|
||||
if (SUCCEEDED(hr))
|
||||
hr = IMFTopology_AddNode(context->output_topology, cloned_node);
|
||||
|
||||
- if (SUCCEEDED(hr) && ret)
|
||||
- {
|
||||
- *ret = cloned_node;
|
||||
- IMFTopologyNode_AddRef(*ret);
|
||||
- }
|
||||
-
|
||||
IMFTopologyNode_Release(cloned_node);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
-typedef HRESULT (*p_topology_loader_connect_func)(struct topoloader_context *context, IMFTopologyNode *upstream_node,
|
||||
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index);
|
||||
-
|
||||
-static HRESULT topology_loader_connect_source_node(struct topoloader_context *context, IMFTopologyNode *upstream_node,
|
||||
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index)
|
||||
-{
|
||||
- FIXME("Unimplemented.\n");
|
||||
-
|
||||
- return E_NOTIMPL;
|
||||
-}
|
||||
-
|
||||
-static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, IMFTopologyNode *upstream_node,
|
||||
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned input_index)
|
||||
-{
|
||||
- static const p_topology_loader_connect_func connectors[MF_TOPOLOGY_TEE_NODE+1][MF_TOPOLOGY_TEE_NODE+1] =
|
||||
- {
|
||||
- /* OUTPUT */ { NULL },
|
||||
- /* SOURCESTREAM */ { topology_loader_connect_source_node, NULL, NULL, NULL },
|
||||
- /* TRANSFORM */ { NULL },
|
||||
- /* TEE */ { NULL },
|
||||
- };
|
||||
- MF_TOPOLOGY_TYPE u_type, d_type;
|
||||
- IMFTopologyNode *node;
|
||||
- TOPOID id;
|
||||
-
|
||||
- /* Downstream node might have already been cloned. */
|
||||
- IMFTopologyNode_GetTopoNodeID(downstream_node, &id);
|
||||
- if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &node)))
|
||||
- topology_loader_clone_node(context, downstream_node, &node, context->marker + 1);
|
||||
-
|
||||
- IMFTopologyNode_ConnectOutput(upstream_node, output_index, node, input_index);
|
||||
-
|
||||
- IMFTopologyNode_GetNodeType(upstream_node, &u_type);
|
||||
- IMFTopologyNode_GetNodeType(downstream_node, &d_type);
|
||||
-
|
||||
- if (!connectors[u_type][d_type])
|
||||
- {
|
||||
- WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type);
|
||||
- return E_FAIL;
|
||||
- }
|
||||
-
|
||||
- return connectors[u_type][d_type](context, upstream_node, output_index, downstream_node, input_index);
|
||||
-}
|
||||
-
|
||||
-static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context, unsigned int *layer_size)
|
||||
-{
|
||||
- IMFTopologyNode *downstream_node, *node, *orig_node;
|
||||
- unsigned int input_index, size = 0;
|
||||
- MF_TOPOLOGY_TYPE node_type;
|
||||
- HRESULT hr = S_OK;
|
||||
- TOPOID id;
|
||||
-
|
||||
- while ((node = topology_loader_get_node_for_marker(context, &id)))
|
||||
- {
|
||||
- ++size;
|
||||
-
|
||||
- IMFTopology_GetNodeByID(context->input_topology, id, &orig_node);
|
||||
-
|
||||
- IMFTopologyNode_GetNodeType(node, &node_type);
|
||||
- switch (node_type)
|
||||
- {
|
||||
- case MF_TOPOLOGY_SOURCESTREAM_NODE:
|
||||
- if (FAILED(IMFTopologyNode_GetOutput(orig_node, 0, &downstream_node, &input_index)))
|
||||
- {
|
||||
- IMFTopology_RemoveNode(context->output_topology, node);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- hr = topology_loader_resolve_branch(context, node, 0, downstream_node, input_index);
|
||||
- break;
|
||||
- case MF_TOPOLOGY_TRANSFORM_NODE:
|
||||
- case MF_TOPOLOGY_TEE_NODE:
|
||||
- FIXME("Unsupported node type %d.\n", node_type);
|
||||
- break;
|
||||
- default:
|
||||
- WARN("Unexpected node type %d.\n", node_type);
|
||||
- }
|
||||
-
|
||||
- IMFTopologyNode_DeleteItem(node, &context->key);
|
||||
-
|
||||
- if (FAILED(hr))
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- *layer_size = size;
|
||||
-
|
||||
- return hr;
|
||||
-}
|
||||
-
|
||||
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
|
||||
IMFTopology **ret_topology, IMFTopology *current_topology)
|
||||
{
|
||||
struct topoloader_context context = { 0 };
|
||||
IMFTopology *output_topology;
|
||||
MF_TOPOLOGY_TYPE node_type;
|
||||
- unsigned int layer_size;
|
||||
IMFTopologyNode *node;
|
||||
unsigned short i = 0;
|
||||
IMFStreamSink *sink;
|
||||
@@ -2136,7 +2016,6 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
|
||||
if (FAILED(hr = MFCreateTopology(&output_topology)))
|
||||
return hr;
|
||||
|
||||
- context.input_topology = input_topology;
|
||||
context.output_topology = output_topology;
|
||||
memset(&context.key, 0xff, sizeof(context.key));
|
||||
|
||||
@@ -2148,26 +2027,13 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
|
||||
|
||||
if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
|
||||
{
|
||||
- if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0)))
|
||||
+ if (FAILED(hr = topology_loader_clone_node(&context, node, 0)))
|
||||
WARN("Failed to clone source node, hr %#x.\n", hr);
|
||||
}
|
||||
|
||||
IMFTopologyNode_Release(node);
|
||||
}
|
||||
|
||||
- for (context.marker = 0;; ++context.marker)
|
||||
- {
|
||||
- if (FAILED(hr = topology_loader_resolve_nodes(&context, &layer_size)))
|
||||
- {
|
||||
- WARN("Failed to resolve for marker %u, hr %#x.\n", context.marker, hr);
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- /* Reached last marker value. */
|
||||
- if (!layer_size)
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
/* For now return original topology. */
|
||||
|
||||
*ret_topology = output_topology;
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,104 @@
|
||||
From f02867e2a1129f7aef4488db827fc52a6131b3d4 Mon Sep 17 00:00:00 2001
|
||||
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
|
||||
Date: Tue, 11 Aug 2020 09:26:59 +1000
|
||||
Subject: [PATCH 02/54] Revert "mf/topoloader: Clone source nodes as a first
|
||||
layer of resulting topology."
|
||||
|
||||
This reverts commit 16d44b61d15193905ef40661bc1547cb45e7b019.
|
||||
---
|
||||
dlls/mf/topology.c | 61 +++-------------------------------------------
|
||||
1 file changed, 4 insertions(+), 57 deletions(-)
|
||||
|
||||
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
|
||||
index 840f1bd25f..8522f56969 100644
|
||||
--- a/dlls/mf/topology.c
|
||||
+++ b/dlls/mf/topology.c
|
||||
@@ -1933,40 +1933,9 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
|
||||
return refcount;
|
||||
}
|
||||
|
||||
-struct topoloader_context
|
||||
-{
|
||||
- IMFTopology *output_topology;
|
||||
- GUID key;
|
||||
-};
|
||||
-
|
||||
-static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node,
|
||||
- unsigned int marker)
|
||||
-{
|
||||
- IMFTopologyNode *cloned_node;
|
||||
- MF_TOPOLOGY_TYPE node_type;
|
||||
- HRESULT hr;
|
||||
-
|
||||
- IMFTopologyNode_GetNodeType(node, &node_type);
|
||||
-
|
||||
- if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node)))
|
||||
- return hr;
|
||||
-
|
||||
- if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node)))
|
||||
- hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker);
|
||||
-
|
||||
- if (SUCCEEDED(hr))
|
||||
- hr = IMFTopology_AddNode(context->output_topology, cloned_node);
|
||||
-
|
||||
- IMFTopologyNode_Release(cloned_node);
|
||||
-
|
||||
- return hr;
|
||||
-}
|
||||
-
|
||||
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
|
||||
- IMFTopology **ret_topology, IMFTopology *current_topology)
|
||||
+ IMFTopology **output_topology, IMFTopology *current_topology)
|
||||
{
|
||||
- struct topoloader_context context = { 0 };
|
||||
- IMFTopology *output_topology;
|
||||
MF_TOPOLOGY_TYPE node_type;
|
||||
IMFTopologyNode *node;
|
||||
unsigned short i = 0;
|
||||
@@ -1974,7 +1943,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
|
||||
IUnknown *object;
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
- FIXME("%p, %p, %p, %p.\n", iface, input_topology, ret_topology, current_topology);
|
||||
+ FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
|
||||
|
||||
if (current_topology)
|
||||
FIXME("Current topology instance is ignored.\n");
|
||||
@@ -2013,32 +1982,10 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
|
||||
return hr;
|
||||
}
|
||||
|
||||
- if (FAILED(hr = MFCreateTopology(&output_topology)))
|
||||
+ if (FAILED(hr = MFCreateTopology(output_topology)))
|
||||
return hr;
|
||||
|
||||
- context.output_topology = output_topology;
|
||||
- memset(&context.key, 0xff, sizeof(context.key));
|
||||
-
|
||||
- /* Clone source nodes, use initial marker value. */
|
||||
- i = 0;
|
||||
- while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node)))
|
||||
- {
|
||||
- IMFTopologyNode_GetNodeType(node, &node_type);
|
||||
-
|
||||
- if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
|
||||
- {
|
||||
- if (FAILED(hr = topology_loader_clone_node(&context, node, 0)))
|
||||
- WARN("Failed to clone source node, hr %#x.\n", hr);
|
||||
- }
|
||||
-
|
||||
- IMFTopologyNode_Release(node);
|
||||
- }
|
||||
-
|
||||
- /* For now return original topology. */
|
||||
-
|
||||
- *ret_topology = output_topology;
|
||||
-
|
||||
- return IMFTopology_CloneFrom(output_topology, input_topology);
|
||||
+ return IMFTopology_CloneFrom(*output_topology, input_topology);
|
||||
}
|
||||
|
||||
static const IMFTopoLoaderVtbl topologyloadervtbl =
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,81 @@
|
||||
From e42f00a2fd98ea18f76b2f8c874d86b27723c57d Mon Sep 17 00:00:00 2001
|
||||
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
|
||||
Date: Tue, 11 Aug 2020 09:27:00 +1000
|
||||
Subject: [PATCH 03/54] Revert "mf/topoloader: Switch to public interface for
|
||||
initial topology validation."
|
||||
|
||||
This reverts commit 8e343024b577892bd4908304ded34b758579698d.
|
||||
---
|
||||
dlls/mf/topology.c | 36 ++++++++++++------------------------
|
||||
1 file changed, 12 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
|
||||
index 8522f56969..abe66c45fd 100644
|
||||
--- a/dlls/mf/topology.c
|
||||
+++ b/dlls/mf/topology.c
|
||||
@@ -1936,50 +1936,38 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
|
||||
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
|
||||
IMFTopology **output_topology, IMFTopology *current_topology)
|
||||
{
|
||||
- MF_TOPOLOGY_TYPE node_type;
|
||||
- IMFTopologyNode *node;
|
||||
- unsigned short i = 0;
|
||||
+ struct topology *topology = unsafe_impl_from_IMFTopology(input_topology);
|
||||
IMFStreamSink *sink;
|
||||
- IUnknown *object;
|
||||
- HRESULT hr = E_FAIL;
|
||||
+ HRESULT hr;
|
||||
+ size_t i;
|
||||
|
||||
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
|
||||
|
||||
if (current_topology)
|
||||
FIXME("Current topology instance is ignored.\n");
|
||||
|
||||
- /* Basic sanity checks for input topology:
|
||||
-
|
||||
- - source nodes must have stream descriptor set;
|
||||
- - sink nodes must be resolved to stream sink objects;
|
||||
- */
|
||||
- while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node)))
|
||||
+ for (i = 0; i < topology->nodes.count; ++i)
|
||||
{
|
||||
- IMFTopologyNode_GetNodeType(node, &node_type);
|
||||
+ struct topology_node *node = topology->nodes.nodes[i];
|
||||
|
||||
- switch (node_type)
|
||||
+ switch (node->node_type)
|
||||
{
|
||||
case MF_TOPOLOGY_OUTPUT_NODE:
|
||||
- if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
|
||||
+ if (node->object)
|
||||
{
|
||||
/* Sinks must be bound beforehand. */
|
||||
- if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink)))
|
||||
- hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
|
||||
- else if (sink)
|
||||
- IMFStreamSink_Release(sink);
|
||||
- IUnknown_Release(object);
|
||||
+ if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink)))
|
||||
+ return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
|
||||
+ IMFStreamSink_Release(sink);
|
||||
}
|
||||
break;
|
||||
case MF_TOPOLOGY_SOURCESTREAM_NODE:
|
||||
- hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL);
|
||||
+ if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL)))
|
||||
+ return hr;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
-
|
||||
- IMFTopologyNode_Release(node);
|
||||
- if (FAILED(hr))
|
||||
- return hr;
|
||||
}
|
||||
|
||||
if (FAILED(hr = MFCreateTopology(output_topology)))
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,50 @@
|
||||
From a78920ed5d799815126b294c4ecf0b039cf5671c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
|
||||
<sdelreal@codeweavers.com>
|
||||
Date: Wed, 1 Apr 2020 16:11:05 -0500
|
||||
Subject: [PATCH 04/54] mf/tests: Sink objects are stream sinks, not media
|
||||
sinks.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Sergio GĂłmez Del Real <sdelreal@codeweavers.com>
|
||||
---
|
||||
dlls/mf/tests/mf.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
|
||||
index aa2c5199b9..9e190388ee 100644
|
||||
--- a/dlls/mf/tests/mf.c
|
||||
+++ b/dlls/mf/tests/mf.c
|
||||
@@ -1400,6 +1400,7 @@ static void test_topology_loader(void)
|
||||
IMFPresentationDescriptor *pd;
|
||||
IMFSourceResolver *resolver;
|
||||
IMFActivate *sink_activate;
|
||||
+ IMFStreamSink *stream_sink;
|
||||
unsigned int count, value;
|
||||
IMFMediaType *media_type;
|
||||
IMFStreamDescriptor *sd;
|
||||
@@ -1512,7 +1513,10 @@ todo_wine
|
||||
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
|
||||
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
|
||||
|
||||
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
|
||||
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
|
||||
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
|
||||
ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTopology_GetCount(topology, &count);
|
||||
@@ -1520,7 +1524,6 @@ todo_wine
|
||||
ok(count == 0, "Unexpected count %u.\n", count);
|
||||
|
||||
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
-todo_wine
|
||||
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
ok(full_topology != topology, "Unexpected instance.\n");
|
||||
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,499 @@
|
||||
From dfb5190b00ce04f7ac0c811cb6350af37826015e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
|
||||
<sdelreal@codeweavers.com>
|
||||
Date: Wed, 1 Apr 2020 16:11:06 -0500
|
||||
Subject: [PATCH 05/54] mf/tests: Add tests for the topology loader.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Sergio GĂłmez Del Real <sdelreal@codeweavers.com>
|
||||
---
|
||||
dlls/mf/tests/mf.c | 435 ++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 433 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
|
||||
index 9e190388ee..8691ef55c9 100644
|
||||
--- a/dlls/mf/tests/mf.c
|
||||
+++ b/dlls/mf/tests/mf.c
|
||||
@@ -1392,26 +1392,169 @@ static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl =
|
||||
test_grabber_callback_OnShutdown,
|
||||
};
|
||||
|
||||
+static HRESULT WINAPI test_media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
|
||||
+{
|
||||
+ if (IsEqualIID(riid, &IID_IMFMediaSource) ||
|
||||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
|
||||
+ IsEqualIID(riid, &IID_IUnknown))
|
||||
+ {
|
||||
+ *out = iface;
|
||||
+ IUnknown_AddRef((IUnknown*)*out);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ *out = NULL;
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI test_media_source_AddRef(IMFMediaSource *iface)
|
||||
+{
|
||||
+ return 2;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI test_media_source_Release(IMFMediaSource *iface)
|
||||
+{
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
|
||||
+ HRESULT hr, const PROPVARIANT *value)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
|
||||
+{
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ IMFPresentationDescriptor *pd;
|
||||
+ IMFMediaType *mediatypes[3];
|
||||
+ IMFStreamDescriptor *sd[2];
|
||||
+
|
||||
+ if (FAILED(hr = MFCreateMediaType(&mediatypes[0])))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_SUBTYPE, &MFVideoFormat_YUY2)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = MFCreateMediaType(&mediatypes[1])))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_SUBTYPE, &MFAudioFormat_MP3)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_NUM_CHANNELS, 2)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = MFCreateMediaType(&mediatypes[2])))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_SUBTYPE, &MFAudioFormat_PCM)))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = MFCreateStreamDescriptor(0, 3, mediatypes, &sd[0])))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = MFCreateStreamDescriptor(1, 3, mediatypes, &sd[1])))
|
||||
+ return hr;
|
||||
+ if (FAILED(hr = MFCreatePresentationDescriptor(2, sd, &pd)))
|
||||
+ return hr;
|
||||
+ *descriptor = pd;
|
||||
+
|
||||
+ IMFMediaType_Release(mediatypes[0]);
|
||||
+ IMFMediaType_Release(mediatypes[1]);
|
||||
+ IMFMediaType_Release(mediatypes[2]);
|
||||
+ IMFStreamDescriptor_Release(sd[0]);
|
||||
+ IMFStreamDescriptor_Release(sd[1]);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
|
||||
+ const GUID *time_format, const PROPVARIANT *start_position)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_Stop(IMFMediaSource *iface)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_Pause(IMFMediaSource *iface)
|
||||
+{
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI test_media_source_Shutdown(IMFMediaSource *iface)
|
||||
+{
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const IMFMediaSourceVtbl test_media_source_vtbl =
|
||||
+{
|
||||
+ test_media_source_QueryInterface,
|
||||
+ test_media_source_AddRef,
|
||||
+ test_media_source_Release,
|
||||
+ test_media_source_GetEvent,
|
||||
+ test_media_source_BeginGetEvent,
|
||||
+ test_media_source_EndGetEvent,
|
||||
+ test_media_source_QueueEvent,
|
||||
+ test_media_source_GetCharacteristics,
|
||||
+ test_media_source_CreatePresentationDescriptor,
|
||||
+ test_media_source_Start,
|
||||
+ test_media_source_Stop,
|
||||
+ test_media_source_Pause,
|
||||
+ test_media_source_Shutdown,
|
||||
+};
|
||||
+
|
||||
static void test_topology_loader(void)
|
||||
{
|
||||
IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl };
|
||||
+ IMFMediaSource test_media_source = { &test_media_source_vtbl };
|
||||
IMFTopology *topology, *topology2, *full_topology;
|
||||
IMFTopologyNode *src_node, *sink_node;
|
||||
+ IMFMediaType *media_type, *current_media_type;
|
||||
IMFPresentationDescriptor *pd;
|
||||
IMFSourceResolver *resolver;
|
||||
IMFActivate *sink_activate;
|
||||
IMFStreamSink *stream_sink;
|
||||
unsigned int count, value;
|
||||
- IMFMediaType *media_type;
|
||||
+ IMFMediaTypeHandler *mth;
|
||||
IMFStreamDescriptor *sd;
|
||||
+ UINT32 enum_src, method;
|
||||
MF_OBJECT_TYPE obj_type;
|
||||
IMFMediaSource *source;
|
||||
IMFTopoLoader *loader;
|
||||
IMFByteStream *stream;
|
||||
IMFAttributes *attr;
|
||||
IMFMediaSink *sink;
|
||||
+ WORD node_count;
|
||||
WCHAR *filename;
|
||||
BOOL selected;
|
||||
+ DWORD flags;
|
||||
HRESULT hr;
|
||||
GUID guid;
|
||||
|
||||
@@ -1527,6 +1670,9 @@ todo_wine
|
||||
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
ok(full_topology != topology, "Unexpected instance.\n");
|
||||
|
||||
+ IMFTopology_GetNodeCount(full_topology, &node_count);
|
||||
+ ok(node_count == 2, "Topology node count is %#x.\n", node_count);
|
||||
+
|
||||
hr = IMFTopology_GetCount(topology, &count);
|
||||
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
|
||||
ok(count == 0, "Unexpected count %u.\n", count);
|
||||
@@ -1553,10 +1699,295 @@ todo_wine {
|
||||
|
||||
IMFTopology_Release(topology2);
|
||||
IMFTopology_Release(full_topology);
|
||||
+ IMFByteStream_Release(stream);
|
||||
+ IMFStreamDescriptor_Release(sd);
|
||||
+
|
||||
+ /* test with stream deselected */
|
||||
+ IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &count);
|
||||
+ ok(count == 1, "Unexpected stream descriptor count.\n");
|
||||
+ hr = IMFPresentationDescriptor_DeselectStream(pd, 0);
|
||||
+ ok(hr == S_OK, "Failed to deselect stream, hr %#x.\n", hr);
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
+ IMFTopologyNode_Release(src_node);
|
||||
+ hr = IMFTopology_GetNode(full_topology, 0, &src_node);
|
||||
+ ok(hr == S_OK, "Failed to get full topology source node, hr %#x.\n", hr);
|
||||
+ IMFPresentationDescriptor_Release(pd);
|
||||
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&pd);
|
||||
+ ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
|
||||
+ IMFStreamDescriptor_Release(sd);
|
||||
+ IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
|
||||
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
|
||||
+ ok(!selected, "Stream should not be selected\n.");
|
||||
|
||||
+ IMFPresentationDescriptor_Release(pd);
|
||||
+ IMFTopologyNode_Release(src_node);
|
||||
+ IMFTopology_Release(full_topology);
|
||||
+ IMFTopology_Release(topology);
|
||||
IMFMediaSource_Release(source);
|
||||
IMFSourceResolver_Release(resolver);
|
||||
- IMFByteStream_Release(stream);
|
||||
+
|
||||
+ /* test source stream with various media types */
|
||||
+ /* first, test default behavior; MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES not set */
|
||||
+ hr = MFCreateTopology(&topology);
|
||||
+ ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFMediaSource_CreatePresentationDescriptor(&test_media_source, &pd);
|
||||
+ ok(hr == S_OK, "Failed to create descriptor, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
|
||||
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
|
||||
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
|
||||
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &media_type);
|
||||
+ ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node);
|
||||
+ ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source);
|
||||
+ ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr);
|
||||
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
|
||||
+ ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr);
|
||||
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
|
||||
+ ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_AddNode(topology, src_node);
|
||||
+ ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = MFCreateMediaType(&media_type);
|
||||
+ ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ 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 = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate);
|
||||
+ ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr);
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+
|
||||
+ hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
|
||||
+ ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
|
||||
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node);
|
||||
+ ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
|
||||
+ ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_AddNode(topology, sink_node);
|
||||
+ ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
|
||||
+ ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src);
|
||||
+ ok(hr == MF_E_ATTRIBUTENOTFOUND, "Attribute should not be set\n.");
|
||||
+ /* if no current media type set, loader uses first index exclusively */
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+todo_wine
|
||||
+ /* when major types differ, error is MF_E_TOPO_CODEC_NOT_FOUND */
|
||||
+ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type);
|
||||
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ /* setting current media type overrides previous behavior; tries with it, and only with it */
|
||||
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
|
||||
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
|
||||
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
|
||||
+ ok(node_count == 2, "Unexpected node count.\n");
|
||||
+
|
||||
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
|
||||
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
|
||||
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
|
||||
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
|
||||
+todo_wine
|
||||
+ ok(node_count == 3, "Unexpected node count.\n");
|
||||
+
|
||||
+ IMFTopology_Release(full_topology);
|
||||
+
|
||||
+ /* now test with MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES set on topology */
|
||||
+ hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1);
|
||||
+ ok(hr == S_OK, "Failed setting attribute\n.");
|
||||
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type);
|
||||
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ /* first, if MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES is not set on source */
|
||||
+ IMFTopologyNode_GetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, &method);
|
||||
+ ok(hr == S_OK, "Attribute should be set\n.");
|
||||
+ IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, method & ~MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES);
|
||||
+ ok(hr == S_OK, "Failed setting attribute %#x\n.", hr);
|
||||
+
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
|
||||
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
|
||||
+ ok(node_count == 2, "Unexpected node count.\n");
|
||||
+ IMFTopologyNode_Release(src_node);
|
||||
+ hr = IMFTopology_GetNode(full_topology, 0, &src_node);
|
||||
+ ok(hr == S_OK, "Failed to get node, hr %#x.\n", hr);
|
||||
+ IMFStreamDescriptor_Release(sd);
|
||||
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&sd);
|
||||
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
|
||||
+ IMFMediaTypeHandler_Release(mth);
|
||||
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
|
||||
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
|
||||
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_media_type);
|
||||
+ ok(hr == S_OK, "Failed to get current media type, hr %#x.\n", hr);
|
||||
+ hr = IMFMediaType_IsEqual(current_media_type, media_type, &flags);
|
||||
+todo_wine {
|
||||
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
+ ok(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA, "Types should be equal.\n");
|
||||
+}
|
||||
+
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+ IMFMediaType_Release(current_media_type);
|
||||
+ IMFMediaTypeHandler_Release(mth);
|
||||
+ IMFStreamSink_Release(stream_sink);
|
||||
+ IMFMediaSink_Release(sink);
|
||||
+ IMFActivate_Release(sink_activate);
|
||||
+ IMFStreamDescriptor_Release(sd);
|
||||
+
|
||||
+ /* add second branch with a valid first branch */
|
||||
+ hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 0);
|
||||
+ ok(hr == S_OK, "Failed setting attribute\n.");
|
||||
+ IMFTopologyNode_Release(src_node);
|
||||
+ hr = IMFTopology_GetNode(topology, 0, &src_node);
|
||||
+ ok(hr == S_OK, "Failed to get node, hr %#x.\n", hr);
|
||||
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&sd);
|
||||
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
|
||||
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
|
||||
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
|
||||
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
|
||||
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
|
||||
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
|
||||
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
+
|
||||
+ IMFTopology_Release(full_topology);
|
||||
+
|
||||
+ IMFStreamDescriptor_Release(sd);
|
||||
+ hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 1, &selected, &sd);
|
||||
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
|
||||
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
|
||||
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &media_type);
|
||||
+ ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
|
||||
+
|
||||
+ IMFTopologyNode_Release(src_node);
|
||||
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node);
|
||||
+ ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source);
|
||||
+ ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr);
|
||||
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
|
||||
+ ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr);
|
||||
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
|
||||
+ ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_AddNode(topology, src_node);
|
||||
+ ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = MFCreateMediaType(&media_type);
|
||||
+ ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ 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 = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate);
|
||||
+ ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr);
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+
|
||||
+ hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
|
||||
+ ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
|
||||
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node);
|
||||
+ ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
|
||||
+ ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_AddNode(topology, sink_node);
|
||||
+ ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_GetNodeCount(topology, &node_count);
|
||||
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
|
||||
+ ok(node_count == 4, "Unexpected node count.\n");
|
||||
+
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
+
|
||||
+ /* unconnected nodes in partial topology are discarded */
|
||||
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
|
||||
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
|
||||
+todo_wine
|
||||
+ ok(node_count == 3, "Unexpected node count %d.\n", node_count);
|
||||
+
|
||||
+ IMFTopology_Release(full_topology);
|
||||
+
|
||||
+ /* connect nodes for second branch */
|
||||
+ hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
|
||||
+ ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr);
|
||||
+
|
||||
+ /* all branches must have valid media types */
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+todo_wine
|
||||
+ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
|
||||
+
|
||||
+ /* set valid media type for second branch */
|
||||
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
|
||||
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
|
||||
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
|
||||
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
|
||||
+todo_wine
|
||||
+ ok(node_count == 6, "Unexpected node count %d.\n", node_count);
|
||||
+
|
||||
+ IMFTopology_Release(full_topology);
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+ IMFTopologyNode_Release(src_node);
|
||||
+ IMFTopologyNode_Release(sink_node);
|
||||
+ IMFMediaTypeHandler_Release(mth);
|
||||
+ IMFStreamSink_Release(stream_sink);
|
||||
+ IMFMediaSink_Release(sink);
|
||||
+ IMFActivate_Release(sink_activate);
|
||||
+ IMFStreamDescriptor_Release(sd);
|
||||
+
|
||||
+ IMFPresentationDescriptor_Release(pd);
|
||||
+ IMFTopology_Release(topology);
|
||||
IMFTopoLoader_Release(loader);
|
||||
|
||||
hr = MFShutdown();
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,419 @@
|
||||
From 01329fe9741031c7ae7cbe74f7b79d5a92f5e52c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
|
||||
<sdelreal@codeweavers.com>
|
||||
Date: Wed, 1 Apr 2020 16:11:07 -0500
|
||||
Subject: [PATCH 06/54] mf: Partially implement the topology loader.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Sergio GĂłmez Del Real <sdelreal@codeweavers.com>
|
||||
---
|
||||
dlls/mf/tests/mf.c | 3 -
|
||||
dlls/mf/topology.c | 337 ++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 321 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
|
||||
index 8691ef55c9..f4f72dda5e 100644
|
||||
--- a/dlls/mf/tests/mf.c
|
||||
+++ b/dlls/mf/tests/mf.c
|
||||
@@ -1572,7 +1572,6 @@ static void test_topology_loader(void)
|
||||
|
||||
/* Empty topology */
|
||||
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
-todo_wine
|
||||
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = MFCreateSourceResolver(&resolver);
|
||||
@@ -1617,7 +1616,6 @@ todo_wine
|
||||
|
||||
/* Source node only. */
|
||||
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
-todo_wine
|
||||
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
/* Add grabber sink. */
|
||||
@@ -1643,7 +1641,6 @@ todo_wine
|
||||
ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
|
||||
-todo_wine
|
||||
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
|
||||
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
|
||||
index abe66c45fd..d4a59f7136 100644
|
||||
--- a/dlls/mf/topology.c
|
||||
+++ b/dlls/mf/topology.c
|
||||
@@ -1933,47 +1933,352 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
|
||||
return refcount;
|
||||
}
|
||||
|
||||
+static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last)
|
||||
+{
|
||||
+ IMFTopology *full_topo = &topology->IMFTopology_iface;
|
||||
+ IMFTopologyNode *in, *out;
|
||||
+ DWORD index;
|
||||
+
|
||||
+ in = first;
|
||||
+ IMFTopology_AddNode(full_topo, in);
|
||||
+ while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index)))
|
||||
+ {
|
||||
+ IMFTopology_AddNode(full_topo, out);
|
||||
+ in = out;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method)
|
||||
+{
|
||||
+ IMFStreamSink *streamsink;
|
||||
+ IMFMediaTypeHandler *mth;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
|
||||
+ IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
|
||||
+ if (method == MF_CONNECT_DIRECT)
|
||||
+ {
|
||||
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype)))
|
||||
+ return hr;
|
||||
+ hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
|
||||
+ return hr;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ IMFTopologyNode *node_dec, *node_conv;
|
||||
+ GUID major_type, subtype, mft_category;
|
||||
+ MFT_REGISTER_TYPE_INFO mft_typeinfo;
|
||||
+ UINT32 flags = MFT_ENUM_FLAG_ALL;
|
||||
+ IMFActivate **activates_decs;
|
||||
+ UINT32 num_activates_decs;
|
||||
+ int i, j;
|
||||
+
|
||||
+ IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type);
|
||||
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
|
||||
+ mft_category = MFT_CATEGORY_AUDIO_DECODER;
|
||||
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
|
||||
+ mft_category = MFT_CATEGORY_VIDEO_DECODER;
|
||||
+ else
|
||||
+ return MF_E_INVALIDMEDIATYPE;
|
||||
+
|
||||
+ IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype);
|
||||
+ mft_typeinfo.guidMajorType = major_type;
|
||||
+ mft_typeinfo.guidSubtype = subtype;
|
||||
+ MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs);
|
||||
+
|
||||
+ /* for getting converters later on */
|
||||
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
|
||||
+ mft_category = MFT_CATEGORY_AUDIO_EFFECT;
|
||||
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
|
||||
+ mft_category = MFT_CATEGORY_VIDEO_EFFECT;
|
||||
+
|
||||
+ /*
|
||||
+ * Iterate over number of decoders.
|
||||
+ * Try to set input type on decoder with source's output media type.
|
||||
+ * If succeeds, iterate over decoder's output media types.
|
||||
+ * Try to set input type on sink with decoder's output media type.
|
||||
+ * If fails, iterate over number of converters.
|
||||
+ * Try to set input type on converter with decoder's output media type.
|
||||
+ * If succeeds, iterate over converters output media types.
|
||||
+ * Try to set input type on sink with converter's output media type.
|
||||
+ */
|
||||
+ for (i = 0; i < num_activates_decs; i++)
|
||||
+ {
|
||||
+ IMFTransform *decoder;
|
||||
+
|
||||
+ IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
|
||||
+ if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, 0)))
|
||||
+ {
|
||||
+ UINT32 num_activates_convs;
|
||||
+ IMFActivate **activates_convs;
|
||||
+ IMFMediaType *decoder_mtype;
|
||||
+
|
||||
+ int count = 0;
|
||||
+ while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype)))
|
||||
+ {
|
||||
+ IMFTransform *converter;
|
||||
+
|
||||
+ /* succeeded with source -> decoder -> sink */
|
||||
+ if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype)))
|
||||
+ {
|
||||
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
|
||||
+ IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
|
||||
+ IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
|
||||
+ IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
|
||||
+
|
||||
+ IMFActivate_ShutdownObject(activates_convs[i]);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype);
|
||||
+ mft_typeinfo.guidSubtype = subtype;
|
||||
+ MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs);
|
||||
+ for (j = 0; j < num_activates_convs; j++)
|
||||
+ {
|
||||
+ IMFMediaType *converter_mtype;
|
||||
+
|
||||
+ IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform, (void **)&converter);
|
||||
+ if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, 0)))
|
||||
+ {
|
||||
+ int count = 0;
|
||||
+ while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype)))
|
||||
+ {
|
||||
+ /* succeeded with source -> decoder -> converter -> sink */
|
||||
+ if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype)))
|
||||
+ {
|
||||
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
|
||||
+ IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
|
||||
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv);
|
||||
+ IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter);
|
||||
+ IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
|
||||
+ IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0);
|
||||
+ IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0);
|
||||
+
|
||||
+ IMFActivate_ShutdownObject(activates_convs[j]);
|
||||
+ IMFActivate_ShutdownObject(activates_decs[i]);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ IMFActivate_ShutdownObject(activates_convs[j]);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ IMFActivate_ShutdownObject(activates_decs[i]);
|
||||
+ }
|
||||
+ }
|
||||
+ return E_FAIL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT topology_loader_resolve_partial_topology(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology **full_topology)
|
||||
+{
|
||||
+ IMFMediaTypeHandler *mth_src, *mth_sink;
|
||||
+ IMFTopologyNode *clone_src, *clone_sink;
|
||||
+ UINT32 method, enum_src_types, streamid;
|
||||
+ IMFMediaType **src_mediatypes;
|
||||
+ IMFStreamDescriptor *desc;
|
||||
+ IMFAttributes *attrs_src;
|
||||
+ IMFStreamSink *strm_sink;
|
||||
+ IMFMediaType *mtype_src;
|
||||
+ DWORD num_media_types;
|
||||
+ HRESULT hr;
|
||||
+ int i;
|
||||
+
|
||||
+ attrs_src = src->attributes;
|
||||
+ if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc)))
|
||||
+ return hr;
|
||||
+ strm_sink = (IMFStreamSink *)sink->object;
|
||||
+
|
||||
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &mth_src)))
|
||||
+ {
|
||||
+ IMFStreamDescriptor_Release(desc);
|
||||
+ return hr;
|
||||
+ }
|
||||
+ if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(strm_sink, &mth_sink)))
|
||||
+ {
|
||||
+ IMFStreamDescriptor_Release(desc);
|
||||
+ IMFMediaTypeHandler_Release(mth_src);
|
||||
+ return hr;
|
||||
+ }
|
||||
+
|
||||
+ hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types);
|
||||
+
|
||||
+ mtype_src = NULL;
|
||||
+ if (FAILED(hr) || !enum_src_types)
|
||||
+ {
|
||||
+ num_media_types = 1;
|
||||
+ enum_src_types = 0;
|
||||
+ if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src)))
|
||||
+ if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src)))
|
||||
+ {
|
||||
+ IMFMediaTypeHandler_Release(mth_src);
|
||||
+ IMFMediaTypeHandler_Release(mth_sink);
|
||||
+ IMFStreamDescriptor_Release(desc);
|
||||
+ return hr;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types);
|
||||
+
|
||||
+ src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types);
|
||||
+
|
||||
+ if (mtype_src)
|
||||
+ src_mediatypes[0] = mtype_src;
|
||||
+ else
|
||||
+ for (i = 0; i < num_media_types; i++)
|
||||
+ IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]);
|
||||
+
|
||||
+
|
||||
+ MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src);
|
||||
+ MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink);
|
||||
+ IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface);
|
||||
+ IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface);
|
||||
+
|
||||
+ if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid)))
|
||||
+ IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
|
||||
+
|
||||
+ if (enum_src_types)
|
||||
+ {
|
||||
+ hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
|
||||
+ if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
|
||||
+ {
|
||||
+ for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
|
||||
+ for (i = 0; i < num_media_types; i++)
|
||||
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
|
||||
+ {
|
||||
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
|
||||
+ heap_free(src_mediatypes);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ for (i = 0; i < num_media_types; i++)
|
||||
+ for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
|
||||
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
|
||||
+ {
|
||||
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
|
||||
+ heap_free(src_mediatypes);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
|
||||
+ {
|
||||
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
|
||||
+ heap_free(src_mediatypes);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ heap_free(src_mediatypes);
|
||||
+ return MF_E_TOPO_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
|
||||
IMFTopology **output_topology, IMFTopology *current_topology)
|
||||
{
|
||||
struct topology *topology = unsafe_impl_from_IMFTopology(input_topology);
|
||||
+ struct topology_node *(*node_pairs)[2];
|
||||
+ int num_connections;
|
||||
IMFStreamSink *sink;
|
||||
HRESULT hr;
|
||||
- size_t i;
|
||||
+ int i, idx;
|
||||
|
||||
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
|
||||
|
||||
if (current_topology)
|
||||
FIXME("Current topology instance is ignored.\n");
|
||||
|
||||
+ if (!topology || topology->nodes.count < 2)
|
||||
+ return MF_E_TOPO_UNSUPPORTED;
|
||||
+
|
||||
+ num_connections = 0;
|
||||
+ for (i = 0; i < topology->nodes.count; i++)
|
||||
+ {
|
||||
+ struct topology_node *node = topology->nodes.nodes[i];
|
||||
+
|
||||
+ if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
|
||||
+ {
|
||||
+ if (node->outputs.count && node->outputs.streams->connection)
|
||||
+ num_connections++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!num_connections)
|
||||
+ return MF_E_TOPO_UNSUPPORTED;
|
||||
+
|
||||
+ node_pairs = heap_alloc_zero(sizeof(struct topology_node *[2]) * num_connections);
|
||||
+
|
||||
+ idx = 0;
|
||||
for (i = 0; i < topology->nodes.count; ++i)
|
||||
{
|
||||
struct topology_node *node = topology->nodes.nodes[i];
|
||||
|
||||
- switch (node->node_type)
|
||||
+ if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
|
||||
{
|
||||
- case MF_TOPOLOGY_OUTPUT_NODE:
|
||||
- if (node->object)
|
||||
+ if (node->outputs.count && node->outputs.streams->connection)
|
||||
+ {
|
||||
+ node_pairs[idx][0] = node;
|
||||
+ if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_TRANSFORM_NODE)
|
||||
{
|
||||
- /* Sinks must be bound beforehand. */
|
||||
- if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink)))
|
||||
- return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
|
||||
- IMFStreamSink_Release(sink);
|
||||
+ struct topology_node *sink = node->outputs.streams->connection;
|
||||
+
|
||||
+ while (sink && sink->node_type != MF_TOPOLOGY_OUTPUT_NODE && sink->outputs.count)
|
||||
+ sink = sink->outputs.streams->connection;
|
||||
+ if (!sink || !sink->outputs.count)
|
||||
+ {
|
||||
+ FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
|
||||
+ heap_free(node_pairs);
|
||||
+ return MF_E_TOPO_UNSUPPORTED;
|
||||
+ }
|
||||
+ node_pairs[idx][1] = sink;
|
||||
}
|
||||
- break;
|
||||
- case MF_TOPOLOGY_SOURCESTREAM_NODE:
|
||||
- if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL)))
|
||||
- return hr;
|
||||
- break;
|
||||
- default:
|
||||
- ;
|
||||
+ else if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_OUTPUT_NODE)
|
||||
+ node_pairs[idx][1] = node->outputs.streams->connection;
|
||||
+ else {
|
||||
+ FIXME("Tee nodes currently unhandled.\n");
|
||||
+ heap_free(node_pairs);
|
||||
+ return MF_E_TOPO_UNSUPPORTED;
|
||||
+ }
|
||||
+ idx++;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
+ /* all sinks must be activated */
|
||||
+ for (i = 0; i < num_connections; i++)
|
||||
+ {
|
||||
+ if (FAILED(IUnknown_QueryInterface(node_pairs[i][1]->object, &IID_IMFStreamSink, (void **)&sink)))
|
||||
+ {
|
||||
+ FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
|
||||
+ heap_free(node_pairs);
|
||||
+ return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
|
||||
+ }
|
||||
+ IMFStreamSink_Release(sink);
|
||||
+ }
|
||||
+
|
||||
if (FAILED(hr = MFCreateTopology(output_topology)))
|
||||
return hr;
|
||||
|
||||
- return IMFTopology_CloneFrom(*output_topology, input_topology);
|
||||
+ /* resolve each branch */
|
||||
+ for (i = 0; i < num_connections; i++)
|
||||
+ {
|
||||
+ struct topology_node *src = node_pairs[i][0];
|
||||
+ struct topology_node *sink = node_pairs[i][1];
|
||||
+ struct topology *full_topology = unsafe_impl_from_IMFTopology(*output_topology);
|
||||
+
|
||||
+ if (FAILED(hr = topology_loader_resolve_partial_topology(src, sink, topology, &full_topology)))
|
||||
+ {
|
||||
+ heap_free(node_pairs);
|
||||
+ return hr;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ heap_free(node_pairs);
|
||||
+ return S_OK;
|
||||
}
|
||||
|
||||
static const IMFTopoLoaderVtbl topologyloadervtbl =
|
||||
--
|
||||
2.28.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,154 @@
|
||||
From 431129df1f3ee134e792b05456325c91d76a683d Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Mon, 30 Mar 2020 15:19:01 -0500
|
||||
Subject: [PATCH 08/54] winegstreamer: Implement IMFMediaSource::Shutdown.
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/mfplat/tests/mfplat.c | 2 +-
|
||||
dlls/winegstreamer/media_source.c | 39 +++++++++++++++++++++++++++++--
|
||||
2 files changed, 38 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
|
||||
index c9548c6b18..af7e0d0459 100644
|
||||
--- a/dlls/mfplat/tests/mfplat.c
|
||||
+++ b/dlls/mfplat/tests/mfplat.c
|
||||
@@ -626,13 +626,13 @@ todo_wine
|
||||
IMFMediaTypeHandler_Release(handler);
|
||||
IMFPresentationDescriptor_Release(descriptor);
|
||||
|
||||
+skip_source_tests:
|
||||
hr = IMFMediaSource_Shutdown(mediasource);
|
||||
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = IMFMediaSource_CreatePresentationDescriptor(mediasource, NULL);
|
||||
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
-skip_source_tests:
|
||||
IMFMediaSource_Release(mediasource);
|
||||
IMFByteStream_Release(stream);
|
||||
|
||||
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
|
||||
index df28f54444..09a40a0620 100644
|
||||
--- a/dlls/winegstreamer/media_source.c
|
||||
+++ b/dlls/winegstreamer/media_source.c
|
||||
@@ -20,6 +20,14 @@ struct media_source
|
||||
IMFMediaSource IMFMediaSource_iface;
|
||||
LONG ref;
|
||||
IMFMediaEventQueue *event_queue;
|
||||
+ enum
|
||||
+ {
|
||||
+ SOURCE_OPENING,
|
||||
+ SOURCE_STOPPED, /* (READY) */
|
||||
+ SOURCE_PAUSED,
|
||||
+ SOURCE_RUNNING,
|
||||
+ SOURCE_SHUTDOWN,
|
||||
+ } state;
|
||||
};
|
||||
|
||||
static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
|
||||
@@ -81,6 +89,9 @@ static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags,
|
||||
|
||||
TRACE("(%p)->(%#x, %p)\n", source, flags, event);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
|
||||
}
|
||||
|
||||
@@ -90,6 +101,9 @@ static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsync
|
||||
|
||||
TRACE("(%p)->(%p, %p)\n", source, callback, state);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
|
||||
}
|
||||
|
||||
@@ -99,6 +113,9 @@ static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncRe
|
||||
|
||||
TRACE("(%p)->(%p, %p)\n", source, result, event);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
|
||||
}
|
||||
|
||||
@@ -109,6 +126,9 @@ static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventT
|
||||
|
||||
TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
|
||||
}
|
||||
|
||||
@@ -118,6 +138,9 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO
|
||||
|
||||
FIXME("(%p)->(%p): stub\n", source, characteristics);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
@@ -127,6 +150,9 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
|
||||
|
||||
FIXME("(%p)->(%p): stub\n", source, descriptor);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
@@ -137,6 +163,9 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD
|
||||
|
||||
FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
@@ -146,6 +175,9 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
|
||||
|
||||
FIXME("(%p): stub\n", source);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
@@ -170,9 +202,10 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
|
||||
{
|
||||
struct media_source *source = impl_from_IMFMediaSource(iface);
|
||||
|
||||
- FIXME("(%p): stub\n", source);
|
||||
+ TRACE("(%p)\n", source);
|
||||
|
||||
- return E_NOTIMPL;
|
||||
+ source->state = SOURCE_SHUTDOWN;
|
||||
+ return media_source_teardown(source);
|
||||
}
|
||||
|
||||
static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
|
||||
@@ -203,6 +236,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
|
||||
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
|
||||
goto fail;
|
||||
|
||||
+ object->state = SOURCE_STOPPED;
|
||||
+
|
||||
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
|
||||
object->ref = 1;
|
||||
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,441 @@
|
||||
From 34ca87dde0bd4e3cab92aaf674903791de20bdc0 Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Mon, 30 Mar 2020 14:19:35 -0500
|
||||
Subject: [PATCH 09/54] winegstreamer: Add a GstPad wrapping the media source's
|
||||
bytestream.
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/winegstreamer/gst_cbs.c | 58 ++++++++
|
||||
dlls/winegstreamer/gst_cbs.h | 12 +-
|
||||
dlls/winegstreamer/media_source.c | 237 +++++++++++++++++++++++++++++-
|
||||
3 files changed, 302 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
|
||||
index bf7103b160..dfe33dd627 100644
|
||||
--- a/dlls/winegstreamer/gst_cbs.c
|
||||
+++ b/dlls/winegstreamer/gst_cbs.c
|
||||
@@ -49,6 +49,8 @@ static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
|
||||
|
||||
if (cbdata->type < GSTDEMUX_MAX)
|
||||
perform_cb_gstdemux(cbdata);
|
||||
+ else if (cbdata->type < MEDIA_SOURCE_MAX)
|
||||
+ perform_cb_media_source(cbdata);
|
||||
|
||||
pthread_mutex_lock(&cbdata->lock);
|
||||
cbdata->finished = 1;
|
||||
@@ -301,3 +303,59 @@ gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
|
||||
|
||||
return cbdata.u.query_sink_data.ret;
|
||||
}
|
||||
+
|
||||
+GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
|
||||
+ GstBuffer **buf)
|
||||
+{
|
||||
+ struct cb_data cbdata = { PULL_FROM_BYTESTREAM };
|
||||
+
|
||||
+ cbdata.u.getrange_data.pad = pad;
|
||||
+ cbdata.u.getrange_data.parent = parent;
|
||||
+ cbdata.u.getrange_data.ofs = ofs;
|
||||
+ cbdata.u.getrange_data.len = len;
|
||||
+ cbdata.u.getrange_data.buf = buf;
|
||||
+
|
||||
+ call_cb(&cbdata);
|
||||
+
|
||||
+ return cbdata.u.getrange_data.ret;
|
||||
+}
|
||||
+
|
||||
+gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
|
||||
+{
|
||||
+ struct cb_data cbdata = { QUERY_BYTESTREAM };
|
||||
+
|
||||
+ cbdata.u.query_function_data.pad = pad;
|
||||
+ cbdata.u.query_function_data.parent = parent;
|
||||
+ cbdata.u.query_function_data.query = query;
|
||||
+
|
||||
+ call_cb(&cbdata);
|
||||
+
|
||||
+ return cbdata.u.query_function_data.ret;
|
||||
+}
|
||||
+
|
||||
+gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
|
||||
+{
|
||||
+ struct cb_data cbdata = { ACTIVATE_BYTESTREAM_PAD_MODE };
|
||||
+
|
||||
+ cbdata.u.activate_mode_data.pad = pad;
|
||||
+ cbdata.u.activate_mode_data.parent = parent;
|
||||
+ cbdata.u.activate_mode_data.mode = mode;
|
||||
+ cbdata.u.activate_mode_data.activate = activate;
|
||||
+
|
||||
+ call_cb(&cbdata);
|
||||
+
|
||||
+ return cbdata.u.activate_mode_data.ret;
|
||||
+}
|
||||
+
|
||||
+gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
|
||||
+{
|
||||
+ struct cb_data cbdata = { PROCESS_BYTESTREAM_PAD_EVENT };
|
||||
+
|
||||
+ cbdata.u.event_src_data.pad = pad;
|
||||
+ cbdata.u.event_src_data.parent = parent;
|
||||
+ cbdata.u.event_src_data.event = event;
|
||||
+
|
||||
+ call_cb(&cbdata);
|
||||
+
|
||||
+ return cbdata.u.event_src_data.ret;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
|
||||
index 4725f23ad1..10e999feea 100644
|
||||
--- a/dlls/winegstreamer/gst_cbs.h
|
||||
+++ b/dlls/winegstreamer/gst_cbs.h
|
||||
@@ -43,7 +43,12 @@ enum CB_TYPE {
|
||||
AUTOPLUG_BLACKLIST,
|
||||
UNKNOWN_TYPE,
|
||||
QUERY_SINK,
|
||||
- GSTDEMUX_MAX
|
||||
+ GSTDEMUX_MAX,
|
||||
+ PULL_FROM_BYTESTREAM,
|
||||
+ QUERY_BYTESTREAM,
|
||||
+ ACTIVATE_BYTESTREAM_PAD_MODE,
|
||||
+ PROCESS_BYTESTREAM_PAD_EVENT,
|
||||
+ MEDIA_SOURCE_MAX,
|
||||
};
|
||||
|
||||
struct cb_data {
|
||||
@@ -138,6 +143,7 @@ struct cb_data {
|
||||
|
||||
void mark_wine_thread(void) DECLSPEC_HIDDEN;
|
||||
void perform_cb_gstdemux(struct cb_data *data) DECLSPEC_HIDDEN;
|
||||
+void perform_cb_media_source(struct cb_data *data) DECLSPEC_HIDDEN;
|
||||
|
||||
GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user) DECLSPEC_HIDDEN;
|
||||
void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
|
||||
@@ -154,5 +160,9 @@ GstAutoplugSelectResult autoplug_blacklist_wrapper(GstElement *bin, GstPad *pad,
|
||||
void unknown_type_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user) DECLSPEC_HIDDEN;
|
||||
void Gstreamer_transform_pad_added_wrapper(GstElement *filter, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
|
||||
gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
|
||||
+GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len, GstBuffer **buf) DECLSPEC_HIDDEN;
|
||||
+gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
|
||||
+gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
|
||||
+gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif
|
||||
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
|
||||
index 09a40a0620..48119e4a89 100644
|
||||
--- a/dlls/winegstreamer/media_source.c
|
||||
+++ b/dlls/winegstreamer/media_source.c
|
||||
@@ -1,4 +1,9 @@
|
||||
+#include "config.h"
|
||||
+
|
||||
+#include <gst/gst.h>
|
||||
+
|
||||
#include "gst_private.h"
|
||||
+#include "gst_cbs.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -8,6 +13,7 @@
|
||||
#include "mfapi.h"
|
||||
#include "mferror.h"
|
||||
#include "mfidl.h"
|
||||
+#include "mfobjects.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/heap.h"
|
||||
@@ -15,11 +21,24 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
|
||||
|
||||
+static struct source_desc
|
||||
+{
|
||||
+ GstStaticCaps bytestream_caps;
|
||||
+} source_descs[] =
|
||||
+{
|
||||
+ {/*SOURCE_TYPE_MPEG_4*/
|
||||
+ GST_STATIC_CAPS("video/quicktime"),
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
struct media_source
|
||||
{
|
||||
IMFMediaSource IMFMediaSource_iface;
|
||||
LONG ref;
|
||||
+ enum source_type type;
|
||||
IMFMediaEventQueue *event_queue;
|
||||
+ IMFByteStream *byte_stream;
|
||||
+ GstPad *my_src;
|
||||
enum
|
||||
{
|
||||
SOURCE_OPENING,
|
||||
@@ -35,6 +54,154 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac
|
||||
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
|
||||
}
|
||||
|
||||
+GstFlowReturn pull_from_bytestream(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
|
||||
+ GstBuffer **buf)
|
||||
+{
|
||||
+ struct media_source *source = gst_pad_get_element_private(pad);
|
||||
+ IMFByteStream *byte_stream = source->byte_stream;
|
||||
+ ULONG bytes_read;
|
||||
+ GstMapInfo info;
|
||||
+ BOOL is_eof;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ TRACE("gstreamer requesting %u bytes at %s from source %p into buffer %p\n", len, wine_dbgstr_longlong(ofs), source, buf);
|
||||
+
|
||||
+ if (ofs != GST_BUFFER_OFFSET_NONE)
|
||||
+ {
|
||||
+ if (FAILED(IMFByteStream_SetCurrentPosition(byte_stream, ofs)))
|
||||
+ return GST_FLOW_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ if (FAILED(IMFByteStream_IsEndOfStream(byte_stream, &is_eof)))
|
||||
+ return GST_FLOW_ERROR;
|
||||
+ if (is_eof)
|
||||
+ return GST_FLOW_EOS;
|
||||
+
|
||||
+ if (!(*buf))
|
||||
+ *buf = gst_buffer_new_and_alloc(len);
|
||||
+ gst_buffer_map(*buf, &info, GST_MAP_WRITE);
|
||||
+ hr = IMFByteStream_Read(byte_stream, info.data, len, &bytes_read);
|
||||
+ gst_buffer_unmap(*buf, &info);
|
||||
+
|
||||
+ gst_buffer_set_size(*buf, bytes_read);
|
||||
+
|
||||
+ if (FAILED(hr))
|
||||
+ {
|
||||
+ return GST_FLOW_ERROR;
|
||||
+ }
|
||||
+ GST_BUFFER_OFFSET(*buf) = ofs;
|
||||
+ return GST_FLOW_OK;
|
||||
+}
|
||||
+
|
||||
+static gboolean query_bytestream(GstPad *pad, GstObject *parent, GstQuery *query)
|
||||
+{
|
||||
+ struct media_source *source = gst_pad_get_element_private(pad);
|
||||
+ GstFormat format;
|
||||
+ QWORD bytestream_len;
|
||||
+
|
||||
+ TRACE("GStreamer queries source %p for %s\n", source, GST_QUERY_TYPE_NAME(query));
|
||||
+
|
||||
+ if (FAILED(IMFByteStream_GetLength(source->byte_stream, &bytestream_len)))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ switch (GST_QUERY_TYPE(query))
|
||||
+ {
|
||||
+ case GST_QUERY_DURATION:
|
||||
+ {
|
||||
+ gst_query_parse_duration (query, &format, NULL);
|
||||
+ if (format == GST_FORMAT_PERCENT) {
|
||||
+ gst_query_set_duration (query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ else if (format == GST_FORMAT_BYTES)
|
||||
+ {
|
||||
+ QWORD length;
|
||||
+ IMFByteStream_GetLength(source->byte_stream, &length);
|
||||
+ gst_query_set_duration (query, GST_FORMAT_BYTES, length);
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ case GST_QUERY_SEEKING:
|
||||
+ {
|
||||
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
|
||||
+ if (format != GST_FORMAT_BYTES)
|
||||
+ {
|
||||
+ WARN("Cannot seek using format \"%s\".\n", gst_format_get_name(format));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, bytestream_len);
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ case GST_QUERY_SCHEDULING:
|
||||
+ {
|
||||
+ gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
|
||||
+ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ case GST_QUERY_CAPS:
|
||||
+ {
|
||||
+ GstCaps *caps, *filter;
|
||||
+
|
||||
+ gst_query_parse_caps(query, &filter);
|
||||
+
|
||||
+ caps = gst_static_caps_get(&source_descs[source->type].bytestream_caps);
|
||||
+
|
||||
+ if (filter) {
|
||||
+ GstCaps* filtered;
|
||||
+ filtered = gst_caps_intersect_full(
|
||||
+ filter, caps, GST_CAPS_INTERSECT_FIRST);
|
||||
+ gst_caps_unref(caps);
|
||||
+ caps = filtered;
|
||||
+ }
|
||||
+ gst_query_set_caps_result(query, caps);
|
||||
+ gst_caps_unref(caps);
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ default:
|
||||
+ {
|
||||
+ WARN("Unhandled query type %s\n", GST_QUERY_TYPE_NAME(query));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static gboolean activate_bytestream_pad_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
|
||||
+{
|
||||
+ struct media_source *source = gst_pad_get_element_private(pad);
|
||||
+
|
||||
+ TRACE("%s source pad for mediasource %p in %s mode.\n",
|
||||
+ activate ? "Activating" : "Deactivating", source, gst_pad_mode_get_name(mode));
|
||||
+
|
||||
+ switch (mode) {
|
||||
+ case GST_PAD_MODE_PULL:
|
||||
+ return TRUE;
|
||||
+ default:
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static gboolean process_bytestream_pad_event(GstPad *pad, GstObject *parent, GstEvent *event)
|
||||
+{
|
||||
+ struct media_source *source = gst_pad_get_element_private(pad);
|
||||
+
|
||||
+ TRACE("source %p, type \"%s\".\n", source, GST_EVENT_TYPE_NAME(event));
|
||||
+
|
||||
+ switch (event->type) {
|
||||
+ /* the seek event should fail in pull mode */
|
||||
+ case GST_EVENT_SEEK:
|
||||
+ return FALSE;
|
||||
+ default:
|
||||
+ WARN("Ignoring \"%s\" event.\n", GST_EVENT_TYPE_NAME(event));
|
||||
+ case GST_EVENT_TAG:
|
||||
+ case GST_EVENT_QOS:
|
||||
+ case GST_EVENT_RECONFIGURE:
|
||||
+ return gst_pad_event_default(pad, parent, event);
|
||||
+ }
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
|
||||
{
|
||||
struct media_source *source = impl_from_IMFMediaSource(iface);
|
||||
@@ -187,13 +354,20 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
|
||||
|
||||
FIXME("(%p): stub\n", source);
|
||||
|
||||
+ if (source->state == SOURCE_SHUTDOWN)
|
||||
+ return MF_E_SHUTDOWN;
|
||||
+
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT media_source_teardown(struct media_source *source)
|
||||
{
|
||||
+ if (source->my_src)
|
||||
+ gst_object_unref(GST_OBJECT(source->my_src));
|
||||
if (source->event_queue)
|
||||
IMFMediaEventQueue_Release(source->event_queue);
|
||||
+ if (source->byte_stream)
|
||||
+ IMFByteStream_Release(source->byte_stream);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -227,19 +401,35 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
|
||||
|
||||
static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_type type, struct media_source **out_media_source)
|
||||
{
|
||||
+ GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
|
||||
+ "mf_src",
|
||||
+ GST_PAD_SRC,
|
||||
+ GST_PAD_ALWAYS,
|
||||
+ source_descs[type].bytestream_caps);
|
||||
+
|
||||
struct media_source *object = heap_alloc_zero(sizeof(*object));
|
||||
HRESULT hr;
|
||||
|
||||
if (!object)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
+ object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
|
||||
+ object->ref = 1;
|
||||
+ object->type = type;
|
||||
+ object->byte_stream = bytestream;
|
||||
+ IMFByteStream_AddRef(bytestream);
|
||||
+
|
||||
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
|
||||
goto fail;
|
||||
|
||||
- object->state = SOURCE_STOPPED;
|
||||
+ object->my_src = gst_pad_new_from_static_template(&src_template, "mf-src");
|
||||
+ gst_pad_set_element_private(object->my_src, object);
|
||||
+ gst_pad_set_getrange_function(object->my_src, pull_from_bytestream_wrapper);
|
||||
+ gst_pad_set_query_function(object->my_src, query_bytestream_wrapper);
|
||||
+ gst_pad_set_activatemode_function(object->my_src, activate_bytestream_pad_mode_wrapper);
|
||||
+ gst_pad_set_event_function(object->my_src, process_bytestream_pad_event_wrapper);
|
||||
|
||||
- object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
|
||||
- object->ref = 1;
|
||||
+ object->state = SOURCE_STOPPED;
|
||||
|
||||
*out_media_source = object;
|
||||
return S_OK;
|
||||
@@ -249,6 +439,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
|
||||
|
||||
media_source_teardown(object);
|
||||
heap_free(object);
|
||||
+ *out_media_source = NULL;
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -712,4 +903,42 @@ HRESULT container_stream_handler_construct(REFIID riid, void **obj, enum source_
|
||||
IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
|
||||
|
||||
return hr;
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
+
|
||||
+/* helper for callback forwarding */
|
||||
+void perform_cb_media_source(struct cb_data *cbdata)
|
||||
+{
|
||||
+ switch(cbdata->type)
|
||||
+ {
|
||||
+ case PULL_FROM_BYTESTREAM:
|
||||
+ {
|
||||
+ struct getrange_data *data = &cbdata->u.getrange_data;
|
||||
+ cbdata->u.getrange_data.ret = pull_from_bytestream(data->pad, data->parent,
|
||||
+ data->ofs, data->len, data->buf);
|
||||
+ break;
|
||||
+ }
|
||||
+ case QUERY_BYTESTREAM:
|
||||
+ {
|
||||
+ struct query_function_data *data = &cbdata->u.query_function_data;
|
||||
+ cbdata->u.query_function_data.ret = query_bytestream(data->pad, data->parent, data->query);
|
||||
+ break;
|
||||
+ }
|
||||
+ case ACTIVATE_BYTESTREAM_PAD_MODE:
|
||||
+ {
|
||||
+ struct activate_mode_data *data = &cbdata->u.activate_mode_data;
|
||||
+ cbdata->u.activate_mode_data.ret = activate_bytestream_pad_mode(data->pad, data->parent, data->mode, data->activate);
|
||||
+ break;
|
||||
+ }
|
||||
+ case PROCESS_BYTESTREAM_PAD_EVENT:
|
||||
+ {
|
||||
+ struct event_src_data *data = &cbdata->u.event_src_data;
|
||||
+ cbdata->u.event_src_data.ret = process_bytestream_pad_event(data->pad, data->parent, data->event);
|
||||
+ break;
|
||||
+ }
|
||||
+ default:
|
||||
+ {
|
||||
+ ERR("Wrong callback forwarder called\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,221 @@
|
||||
From 42170f6bd111e333694f4122e38944c5f87ac1f2 Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Tue, 31 Mar 2020 13:34:57 -0500
|
||||
Subject: [PATCH 10/54] winegstreamer: Find an appropriate demuxer for the
|
||||
source.
|
||||
|
||||
We can add a path later which uses decodebin as the demuxer, for use with formats not supported on windows. (like Theora)
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/winegstreamer/gst_cbs.c | 15 ++++-
|
||||
dlls/winegstreamer/gst_cbs.h | 2 +
|
||||
dlls/winegstreamer/media_source.c | 99 ++++++++++++++++++++++++++++++-
|
||||
3 files changed, 114 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
|
||||
index dfe33dd627..cf49745f1d 100644
|
||||
--- a/dlls/winegstreamer/gst_cbs.c
|
||||
+++ b/dlls/winegstreamer/gst_cbs.c
|
||||
@@ -358,4 +358,17 @@ gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, Gs
|
||||
call_cb(&cbdata);
|
||||
|
||||
return cbdata.u.event_src_data.ret;
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
+
|
||||
+GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user)
|
||||
+{
|
||||
+ struct cb_data cbdata = { WATCH_SOURCE_BUS };
|
||||
+
|
||||
+ cbdata.u.watch_bus_data.bus = bus;
|
||||
+ cbdata.u.watch_bus_data.msg = message;
|
||||
+ cbdata.u.watch_bus_data.user = user;
|
||||
+
|
||||
+ call_cb(&cbdata);
|
||||
+
|
||||
+ return cbdata.u.watch_bus_data.ret;
|
||||
+}
|
||||
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
|
||||
index 10e999feea..0d7acaf0b8 100644
|
||||
--- a/dlls/winegstreamer/gst_cbs.h
|
||||
+++ b/dlls/winegstreamer/gst_cbs.h
|
||||
@@ -48,6 +48,7 @@ enum CB_TYPE {
|
||||
QUERY_BYTESTREAM,
|
||||
ACTIVATE_BYTESTREAM_PAD_MODE,
|
||||
PROCESS_BYTESTREAM_PAD_EVENT,
|
||||
+ WATCH_SOURCE_BUS,
|
||||
MEDIA_SOURCE_MAX,
|
||||
};
|
||||
|
||||
@@ -164,5 +165,6 @@ GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint
|
||||
gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
|
||||
gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
|
||||
gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
|
||||
+GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif
|
||||
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
|
||||
index 48119e4a89..e1f5c77375 100644
|
||||
--- a/dlls/winegstreamer/media_source.c
|
||||
+++ b/dlls/winegstreamer/media_source.c
|
||||
@@ -38,7 +38,12 @@ struct media_source
|
||||
enum source_type type;
|
||||
IMFMediaEventQueue *event_queue;
|
||||
IMFByteStream *byte_stream;
|
||||
- GstPad *my_src;
|
||||
+ struct media_stream **streams;
|
||||
+ ULONG stream_count;
|
||||
+ GstBus *bus;
|
||||
+ GstElement *container;
|
||||
+ GstElement *demuxer;
|
||||
+ GstPad *my_src, *their_sink;
|
||||
enum
|
||||
{
|
||||
SOURCE_OPENING,
|
||||
@@ -202,6 +207,37 @@ static gboolean process_bytestream_pad_event(GstPad *pad, GstObject *parent, Gst
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+GstBusSyncReply watch_source_bus(GstBus *bus, GstMessage *message, gpointer user)
|
||||
+{
|
||||
+ struct media_source *source = (struct media_source *) user;
|
||||
+ gchar *dbg_info = NULL;
|
||||
+ GError *err = NULL;
|
||||
+
|
||||
+ TRACE("source %p message type %s\n", source, GST_MESSAGE_TYPE_NAME(message));
|
||||
+
|
||||
+ switch (message->type)
|
||||
+ {
|
||||
+ case GST_MESSAGE_ERROR:
|
||||
+ gst_message_parse_error(message, &err, &dbg_info);
|
||||
+ ERR("%s: %s\n", GST_OBJECT_NAME(message->src), err->message);
|
||||
+ ERR("%s\n", dbg_info);
|
||||
+ g_error_free(err);
|
||||
+ g_free(dbg_info);
|
||||
+ break;
|
||||
+ case GST_MESSAGE_WARNING:
|
||||
+ gst_message_parse_warning(message, &err, &dbg_info);
|
||||
+ WARN("%s: %s\n", GST_OBJECT_NAME(message->src), err->message);
|
||||
+ WARN("%s\n", dbg_info);
|
||||
+ g_error_free(err);
|
||||
+ g_free(dbg_info);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return GST_BUS_PASS;
|
||||
+}
|
||||
+
|
||||
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
|
||||
{
|
||||
struct media_source *source = impl_from_IMFMediaSource(iface);
|
||||
@@ -364,6 +400,13 @@ static HRESULT media_source_teardown(struct media_source *source)
|
||||
{
|
||||
if (source->my_src)
|
||||
gst_object_unref(GST_OBJECT(source->my_src));
|
||||
+ if (source->their_sink)
|
||||
+ gst_object_unref(GST_OBJECT(source->their_sink));
|
||||
+ if (source->container)
|
||||
+ {
|
||||
+ gst_element_set_state(source->container, GST_STATE_NULL);
|
||||
+ gst_object_unref(GST_OBJECT(source->container));
|
||||
+ }
|
||||
if (source->event_queue)
|
||||
IMFMediaEventQueue_Release(source->event_queue);
|
||||
if (source->byte_stream)
|
||||
@@ -408,7 +451,10 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
|
||||
source_descs[type].bytestream_caps);
|
||||
|
||||
struct media_source *object = heap_alloc_zero(sizeof(*object));
|
||||
+ GList *demuxer_list_one, *demuxer_list_two;
|
||||
+ GstElementFactory *demuxer_factory = NULL;
|
||||
HRESULT hr;
|
||||
+ int ret;
|
||||
|
||||
if (!object)
|
||||
return E_OUTOFMEMORY;
|
||||
@@ -422,6 +468,11 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
|
||||
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
|
||||
goto fail;
|
||||
|
||||
+ object->container = gst_bin_new(NULL);
|
||||
+ object->bus = gst_bus_new();
|
||||
+ gst_bus_set_sync_handler(object->bus, watch_source_bus_wrapper, object, NULL);
|
||||
+ gst_element_set_bus(object->container, object->bus);
|
||||
+
|
||||
object->my_src = gst_pad_new_from_static_template(&src_template, "mf-src");
|
||||
gst_pad_set_element_private(object->my_src, object);
|
||||
gst_pad_set_getrange_function(object->my_src, pull_from_bytestream_wrapper);
|
||||
@@ -429,6 +480,44 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
|
||||
gst_pad_set_activatemode_function(object->my_src, activate_bytestream_pad_mode_wrapper);
|
||||
gst_pad_set_event_function(object->my_src, process_bytestream_pad_event_wrapper);
|
||||
|
||||
+ /* Find demuxer */
|
||||
+ demuxer_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEMUXER, 1);
|
||||
+
|
||||
+ demuxer_list_two = gst_element_factory_list_filter(demuxer_list_one, gst_static_caps_get(&source_descs[type].bytestream_caps), GST_PAD_SINK, 0);
|
||||
+ gst_plugin_feature_list_free(demuxer_list_one);
|
||||
+
|
||||
+ if (!(g_list_length(demuxer_list_two)))
|
||||
+ {
|
||||
+ ERR("Failed to find demuxer for source.\n");
|
||||
+ gst_plugin_feature_list_free(demuxer_list_two);
|
||||
+ hr = E_FAIL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ demuxer_factory = g_list_first(demuxer_list_two)->data;
|
||||
+ gst_object_ref(demuxer_factory);
|
||||
+ gst_plugin_feature_list_free(demuxer_list_two);
|
||||
+
|
||||
+ TRACE("Found demuxer %s.\n", GST_ELEMENT_NAME(demuxer_factory));
|
||||
+
|
||||
+ object->demuxer = gst_element_factory_create(demuxer_factory, NULL);
|
||||
+ if (!(object->demuxer))
|
||||
+ {
|
||||
+ WARN("Failed to create demuxer for source\n");
|
||||
+ hr = E_OUTOFMEMORY;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ gst_bin_add(GST_BIN(object->container), object->demuxer);
|
||||
+
|
||||
+ object->their_sink = gst_element_get_static_pad(object->demuxer, "sink");
|
||||
+
|
||||
+ if ((ret = gst_pad_link(object->my_src, object->their_sink)) < 0)
|
||||
+ {
|
||||
+ WARN("Failed to link our bytestream pad to the demuxer input\n");
|
||||
+ hr = E_OUTOFMEMORY;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
object->state = SOURCE_STOPPED;
|
||||
|
||||
*out_media_source = object;
|
||||
@@ -437,6 +526,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
|
||||
fail:
|
||||
WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
|
||||
|
||||
+ if (demuxer_factory)
|
||||
+ gst_object_unref(demuxer_factory);
|
||||
media_source_teardown(object);
|
||||
heap_free(object);
|
||||
*out_media_source = NULL;
|
||||
@@ -935,6 +1026,12 @@ void perform_cb_media_source(struct cb_data *cbdata)
|
||||
cbdata->u.event_src_data.ret = process_bytestream_pad_event(data->pad, data->parent, data->event);
|
||||
break;
|
||||
}
|
||||
+ case WATCH_SOURCE_BUS:
|
||||
+ {
|
||||
+ struct watch_bus_data *data = &cbdata->u.watch_bus_data;
|
||||
+ cbdata->u.watch_bus_data.ret = watch_source_bus(data->bus, data->msg, data->user);
|
||||
+ break;
|
||||
+ }
|
||||
default:
|
||||
{
|
||||
ERR("Wrong callback forwarder called\n");
|
||||
--
|
||||
2.28.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,327 @@
|
||||
From c8d76047c38b229c76f6ecd810e0fdb2f73ee788 Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Tue, 31 Mar 2020 11:11:05 -0500
|
||||
Subject: [PATCH 12/54] winegstreamer: Implement
|
||||
IMFMediaStream::GetStreamDescriptor.
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/winegstreamer/gst_private.h | 4 +
|
||||
dlls/winegstreamer/media_source.c | 45 ++++++-
|
||||
dlls/winegstreamer/mfplat.c | 196 ++++++++++++++++++++++++++++++
|
||||
3 files changed, 244 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
|
||||
index 71ca429088..780cf1b02f 100644
|
||||
--- a/dlls/winegstreamer/gst_private.h
|
||||
+++ b/dlls/winegstreamer/gst_private.h
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "winuser.h"
|
||||
#include "dshow.h"
|
||||
#include "strmif.h"
|
||||
+#include "mfobjects.h"
|
||||
#include "wine/heap.h"
|
||||
#include "wine/strmbase.h"
|
||||
|
||||
@@ -54,6 +55,9 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
|
||||
|
||||
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
||||
|
||||
+GstCaps *make_mf_compatible_caps(GstCaps *caps);
|
||||
+IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
|
||||
+
|
||||
enum source_type
|
||||
{
|
||||
SOURCE_TYPE_MPEG_4,
|
||||
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
|
||||
index 8335c64338..a654d555bc 100644
|
||||
--- a/dlls/winegstreamer/media_source.c
|
||||
+++ b/dlls/winegstreamer/media_source.c
|
||||
@@ -507,7 +507,10 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
|
||||
if (stream->state == STREAM_SHUTDOWN)
|
||||
return MF_E_SHUTDOWN;
|
||||
|
||||
- return E_NOTIMPL;
|
||||
+ IMFStreamDescriptor_AddRef(stream->descriptor);
|
||||
+ *descriptor = stream->descriptor;
|
||||
+
|
||||
+ return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
|
||||
@@ -539,6 +542,9 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
|
||||
static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
|
||||
{
|
||||
struct media_stream *object = heap_alloc_zero(sizeof(*object));
|
||||
+ IMFMediaTypeHandler *type_handler = NULL;
|
||||
+ IMFMediaType *stream_type = NULL;
|
||||
+ GstCaps *caps = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
|
||||
@@ -567,6 +573,36 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
|
||||
g_object_set(object->appsink, "async", FALSE, NULL); /* <- This allows us interact with the bin w/o prerolling */
|
||||
g_signal_connect(object->appsink, "new-sample", G_CALLBACK(stream_new_sample_wrapper), object);
|
||||
|
||||
+ if (!(caps = gst_pad_query_caps(pad, NULL)))
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (TRACE_ON(mfplat))
|
||||
+ {
|
||||
+ gchar *caps_str = gst_caps_to_string(caps);
|
||||
+ TRACE("caps %s\n", debugstr_a(caps_str));
|
||||
+ g_free(caps_str);
|
||||
+ }
|
||||
+
|
||||
+ if (!(stream_type = mf_media_type_from_caps(caps)))
|
||||
+ goto fail;
|
||||
+
|
||||
+ gst_caps_unref(caps);
|
||||
+ caps = NULL;
|
||||
+
|
||||
+ if (FAILED(hr = MFCreateStreamDescriptor(stream_id, 1, &stream_type, &object->descriptor)))
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(object->descriptor, &type_handler)))
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type)))
|
||||
+ goto fail;
|
||||
+
|
||||
+ IMFMediaTypeHandler_Release(type_handler);
|
||||
+ type_handler = NULL;
|
||||
+ IMFMediaType_Release(stream_type);
|
||||
+ stream_type = NULL;
|
||||
+
|
||||
object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
|
||||
gst_pad_set_element_private(pad, object);
|
||||
|
||||
@@ -582,6 +618,13 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
|
||||
fail:
|
||||
WARN("Failed to construct media stream, hr %#x.\n", hr);
|
||||
|
||||
+ if (caps)
|
||||
+ gst_caps_unref(caps);
|
||||
+ if (stream_type)
|
||||
+ IMFMediaType_Release(stream_type);
|
||||
+ if (type_handler)
|
||||
+ IMFMediaTypeHandler_Release(type_handler);
|
||||
+
|
||||
IMFMediaStream_Release(&object->IMFMediaStream_iface);
|
||||
return hr;
|
||||
}
|
||||
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
|
||||
index 16e55247de..90eb583c4a 100644
|
||||
--- a/dlls/winegstreamer/mfplat.c
|
||||
+++ b/dlls/winegstreamer/mfplat.c
|
||||
@@ -16,6 +16,11 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
+#include "config.h"
|
||||
+#include <gst/gst.h>
|
||||
+
|
||||
+#include "gst_private.h"
|
||||
+
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "gst_private.h"
|
||||
@@ -442,3 +447,194 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
|
||||
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
+
|
||||
+const static struct
|
||||
+{
|
||||
+ const GUID *subtype;
|
||||
+ GstVideoFormat format;
|
||||
+}
|
||||
+uncompressed_formats[] =
|
||||
+{
|
||||
+ {&MFVideoFormat_ARGB32, GST_VIDEO_FORMAT_BGRA},
|
||||
+ {&MFVideoFormat_RGB32, GST_VIDEO_FORMAT_BGRx},
|
||||
+ {&MFVideoFormat_RGB24, GST_VIDEO_FORMAT_BGR},
|
||||
+ {&MFVideoFormat_RGB565, GST_VIDEO_FORMAT_BGR16},
|
||||
+ {&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15},
|
||||
+};
|
||||
+
|
||||
+/* caps will be modified to represent the exact type needed for the format */
|
||||
+static IMFMediaType* transform_to_media_type(GstCaps *caps)
|
||||
+{
|
||||
+ IMFMediaType *media_type;
|
||||
+ GstStructure *info;
|
||||
+ const char *mime_type;
|
||||
+
|
||||
+ if (TRACE_ON(mfplat))
|
||||
+ {
|
||||
+ gchar *human_readable = gst_caps_to_string(caps);
|
||||
+ TRACE("caps = %s\n", debugstr_a(human_readable));
|
||||
+ g_free(human_readable);
|
||||
+ }
|
||||
+
|
||||
+ if (FAILED(MFCreateMediaType(&media_type)))
|
||||
+ {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ info = gst_caps_get_structure(caps, 0);
|
||||
+ mime_type = gst_structure_get_name(info);
|
||||
+
|
||||
+ if (!(strncmp(mime_type, "video", 5)))
|
||||
+ {
|
||||
+ GstVideoInfo video_info;
|
||||
+
|
||||
+ if (!(gst_video_info_from_caps(&video_info, caps)))
|
||||
+ {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
||||
+
|
||||
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)video_info.width << 32) | video_info.height);
|
||||
+
|
||||
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ((UINT64)video_info.fps_n << 32) | video_info.fps_d);
|
||||
+
|
||||
+ if (!(strcmp(mime_type, "video/x-raw")))
|
||||
+ {
|
||||
+ GUID fourcc_subtype = MFVideoFormat_Base;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, FALSE);
|
||||
+
|
||||
+ /* First try FOURCC */
|
||||
+ if ((fourcc_subtype.Data1 = gst_video_format_to_fourcc(video_info.finfo->format)))
|
||||
+ {
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &fourcc_subtype);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ for (i = 0; i < ARRAY_SIZE(uncompressed_formats); i++)
|
||||
+ {
|
||||
+ if (uncompressed_formats[i].format == video_info.finfo->format)
|
||||
+ {
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, uncompressed_formats[i].subtype);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (i == ARRAY_SIZE(uncompressed_formats))
|
||||
+ FIXME("Unrecognized format.\n");
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ FIXME("Unrecognized video format %s\n", mime_type);
|
||||
+ }
|
||||
+ else if (!(strncmp(mime_type, "audio", 5)))
|
||||
+ {
|
||||
+ gint rate, channels, bitrate;
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
|
||||
+
|
||||
+ if (gst_structure_get_int(info, "rate", &rate))
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, rate);
|
||||
+
|
||||
+ if (gst_structure_get_int(info, "channels", &channels))
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channels);
|
||||
+
|
||||
+ if (gst_structure_get_int(info, "bitrate", &bitrate))
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AVG_BITRATE, bitrate);
|
||||
+
|
||||
+ if (!(strcmp(mime_type, "audio/x-raw")))
|
||||
+ {
|
||||
+ const char *format;
|
||||
+ if ((format = gst_structure_get_string(info, "format")))
|
||||
+ {
|
||||
+ char type;
|
||||
+ unsigned int bits_per_sample;
|
||||
+ char endian[2];
|
||||
+ char new_format[6];
|
||||
+ if ((strlen(format) > 5) || (sscanf(format, "%c%u%2c", &type, &bits_per_sample, endian) < 2))
|
||||
+ {
|
||||
+ FIXME("Unhandled audio format %s\n", format);
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (type == 'F')
|
||||
+ {
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float);
|
||||
+ }
|
||||
+ else if (type == 'U' || type == 'S')
|
||||
+ {
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
|
||||
+ if (bits_per_sample == 8)
|
||||
+ type = 'U';
|
||||
+ else
|
||||
+ type = 'S';
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ FIXME("Unrecognized audio format: %s\n", format);
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, bits_per_sample);
|
||||
+
|
||||
+ if (endian[0] == 'B')
|
||||
+ endian[0] = 'L';
|
||||
+
|
||||
+ sprintf(new_format, "%c%u%.2s", type, bits_per_sample, bits_per_sample > 8 ? endian : 0);
|
||||
+ gst_caps_set_simple(caps, "format", G_TYPE_STRING, new_format, NULL);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ERR("Failed to get audio format\n");
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ FIXME("Unrecognized audio format %s\n", mime_type);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ return media_type;
|
||||
+}
|
||||
+
|
||||
+/* returns NULL if doesn't match exactly */
|
||||
+IMFMediaType *mf_media_type_from_caps(GstCaps *caps)
|
||||
+{
|
||||
+ GstCaps *writeable_caps;
|
||||
+ IMFMediaType *ret;
|
||||
+
|
||||
+ writeable_caps = gst_caps_copy(caps);
|
||||
+ ret = transform_to_media_type(writeable_caps);
|
||||
+
|
||||
+ if (!(gst_caps_is_equal(caps, writeable_caps)))
|
||||
+ {
|
||||
+ IMFMediaType_Release(ret);
|
||||
+ ret = NULL;
|
||||
+ }
|
||||
+ gst_caps_unref(writeable_caps);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+GstCaps *make_mf_compatible_caps(GstCaps *caps)
|
||||
+{
|
||||
+ GstCaps *ret;
|
||||
+ IMFMediaType *media_type;
|
||||
+
|
||||
+ ret = gst_caps_copy(caps);
|
||||
+
|
||||
+ if ((media_type = transform_to_media_type(ret)))
|
||||
+ IMFMediaType_Release(media_type);
|
||||
+
|
||||
+ if (!media_type)
|
||||
+ {
|
||||
+ gst_caps_unref(ret);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,98 @@
|
||||
From a3c30ab707ba1b3216cdad1a8543839d0b04568a Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Tue, 24 Mar 2020 16:00:26 -0500
|
||||
Subject: [PATCH 13/54] winegstreamer: Translate H.264 caps to attributes.
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/winegstreamer/mfplat.c | 67 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 67 insertions(+)
|
||||
|
||||
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
|
||||
index 90eb583c4a..1b37e1cc90 100644
|
||||
--- a/dlls/winegstreamer/mfplat.c
|
||||
+++ b/dlls/winegstreamer/mfplat.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "gst_private.h"
|
||||
#include "mfapi.h"
|
||||
#include "mfidl.h"
|
||||
+#include "codecapi.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/heap.h"
|
||||
@@ -525,6 +526,72 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
|
||||
FIXME("Unrecognized format.\n");
|
||||
}
|
||||
}
|
||||
+ else if (!(strcmp(mime_type, "video/x-h264")))
|
||||
+ {
|
||||
+ const char *profile, *level;
|
||||
+
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_H264);
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, TRUE);
|
||||
+
|
||||
+ if ((profile = gst_structure_get_string(info, "profile")))
|
||||
+ {
|
||||
+ if (!(strcmp(profile, "main")))
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Main);
|
||||
+ else if (!(strcmp(profile, "high")))
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_High);
|
||||
+ else if (!(strcmp(profile, "high-4:4:4")))
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_444);
|
||||
+ else
|
||||
+ FIXME("Unrecognized profile %s\n", profile);
|
||||
+ }
|
||||
+ if ((level = gst_structure_get_string(info, "level")))
|
||||
+ {
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ const static struct
|
||||
+ {
|
||||
+ const char *name;
|
||||
+ enum eAVEncH264VLevel val;
|
||||
+ } levels[] =
|
||||
+ {
|
||||
+ {"1", eAVEncH264VLevel1},
|
||||
+ {"1.1", eAVEncH264VLevel1_1},
|
||||
+ {"1.2", eAVEncH264VLevel1_2},
|
||||
+ {"1.3", eAVEncH264VLevel1_3},
|
||||
+ {"2", eAVEncH264VLevel2},
|
||||
+ {"2.1", eAVEncH264VLevel2_1},
|
||||
+ {"2.2", eAVEncH264VLevel2_2},
|
||||
+ {"3", eAVEncH264VLevel3},
|
||||
+ {"3.1", eAVEncH264VLevel3_1},
|
||||
+ {"3.2", eAVEncH264VLevel3_2},
|
||||
+ {"4", eAVEncH264VLevel4},
|
||||
+ {"4.1", eAVEncH264VLevel4_1},
|
||||
+ {"4.2", eAVEncH264VLevel4_2},
|
||||
+ {"5", eAVEncH264VLevel5},
|
||||
+ {"5.1", eAVEncH264VLevel5_1},
|
||||
+ {"5.2", eAVEncH264VLevel5_2},
|
||||
+ };
|
||||
+ for (i = 0 ; i < ARRAY_SIZE(levels); i++)
|
||||
+ {
|
||||
+ if (!(strcmp(level, levels[i].name)))
|
||||
+ {
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_LEVEL, levels[i].val);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (i == ARRAY_SIZE(levels))
|
||||
+ {
|
||||
+ FIXME("Unrecognized level %s", level);
|
||||
+ }
|
||||
+ }
|
||||
+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL);
|
||||
+ gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL);
|
||||
+ for (unsigned int i = 0; i < gst_caps_get_size(caps); i++)
|
||||
+ {
|
||||
+ GstStructure *structure = gst_caps_get_structure (caps, i);
|
||||
+ gst_structure_remove_field(structure, "codec_data");
|
||||
+ }
|
||||
+ }
|
||||
else
|
||||
FIXME("Unrecognized video format %s\n", mime_type);
|
||||
}
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,82 @@
|
||||
From 3c23e1570ad895c52069c895a3e50353730d20c1 Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Tue, 24 Mar 2020 16:01:20 -0500
|
||||
Subject: [PATCH 14/54] winegstreamer: Translate WMV caps to attributes.
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/winegstreamer/mfplat.c | 51 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 51 insertions(+)
|
||||
|
||||
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
|
||||
index 1b37e1cc90..96195c887c 100644
|
||||
--- a/dlls/winegstreamer/mfplat.c
|
||||
+++ b/dlls/winegstreamer/mfplat.c
|
||||
@@ -463,6 +463,24 @@ uncompressed_formats[] =
|
||||
{&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15},
|
||||
};
|
||||
|
||||
+static void codec_data_to_user_data(GstStructure *structure, IMFMediaType *type)
|
||||
+{
|
||||
+ const GValue *codec_data;
|
||||
+
|
||||
+ if ((codec_data = gst_structure_get_value(structure, "codec_data")))
|
||||
+ {
|
||||
+ GstBuffer *codec_data_buffer = gst_value_get_buffer(codec_data);
|
||||
+ if (codec_data_buffer)
|
||||
+ {
|
||||
+ gsize codec_data_size = gst_buffer_get_size(codec_data_buffer);
|
||||
+ gpointer codec_data_raw = heap_alloc(codec_data_size);
|
||||
+ gst_buffer_extract(codec_data_buffer, 0, codec_data_raw, codec_data_size);
|
||||
+ IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, codec_data_raw, codec_data_size);
|
||||
+ heap_free(codec_data_raw);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* caps will be modified to represent the exact type needed for the format */
|
||||
static IMFMediaType* transform_to_media_type(GstCaps *caps)
|
||||
{
|
||||
@@ -592,6 +610,39 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
|
||||
gst_structure_remove_field(structure, "codec_data");
|
||||
}
|
||||
}
|
||||
+ else if (!(strcmp(mime_type, "video/x-wmv")))
|
||||
+ {
|
||||
+ gint wmv_version;
|
||||
+ const char *format;
|
||||
+
|
||||
+ if (gst_structure_get_int(info, "wmvversion", &wmv_version))
|
||||
+ {
|
||||
+ switch (wmv_version)
|
||||
+ {
|
||||
+ case 1:
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV1);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV2);
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV3);
|
||||
+ break;
|
||||
+ default:
|
||||
+ FIXME("Unrecognized wmvversion %d\n", wmv_version);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if ((format = gst_structure_get_string(info, "format")))
|
||||
+ {
|
||||
+ if (!(strcmp(format, "WVC1")))
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WVC1);
|
||||
+ else
|
||||
+ FIXME("Unrecognized format %s\n", format);
|
||||
+ }
|
||||
+
|
||||
+ codec_data_to_user_data(info, media_type);
|
||||
+ }
|
||||
else
|
||||
FIXME("Unrecognized video format %s\n", mime_type);
|
||||
}
|
||||
--
|
||||
2.28.0
|
||||
|
@@ -0,0 +1,138 @@
|
||||
From 13019300d005d7bcea386435894841a7154231e9 Mon Sep 17 00:00:00 2001
|
||||
From: Derek Lesho <dlesho@codeweavers.com>
|
||||
Date: Tue, 24 Mar 2020 16:02:27 -0500
|
||||
Subject: [PATCH 15/54] winegstreamer: Translate AAC caps to attributes.
|
||||
|
||||
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
|
||||
---
|
||||
dlls/winegstreamer/mfplat.c | 107 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 107 insertions(+)
|
||||
|
||||
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
|
||||
index 96195c887c..ecb5de8b88 100644
|
||||
--- a/dlls/winegstreamer/mfplat.c
|
||||
+++ b/dlls/winegstreamer/mfplat.c
|
||||
@@ -463,6 +463,15 @@ uncompressed_formats[] =
|
||||
{&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15},
|
||||
};
|
||||
|
||||
+struct aac_user_data
|
||||
+{
|
||||
+ WORD payload_type;
|
||||
+ WORD profile_level_indication;
|
||||
+ WORD struct_type;
|
||||
+ WORD reserved;
|
||||
+ /* audio-specific-config is stored here */
|
||||
+};
|
||||
+
|
||||
static void codec_data_to_user_data(GstStructure *structure, IMFMediaType *type)
|
||||
{
|
||||
const GValue *codec_data;
|
||||
@@ -708,6 +717,104 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
|
||||
ERR("Failed to get audio format\n");
|
||||
}
|
||||
}
|
||||
+ else if (!(strcmp(mime_type, "audio/mpeg")))
|
||||
+ {
|
||||
+ int mpeg_version = -1;
|
||||
+
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, TRUE);
|
||||
+
|
||||
+ if (!(gst_structure_get_int(info, "mpegversion", &mpeg_version)))
|
||||
+ ERR("Failed to get mpegversion\n");
|
||||
+ switch (mpeg_version)
|
||||
+ {
|
||||
+ case 2:
|
||||
+ case 4:
|
||||
+ {
|
||||
+ const char *format, *profile, *level;
|
||||
+ DWORD profile_level_indication = 0;
|
||||
+ const GValue *codec_data;
|
||||
+ DWORD asc_size = 0;
|
||||
+ struct aac_user_data *user_data = NULL;
|
||||
+
|
||||
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_AAC);
|
||||
+
|
||||
+ codec_data = gst_structure_get_value(info, "codec_data");
|
||||
+ if (codec_data)
|
||||
+ {
|
||||
+ GstBuffer *codec_data_buffer = gst_value_get_buffer(codec_data);
|
||||
+ if (codec_data_buffer)
|
||||
+ {
|
||||
+ if ((asc_size = gst_buffer_get_size(codec_data_buffer)) >= 2)
|
||||
+ {
|
||||
+ user_data = heap_alloc_zero(sizeof(*user_data)+asc_size);
|
||||
+ gst_buffer_extract(codec_data_buffer, 0, (gpointer)(user_data + 1), asc_size);
|
||||
+ }
|
||||
+ else
|
||||
+ ERR("Unexpected buffer size\n");
|
||||
+ }
|
||||
+ else
|
||||
+ ERR("codec_data not a buffer\n");
|
||||
+ }
|
||||
+ else
|
||||
+ ERR("codec_data not found\n");
|
||||
+ if (!user_data)
|
||||
+ user_data = heap_alloc_zero(sizeof(*user_data));
|
||||
+
|
||||
+ if ((format = gst_structure_get_string(info, "stream-format")))
|
||||
+ {
|
||||
+ DWORD payload_type = -1;
|
||||
+ if (!(strcmp(format, "raw")))
|
||||
+ payload_type = 0;
|
||||
+ else if (!(strcmp(format, "adts")))
|
||||
+ payload_type = 1;
|
||||
+ else if (!(strcmp(format, "adif")))
|
||||
+ payload_type = 2;
|
||||
+ else if (!(strcmp(format, "loas")))
|
||||
+ payload_type = 3;
|
||||
+ else
|
||||
+ FIXME("Unrecognized stream-format\n");
|
||||
+ if (payload_type != -1)
|
||||
+ {
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_PAYLOAD_TYPE, payload_type);
|
||||
+ user_data->payload_type = payload_type;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ERR("Stream format not present\n");
|
||||
+ }
|
||||
+
|
||||
+ profile = gst_structure_get_string(info, "profile");
|
||||
+ level = gst_structure_get_string(info, "level");
|
||||
+ /* Data from http://archive.is/whp6P#45% */
|
||||
+ if (profile && level)
|
||||
+ {
|
||||
+ if (!(strcmp(profile, "lc")) && !(strcmp(level, "2")))
|
||||
+ profile_level_indication = 0x29;
|
||||
+ else if (!(strcmp(profile, "lc")) && !(strcmp(level, "4")))
|
||||
+ profile_level_indication = 0x2A;
|
||||
+ else if (!(strcmp(profile, "lc")) && !(strcmp(level, "5")))
|
||||
+ profile_level_indication = 0x2B;
|
||||
+ else
|
||||
+ FIXME("Unhandled profile/level combo\n");
|
||||
+ }
|
||||
+ else
|
||||
+ ERR("Profile or level not present\n");
|
||||
+
|
||||
+ if (profile_level_indication)
|
||||
+ {
|
||||
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, profile_level_indication);
|
||||
+ user_data->profile_level_indication = profile_level_indication;
|
||||
+ }
|
||||
+
|
||||
+ IMFMediaType_SetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)user_data, sizeof(*user_data) + asc_size);
|
||||
+ heap_free(user_data);
|
||||
+ break;
|
||||
+ }
|
||||
+ default:
|
||||
+ FIXME("Unhandled mpegversion %d\n", mpeg_version);
|
||||
+ }
|
||||
+ }
|
||||
else
|
||||
FIXME("Unrecognized audio format %s\n", mime_type);
|
||||
}
|
||||
--
|
||||
2.28.0
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user