6672 lines
198 KiB
C
6672 lines
198 KiB
C
/*
|
|
* Copyright 2014 Austin English
|
|
*
|
|
* 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 <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#define COBJMACROS
|
|
#define NONAMELESSUNION
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "winreg.h"
|
|
|
|
#include "initguid.h"
|
|
#include "ole2.h"
|
|
#include "propsys.h"
|
|
|
|
#include "wine/debug.h"
|
|
#include "wine/unicode.h"
|
|
#include "wine/list.h"
|
|
|
|
#include "mfplat_private.h"
|
|
#include "mfreadwrite.h"
|
|
#include "propvarutil.h"
|
|
#include "strsafe.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
|
|
|
|
static LONG platform_lock;
|
|
|
|
struct system_time_source
|
|
{
|
|
IMFPresentationTimeSource IMFPresentationTimeSource_iface;
|
|
IMFClockStateSink IMFClockStateSink_iface;
|
|
LONG refcount;
|
|
MFCLOCK_STATE state;
|
|
CRITICAL_SECTION cs;
|
|
};
|
|
|
|
static struct system_time_source *impl_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct system_time_source, IMFPresentationTimeSource_iface);
|
|
}
|
|
|
|
static struct system_time_source *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct system_time_source, IMFClockStateSink_iface);
|
|
}
|
|
|
|
static const WCHAR transform_keyW[] = {'M','e','d','i','a','F','o','u','n','d','a','t','i','o','n','\\',
|
|
'T','r','a','n','s','f','o','r','m','s',0};
|
|
static const WCHAR categories_keyW[] = {'M','e','d','i','a','F','o','u','n','d','a','t','i','o','n','\\',
|
|
'T','r','a','n','s','f','o','r','m','s','\\',
|
|
'C','a','t','e','g','o','r','i','e','s',0};
|
|
static const WCHAR inputtypesW[] = {'I','n','p','u','t','T','y','p','e','s',0};
|
|
static const WCHAR outputtypesW[] = {'O','u','t','p','u','t','T','y','p','e','s',0};
|
|
static const WCHAR szGUIDFmt[] =
|
|
{
|
|
'%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0',
|
|
'2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2',
|
|
'x','%','0','2','x','%','0','2','x','%','0','2','x',0
|
|
};
|
|
|
|
static const BYTE guid_conv_table[256] =
|
|
{
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
|
|
0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
|
|
0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
|
|
};
|
|
|
|
static WCHAR* GUIDToString(WCHAR *str, REFGUID guid)
|
|
{
|
|
sprintfW(str, szGUIDFmt, guid->Data1, guid->Data2,
|
|
guid->Data3, guid->Data4[0], guid->Data4[1],
|
|
guid->Data4[2], guid->Data4[3], guid->Data4[4],
|
|
guid->Data4[5], guid->Data4[6], guid->Data4[7]);
|
|
|
|
return str;
|
|
}
|
|
|
|
static inline BOOL is_valid_hex(WCHAR c)
|
|
{
|
|
if (!(((c >= '0') && (c <= '9')) ||
|
|
((c >= 'a') && (c <= 'f')) ||
|
|
((c >= 'A') && (c <= 'F'))))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL GUIDFromString(LPCWSTR s, GUID *id)
|
|
{
|
|
int i;
|
|
|
|
/* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */
|
|
|
|
id->Data1 = 0;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (!is_valid_hex(s[i])) return FALSE;
|
|
id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
|
|
}
|
|
if (s[8]!='-') return FALSE;
|
|
|
|
id->Data2 = 0;
|
|
for (i = 9; i < 13; i++)
|
|
{
|
|
if (!is_valid_hex(s[i])) return FALSE;
|
|
id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
|
|
}
|
|
if (s[13]!='-') return FALSE;
|
|
|
|
id->Data3 = 0;
|
|
for (i = 14; i < 18; i++)
|
|
{
|
|
if (!is_valid_hex(s[i])) return FALSE;
|
|
id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
|
|
}
|
|
if (s[18]!='-') return FALSE;
|
|
|
|
for (i = 19; i < 36; i+=2)
|
|
{
|
|
if (i == 23)
|
|
{
|
|
if (s[i]!='-') return FALSE;
|
|
i++;
|
|
}
|
|
if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
|
|
id->Data4[(i-19)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
|
|
}
|
|
|
|
if (!s[37]) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
|
|
{
|
|
switch (reason)
|
|
{
|
|
case DLL_WINE_PREATTACH:
|
|
return FALSE; /* prefer native version */
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls(instance);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static HRESULT register_transform(CLSID *clsid, WCHAR *name,
|
|
UINT32 cinput, MFT_REGISTER_TYPE_INFO *input_types,
|
|
UINT32 coutput, MFT_REGISTER_TYPE_INFO *output_types)
|
|
{
|
|
static const WCHAR reg_format[] = {'%','s','\\','%','s',0};
|
|
HKEY hclsid = 0;
|
|
WCHAR buffer[64];
|
|
DWORD size;
|
|
WCHAR str[250];
|
|
|
|
GUIDToString(buffer, clsid);
|
|
sprintfW(str, reg_format, transform_keyW, buffer);
|
|
|
|
if (RegCreateKeyW(HKEY_CLASSES_ROOT, str, &hclsid))
|
|
return E_FAIL;
|
|
|
|
size = (strlenW(name) + 1) * sizeof(WCHAR);
|
|
if (RegSetValueExW(hclsid, NULL, 0, REG_SZ, (BYTE *)name, size))
|
|
goto err;
|
|
|
|
if (cinput && input_types)
|
|
{
|
|
size = cinput * sizeof(MFT_REGISTER_TYPE_INFO);
|
|
if (RegSetValueExW(hclsid, inputtypesW, 0, REG_BINARY, (BYTE *)input_types, size))
|
|
goto err;
|
|
}
|
|
|
|
if (coutput && output_types)
|
|
{
|
|
size = coutput * sizeof(MFT_REGISTER_TYPE_INFO);
|
|
if (RegSetValueExW(hclsid, outputtypesW, 0, REG_BINARY, (BYTE *)output_types, size))
|
|
goto err;
|
|
}
|
|
|
|
RegCloseKey(hclsid);
|
|
return S_OK;
|
|
|
|
err:
|
|
RegCloseKey(hclsid);
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT register_category(CLSID *clsid, GUID *category)
|
|
{
|
|
static const WCHAR reg_format[] = {'%','s','\\','%','s','\\','%','s',0};
|
|
HKEY htmp1;
|
|
WCHAR guid1[64], guid2[64];
|
|
WCHAR str[350];
|
|
|
|
GUIDToString(guid1, category);
|
|
GUIDToString(guid2, clsid);
|
|
|
|
sprintfW(str, reg_format, categories_keyW, guid1, guid2);
|
|
|
|
if (RegCreateKeyW(HKEY_CLASSES_ROOT, str, &htmp1))
|
|
return E_FAIL;
|
|
|
|
RegCloseKey(htmp1);
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFTRegister (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFTRegister(CLSID clsid, GUID category, LPWSTR name, UINT32 flags, UINT32 cinput,
|
|
MFT_REGISTER_TYPE_INFO *input_types, UINT32 coutput,
|
|
MFT_REGISTER_TYPE_INFO *output_types, IMFAttributes *attributes)
|
|
{
|
|
HRESULT hr;
|
|
|
|
TRACE("(%s, %s, %s, %x, %u, %p, %u, %p, %p)\n", debugstr_guid(&clsid), debugstr_guid(&category),
|
|
debugstr_w(name), flags, cinput, input_types,
|
|
coutput, output_types, attributes);
|
|
|
|
if (attributes)
|
|
FIXME("attributes not yet supported.\n");
|
|
|
|
if (flags)
|
|
FIXME("flags not yet supported.\n");
|
|
|
|
hr = register_transform(&clsid, name, cinput, input_types, coutput, output_types);
|
|
if(FAILED(hr))
|
|
ERR("Failed to write register transform\n");
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = register_category(&clsid, &category);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT WINAPI MFTRegisterLocal(IClassFactory *factory, REFGUID category, LPCWSTR name,
|
|
UINT32 flags, UINT32 cinput, const MFT_REGISTER_TYPE_INFO *input_types,
|
|
UINT32 coutput, const MFT_REGISTER_TYPE_INFO* output_types)
|
|
{
|
|
FIXME("(%p, %s, %s, %x, %u, %p, %u, %p)\n", factory, debugstr_guid(category), debugstr_w(name),
|
|
flags, cinput, input_types, coutput, output_types);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory)
|
|
{
|
|
FIXME("(%p)\n", factory);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
MFTIME WINAPI MFGetSystemTime(void)
|
|
{
|
|
MFTIME mf;
|
|
|
|
TRACE("()\n");
|
|
|
|
GetSystemTimeAsFileTime( (FILETIME*)&mf );
|
|
|
|
return mf;
|
|
}
|
|
|
|
static BOOL match_type(const WCHAR *clsid_str, const WCHAR *type_str, MFT_REGISTER_TYPE_INFO *type)
|
|
{
|
|
HKEY htransform, hfilter;
|
|
DWORD reg_type, size;
|
|
LONG ret = FALSE;
|
|
MFT_REGISTER_TYPE_INFO *info = NULL;
|
|
int i;
|
|
|
|
if (RegOpenKeyW(HKEY_CLASSES_ROOT, transform_keyW, &htransform))
|
|
return FALSE;
|
|
|
|
if (RegOpenKeyW(htransform, clsid_str, &hfilter))
|
|
{
|
|
RegCloseKey(htransform);
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegQueryValueExW(hfilter, type_str, NULL, ®_type, NULL, &size) != ERROR_SUCCESS)
|
|
goto out;
|
|
|
|
if (reg_type != REG_BINARY)
|
|
goto out;
|
|
|
|
if (!size || size % (sizeof(MFT_REGISTER_TYPE_INFO)) != 0)
|
|
goto out;
|
|
|
|
info = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (!info)
|
|
goto out;
|
|
|
|
if (RegQueryValueExW(hfilter, type_str, NULL, ®_type, (LPBYTE)info, &size) != ERROR_SUCCESS)
|
|
goto out;
|
|
|
|
for (i = 0; i < size / sizeof(MFT_REGISTER_TYPE_INFO); i++)
|
|
{
|
|
if (IsEqualGUID(&info[i].guidMajorType, &type->guidMajorType) &&
|
|
IsEqualGUID(&info[i].guidSubtype, &type->guidSubtype))
|
|
{
|
|
ret = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
HeapFree(GetProcessHeap(), 0, info);
|
|
RegCloseKey(hfilter);
|
|
RegCloseKey(htransform);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFTEnum (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type,
|
|
MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes,
|
|
CLSID **pclsids, UINT32 *pcount)
|
|
{
|
|
WCHAR buffer[64], clsid_str[MAX_PATH] = {0};
|
|
HKEY hcategory, hlist;
|
|
DWORD index = 0;
|
|
DWORD size = MAX_PATH;
|
|
CLSID *clsids = NULL;
|
|
UINT32 count = 0;
|
|
LONG ret;
|
|
|
|
TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_guid(&category), flags, input_type,
|
|
output_type, attributes, pclsids, pcount);
|
|
|
|
if (!pclsids || !pcount)
|
|
return E_INVALIDARG;
|
|
|
|
if (RegOpenKeyW(HKEY_CLASSES_ROOT, categories_keyW, &hcategory))
|
|
return E_FAIL;
|
|
|
|
GUIDToString(buffer, &category);
|
|
|
|
ret = RegOpenKeyW(hcategory, buffer, &hlist);
|
|
RegCloseKey(hcategory);
|
|
if (ret) return E_FAIL;
|
|
|
|
while (RegEnumKeyExW(hlist, index, clsid_str, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
{
|
|
GUID clsid;
|
|
void *tmp;
|
|
|
|
if (!GUIDFromString(clsid_str, &clsid))
|
|
goto next;
|
|
|
|
if (output_type && !match_type(clsid_str, outputtypesW, output_type))
|
|
goto next;
|
|
|
|
if (input_type && !match_type(clsid_str, inputtypesW, input_type))
|
|
goto next;
|
|
|
|
tmp = CoTaskMemRealloc(clsids, (count + 1) * sizeof(GUID));
|
|
if (!tmp)
|
|
{
|
|
CoTaskMemFree(clsids);
|
|
RegCloseKey(hlist);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
clsids = tmp;
|
|
clsids[count++] = clsid;
|
|
|
|
next:
|
|
size = MAX_PATH;
|
|
index++;
|
|
}
|
|
|
|
*pclsids = clsids;
|
|
*pcount = count;
|
|
|
|
RegCloseKey(hlist);
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFTEnumEx (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_INFO *input_type,
|
|
const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate,
|
|
UINT32 *pcount)
|
|
{
|
|
FIXME("(%s, %x, %p, %p, %p, %p): stub\n", debugstr_guid(&category), flags, input_type,
|
|
output_type, activate, pcount);
|
|
|
|
*pcount = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFTUnregister (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFTUnregister(CLSID clsid)
|
|
{
|
|
WCHAR buffer[64], category[MAX_PATH];
|
|
HKEY htransform, hcategory, htmp;
|
|
DWORD size = MAX_PATH;
|
|
DWORD index = 0;
|
|
|
|
TRACE("(%s)\n", debugstr_guid(&clsid));
|
|
|
|
GUIDToString(buffer, &clsid);
|
|
|
|
if (!RegOpenKeyW(HKEY_CLASSES_ROOT, transform_keyW, &htransform))
|
|
{
|
|
RegDeleteKeyW(htransform, buffer);
|
|
RegCloseKey(htransform);
|
|
}
|
|
|
|
if (!RegOpenKeyW(HKEY_CLASSES_ROOT, categories_keyW, &hcategory))
|
|
{
|
|
while (RegEnumKeyExW(hcategory, index, category, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (!RegOpenKeyW(hcategory, category, &htmp))
|
|
{
|
|
RegDeleteKeyW(htmp, buffer);
|
|
RegCloseKey(htmp);
|
|
}
|
|
size = MAX_PATH;
|
|
index++;
|
|
}
|
|
RegCloseKey(hcategory);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFStartup (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFStartup(ULONG version, DWORD flags)
|
|
{
|
|
#define MF_VERSION_XP MAKELONG( MF_API_VERSION, 1 )
|
|
#define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 )
|
|
|
|
TRACE("%#x, %#x.\n", version, flags);
|
|
|
|
if (version != MF_VERSION_XP && version != MF_VERSION_WIN7)
|
|
return MF_E_BAD_STARTUP_VERSION;
|
|
|
|
if (InterlockedIncrement(&platform_lock) == 1)
|
|
{
|
|
init_system_queues();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFShutdown (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFShutdown(void)
|
|
{
|
|
TRACE("\n");
|
|
|
|
if (platform_lock <= 0)
|
|
return S_OK;
|
|
|
|
if (InterlockedExchangeAdd(&platform_lock, -1) == 1)
|
|
{
|
|
shutdown_system_queues();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFLockPlatform (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFLockPlatform(void)
|
|
{
|
|
InterlockedIncrement(&platform_lock);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFUnlockPlatform (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFUnlockPlatform(void)
|
|
{
|
|
if (InterlockedDecrement(&platform_lock) == 0)
|
|
{
|
|
shutdown_system_queues();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL is_platform_locked(void)
|
|
{
|
|
return platform_lock > 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFCopyImage (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines)
|
|
{
|
|
TRACE("(%p, %d, %p, %d, %u, %u)\n", dest, deststride, src, srcstride, width, lines);
|
|
|
|
while (lines--)
|
|
{
|
|
memcpy(dest, src, width);
|
|
dest += deststride;
|
|
src += srcstride;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
struct guid_def
|
|
{
|
|
const GUID *guid;
|
|
const char *name;
|
|
};
|
|
|
|
static int debug_compare_guid(const void *a, const void *b)
|
|
{
|
|
const GUID *guid = a;
|
|
const struct guid_def *guid_def = b;
|
|
return memcmp(guid, guid_def->guid, sizeof(*guid));
|
|
}
|
|
|
|
const char *debugstr_attr(const GUID *guid)
|
|
{
|
|
static const struct guid_def guid_defs[] =
|
|
{
|
|
#define X(g) { &(g), #g }
|
|
X(MF_READWRITE_MMCSS_CLASS),
|
|
X(MF_SINK_WRITER_ENCODER_CONFIG),
|
|
X(MF_SOURCE_READER_ENABLE_TRANSCODE_ONLY_TRANSFORMS),
|
|
X(MF_MT_ALPHA_MODE),
|
|
X(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS),
|
|
X(MF_MT_PIXEL_ASPECT_RATIO),
|
|
X(MF_MT_WRAPPED_TYPE),
|
|
X(MF_MT_AVG_BITRATE),
|
|
X(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING),
|
|
X(MF_MT_AUDIO_BLOCK_ALIGNMENT),
|
|
X(MF_PD_PMPHOST_CONTEXT),
|
|
X(MF_PD_APP_CONTEXT),
|
|
X(MF_PD_TOTAL_FILE_SIZE),
|
|
X(MF_PD_AUDIO_ENCODING_BITRATE),
|
|
X(MF_PD_VIDEO_ENCODING_BITRATE),
|
|
X(MFSampleExtension_TargetGlobalLuminance),
|
|
X(MF_PD_MIME_TYPE),
|
|
X(MF_PD_LAST_MODIFIED_TIME),
|
|
X(MF_PD_PLAYBACK_ELEMENT_ID),
|
|
X(MF_MT_ALL_SAMPLES_INDEPENDENT),
|
|
X(MF_PD_PREFERRED_LANGUAGE),
|
|
X(MF_PD_PLAYBACK_BOUNDARY_TIME),
|
|
X(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING),
|
|
X(MF_MT_FRAME_SIZE),
|
|
X(MF_SINK_WRITER_ASYNC_CALLBACK),
|
|
X(MF_MT_FRAME_RATE_RANGE_MAX),
|
|
X(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND),
|
|
X(MFSampleExtension_ForwardedDecodeUnits),
|
|
X(MF_EVENT_SOURCE_TOPOLOGY_CANCELED),
|
|
X(MF_MT_VIDEO_ROTATION),
|
|
X(MF_MT_USER_DATA),
|
|
X(MF_EVENT_STREAM_METADATA_SYSTEMID),
|
|
X(MF_MT_AUDIO_CHANNEL_MASK),
|
|
X(MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN),
|
|
X(MF_READWRITE_DISABLE_CONVERTERS),
|
|
X(MFSampleExtension_Token),
|
|
X(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE),
|
|
X(MF_MT_VIDEO_NO_FRAME_ORDERING),
|
|
X(MFSampleExtension_3DVideo_SampleFormat),
|
|
X(MF_MT_SAMPLE_SIZE),
|
|
X(MF_MT_AAC_PAYLOAD_TIME),
|
|
X(MF_SOURCE_READER_D3D11_BIND_FLAGS),
|
|
X(MF_MT_AUDIO_FOLDDOWN_MATRIX),
|
|
X(MF_MT_AUDIO_WMADRC_PEAKREF),
|
|
X(MF_MT_AUDIO_WMADRC_PEAKTARGET),
|
|
X(MF_PD_SAMI_STYLELIST),
|
|
X(MF_MT_AUDIO_WMADRC_AVGREF),
|
|
X(MF_MT_AUDIO_BITS_PER_SAMPLE),
|
|
X(MF_SD_LANGUAGE),
|
|
X(MF_MT_AUDIO_WMADRC_AVGTARGET),
|
|
X(MF_SD_PROTECTED),
|
|
X(MF_READWRITE_MMCSS_PRIORITY_AUDIO),
|
|
X(MF_BYTESTREAM_ORIGIN_NAME),
|
|
X(MF_BYTESTREAM_CONTENT_TYPE),
|
|
X(MF_MT_DEPTH_MEASUREMENT),
|
|
X(MF_MT_VIDEO_3D_NUM_VIEWS),
|
|
X(MF_BYTESTREAM_DURATION),
|
|
X(MF_SD_SAMI_LANGUAGE),
|
|
X(MF_EVENT_OUTPUT_NODE),
|
|
X(MF_BYTESTREAM_LAST_MODIFIED_TIME),
|
|
X(MF_MT_FRAME_RATE_RANGE_MIN),
|
|
X(MF_BYTESTREAM_IFO_FILE_URI),
|
|
X(MF_EVENT_TOPOLOGY_STATUS),
|
|
X(MF_BYTESTREAM_DLNA_PROFILE_ID),
|
|
X(MF_MT_MAJOR_TYPE),
|
|
X(MF_EVENT_SOURCE_CHARACTERISTICS),
|
|
X(MF_EVENT_SOURCE_CHARACTERISTICS_OLD),
|
|
X(MF_MT_VIDEO_3D_FIRST_IS_LEFT),
|
|
X(MF_PD_ADAPTIVE_STREAMING),
|
|
X(MFSampleExtension_Timestamp),
|
|
X(MF_MT_SUBTYPE),
|
|
X(MF_SD_MUTUALLY_EXCLUSIVE),
|
|
X(MF_SD_STREAM_NAME),
|
|
X(MF_EVENT_STREAM_METADATA_CONTENT_KEYIDS),
|
|
X(MF_MT_VIDEO_3D_FORMAT),
|
|
X(MF_EVENT_STREAM_METADATA_KEYDATA),
|
|
X(MF_SINK_WRITER_D3D_MANAGER),
|
|
X(MF_SOURCE_READER_D3D_MANAGER),
|
|
X(MFSampleExtension_3DVideo),
|
|
X(MF_EVENT_SOURCE_FAKE_START),
|
|
X(MF_EVENT_SOURCE_PROJECTSTART),
|
|
X(MF_EVENT_SOURCE_ACTUAL_START),
|
|
X(MF_MT_AUDIO_SAMPLES_PER_BLOCK),
|
|
X(MF_SOURCE_READER_ASYNC_CALLBACK),
|
|
X(MF_MT_AUDIO_FLAC_MAX_BLOCK_SIZE),
|
|
X(MF_MT_FIXED_SIZE_SAMPLES),
|
|
X(MF_EVENT_SCRUBSAMPLE_TIME),
|
|
X(MF_MT_INTERLACE_MODE),
|
|
X(MF_MT_VIDEO_RENDERER_EXTENSION_PROFILE),
|
|
X(MF_MT_AUDIO_PREFER_WAVEFORMATEX),
|
|
X(MFSampleExtension_ForwardedDecodeUnitType),
|
|
X(MF_MT_AUDIO_AVG_BYTES_PER_SECOND),
|
|
X(MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS),
|
|
X(MF_EVENT_MFT_INPUT_STREAM_ID),
|
|
X(MF_READWRITE_MMCSS_PRIORITY),
|
|
X(MF_MT_VIDEO_3D),
|
|
X(MF_EVENT_START_PRESENTATION_TIME),
|
|
X(MF_EVENT_SESSIONCAPS),
|
|
X(MF_EVENT_PRESENTATION_TIME_OFFSET),
|
|
X(MF_EVENT_SESSIONCAPS_DELTA),
|
|
X(MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT),
|
|
X(MFSampleExtension_DecodeTimestamp),
|
|
X(MF_MT_VIDEO_H264_NO_FMOASO),
|
|
X(MF_SINK_WRITER_DISABLE_THROTTLING),
|
|
X(MF_READWRITE_D3D_OPTIONAL),
|
|
X(MF_READWRITE_MMCSS_CLASS_AUDIO),
|
|
X(MF_SOURCE_READER_DISABLE_CAMERA_PLUGINS),
|
|
X(MF_PD_AUDIO_ISVARIABLEBITRATE),
|
|
X(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION),
|
|
X(MF_MT_AUDIO_SAMPLES_PER_SECOND),
|
|
X(MF_MT_FRAME_RATE),
|
|
X(MF_SOURCE_READER_MEDIASOURCE_CONFIG),
|
|
X(MF_MT_COMPRESSED),
|
|
X(MF_EVENT_MFT_CONTEXT),
|
|
X(MF_MT_FORWARD_CUSTOM_SEI),
|
|
X(MF_MT_DEPTH_VALUE_UNIT),
|
|
X(MF_MT_AUDIO_NUM_CHANNELS),
|
|
X(MF_EVENT_DO_THINNING),
|
|
X(MF_SOURCE_READER_DISABLE_DXVA),
|
|
X(MF_MT_FORWARD_CUSTOM_NALU),
|
|
X(MF_MT_SECURE),
|
|
X(MF_MT_VIDEO_3D_LEFT_IS_BASE),
|
|
#undef X
|
|
};
|
|
struct guid_def *ret = NULL;
|
|
|
|
if (guid)
|
|
ret = bsearch(guid, guid_defs, ARRAY_SIZE(guid_defs), sizeof(*guid_defs), debug_compare_guid);
|
|
|
|
return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbgstr_guid(guid);
|
|
}
|
|
|
|
const char *debugstr_mf_guid(const GUID *guid)
|
|
{
|
|
static const struct guid_def guid_defs[] =
|
|
{
|
|
#define X(g) { &(g), #g }
|
|
X(MFAudioFormat_ADTS),
|
|
X(MFAudioFormat_PCM),
|
|
X(MFAudioFormat_PCM_HDCP),
|
|
X(MFAudioFormat_Float),
|
|
X(MFAudioFormat_DTS),
|
|
X(MFAudioFormat_DRM),
|
|
X(MFAudioFormat_MSP1),
|
|
X(MFAudioFormat_Vorbis),
|
|
X(MFAudioFormat_AAC),
|
|
X(MFVideoFormat_RGB24),
|
|
X(MFVideoFormat_ARGB32),
|
|
X(MFVideoFormat_RGB32),
|
|
X(MFVideoFormat_RGB565),
|
|
X(MFVideoFormat_RGB555),
|
|
X(MFVideoFormat_A2R10G10B10),
|
|
X(MFMediaType_Script),
|
|
X(MFMediaType_Image),
|
|
X(MFMediaType_HTML),
|
|
X(MFMediaType_Binary),
|
|
X(MFVideoFormat_MPEG2),
|
|
X(MFMediaType_FileTransfer),
|
|
X(MFVideoFormat_RGB8),
|
|
X(MFAudioFormat_Dolby_AC3),
|
|
X(MFVideoFormat_L8),
|
|
X(MFAudioFormat_LPCM),
|
|
X(MFVideoFormat_420O),
|
|
X(MFVideoFormat_AI44),
|
|
X(MFVideoFormat_AV1),
|
|
X(MFVideoFormat_AYUV),
|
|
X(MFVideoFormat_H263),
|
|
X(MFVideoFormat_H264),
|
|
X(MFVideoFormat_H265),
|
|
X(MFVideoFormat_HEVC),
|
|
X(MFVideoFormat_HEVC_ES),
|
|
X(MFVideoFormat_I420),
|
|
X(MFVideoFormat_IYUV),
|
|
X(MFVideoFormat_M4S2),
|
|
X(MFVideoFormat_MJPG),
|
|
X(MFVideoFormat_MP43),
|
|
X(MFVideoFormat_MP4S),
|
|
X(MFVideoFormat_MP4V),
|
|
X(MFVideoFormat_MPG1),
|
|
X(MFVideoFormat_MSS1),
|
|
X(MFVideoFormat_MSS2),
|
|
X(MFVideoFormat_NV11),
|
|
X(MFVideoFormat_NV12),
|
|
X(MFVideoFormat_ORAW),
|
|
X(MFAudioFormat_Opus),
|
|
X(MFVideoFormat_D16),
|
|
X(MFAudioFormat_MPEG),
|
|
X(MFVideoFormat_P010),
|
|
X(MFVideoFormat_P016),
|
|
X(MFVideoFormat_P210),
|
|
X(MFVideoFormat_P216),
|
|
X(MFVideoFormat_L16),
|
|
X(MFAudioFormat_MP3),
|
|
X(MFVideoFormat_UYVY),
|
|
X(MFVideoFormat_VP10),
|
|
X(MFVideoFormat_VP80),
|
|
X(MFVideoFormat_VP90),
|
|
X(MFVideoFormat_WMV1),
|
|
X(MFVideoFormat_WMV2),
|
|
X(MFVideoFormat_WMV3),
|
|
X(MFVideoFormat_WVC1),
|
|
X(MFVideoFormat_Y210),
|
|
X(MFVideoFormat_Y216),
|
|
X(MFVideoFormat_Y410),
|
|
X(MFVideoFormat_Y416),
|
|
X(MFVideoFormat_Y41P),
|
|
X(MFVideoFormat_Y41T),
|
|
X(MFVideoFormat_Y42T),
|
|
X(MFVideoFormat_YUY2),
|
|
X(MFVideoFormat_YV12),
|
|
X(MFVideoFormat_YVU9),
|
|
X(MFVideoFormat_YVYU),
|
|
X(MFAudioFormat_WMAudioV8),
|
|
X(MFAudioFormat_ALAC),
|
|
X(MFAudioFormat_AMR_NB),
|
|
X(MFMediaType_Audio),
|
|
X(MFAudioFormat_WMAudioV9),
|
|
X(MFAudioFormat_AMR_WB),
|
|
X(MFAudioFormat_WMAudio_Lossless),
|
|
X(MFAudioFormat_AMR_WP),
|
|
X(MFAudioFormat_WMASPDIF),
|
|
X(MFVideoFormat_DV25),
|
|
X(MFVideoFormat_DV50),
|
|
X(MFVideoFormat_DVC),
|
|
X(MFVideoFormat_DVH1),
|
|
X(MFVideoFormat_DVHD),
|
|
X(MFVideoFormat_DVSD),
|
|
X(MFVideoFormat_DVSL),
|
|
X(MFVideoFormat_A16B16G16R16F),
|
|
X(MFVideoFormat_v210),
|
|
X(MFVideoFormat_v216),
|
|
X(MFVideoFormat_v410),
|
|
X(MFMediaType_Video),
|
|
X(MFAudioFormat_AAC_HDCP),
|
|
X(MFAudioFormat_Dolby_AC3_HDCP),
|
|
X(MFMediaType_Subtitle),
|
|
X(MFMediaType_Stream),
|
|
X(MFAudioFormat_Dolby_AC3_SPDIF),
|
|
X(MFAudioFormat_Float_SpatialObjects),
|
|
X(MFMediaType_SAMI),
|
|
X(MFAudioFormat_ADTS_HDCP),
|
|
X(MFAudioFormat_FLAC),
|
|
X(MFAudioFormat_Dolby_DDPlus),
|
|
X(MFMediaType_MultiplexedFrames),
|
|
X(MFAudioFormat_Base_HDCP),
|
|
X(MFVideoFormat_Base_HDCP),
|
|
X(MFVideoFormat_H264_HDCP),
|
|
X(MFVideoFormat_HEVC_HDCP),
|
|
X(MFMediaType_Default),
|
|
X(MFMediaType_Protected),
|
|
X(MFVideoFormat_H264_ES),
|
|
X(MFMediaType_Perception),
|
|
#undef X
|
|
};
|
|
struct guid_def *ret = NULL;
|
|
|
|
if (guid)
|
|
ret = bsearch(guid, guid_defs, ARRAY_SIZE(guid_defs), sizeof(*guid_defs), debug_compare_guid);
|
|
|
|
return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbgstr_guid(guid);
|
|
}
|
|
|
|
struct event_id
|
|
{
|
|
DWORD id;
|
|
const char *name;
|
|
};
|
|
|
|
static int debug_event_id(const void *a, const void *b)
|
|
{
|
|
const DWORD *id = a;
|
|
const struct event_id *event_id = b;
|
|
return *id - event_id->id;
|
|
}
|
|
|
|
static const char *debugstr_eventid(DWORD event)
|
|
{
|
|
static const struct event_id
|
|
{
|
|
DWORD id;
|
|
const char *name;
|
|
}
|
|
event_ids[] =
|
|
{
|
|
#define X(e) { e, #e }
|
|
X(MEUnknown),
|
|
X(MEError),
|
|
X(MEExtendedType),
|
|
X(MENonFatalError),
|
|
X(MESessionUnknown),
|
|
X(MESessionTopologySet),
|
|
X(MESessionTopologiesCleared),
|
|
X(MESessionStarted),
|
|
X(MESessionPaused),
|
|
X(MESessionStopped),
|
|
X(MESessionClosed),
|
|
X(MESessionEnded),
|
|
X(MESessionRateChanged),
|
|
X(MESessionScrubSampleComplete),
|
|
X(MESessionCapabilitiesChanged),
|
|
X(MESessionTopologyStatus),
|
|
X(MESessionNotifyPresentationTime),
|
|
X(MENewPresentation),
|
|
X(MELicenseAcquisitionStart),
|
|
X(MELicenseAcquisitionCompleted),
|
|
X(MEIndividualizationStart),
|
|
X(MEIndividualizationCompleted),
|
|
X(MEEnablerProgress),
|
|
X(MEEnablerCompleted),
|
|
X(MEPolicyError),
|
|
X(MEPolicyReport),
|
|
X(MEBufferingStarted),
|
|
X(MEBufferingStopped),
|
|
X(MEConnectStart),
|
|
X(MEConnectEnd),
|
|
X(MEReconnectStart),
|
|
X(MEReconnectEnd),
|
|
X(MERendererEvent),
|
|
X(MESessionStreamSinkFormatChanged),
|
|
X(MESourceUnknown),
|
|
X(MESourceStarted),
|
|
X(MEStreamStarted),
|
|
X(MESourceSeeked),
|
|
X(MEStreamSeeked),
|
|
X(MENewStream),
|
|
X(MEUpdatedStream),
|
|
X(MESourceStopped),
|
|
X(MEStreamStopped),
|
|
X(MESourcePaused),
|
|
X(MEStreamPaused),
|
|
X(MEEndOfPresentation),
|
|
X(MEEndOfStream),
|
|
X(MEMediaSample),
|
|
X(MEStreamTick),
|
|
X(MEStreamThinMode),
|
|
X(MEStreamFormatChanged),
|
|
X(MESourceRateChanged),
|
|
X(MEEndOfPresentationSegment),
|
|
X(MESourceCharacteristicsChanged),
|
|
X(MESourceRateChangeRequested),
|
|
X(MESourceMetadataChanged),
|
|
X(MESequencerSourceTopologyUpdated),
|
|
X(MESinkUnknown),
|
|
X(MEStreamSinkStarted),
|
|
X(MEStreamSinkStopped),
|
|
X(MEStreamSinkPaused),
|
|
X(MEStreamSinkRateChanged),
|
|
X(MEStreamSinkRequestSample),
|
|
X(MEStreamSinkMarker),
|
|
X(MEStreamSinkPrerolled),
|
|
X(MEStreamSinkScrubSampleComplete),
|
|
X(MEStreamSinkFormatChanged),
|
|
X(MEStreamSinkDeviceChanged),
|
|
X(MEQualityNotify),
|
|
X(MESinkInvalidated),
|
|
X(MEAudioSessionNameChanged),
|
|
X(MEAudioSessionVolumeChanged),
|
|
X(MEAudioSessionDeviceRemoved),
|
|
X(MEAudioSessionServerShutdown),
|
|
X(MEAudioSessionGroupingParamChanged),
|
|
X(MEAudioSessionIconChanged),
|
|
X(MEAudioSessionFormatChanged),
|
|
X(MEAudioSessionDisconnected),
|
|
X(MEAudioSessionExclusiveModeOverride),
|
|
X(METrustUnknown),
|
|
X(MEPolicyChanged),
|
|
X(MEContentProtectionMessage),
|
|
X(MEPolicySet),
|
|
X(MEWMDRMLicenseBackupCompleted),
|
|
X(MEWMDRMLicenseBackupProgress),
|
|
X(MEWMDRMLicenseRestoreCompleted),
|
|
X(MEWMDRMLicenseRestoreProgress),
|
|
X(MEWMDRMLicenseAcquisitionCompleted),
|
|
X(MEWMDRMIndividualizationCompleted),
|
|
X(MEWMDRMIndividualizationProgress),
|
|
X(MEWMDRMProximityCompleted),
|
|
X(MEWMDRMLicenseStoreCleaned),
|
|
X(MEWMDRMRevocationDownloadCompleted),
|
|
#undef X
|
|
};
|
|
|
|
struct event_id *ret = bsearch(&event, event_ids, ARRAY_SIZE(event_ids), sizeof(*event_ids), debug_event_id);
|
|
return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbg_sprintf("%u", event);
|
|
}
|
|
|
|
static inline struct attributes *impl_from_IMFAttributes(IMFAttributes *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct attributes, IMFAttributes_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out)
|
|
{
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFAttributes) ||
|
|
IsEqualGUID(riid, &IID_IUnknown))
|
|
{
|
|
*out = iface;
|
|
IMFAttributes_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI mfattributes_AddRef(IMFAttributes *iface)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
ULONG refcount = InterlockedIncrement(&attributes->ref);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI mfattributes_Release(IMFAttributes *iface)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
ULONG refcount = InterlockedDecrement(&attributes->ref);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
clear_attributes_object(attributes);
|
|
heap_free(attributes);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static struct attribute *attributes_find_item(struct attributes *attributes, REFGUID key, size_t *index)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < attributes->count; ++i)
|
|
{
|
|
if (IsEqualGUID(key, &attributes->attributes[i].key))
|
|
{
|
|
if (index)
|
|
*index = i;
|
|
return &attributes->attributes[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static HRESULT attributes_get_item(struct attributes *attributes, const GUID *key, PROPVARIANT *value)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
attribute = attributes_find_item(attributes, key, NULL);
|
|
if (attribute)
|
|
{
|
|
if (attribute->value.vt == value->vt && !(value->vt == VT_UNKNOWN && !attribute->value.u.punkVal))
|
|
hr = PropVariantCopy(value, &attribute->value);
|
|
else
|
|
hr = MF_E_INVALIDTYPE;
|
|
}
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetItem(struct attributes *attributes, REFGUID key, PROPVARIANT *value)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
if ((attribute = attributes_find_item(attributes, key, NULL)))
|
|
hr = PropVariantCopy(value, &attribute->value);
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetItemType(struct attributes *attributes, REFGUID key, MF_ATTRIBUTE_TYPE *type)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
if ((attribute = attributes_find_item(attributes, key, NULL)))
|
|
{
|
|
*type = attribute->value.vt;
|
|
}
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_CompareItem(struct attributes *attributes, REFGUID key, REFPROPVARIANT value, BOOL *result)
|
|
{
|
|
struct attribute *attribute;
|
|
|
|
*result = FALSE;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
if ((attribute = attributes_find_item(attributes, key, NULL)))
|
|
{
|
|
*result = attribute->value.vt == value->vt &&
|
|
!PropVariantCompareEx(&attribute->value, value, PVCU_DEFAULT, PVCF_DEFAULT);
|
|
}
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_Compare(struct attributes *attributes, IMFAttributes *theirs,
|
|
MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
|
|
{
|
|
IMFAttributes *smaller, *other;
|
|
MF_ATTRIBUTE_TYPE type;
|
|
HRESULT hr = S_OK;
|
|
UINT32 count;
|
|
BOOL result;
|
|
size_t i;
|
|
|
|
if (FAILED(hr = IMFAttributes_GetCount(theirs, &count)))
|
|
return hr;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
result = TRUE;
|
|
|
|
switch (match_type)
|
|
{
|
|
case MF_ATTRIBUTES_MATCH_OUR_ITEMS:
|
|
for (i = 0; i < attributes->count; ++i)
|
|
{
|
|
if (FAILED(hr = IMFAttributes_CompareItem(theirs, &attributes->attributes[i].key,
|
|
&attributes->attributes[i].value, &result)))
|
|
break;
|
|
if (!result)
|
|
break;
|
|
}
|
|
break;
|
|
case MF_ATTRIBUTES_MATCH_THEIR_ITEMS:
|
|
hr = IMFAttributes_Compare(theirs, &attributes->IMFAttributes_iface, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result);
|
|
break;
|
|
case MF_ATTRIBUTES_MATCH_ALL_ITEMS:
|
|
if (count != attributes->count)
|
|
{
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (FAILED(hr = IMFAttributes_CompareItem(theirs, &attributes->attributes[i].key,
|
|
&attributes->attributes[i].value, &result)))
|
|
break;
|
|
if (!result)
|
|
break;
|
|
}
|
|
break;
|
|
case MF_ATTRIBUTES_MATCH_INTERSECTION:
|
|
for (i = 0; i < attributes->count; ++i)
|
|
{
|
|
if (FAILED(IMFAttributes_GetItemType(theirs, &attributes->attributes[i].key, &type)))
|
|
continue;
|
|
|
|
if (FAILED(hr = IMFAttributes_CompareItem(theirs, &attributes->attributes[i].key,
|
|
&attributes->attributes[i].value, &result)))
|
|
break;
|
|
|
|
if (!result)
|
|
break;
|
|
}
|
|
break;
|
|
case MF_ATTRIBUTES_MATCH_SMALLER:
|
|
smaller = attributes->count > count ? theirs : &attributes->IMFAttributes_iface;
|
|
other = attributes->count > count ? &attributes->IMFAttributes_iface : theirs;
|
|
hr = IMFAttributes_Compare(smaller, other, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result);
|
|
break;
|
|
default:
|
|
WARN("Unknown match type %d.\n", match_type);
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
if (SUCCEEDED(hr))
|
|
*ret = result;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetUINT32(struct attributes *attributes, REFGUID key, UINT32 *value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
PropVariantInit(&attrval);
|
|
attrval.vt = VT_UI4;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
*value = attrval.u.ulVal;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetUINT64(struct attributes *attributes, REFGUID key, UINT64 *value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
PropVariantInit(&attrval);
|
|
attrval.vt = VT_UI8;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
*value = attrval.u.uhVal.QuadPart;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetDouble(struct attributes *attributes, REFGUID key, double *value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
PropVariantInit(&attrval);
|
|
attrval.vt = VT_R8;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
*value = attrval.u.dblVal;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetGUID(struct attributes *attributes, REFGUID key, GUID *value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
PropVariantInit(&attrval);
|
|
attrval.vt = VT_CLSID;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
*value = *attrval.u.puuid;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetStringLength(struct attributes *attributes, REFGUID key, UINT32 *length)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
attribute = attributes_find_item(attributes, key, NULL);
|
|
if (attribute)
|
|
{
|
|
if (attribute->value.vt == MF_ATTRIBUTE_STRING)
|
|
*length = strlenW(attribute->value.u.pwszVal);
|
|
else
|
|
hr = MF_E_INVALIDTYPE;
|
|
}
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetString(struct attributes *attributes, REFGUID key, WCHAR *value,
|
|
UINT32 size, UINT32 *length)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
attribute = attributes_find_item(attributes, key, NULL);
|
|
if (attribute)
|
|
{
|
|
if (attribute->value.vt == MF_ATTRIBUTE_STRING)
|
|
{
|
|
int len = strlenW(attribute->value.u.pwszVal);
|
|
|
|
if (length)
|
|
*length = len;
|
|
|
|
if (size <= len)
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER;
|
|
else
|
|
memcpy(value, attribute->value.u.pwszVal, (len + 1) * sizeof(WCHAR));
|
|
}
|
|
else
|
|
hr = MF_E_INVALIDTYPE;
|
|
}
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetAllocatedString(struct attributes *attributes, REFGUID key, WCHAR **value, UINT32 *length)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
PropVariantInit(&attrval);
|
|
attrval.vt = VT_LPWSTR;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*value = attrval.u.pwszVal;
|
|
*length = lstrlenW(*value);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetBlobSize(struct attributes *attributes, REFGUID key, UINT32 *size)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
attribute = attributes_find_item(attributes, key, NULL);
|
|
if (attribute)
|
|
{
|
|
if (attribute->value.vt == MF_ATTRIBUTE_BLOB)
|
|
*size = attribute->value.u.caub.cElems;
|
|
else
|
|
hr = MF_E_INVALIDTYPE;
|
|
}
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetBlob(struct attributes *attributes, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
|
|
{
|
|
struct attribute *attribute;
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
attribute = attributes_find_item(attributes, key, NULL);
|
|
if (attribute)
|
|
{
|
|
if (attribute->value.vt == MF_ATTRIBUTE_BLOB)
|
|
{
|
|
UINT32 size = attribute->value.u.caub.cElems;
|
|
|
|
if (bufsize >= size)
|
|
hr = PropVariantToBuffer(&attribute->value, buf, size);
|
|
else
|
|
hr = E_NOT_SUFFICIENT_BUFFER;
|
|
|
|
if (blobsize)
|
|
*blobsize = size;
|
|
}
|
|
else
|
|
hr = MF_E_INVALIDTYPE;
|
|
}
|
|
else
|
|
hr = MF_E_ATTRIBUTENOTFOUND;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetAllocatedBlob(struct attributes *attributes, REFGUID key, UINT8 **buf, UINT32 *size)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
attrval.vt = VT_VECTOR | VT_UI1;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*buf = attrval.u.caub.pElems;
|
|
*size = attrval.u.caub.cElems;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_GetUnknown(struct attributes *attributes, REFGUID key, REFIID riid, void **out)
|
|
{
|
|
PROPVARIANT attrval;
|
|
HRESULT hr;
|
|
|
|
PropVariantInit(&attrval);
|
|
attrval.vt = VT_UNKNOWN;
|
|
hr = attributes_get_item(attributes, key, &attrval);
|
|
if (SUCCEEDED(hr))
|
|
hr = IUnknown_QueryInterface(attrval.u.punkVal, riid, out);
|
|
PropVariantClear(&attrval);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT attributes_set_item(struct attributes *attributes, REFGUID key, REFPROPVARIANT value)
|
|
{
|
|
struct attribute *attribute;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
attribute = attributes_find_item(attributes, key, NULL);
|
|
if (!attribute)
|
|
{
|
|
if (!mf_array_reserve((void **)&attributes->attributes, &attributes->capacity, attributes->count + 1,
|
|
sizeof(*attributes->attributes)))
|
|
{
|
|
LeaveCriticalSection(&attributes->cs);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
attributes->attributes[attributes->count].key = *key;
|
|
attribute = &attributes->attributes[attributes->count++];
|
|
}
|
|
else
|
|
PropVariantClear(&attribute->value);
|
|
|
|
PropVariantCopy(&attribute->value, value);
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_SetItem(struct attributes *attributes, REFGUID key, REFPROPVARIANT value)
|
|
{
|
|
PROPVARIANT empty;
|
|
|
|
switch (value->vt)
|
|
{
|
|
case MF_ATTRIBUTE_UINT32:
|
|
case MF_ATTRIBUTE_UINT64:
|
|
case MF_ATTRIBUTE_DOUBLE:
|
|
case MF_ATTRIBUTE_GUID:
|
|
case MF_ATTRIBUTE_STRING:
|
|
case MF_ATTRIBUTE_BLOB:
|
|
case MF_ATTRIBUTE_IUNKNOWN:
|
|
return attributes_set_item(attributes, key, value);
|
|
default:
|
|
PropVariantInit(&empty);
|
|
attributes_set_item(attributes, key, &empty);
|
|
return MF_E_INVALIDTYPE;
|
|
}
|
|
}
|
|
|
|
HRESULT attributes_DeleteItem(struct attributes *attributes, REFGUID key)
|
|
{
|
|
struct attribute *attribute;
|
|
size_t index = 0;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
if ((attribute = attributes_find_item(attributes, key, &index)))
|
|
{
|
|
size_t count;
|
|
|
|
PropVariantClear(&attribute->value);
|
|
|
|
attributes->count--;
|
|
count = attributes->count - index;
|
|
if (count)
|
|
memmove(&attributes->attributes[index], &attributes->attributes[index + 1], count * sizeof(*attributes->attributes));
|
|
}
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_DeleteAllItems(struct attributes *attributes)
|
|
{
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
while (attributes->count)
|
|
{
|
|
PropVariantClear(&attributes->attributes[--attributes->count].value);
|
|
}
|
|
heap_free(attributes->attributes);
|
|
attributes->attributes = NULL;
|
|
attributes->capacity = 0;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_SetUINT32(struct attributes *attributes, REFGUID key, UINT32 value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
attrval.vt = VT_UI4;
|
|
attrval.u.ulVal = value;
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_SetUINT64(struct attributes *attributes, REFGUID key, UINT64 value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
attrval.vt = VT_UI8;
|
|
attrval.u.uhVal.QuadPart = value;
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_SetDouble(struct attributes *attributes, REFGUID key, double value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
attrval.vt = VT_R8;
|
|
attrval.u.dblVal = value;
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_SetGUID(struct attributes *attributes, REFGUID key, REFGUID value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
InitPropVariantFromCLSID(value, &attrval);
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_SetString(struct attributes *attributes, REFGUID key, const WCHAR *value)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
attrval.vt = VT_LPWSTR;
|
|
attrval.u.pwszVal = (WCHAR *)value;
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_SetBlob(struct attributes *attributes, REFGUID key, const UINT8 *buf, UINT32 size)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
attrval.vt = VT_VECTOR | VT_UI1;
|
|
attrval.u.caub.cElems = size;
|
|
attrval.u.caub.pElems = (UINT8 *)buf;
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_SetUnknown(struct attributes *attributes, REFGUID key, IUnknown *unknown)
|
|
{
|
|
PROPVARIANT attrval;
|
|
|
|
attrval.vt = VT_UNKNOWN;
|
|
attrval.u.punkVal = unknown;
|
|
return attributes_set_item(attributes, key, &attrval);
|
|
}
|
|
|
|
HRESULT attributes_LockStore(struct attributes *attributes)
|
|
{
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_UnlockStore(struct attributes *attributes)
|
|
{
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_GetCount(struct attributes *attributes, UINT32 *count)
|
|
{
|
|
EnterCriticalSection(&attributes->cs);
|
|
*count = attributes->count;
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT attributes_GetItemByIndex(struct attributes *attributes, UINT32 index, GUID *key, PROPVARIANT *value)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
if (index < attributes->count)
|
|
{
|
|
*key = attributes->attributes[index].key;
|
|
if (value)
|
|
PropVariantCopy(value, &attributes->attributes[index].value);
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT attributes_CopyAllItems(struct attributes *attributes, IMFAttributes *dest)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
size_t i;
|
|
|
|
EnterCriticalSection(&attributes->cs);
|
|
|
|
IMFAttributes_LockStore(dest);
|
|
|
|
IMFAttributes_DeleteAllItems(dest);
|
|
|
|
for (i = 0; i < attributes->count; ++i)
|
|
{
|
|
hr = IMFAttributes_SetItem(dest, &attributes->attributes[i].key, &attributes->attributes[i].value);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
IMFAttributes_UnlockStore(dest);
|
|
|
|
LeaveCriticalSection(&attributes->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetItem(IMFAttributes *iface, REFGUID key, PROPVARIANT *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetItem(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetItemType(IMFAttributes *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
|
|
|
|
return attributes_GetItemType(attributes, key, type);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_CompareItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, result);
|
|
|
|
return attributes_CompareItem(attributes, key, value, result);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_Compare(IMFAttributes *iface, IMFAttributes *theirs,
|
|
MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %p, %d, %p.\n", iface, theirs, match_type, ret);
|
|
|
|
return attributes_Compare(attributes, theirs, match_type, ret);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetUINT32(IMFAttributes *iface, REFGUID key, UINT32 *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetUINT32(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetUINT64(IMFAttributes *iface, REFGUID key, UINT64 *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetUINT64(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetDouble(IMFAttributes *iface, REFGUID key, double *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetDouble(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetGUID(IMFAttributes *iface, REFGUID key, GUID *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetGUID(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetStringLength(IMFAttributes *iface, REFGUID key, UINT32 *length)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
|
|
|
|
return attributes_GetStringLength(attributes, key, length);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetString(IMFAttributes *iface, REFGUID key, WCHAR *value,
|
|
UINT32 size, UINT32 *length)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_attr(key), value, size, length);
|
|
|
|
return attributes_GetString(attributes, key, value, size, length);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetAllocatedString(IMFAttributes *iface, REFGUID key, WCHAR **value, UINT32 *length)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
|
|
|
|
return attributes_GetAllocatedString(attributes, key, value, length);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetBlobSize(IMFAttributes *iface, REFGUID key, UINT32 *size)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
|
|
|
|
return attributes_GetBlobSize(attributes, key, size);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetBlob(IMFAttributes *iface, REFGUID key, UINT8 *buf,
|
|
UINT32 bufsize, UINT32 *blobsize)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
|
|
|
|
return attributes_GetBlob(attributes, key, buf, bufsize, blobsize);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetAllocatedBlob(IMFAttributes *iface, REFGUID key, UINT8 **buf, UINT32 *size)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
|
|
|
|
return attributes_GetAllocatedBlob(attributes, key, buf, size);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetUnknown(IMFAttributes *iface, REFGUID key, REFIID riid, void **out)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
|
|
|
|
return attributes_GetUnknown(attributes, key, riid, out);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_SetItem(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_DeleteItem(IMFAttributes *iface, REFGUID key)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_attr(key));
|
|
|
|
return attributes_DeleteItem(attributes, key);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_DeleteAllItems(IMFAttributes *iface)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return attributes_DeleteAllItems(attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetUINT32(IMFAttributes *iface, REFGUID key, UINT32 value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_SetUINT32(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetUINT64(IMFAttributes *iface, REFGUID key, UINT64 value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
|
|
|
|
return attributes_SetUINT64(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetDouble(IMFAttributes *iface, REFGUID key, double value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_SetDouble(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetGUID(IMFAttributes *iface, REFGUID key, REFGUID value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
|
|
|
|
return attributes_SetGUID(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetString(IMFAttributes *iface, REFGUID key, const WCHAR *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
|
|
|
|
return attributes_SetString(attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetBlob(IMFAttributes *iface, REFGUID key, const UINT8 *buf, UINT32 size)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
|
|
|
|
return attributes_SetBlob(attributes, key, buf, size);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_SetUnknown(IMFAttributes *iface, REFGUID key, IUnknown *unknown)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
|
|
|
|
return attributes_SetUnknown(attributes, key, unknown);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_LockStore(IMFAttributes *iface)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return attributes_LockStore(attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_UnlockStore(IMFAttributes *iface)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return attributes_UnlockStore(attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetCount(IMFAttributes *iface, UINT32 *count)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, count);
|
|
|
|
return attributes_GetCount(attributes, count);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_GetItemByIndex(IMFAttributes *iface, UINT32 index, GUID *key, PROPVARIANT *value)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
|
|
|
|
return attributes_GetItemByIndex(attributes, index, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfattributes_CopyAllItems(IMFAttributes *iface, IMFAttributes *dest)
|
|
{
|
|
struct attributes *attributes = impl_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, dest);
|
|
|
|
return attributes_CopyAllItems(attributes, dest);
|
|
}
|
|
|
|
static const IMFAttributesVtbl mfattributes_vtbl =
|
|
{
|
|
mfattributes_QueryInterface,
|
|
mfattributes_AddRef,
|
|
mfattributes_Release,
|
|
mfattributes_GetItem,
|
|
mfattributes_GetItemType,
|
|
mfattributes_CompareItem,
|
|
mfattributes_Compare,
|
|
mfattributes_GetUINT32,
|
|
mfattributes_GetUINT64,
|
|
mfattributes_GetDouble,
|
|
mfattributes_GetGUID,
|
|
mfattributes_GetStringLength,
|
|
mfattributes_GetString,
|
|
mfattributes_GetAllocatedString,
|
|
mfattributes_GetBlobSize,
|
|
mfattributes_GetBlob,
|
|
mfattributes_GetAllocatedBlob,
|
|
mfattributes_GetUnknown,
|
|
mfattributes_SetItem,
|
|
mfattributes_DeleteItem,
|
|
mfattributes_DeleteAllItems,
|
|
mfattributes_SetUINT32,
|
|
mfattributes_SetUINT64,
|
|
mfattributes_SetDouble,
|
|
mfattributes_SetGUID,
|
|
mfattributes_SetString,
|
|
mfattributes_SetBlob,
|
|
mfattributes_SetUnknown,
|
|
mfattributes_LockStore,
|
|
mfattributes_UnlockStore,
|
|
mfattributes_GetCount,
|
|
mfattributes_GetItemByIndex,
|
|
mfattributes_CopyAllItems
|
|
};
|
|
|
|
HRESULT init_attributes_object(struct attributes *object, UINT32 size)
|
|
{
|
|
object->IMFAttributes_iface.lpVtbl = &mfattributes_vtbl;
|
|
object->ref = 1;
|
|
InitializeCriticalSection(&object->cs);
|
|
|
|
object->attributes = NULL;
|
|
object->count = 0;
|
|
object->capacity = 0;
|
|
if (!mf_array_reserve((void **)&object->attributes, &object->capacity, size,
|
|
sizeof(*object->attributes)))
|
|
{
|
|
DeleteCriticalSection(&object->cs);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void clear_attributes_object(struct attributes *object)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < object->count; i++)
|
|
PropVariantClear(&object->attributes[i].value);
|
|
heap_free(object->attributes);
|
|
|
|
DeleteCriticalSection(&object->cs);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFCreateAttributes (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size)
|
|
{
|
|
struct attributes *object;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %d\n", attributes, size);
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = init_attributes_object(object, size)))
|
|
{
|
|
heap_free(object);
|
|
return hr;
|
|
}
|
|
*attributes = &object->IMFAttributes_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#define ATTRIBUTES_STORE_MAGIC 0x494d4641 /* IMFA */
|
|
|
|
struct attributes_store_header
|
|
{
|
|
DWORD magic;
|
|
UINT32 count;
|
|
};
|
|
|
|
struct attributes_store_item
|
|
{
|
|
GUID key;
|
|
QWORD type;
|
|
union
|
|
{
|
|
double f;
|
|
UINT32 i32;
|
|
UINT64 i64;
|
|
struct
|
|
{
|
|
DWORD size;
|
|
DWORD offset;
|
|
} subheader;
|
|
} u;
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFGetAttributesAsBlobSize (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFGetAttributesAsBlobSize(IMFAttributes *attributes, UINT32 *size)
|
|
{
|
|
unsigned int i, count, length;
|
|
HRESULT hr;
|
|
GUID key;
|
|
|
|
TRACE("%p, %p.\n", attributes, size);
|
|
|
|
IMFAttributes_LockStore(attributes);
|
|
|
|
hr = IMFAttributes_GetCount(attributes, &count);
|
|
|
|
*size = sizeof(struct attributes_store_header);
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
MF_ATTRIBUTE_TYPE type;
|
|
|
|
hr = IMFAttributes_GetItemByIndex(attributes, i, &key, NULL);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
*size += sizeof(struct attributes_store_item);
|
|
|
|
IMFAttributes_GetItemType(attributes, &key, &type);
|
|
|
|
switch (type)
|
|
{
|
|
case MF_ATTRIBUTE_GUID:
|
|
*size += sizeof(GUID);
|
|
break;
|
|
case MF_ATTRIBUTE_STRING:
|
|
IMFAttributes_GetStringLength(attributes, &key, &length);
|
|
*size += (length + 1) * sizeof(WCHAR);
|
|
break;
|
|
case MF_ATTRIBUTE_BLOB:
|
|
IMFAttributes_GetBlobSize(attributes, &key, &length);
|
|
*size += length;
|
|
break;
|
|
case MF_ATTRIBUTE_UINT32:
|
|
case MF_ATTRIBUTE_UINT64:
|
|
case MF_ATTRIBUTE_DOUBLE:
|
|
case MF_ATTRIBUTE_IUNKNOWN:
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
IMFAttributes_UnlockStore(attributes);
|
|
|
|
return hr;
|
|
}
|
|
|
|
struct attr_serialize_context
|
|
{
|
|
UINT8 *buffer;
|
|
UINT8 *ptr;
|
|
UINT32 size;
|
|
};
|
|
|
|
static void attributes_serialize_write(struct attr_serialize_context *context, const void *value, unsigned int size)
|
|
{
|
|
memcpy(context->ptr, value, size);
|
|
context->ptr += size;
|
|
}
|
|
|
|
static BOOL attributes_serialize_write_item(struct attr_serialize_context *context, struct attributes_store_item *item,
|
|
const void *value)
|
|
{
|
|
switch (item->type)
|
|
{
|
|
case MF_ATTRIBUTE_UINT32:
|
|
case MF_ATTRIBUTE_UINT64:
|
|
case MF_ATTRIBUTE_DOUBLE:
|
|
attributes_serialize_write(context, item, sizeof(*item));
|
|
break;
|
|
case MF_ATTRIBUTE_GUID:
|
|
case MF_ATTRIBUTE_STRING:
|
|
case MF_ATTRIBUTE_BLOB:
|
|
item->u.subheader.offset = context->size - item->u.subheader.size;
|
|
attributes_serialize_write(context, item, sizeof(*item));
|
|
memcpy(context->buffer + item->u.subheader.offset, value, item->u.subheader.size);
|
|
context->size -= item->u.subheader.size;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFGetAttributesAsBlob (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size)
|
|
{
|
|
struct attributes_store_header header;
|
|
struct attr_serialize_context context;
|
|
unsigned int required_size, i;
|
|
PROPVARIANT value;
|
|
UINT32 count;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %u.\n", attributes, buffer, size);
|
|
|
|
if (FAILED(hr = MFGetAttributesAsBlobSize(attributes, &required_size)))
|
|
return hr;
|
|
|
|
if (required_size > size)
|
|
return MF_E_BUFFERTOOSMALL;
|
|
|
|
context.buffer = buffer;
|
|
context.ptr = buffer;
|
|
context.size = required_size;
|
|
|
|
IMFAttributes_LockStore(attributes);
|
|
|
|
header.magic = ATTRIBUTES_STORE_MAGIC;
|
|
header.count = 0; /* Will be updated later */
|
|
IMFAttributes_GetCount(attributes, &count);
|
|
|
|
attributes_serialize_write(&context, &header, sizeof(header));
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
struct attributes_store_item item;
|
|
const void *data = NULL;
|
|
|
|
hr = IMFAttributes_GetItemByIndex(attributes, i, &item.key, &value);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
item.type = value.vt;
|
|
|
|
switch (value.vt)
|
|
{
|
|
case MF_ATTRIBUTE_UINT32:
|
|
case MF_ATTRIBUTE_UINT64:
|
|
item.u.i64 = value.u.uhVal.QuadPart;
|
|
break;
|
|
case MF_ATTRIBUTE_DOUBLE:
|
|
item.u.f = value.u.dblVal;
|
|
break;
|
|
case MF_ATTRIBUTE_GUID:
|
|
item.u.subheader.size = sizeof(*value.u.puuid);
|
|
data = value.u.puuid;
|
|
break;
|
|
case MF_ATTRIBUTE_STRING:
|
|
item.u.subheader.size = (strlenW(value.u.pwszVal) + 1) * sizeof(WCHAR);
|
|
data = value.u.pwszVal;
|
|
break;
|
|
case MF_ATTRIBUTE_BLOB:
|
|
item.u.subheader.size = value.u.caub.cElems;
|
|
data = value.u.caub.pElems;
|
|
break;
|
|
case MF_ATTRIBUTE_IUNKNOWN:
|
|
break;
|
|
default:
|
|
WARN("Unknown attribute type %#x.\n", value.vt);
|
|
}
|
|
|
|
if (attributes_serialize_write_item(&context, &item, data))
|
|
header.count++;
|
|
|
|
PropVariantClear(&value);
|
|
}
|
|
|
|
memcpy(context.buffer, &header, sizeof(header));
|
|
|
|
IMFAttributes_UnlockStore(attributes);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT attributes_deserialize_read(struct attr_serialize_context *context, void *value, unsigned int size)
|
|
{
|
|
if (context->size < (context->ptr - context->buffer) + size)
|
|
return E_INVALIDARG;
|
|
|
|
memcpy(value, context->ptr, size);
|
|
context->ptr += size;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFInitAttributesFromBlob (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *dest, const UINT8 *buffer, UINT size)
|
|
{
|
|
struct attr_serialize_context context;
|
|
struct attributes_store_header header;
|
|
struct attributes_store_item item;
|
|
IMFAttributes *attributes;
|
|
unsigned int i;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %u.\n", dest, buffer, size);
|
|
|
|
context.buffer = (UINT8 *)buffer;
|
|
context.ptr = (UINT8 *)buffer;
|
|
context.size = size;
|
|
|
|
/* Validate buffer structure. */
|
|
if (FAILED(hr = attributes_deserialize_read(&context, &header, sizeof(header))))
|
|
return hr;
|
|
|
|
if (header.magic != ATTRIBUTES_STORE_MAGIC)
|
|
return E_UNEXPECTED;
|
|
|
|
if (FAILED(hr = MFCreateAttributes(&attributes, header.count)))
|
|
return hr;
|
|
|
|
for (i = 0; i < header.count; ++i)
|
|
{
|
|
if (FAILED(hr = attributes_deserialize_read(&context, &item, sizeof(item))))
|
|
break;
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
switch (item.type)
|
|
{
|
|
case MF_ATTRIBUTE_UINT32:
|
|
hr = IMFAttributes_SetUINT32(attributes, &item.key, item.u.i32);
|
|
break;
|
|
case MF_ATTRIBUTE_UINT64:
|
|
hr = IMFAttributes_SetUINT64(attributes, &item.key, item.u.i64);
|
|
break;
|
|
case MF_ATTRIBUTE_DOUBLE:
|
|
hr = IMFAttributes_SetDouble(attributes, &item.key, item.u.f);
|
|
break;
|
|
case MF_ATTRIBUTE_GUID:
|
|
if (item.u.subheader.size == sizeof(GUID) &&
|
|
item.u.subheader.offset + item.u.subheader.size <= context.size)
|
|
{
|
|
hr = IMFAttributes_SetGUID(attributes, &item.key,
|
|
(const GUID *)(context.buffer + item.u.subheader.offset));
|
|
}
|
|
break;
|
|
case MF_ATTRIBUTE_STRING:
|
|
if (item.u.subheader.size >= sizeof(WCHAR) &&
|
|
item.u.subheader.offset + item.u.subheader.size <= context.size)
|
|
{
|
|
hr = IMFAttributes_SetString(attributes, &item.key,
|
|
(const WCHAR *)(context.buffer + item.u.subheader.offset));
|
|
}
|
|
break;
|
|
case MF_ATTRIBUTE_BLOB:
|
|
if (item.u.subheader.size > 0 && item.u.subheader.offset + item.u.subheader.size <= context.size)
|
|
{
|
|
hr = IMFAttributes_SetBlob(attributes, &item.key, context.buffer + item.u.subheader.offset,
|
|
item.u.subheader.size);
|
|
}
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IMFAttributes_DeleteAllItems(dest);
|
|
hr = IMFAttributes_CopyAllItems(attributes, dest);
|
|
}
|
|
|
|
IMFAttributes_Release(attributes);
|
|
|
|
return hr;
|
|
}
|
|
|
|
typedef struct bytestream
|
|
{
|
|
struct attributes attributes;
|
|
IMFByteStream IMFByteStream_iface;
|
|
IMFGetService IMFGetService_iface;
|
|
IMFAsyncCallback read_callback;
|
|
IMFAsyncCallback write_callback;
|
|
IStream *stream;
|
|
HANDLE hfile;
|
|
QWORD position;
|
|
DWORD capabilities;
|
|
struct list pending;
|
|
CRITICAL_SECTION cs;
|
|
} mfbytestream;
|
|
|
|
static inline mfbytestream *impl_from_IMFByteStream(IMFByteStream *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, mfbytestream, IMFByteStream_iface);
|
|
}
|
|
|
|
static struct bytestream *impl_bytestream_from_IMFGetService(IMFGetService *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream, IMFGetService_iface);
|
|
}
|
|
|
|
static struct bytestream *impl_from_read_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream, read_callback);
|
|
}
|
|
|
|
static struct bytestream *impl_from_write_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream, write_callback);
|
|
}
|
|
|
|
enum async_stream_op_type
|
|
{
|
|
ASYNC_STREAM_OP_READ,
|
|
ASYNC_STREAM_OP_WRITE,
|
|
};
|
|
|
|
struct async_stream_op
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG refcount;
|
|
union
|
|
{
|
|
const BYTE *src;
|
|
BYTE *dest;
|
|
} u;
|
|
QWORD position;
|
|
ULONG requested_length;
|
|
ULONG actual_length;
|
|
IMFAsyncResult *caller;
|
|
struct list entry;
|
|
enum async_stream_op_type type;
|
|
};
|
|
|
|
static struct async_stream_op *impl_async_stream_op_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct async_stream_op, IUnknown_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI async_stream_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
IUnknown_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI async_stream_op_AddRef(IUnknown *iface)
|
|
{
|
|
struct async_stream_op *op = impl_async_stream_op_from_IUnknown(iface);
|
|
ULONG refcount = InterlockedIncrement(&op->refcount);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI async_stream_op_Release(IUnknown *iface)
|
|
{
|
|
struct async_stream_op *op = impl_async_stream_op_from_IUnknown(iface);
|
|
ULONG refcount = InterlockedDecrement(&op->refcount);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
if (op->caller)
|
|
IMFAsyncResult_Release(op->caller);
|
|
heap_free(op);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static const IUnknownVtbl async_stream_op_vtbl =
|
|
{
|
|
async_stream_op_QueryInterface,
|
|
async_stream_op_AddRef,
|
|
async_stream_op_Release,
|
|
};
|
|
|
|
static HRESULT bytestream_create_io_request(struct bytestream *stream, enum async_stream_op_type type,
|
|
const BYTE *data, ULONG size, IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct async_stream_op *op;
|
|
IMFAsyncResult *request;
|
|
HRESULT hr;
|
|
|
|
op = heap_alloc(sizeof(*op));
|
|
if (!op)
|
|
return E_OUTOFMEMORY;
|
|
|
|
op->IUnknown_iface.lpVtbl = &async_stream_op_vtbl;
|
|
op->refcount = 1;
|
|
op->u.src = data;
|
|
op->position = stream->position;
|
|
op->requested_length = size;
|
|
op->type = type;
|
|
if (FAILED(hr = MFCreateAsyncResult((IUnknown *)&stream->IMFByteStream_iface, callback, state, &op->caller)))
|
|
goto failed;
|
|
|
|
if (FAILED(hr = MFCreateAsyncResult(&op->IUnknown_iface, type == ASYNC_STREAM_OP_READ ? &stream->read_callback :
|
|
&stream->write_callback, NULL, &request)))
|
|
goto failed;
|
|
|
|
MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, request);
|
|
IMFAsyncResult_Release(request);
|
|
|
|
failed:
|
|
IUnknown_Release(&op->IUnknown_iface);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT bytestream_complete_io_request(struct bytestream *stream, enum async_stream_op_type type,
|
|
IMFAsyncResult *result, ULONG *actual_length)
|
|
{
|
|
struct async_stream_op *op = NULL, *cur;
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&stream->cs);
|
|
LIST_FOR_EACH_ENTRY(cur, &stream->pending, struct async_stream_op, entry)
|
|
{
|
|
if (cur->caller == result && cur->type == type)
|
|
{
|
|
op = cur;
|
|
list_remove(&cur->entry);
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&stream->cs);
|
|
|
|
if (!op)
|
|
return E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(hr = IMFAsyncResult_GetStatus(result)))
|
|
*actual_length = op->actual_length;
|
|
|
|
IUnknown_Release(&op->IUnknown_iface);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
IMFAsyncCallback_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_read_callback_AddRef(IMFAsyncCallback *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface);
|
|
return IMFByteStream_AddRef(&stream->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_read_callback_Release(IMFAsyncCallback *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface);
|
|
return IMFByteStream_Release(&stream->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_write_callback_AddRef(IMFAsyncCallback *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_write_callback_IMFAsyncCallback(iface);
|
|
return IMFByteStream_AddRef(&stream->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_write_callback_Release(IMFAsyncCallback *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_write_callback_IMFAsyncCallback(iface);
|
|
return IMFByteStream_Release(&stream->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_QueryInterface(IMFByteStream *iface, REFIID riid, void **out)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFByteStream) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*out = &stream->IMFByteStream_iface;
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IMFAttributes))
|
|
{
|
|
*out = &stream->attributes.IMFAttributes_iface;
|
|
}
|
|
else if (stream->IMFGetService_iface.lpVtbl && IsEqualIID(riid, &IID_IMFGetService))
|
|
{
|
|
*out = &stream->IMFGetService_iface;
|
|
}
|
|
else
|
|
{
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown*)*out);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_AddRef(IMFByteStream *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
ULONG refcount = InterlockedIncrement(&stream->attributes.ref);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_Release(IMFByteStream *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
ULONG refcount = InterlockedDecrement(&stream->attributes.ref);
|
|
struct async_stream_op *cur, *cur2;
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
clear_attributes_object(&stream->attributes);
|
|
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &stream->pending, struct async_stream_op, entry)
|
|
{
|
|
list_remove(&cur->entry);
|
|
IUnknown_Release(&cur->IUnknown_iface);
|
|
}
|
|
DeleteCriticalSection(&stream->cs);
|
|
if (stream->stream)
|
|
IStream_Release(stream->stream);
|
|
if (stream->hfile)
|
|
CloseHandle(stream->hfile);
|
|
heap_free(stream);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_GetCapabilities(IMFByteStream *iface, DWORD *capabilities)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, capabilities);
|
|
|
|
*capabilities = stream->capabilities;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_GetLength(IMFByteStream *iface, QWORD *length)
|
|
{
|
|
FIXME("%p, %p.\n", iface, length);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_SetLength(IMFByteStream *iface, QWORD length)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %s\n", This, wine_dbgstr_longlong(length));
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_GetCurrentPosition(IMFByteStream *iface, QWORD *position)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %p\n", This, position);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_SetCurrentPosition(IMFByteStream *iface, QWORD position)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %s\n", This, wine_dbgstr_longlong(position));
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_IsEndOfStream(IMFByteStream *iface, BOOL *endstream)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %p\n", This, endstream);
|
|
|
|
if(endstream)
|
|
*endstream = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_Read(IMFByteStream *iface, BYTE *data, ULONG count, ULONG *byte_read)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %p, %u, %p\n", This, data, count, byte_read);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_BeginRead(IMFByteStream *iface, BYTE *data, ULONG size, IMFAsyncCallback *callback,
|
|
IUnknown *state)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
|
|
|
|
return bytestream_create_io_request(stream, ASYNC_STREAM_OP_READ, data, size, callback, state);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_EndRead(IMFByteStream *iface, IMFAsyncResult *result, ULONG *byte_read)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, result, byte_read);
|
|
|
|
return bytestream_complete_io_request(stream, ASYNC_STREAM_OP_READ, result, byte_read);
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_Write(IMFByteStream *iface, const BYTE *data, ULONG count, ULONG *written)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %p, %u, %p\n", This, data, count, written);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_BeginWrite(IMFByteStream *iface, const BYTE *data, ULONG size,
|
|
IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
|
|
|
|
return bytestream_create_io_request(stream, ASYNC_STREAM_OP_WRITE, data, size, callback, state);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_EndWrite(IMFByteStream *iface, IMFAsyncResult *result, ULONG *written)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, result, written);
|
|
|
|
return bytestream_complete_io_request(stream, ASYNC_STREAM_OP_WRITE, result, written);
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN seek, LONGLONG offset,
|
|
DWORD flags, QWORD *current)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p, %u, %s, 0x%08x, %p\n", This, seek, wine_dbgstr_longlong(offset), flags, current);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_Flush(IMFByteStream *iface)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p\n", This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_Close(IMFByteStream *iface)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream(iface);
|
|
|
|
FIXME("%p\n", This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMFByteStreamVtbl mfbytestream_vtbl =
|
|
{
|
|
bytestream_QueryInterface,
|
|
bytestream_AddRef,
|
|
bytestream_Release,
|
|
bytestream_GetCapabilities,
|
|
mfbytestream_GetLength,
|
|
mfbytestream_SetLength,
|
|
mfbytestream_GetCurrentPosition,
|
|
mfbytestream_SetCurrentPosition,
|
|
mfbytestream_IsEndOfStream,
|
|
mfbytestream_Read,
|
|
bytestream_BeginRead,
|
|
bytestream_EndRead,
|
|
mfbytestream_Write,
|
|
bytestream_BeginWrite,
|
|
bytestream_EndWrite,
|
|
mfbytestream_Seek,
|
|
mfbytestream_Flush,
|
|
mfbytestream_Close
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_stream_GetLength(IMFByteStream *iface, QWORD *length)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
STATSTG statstg;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p.\n", iface, length);
|
|
|
|
if (FAILED(hr = IStream_Stat(stream->stream, &statstg, STATFLAG_NONAME)))
|
|
return hr;
|
|
|
|
*length = statstg.cbSize.QuadPart;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_SetLength(IMFByteStream *iface, QWORD length)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
ULARGE_INTEGER size;
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(length));
|
|
|
|
size.QuadPart = length;
|
|
return IStream_SetSize(stream->stream, size);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_GetCurrentPosition(IMFByteStream *iface, QWORD *position)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, position);
|
|
|
|
*position = stream->position;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_SetCurrentPosition(IMFByteStream *iface, QWORD position)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(position));
|
|
|
|
stream->position = position;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_IsEndOfStream(IMFByteStream *iface, BOOL *ret)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
STATSTG statstg;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p.\n", iface, ret);
|
|
|
|
if (FAILED(hr = IStream_Stat(stream->stream, &statstg, STATFLAG_NONAME)))
|
|
return hr;
|
|
|
|
*ret = stream->position >= statstg.cbSize.QuadPart;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_Read(IMFByteStream *iface, BYTE *buffer, ULONG size, ULONG *read_len)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
LARGE_INTEGER position;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %u, %p.\n", iface, buffer, size, read_len);
|
|
|
|
position.QuadPart = stream->position;
|
|
if (FAILED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL)))
|
|
return hr;
|
|
|
|
if (SUCCEEDED(hr = IStream_Read(stream->stream, buffer, size, read_len)))
|
|
stream->position += *read_len;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_Write(IMFByteStream *iface, const BYTE *buffer, ULONG size, ULONG *written)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
LARGE_INTEGER position;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %u, %p.\n", iface, buffer, size, written);
|
|
|
|
position.QuadPart = stream->position;
|
|
if (FAILED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL)))
|
|
return hr;
|
|
|
|
if (SUCCEEDED(hr = IStream_Write(stream->stream, buffer, size, written)))
|
|
stream->position += *written;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN origin, LONGLONG offset,
|
|
DWORD flags, QWORD *current)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %u, %s, %#x, %p.\n", iface, origin, wine_dbgstr_longlong(offset), flags, current);
|
|
|
|
switch (origin)
|
|
{
|
|
case msoBegin:
|
|
stream->position = offset;
|
|
break;
|
|
case msoCurrent:
|
|
stream->position += offset;
|
|
break;
|
|
default:
|
|
WARN("Unknown origin mode %d.\n", origin);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*current = stream->position;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_Flush(IMFByteStream *iface)
|
|
{
|
|
struct bytestream *stream = impl_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IStream_Commit(stream->stream, STGC_DEFAULT);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_Close(IMFByteStream *iface)
|
|
{
|
|
TRACE("%p.\n", iface);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFByteStreamVtbl bytestream_stream_vtbl =
|
|
{
|
|
bytestream_QueryInterface,
|
|
bytestream_AddRef,
|
|
bytestream_Release,
|
|
bytestream_GetCapabilities,
|
|
bytestream_stream_GetLength,
|
|
bytestream_stream_SetLength,
|
|
bytestream_stream_GetCurrentPosition,
|
|
bytestream_stream_SetCurrentPosition,
|
|
bytestream_stream_IsEndOfStream,
|
|
bytestream_stream_Read,
|
|
bytestream_BeginRead,
|
|
bytestream_EndRead,
|
|
bytestream_stream_Write,
|
|
bytestream_BeginWrite,
|
|
bytestream_EndWrite,
|
|
bytestream_stream_Seek,
|
|
bytestream_stream_Flush,
|
|
bytestream_stream_Close,
|
|
};
|
|
|
|
static inline mfbytestream *impl_from_IMFByteStream_IMFAttributes(IMFAttributes *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, mfbytestream, attributes.IMFAttributes_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI mfbytestream_attributes_QueryInterface(
|
|
IMFAttributes *iface, REFIID riid, void **out)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream_IMFAttributes(iface);
|
|
return IMFByteStream_QueryInterface(&This->IMFByteStream_iface, riid, out);
|
|
}
|
|
|
|
static ULONG WINAPI mfbytestream_attributes_AddRef(IMFAttributes *iface)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream_IMFAttributes(iface);
|
|
return IMFByteStream_AddRef(&This->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI mfbytestream_attributes_Release(IMFAttributes *iface)
|
|
{
|
|
mfbytestream *This = impl_from_IMFByteStream_IMFAttributes(iface);
|
|
return IMFByteStream_Release(&This->IMFByteStream_iface);
|
|
}
|
|
|
|
static const IMFAttributesVtbl mfbytestream_attributes_vtbl =
|
|
{
|
|
mfbytestream_attributes_QueryInterface,
|
|
mfbytestream_attributes_AddRef,
|
|
mfbytestream_attributes_Release,
|
|
mfattributes_GetItem,
|
|
mfattributes_GetItemType,
|
|
mfattributes_CompareItem,
|
|
mfattributes_Compare,
|
|
mfattributes_GetUINT32,
|
|
mfattributes_GetUINT64,
|
|
mfattributes_GetDouble,
|
|
mfattributes_GetGUID,
|
|
mfattributes_GetStringLength,
|
|
mfattributes_GetString,
|
|
mfattributes_GetAllocatedString,
|
|
mfattributes_GetBlobSize,
|
|
mfattributes_GetBlob,
|
|
mfattributes_GetAllocatedBlob,
|
|
mfattributes_GetUnknown,
|
|
mfattributes_SetItem,
|
|
mfattributes_DeleteItem,
|
|
mfattributes_DeleteAllItems,
|
|
mfattributes_SetUINT32,
|
|
mfattributes_SetUINT64,
|
|
mfattributes_SetDouble,
|
|
mfattributes_SetGUID,
|
|
mfattributes_SetString,
|
|
mfattributes_SetBlob,
|
|
mfattributes_SetUnknown,
|
|
mfattributes_LockStore,
|
|
mfattributes_UnlockStore,
|
|
mfattributes_GetCount,
|
|
mfattributes_GetItemByIndex,
|
|
mfattributes_CopyAllItems
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_stream_read_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
|
{
|
|
struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface);
|
|
struct async_stream_op *op;
|
|
LARGE_INTEGER position;
|
|
IUnknown *object;
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
|
|
return hr;
|
|
|
|
op = impl_async_stream_op_from_IUnknown(object);
|
|
|
|
position.QuadPart = op->position;
|
|
if (SUCCEEDED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL)))
|
|
{
|
|
if (SUCCEEDED(hr = IStream_Read(stream->stream, op->u.dest, op->requested_length, &op->actual_length)))
|
|
stream->position += op->actual_length;
|
|
}
|
|
|
|
IMFAsyncResult_SetStatus(op->caller, hr);
|
|
|
|
EnterCriticalSection(&stream->cs);
|
|
list_add_tail(&stream->pending, &op->entry);
|
|
LeaveCriticalSection(&stream->cs);
|
|
|
|
MFInvokeCallback(op->caller);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_stream_write_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
|
{
|
|
struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface);
|
|
struct async_stream_op *op;
|
|
LARGE_INTEGER position;
|
|
IUnknown *object;
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
|
|
return hr;
|
|
|
|
op = impl_async_stream_op_from_IUnknown(object);
|
|
|
|
position.QuadPart = op->position;
|
|
if (SUCCEEDED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL)))
|
|
{
|
|
if (SUCCEEDED(hr = IStream_Write(stream->stream, op->u.src, op->requested_length, &op->actual_length)))
|
|
stream->position += op->actual_length;
|
|
}
|
|
|
|
IMFAsyncResult_SetStatus(op->caller, hr);
|
|
|
|
EnterCriticalSection(&stream->cs);
|
|
list_add_tail(&stream->pending, &op->entry);
|
|
LeaveCriticalSection(&stream->cs);
|
|
|
|
MFInvokeCallback(op->caller);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFAsyncCallbackVtbl bytestream_stream_read_callback_vtbl =
|
|
{
|
|
bytestream_callback_QueryInterface,
|
|
bytestream_read_callback_AddRef,
|
|
bytestream_read_callback_Release,
|
|
bytestream_callback_GetParameters,
|
|
bytestream_stream_read_callback_Invoke,
|
|
};
|
|
|
|
static const IMFAsyncCallbackVtbl bytestream_stream_write_callback_vtbl =
|
|
{
|
|
bytestream_callback_QueryInterface,
|
|
bytestream_write_callback_AddRef,
|
|
bytestream_write_callback_Release,
|
|
bytestream_callback_GetParameters,
|
|
bytestream_stream_write_callback_Invoke,
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateMFByteStreamOnStream (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream)
|
|
{
|
|
struct bytestream *object;
|
|
LARGE_INTEGER position;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p.\n", stream, bytestream);
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
|
|
{
|
|
heap_free(object);
|
|
return hr;
|
|
}
|
|
|
|
object->IMFByteStream_iface.lpVtbl = &bytestream_stream_vtbl;
|
|
object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl;
|
|
object->read_callback.lpVtbl = &bytestream_stream_read_callback_vtbl;
|
|
object->write_callback.lpVtbl = &bytestream_stream_write_callback_vtbl;
|
|
InitializeCriticalSection(&object->cs);
|
|
list_init(&object->pending);
|
|
|
|
object->stream = stream;
|
|
IStream_AddRef(object->stream);
|
|
position.QuadPart = 0;
|
|
IStream_Seek(object->stream, position, STREAM_SEEK_SET, NULL);
|
|
object->capabilities = MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE;
|
|
|
|
*bytestream = &object->IMFByteStream_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_file_read_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
|
{
|
|
FIXME("%p, %p.\n", iface, result);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_file_write_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
|
{
|
|
FIXME("%p, %p.\n", iface, result);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMFAsyncCallbackVtbl bytestream_file_read_callback_vtbl =
|
|
{
|
|
bytestream_callback_QueryInterface,
|
|
bytestream_read_callback_AddRef,
|
|
bytestream_read_callback_Release,
|
|
bytestream_callback_GetParameters,
|
|
bytestream_file_read_callback_Invoke,
|
|
};
|
|
|
|
static const IMFAsyncCallbackVtbl bytestream_file_write_callback_vtbl =
|
|
{
|
|
bytestream_callback_QueryInterface,
|
|
bytestream_write_callback_AddRef,
|
|
bytestream_write_callback_Release,
|
|
bytestream_callback_GetParameters,
|
|
bytestream_file_write_callback_Invoke,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_file_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
|
|
{
|
|
struct bytestream *stream = impl_bytestream_from_IMFGetService(iface);
|
|
return IMFByteStream_QueryInterface(&stream->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_file_getservice_AddRef(IMFGetService *iface)
|
|
{
|
|
struct bytestream *stream = impl_bytestream_from_IMFGetService(iface);
|
|
return IMFByteStream_AddRef(&stream->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_file_getservice_Release(IMFGetService *iface)
|
|
{
|
|
struct bytestream *stream = impl_bytestream_from_IMFGetService(iface);
|
|
return IMFByteStream_Release(&stream->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_file_getservice_GetService(IMFGetService *iface, REFGUID service,
|
|
REFIID riid, void **obj)
|
|
{
|
|
FIXME("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMFGetServiceVtbl bytestream_file_getservice_vtbl =
|
|
{
|
|
bytestream_file_getservice_QueryInterface,
|
|
bytestream_file_getservice_AddRef,
|
|
bytestream_file_getservice_Release,
|
|
bytestream_file_getservice_GetService,
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateFile (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags,
|
|
LPCWSTR url, IMFByteStream **bytestream)
|
|
{
|
|
DWORD capabilities = MFBYTESTREAM_IS_SEEKABLE | MFBYTESTREAM_DOES_NOT_USE_NETWORK;
|
|
struct bytestream *object;
|
|
DWORD fileaccessmode = 0;
|
|
DWORD filesharemode = FILE_SHARE_READ;
|
|
DWORD filecreation_disposition = 0;
|
|
DWORD fileattributes = 0;
|
|
FILETIME writetime;
|
|
HANDLE file;
|
|
HRESULT hr;
|
|
|
|
FIXME("(%d, %d, %d, %s, %p): stub\n", accessmode, openmode, flags, debugstr_w(url), bytestream);
|
|
|
|
switch (accessmode)
|
|
{
|
|
case MF_ACCESSMODE_READ:
|
|
fileaccessmode = GENERIC_READ;
|
|
capabilities |= MFBYTESTREAM_IS_READABLE;
|
|
break;
|
|
case MF_ACCESSMODE_WRITE:
|
|
fileaccessmode = GENERIC_WRITE;
|
|
capabilities |= MFBYTESTREAM_IS_WRITABLE;
|
|
break;
|
|
case MF_ACCESSMODE_READWRITE:
|
|
fileaccessmode = GENERIC_READ | GENERIC_WRITE;
|
|
capabilities |= (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_WRITABLE);
|
|
break;
|
|
}
|
|
|
|
switch (openmode)
|
|
{
|
|
case MF_OPENMODE_FAIL_IF_NOT_EXIST:
|
|
filecreation_disposition = OPEN_EXISTING;
|
|
break;
|
|
case MF_OPENMODE_FAIL_IF_EXIST:
|
|
filecreation_disposition = CREATE_NEW;
|
|
break;
|
|
case MF_OPENMODE_RESET_IF_EXIST:
|
|
filecreation_disposition = TRUNCATE_EXISTING;
|
|
break;
|
|
case MF_OPENMODE_APPEND_IF_EXIST:
|
|
filecreation_disposition = OPEN_ALWAYS;
|
|
fileaccessmode |= FILE_APPEND_DATA;
|
|
break;
|
|
case MF_OPENMODE_DELETE_IF_EXIST:
|
|
filecreation_disposition = CREATE_ALWAYS;
|
|
break;
|
|
}
|
|
|
|
if (flags & MF_FILEFLAGS_NOBUFFERING)
|
|
fileattributes |= FILE_FLAG_NO_BUFFERING;
|
|
|
|
/* Open HANDLE to file */
|
|
file = CreateFileW(url, fileaccessmode, filesharemode, NULL,
|
|
filecreation_disposition, fileattributes, 0);
|
|
|
|
if(file == INVALID_HANDLE_VALUE)
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
{
|
|
CloseHandle(file);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hr = init_attributes_object(&object->attributes, 2)))
|
|
{
|
|
CloseHandle(file);
|
|
heap_free(object);
|
|
return hr;
|
|
}
|
|
object->IMFByteStream_iface.lpVtbl = &mfbytestream_vtbl;
|
|
object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl;
|
|
object->IMFGetService_iface.lpVtbl = &bytestream_file_getservice_vtbl;
|
|
object->read_callback.lpVtbl = &bytestream_file_read_callback_vtbl;
|
|
object->write_callback.lpVtbl = &bytestream_file_write_callback_vtbl;
|
|
InitializeCriticalSection(&object->cs);
|
|
list_init(&object->pending);
|
|
object->capabilities = capabilities;
|
|
object->hfile = file;
|
|
|
|
if (GetFileTime(file, NULL, NULL, &writetime))
|
|
{
|
|
IMFAttributes_SetBlob(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_LAST_MODIFIED_TIME,
|
|
(const UINT8 *)&writetime, sizeof(writetime));
|
|
}
|
|
|
|
IMFAttributes_SetString(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_ORIGIN_NAME, url);
|
|
|
|
*bytestream = &object->IMFByteStream_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
struct bytestream_wrapper
|
|
{
|
|
IMFByteStreamCacheControl IMFByteStreamCacheControl_iface;
|
|
IMFByteStreamBuffering IMFByteStreamBuffering_iface;
|
|
IMFMediaEventGenerator IMFMediaEventGenerator_iface;
|
|
IMFByteStreamTimeSeek IMFByteStreamTimeSeek_iface;
|
|
IMFSampleOutputStream IMFSampleOutputStream_iface;
|
|
IPropertyStore IPropertyStore_iface;
|
|
IMFByteStream IMFByteStream_iface;
|
|
IMFAttributes IMFAttributes_iface;
|
|
LONG refcount;
|
|
|
|
IMFByteStreamCacheControl *cache_control;
|
|
IMFByteStreamBuffering *stream_buffering;
|
|
IMFMediaEventGenerator *event_generator;
|
|
IMFByteStreamTimeSeek *time_seek;
|
|
IMFSampleOutputStream *sample_output;
|
|
IPropertyStore *propstore;
|
|
IMFByteStream *stream;
|
|
IMFAttributes *attributes;
|
|
BOOL is_closed;
|
|
};
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFByteStream(IMFByteStream *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFByteStream_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFByteStreamCacheControl(IMFByteStreamCacheControl *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFByteStreamCacheControl_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFByteStreamBuffering(IMFByteStreamBuffering *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFByteStreamBuffering_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFMediaEventGenerator_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFByteStreamTimeSeek(IMFByteStreamTimeSeek *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFByteStreamTimeSeek_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFSampleOutputStream(IMFSampleOutputStream *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFSampleOutputStream_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IPropertyStore(IPropertyStore *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IPropertyStore_iface);
|
|
}
|
|
|
|
static struct bytestream_wrapper *impl_wrapper_from_IMFAttributes(IMFAttributes *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct bytestream_wrapper, IMFAttributes_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_QueryInterface(IMFByteStream *iface, REFIID riid, void **out)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFByteStream) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*out = &wrapper->IMFByteStream_iface;
|
|
}
|
|
else if (wrapper->cache_control && IsEqualIID(riid, &IID_IMFByteStreamCacheControl))
|
|
{
|
|
*out = &wrapper->IMFByteStreamCacheControl_iface;
|
|
}
|
|
else if (wrapper->stream_buffering && IsEqualIID(riid, &IID_IMFByteStreamBuffering))
|
|
{
|
|
*out = &wrapper->IMFByteStreamBuffering_iface;
|
|
}
|
|
else if (wrapper->event_generator && IsEqualIID(riid, &IID_IMFMediaEventGenerator))
|
|
{
|
|
*out = &wrapper->IMFMediaEventGenerator_iface;
|
|
}
|
|
else if (wrapper->time_seek && IsEqualIID(riid, &IID_IMFByteStreamTimeSeek))
|
|
{
|
|
*out = &wrapper->IMFByteStreamTimeSeek_iface;
|
|
}
|
|
else if (wrapper->sample_output && IsEqualIID(riid, &IID_IMFSampleOutputStream))
|
|
{
|
|
*out = &wrapper->IMFSampleOutputStream_iface;
|
|
}
|
|
else if (wrapper->propstore && IsEqualIID(riid, &IID_IPropertyStore))
|
|
{
|
|
*out = &wrapper->IPropertyStore_iface;
|
|
}
|
|
else if (wrapper->attributes && IsEqualIID(riid, &IID_IMFAttributes))
|
|
{
|
|
*out = &wrapper->IMFAttributes_iface;
|
|
}
|
|
else
|
|
{
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown *)*out);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_AddRef(IMFByteStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
ULONG refcount = InterlockedIncrement(&wrapper->refcount);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_Release(IMFByteStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
ULONG refcount = InterlockedDecrement(&wrapper->refcount);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
if (wrapper->cache_control)
|
|
IMFByteStreamCacheControl_Release(wrapper->cache_control);
|
|
if (wrapper->stream_buffering)
|
|
IMFByteStreamBuffering_Release(wrapper->stream_buffering);
|
|
if (wrapper->event_generator)
|
|
IMFMediaEventGenerator_Release(wrapper->event_generator);
|
|
if (wrapper->time_seek)
|
|
IMFByteStreamTimeSeek_Release(wrapper->time_seek);
|
|
if (wrapper->sample_output)
|
|
IMFSampleOutputStream_Release(wrapper->sample_output);
|
|
if (wrapper->propstore)
|
|
IPropertyStore_Release(wrapper->propstore);
|
|
if (wrapper->attributes)
|
|
IMFAttributes_Release(wrapper->attributes);
|
|
IMFByteStream_Release(wrapper->stream);
|
|
heap_free(wrapper);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_GetCapabilities(IMFByteStream *iface, DWORD *capabilities)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, capabilities);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_GetCapabilities(wrapper->stream, capabilities);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_GetLength(IMFByteStream *iface, QWORD *length)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, length);
|
|
|
|
if (wrapper->is_closed)
|
|
return MF_E_INVALIDREQUEST;
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_GetLength(wrapper->stream, length);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_SetLength(IMFByteStream *iface, QWORD length)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(length));
|
|
|
|
if (wrapper->is_closed)
|
|
return MF_E_INVALIDREQUEST;
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_SetLength(wrapper->stream, length);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_GetCurrentPosition(IMFByteStream *iface, QWORD *position)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, position);
|
|
|
|
if (wrapper->is_closed)
|
|
return MF_E_INVALIDREQUEST;
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_GetCurrentPosition(wrapper->stream, position);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_SetCurrentPosition(IMFByteStream *iface, QWORD position)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(position));
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_SetCurrentPosition(wrapper->stream, position);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_IsEndOfStream(IMFByteStream *iface, BOOL *eos)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, eos);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_IsEndOfStream(wrapper->stream, eos);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_Read(IMFByteStream *iface, BYTE *data, ULONG count, ULONG *byte_read)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %u, %p.\n", iface, data, count, byte_read);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_Read(wrapper->stream, data, count, byte_read);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_BeginRead(IMFByteStream *iface, BYTE *data, ULONG size,
|
|
IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_BeginRead(wrapper->stream, data, size, callback, state);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_EndRead(IMFByteStream *iface, IMFAsyncResult *result, ULONG *byte_read)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, result, byte_read);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_EndRead(wrapper->stream, result, byte_read);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_Write(IMFByteStream *iface, const BYTE *data, ULONG count, ULONG *written)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %u, %p.\n", iface, data, count, written);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_Write(wrapper->stream, data, count, written);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_BeginWrite(IMFByteStream *iface, const BYTE *data, ULONG size,
|
|
IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_BeginWrite(wrapper->stream, data, size, callback, state);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_EndWrite(IMFByteStream *iface, IMFAsyncResult *result, ULONG *written)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, result, written);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_EndWrite(wrapper->stream, result, written);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN seek, LONGLONG offset,
|
|
DWORD flags, QWORD *current)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p, %u, %s, %#x, %p.\n", iface, seek, wine_dbgstr_longlong(offset), flags, current);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST :
|
|
IMFByteStream_Seek(wrapper->stream, seek, offset, flags, current);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_Flush(IMFByteStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p\n", iface);
|
|
|
|
return wrapper->is_closed ? MF_E_INVALIDREQUEST : IMFByteStream_Flush(wrapper->stream);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_Close(IMFByteStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStream(iface);
|
|
|
|
TRACE("%p\n", iface);
|
|
|
|
wrapper->is_closed = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFByteStreamVtbl bytestream_wrapper_vtbl =
|
|
{
|
|
bytestream_wrapper_QueryInterface,
|
|
bytestream_wrapper_AddRef,
|
|
bytestream_wrapper_Release,
|
|
bytestream_wrapper_GetCapabilities,
|
|
bytestream_wrapper_GetLength,
|
|
bytestream_wrapper_SetLength,
|
|
bytestream_wrapper_GetCurrentPosition,
|
|
bytestream_wrapper_SetCurrentPosition,
|
|
bytestream_wrapper_IsEndOfStream,
|
|
bytestream_wrapper_Read,
|
|
bytestream_wrapper_BeginRead,
|
|
bytestream_wrapper_EndRead,
|
|
bytestream_wrapper_Write,
|
|
bytestream_wrapper_BeginWrite,
|
|
bytestream_wrapper_EndWrite,
|
|
bytestream_wrapper_Seek,
|
|
bytestream_wrapper_Flush,
|
|
bytestream_wrapper_Close,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_cache_control_QueryInterface(IMFByteStreamCacheControl *iface,
|
|
REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamCacheControl(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_cache_control_AddRef(IMFByteStreamCacheControl *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamCacheControl(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_cache_control_Release(IMFByteStreamCacheControl *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamCacheControl(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_cache_control_StopBackgroundTransfer(IMFByteStreamCacheControl *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamCacheControl(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IMFByteStreamCacheControl_StopBackgroundTransfer(wrapper->cache_control);
|
|
}
|
|
|
|
static const IMFByteStreamCacheControlVtbl bytestream_wrapper_cache_control_vtbl =
|
|
{
|
|
bytestream_wrapper_cache_control_QueryInterface,
|
|
bytestream_wrapper_cache_control_AddRef,
|
|
bytestream_wrapper_cache_control_Release,
|
|
bytestream_wrapper_cache_control_StopBackgroundTransfer,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_buffering_QueryInterface(IMFByteStreamBuffering *iface,
|
|
REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamBuffering(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_buffering_AddRef(IMFByteStreamBuffering *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamBuffering(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_buffering_Release(IMFByteStreamBuffering *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamBuffering(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_buffering_SetBufferingParams(IMFByteStreamBuffering *iface,
|
|
MFBYTESTREAM_BUFFERING_PARAMS *params)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamBuffering(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, params);
|
|
|
|
return IMFByteStreamBuffering_SetBufferingParams(wrapper->stream_buffering, params);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_buffering_EnableBuffering(IMFByteStreamBuffering *iface,
|
|
BOOL enable)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamBuffering(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, enable);
|
|
|
|
return IMFByteStreamBuffering_EnableBuffering(wrapper->stream_buffering, enable);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_buffering_StopBuffering(IMFByteStreamBuffering *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamBuffering(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IMFByteStreamBuffering_StopBuffering(wrapper->stream_buffering);
|
|
}
|
|
|
|
static const IMFByteStreamBufferingVtbl bytestream_wrapper_buffering_vtbl =
|
|
{
|
|
bytestream_wrapper_buffering_QueryInterface,
|
|
bytestream_wrapper_buffering_AddRef,
|
|
bytestream_wrapper_buffering_Release,
|
|
bytestream_wrapper_buffering_SetBufferingParams,
|
|
bytestream_wrapper_buffering_EnableBuffering,
|
|
bytestream_wrapper_buffering_StopBuffering,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_timeseek_QueryInterface(IMFByteStreamTimeSeek *iface,
|
|
REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamTimeSeek(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_timeseek_AddRef(IMFByteStreamTimeSeek *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamTimeSeek(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_timeseek_Release(IMFByteStreamTimeSeek *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamTimeSeek(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_timeseek_IsTimeSeekSupported(IMFByteStreamTimeSeek *iface, BOOL *result)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamTimeSeek(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, result);
|
|
|
|
return IMFByteStreamTimeSeek_IsTimeSeekSupported(wrapper->time_seek, result);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_timeseek_TimeSeek(IMFByteStreamTimeSeek *iface, QWORD position)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamTimeSeek(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(position));
|
|
|
|
return IMFByteStreamTimeSeek_TimeSeek(wrapper->time_seek, position);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_timeseek_GetTimeSeekResult(IMFByteStreamTimeSeek *iface, QWORD *start_time,
|
|
QWORD *stop_time, QWORD *duration)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFByteStreamTimeSeek(iface);
|
|
|
|
TRACE("%p, %p, %p, %p.\n", iface, start_time, stop_time, duration);
|
|
|
|
return IMFByteStreamTimeSeek_GetTimeSeekResult(wrapper->time_seek, start_time, stop_time, duration);
|
|
}
|
|
|
|
static const IMFByteStreamTimeSeekVtbl bytestream_wrapper_timeseek_vtbl =
|
|
{
|
|
bytestream_wrapper_timeseek_QueryInterface,
|
|
bytestream_wrapper_timeseek_AddRef,
|
|
bytestream_wrapper_timeseek_Release,
|
|
bytestream_wrapper_timeseek_IsTimeSeekSupported,
|
|
bytestream_wrapper_timeseek_TimeSeek,
|
|
bytestream_wrapper_timeseek_GetTimeSeekResult,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_events_AddRef(IMFMediaEventGenerator *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_events_Release(IMFMediaEventGenerator *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
|
|
TRACE("%p, %#x, %p.\n", iface, flags, event);
|
|
|
|
return IMFMediaEventGenerator_GetEvent(wrapper->event_generator, flags, event);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, callback, state);
|
|
|
|
return IMFMediaEventGenerator_BeginGetEvent(wrapper->event_generator, callback, state);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result, IMFMediaEvent **event)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, result, event);
|
|
|
|
return IMFMediaEventGenerator_EndGetEvent(wrapper->event_generator, result, event);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFMediaEventGenerator(iface);
|
|
|
|
TRACE("%p, %d, %s, %#x, %p.\n", iface, type, debugstr_guid(ext_type), hr, value);
|
|
|
|
return IMFMediaEventGenerator_QueueEvent(wrapper->event_generator, type, ext_type, hr, value);
|
|
}
|
|
|
|
static const IMFMediaEventGeneratorVtbl bytestream_wrapper_events_vtbl =
|
|
{
|
|
bytestream_wrapper_events_QueryInterface,
|
|
bytestream_wrapper_events_AddRef,
|
|
bytestream_wrapper_events_Release,
|
|
bytestream_wrapper_events_GetEvent,
|
|
bytestream_wrapper_events_BeginGetEvent,
|
|
bytestream_wrapper_events_EndGetEvent,
|
|
bytestream_wrapper_events_QueueEvent,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_sample_output_QueryInterface(IMFSampleOutputStream *iface, REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFSampleOutputStream(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_sample_output_AddRef(IMFSampleOutputStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFSampleOutputStream(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_sample_output_Release(IMFSampleOutputStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFSampleOutputStream(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_sample_output_BeginWriteSample(IMFSampleOutputStream *iface, IMFSample *sample,
|
|
IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFSampleOutputStream(iface);
|
|
|
|
TRACE("%p, %p, %p, %p.\n", iface, sample, callback, state);
|
|
|
|
return IMFSampleOutputStream_BeginWriteSample(wrapper->sample_output, sample, callback, state);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_sample_output_EndWriteSample(IMFSampleOutputStream *iface, IMFAsyncResult *result)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFSampleOutputStream(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, result);
|
|
|
|
return IMFSampleOutputStream_EndWriteSample(wrapper->sample_output, result);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_sample_output_Close(IMFSampleOutputStream *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFSampleOutputStream(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IMFSampleOutputStream_Close(wrapper->sample_output);
|
|
}
|
|
|
|
static const IMFSampleOutputStreamVtbl bytestream_wrapper_sample_output_vtbl =
|
|
{
|
|
bytestream_wrapper_sample_output_QueryInterface,
|
|
bytestream_wrapper_sample_output_AddRef,
|
|
bytestream_wrapper_sample_output_Release,
|
|
bytestream_wrapper_sample_output_BeginWriteSample,
|
|
bytestream_wrapper_sample_output_EndWriteSample,
|
|
bytestream_wrapper_sample_output_Close,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_propstore_QueryInterface(IPropertyStore *iface, REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_propstore_AddRef(IPropertyStore *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_propstore_Release(IPropertyStore *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_propstore_GetCount(IPropertyStore *iface, DWORD *count)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, count);
|
|
|
|
return IPropertyStore_GetCount(wrapper->propstore, count);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_propstore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
|
|
TRACE("%p, %u, %p.\n", iface, prop, key);
|
|
|
|
return IPropertyStore_GetAt(wrapper->propstore, prop, key);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_propstore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, key, value);
|
|
|
|
return IPropertyStore_GetValue(wrapper->propstore, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_propstore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, const PROPVARIANT *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, key, value);
|
|
|
|
return IPropertyStore_SetValue(wrapper->propstore, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_propstore_Commit(IPropertyStore *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IPropertyStore(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IPropertyStore_Commit(wrapper->propstore);
|
|
}
|
|
|
|
static const IPropertyStoreVtbl bytestream_wrapper_propstore_vtbl =
|
|
{
|
|
bytestream_wrapper_propstore_QueryInterface,
|
|
bytestream_wrapper_propstore_AddRef,
|
|
bytestream_wrapper_propstore_Release,
|
|
bytestream_wrapper_propstore_GetCount,
|
|
bytestream_wrapper_propstore_GetAt,
|
|
bytestream_wrapper_propstore_GetValue,
|
|
bytestream_wrapper_propstore_SetValue,
|
|
bytestream_wrapper_propstore_Commit,
|
|
};
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
return IMFByteStream_QueryInterface(&wrapper->IMFByteStream_iface, riid, obj);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_attributes_AddRef(IMFAttributes *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
return IMFByteStream_AddRef(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static ULONG WINAPI bytestream_wrapper_attributes_Release(IMFAttributes *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
return IMFByteStream_Release(&wrapper->IMFByteStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetItem(IMFAttributes *iface, REFGUID key, PROPVARIANT *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_GetItem(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetItemType(IMFAttributes *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
|
|
|
|
return IMFAttributes_GetItemType(wrapper->attributes, key, type);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_CompareItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, result);
|
|
|
|
return IMFAttributes_CompareItem(wrapper->attributes, key, value, result);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_Compare(IMFAttributes *iface, IMFAttributes *theirs,
|
|
MF_ATTRIBUTES_MATCH_TYPE match_type, BOOL *ret)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %p, %d, %p.\n", iface, theirs, match_type, ret);
|
|
|
|
return IMFAttributes_Compare(wrapper->attributes, theirs, match_type, ret);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetUINT32(IMFAttributes *iface, REFGUID key, UINT32 *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_GetUINT32(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetUINT64(IMFAttributes *iface, REFGUID key, UINT64 *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_GetUINT64(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetDouble(IMFAttributes *iface, REFGUID key, double *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_GetDouble(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetGUID(IMFAttributes *iface, REFGUID key, GUID *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_GetGUID(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetStringLength(IMFAttributes *iface, REFGUID key, UINT32 *length)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
|
|
|
|
return IMFAttributes_GetStringLength(wrapper->attributes, key, length);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetString(IMFAttributes *iface, REFGUID key, WCHAR *value,
|
|
UINT32 size, UINT32 *length)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_attr(key), value, size, length);
|
|
|
|
return IMFAttributes_GetString(wrapper->attributes, key, value, size, length);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetAllocatedString(IMFAttributes *iface, REFGUID key, WCHAR **value, UINT32 *length)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
|
|
|
|
return IMFAttributes_GetAllocatedString(wrapper->attributes, key, value, length);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetBlobSize(IMFAttributes *iface, REFGUID key, UINT32 *size)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
|
|
|
|
return IMFAttributes_GetBlobSize(wrapper->attributes, key, size);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetBlob(IMFAttributes *iface, REFGUID key, UINT8 *buf,
|
|
UINT32 bufsize, UINT32 *blobsize)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %d, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
|
|
|
|
return IMFAttributes_GetBlob(wrapper->attributes, key, buf, bufsize, blobsize);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetAllocatedBlob(IMFAttributes *iface, REFGUID key, UINT8 **buf, UINT32 *size)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
|
|
|
|
return IMFAttributes_GetAllocatedBlob(wrapper->attributes, key, buf, size);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetUnknown(IMFAttributes *iface, REFGUID key, REFIID riid, void **obj)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), obj);
|
|
|
|
return IMFAttributes_GetUnknown(wrapper->attributes, key, riid, obj);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetItem(IMFAttributes *iface, REFGUID key, REFPROPVARIANT value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_SetItem(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_DeleteItem(IMFAttributes *iface, REFGUID key)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_attr(key));
|
|
|
|
return IMFAttributes_DeleteItem(wrapper->attributes, key);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_DeleteAllItems(IMFAttributes *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IMFAttributes_DeleteAllItems(wrapper->attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetUINT32(IMFAttributes *iface, REFGUID key, UINT32 value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %d.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_SetUINT32(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetUINT64(IMFAttributes *iface, REFGUID key, UINT64 value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
|
|
|
|
return IMFAttributes_SetUINT64(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetDouble(IMFAttributes *iface, REFGUID key, double value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
|
|
|
|
return IMFAttributes_SetDouble(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetGUID(IMFAttributes *iface, REFGUID key, REFGUID value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
|
|
|
|
return IMFAttributes_SetGUID(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetString(IMFAttributes *iface, REFGUID key, const WCHAR *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
|
|
|
|
return IMFAttributes_SetString(wrapper->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetBlob(IMFAttributes *iface, REFGUID key, const UINT8 *buf, UINT32 size)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
|
|
|
|
return IMFAttributes_SetBlob(wrapper->attributes, key, buf, size);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_SetUnknown(IMFAttributes *iface, REFGUID key, IUnknown *unknown)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
|
|
|
|
return IMFAttributes_SetUnknown(wrapper->attributes, key, unknown);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_LockStore(IMFAttributes *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IMFAttributes_LockStore(wrapper->attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_UnlockStore(IMFAttributes *iface)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return IMFAttributes_UnlockStore(wrapper->attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetCount(IMFAttributes *iface, UINT32 *count)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, count);
|
|
|
|
return IMFAttributes_GetCount(wrapper->attributes, count);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_GetItemByIndex(IMFAttributes *iface, UINT32 index, GUID *key, PROPVARIANT *value)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
|
|
|
|
return IMFAttributes_GetItemByIndex(wrapper->attributes, index, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI bytestream_wrapper_attributes_CopyAllItems(IMFAttributes *iface, IMFAttributes *dest)
|
|
{
|
|
struct bytestream_wrapper *wrapper = impl_wrapper_from_IMFAttributes(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, dest);
|
|
|
|
return IMFAttributes_CopyAllItems(wrapper->attributes, dest);
|
|
}
|
|
|
|
static const IMFAttributesVtbl bytestream_wrapper_attributes_vtbl =
|
|
{
|
|
bytestream_wrapper_attributes_QueryInterface,
|
|
bytestream_wrapper_attributes_AddRef,
|
|
bytestream_wrapper_attributes_Release,
|
|
bytestream_wrapper_attributes_GetItem,
|
|
bytestream_wrapper_attributes_GetItemType,
|
|
bytestream_wrapper_attributes_CompareItem,
|
|
bytestream_wrapper_attributes_Compare,
|
|
bytestream_wrapper_attributes_GetUINT32,
|
|
bytestream_wrapper_attributes_GetUINT64,
|
|
bytestream_wrapper_attributes_GetDouble,
|
|
bytestream_wrapper_attributes_GetGUID,
|
|
bytestream_wrapper_attributes_GetStringLength,
|
|
bytestream_wrapper_attributes_GetString,
|
|
bytestream_wrapper_attributes_GetAllocatedString,
|
|
bytestream_wrapper_attributes_GetBlobSize,
|
|
bytestream_wrapper_attributes_GetBlob,
|
|
bytestream_wrapper_attributes_GetAllocatedBlob,
|
|
bytestream_wrapper_attributes_GetUnknown,
|
|
bytestream_wrapper_attributes_SetItem,
|
|
bytestream_wrapper_attributes_DeleteItem,
|
|
bytestream_wrapper_attributes_DeleteAllItems,
|
|
bytestream_wrapper_attributes_SetUINT32,
|
|
bytestream_wrapper_attributes_SetUINT64,
|
|
bytestream_wrapper_attributes_SetDouble,
|
|
bytestream_wrapper_attributes_SetGUID,
|
|
bytestream_wrapper_attributes_SetString,
|
|
bytestream_wrapper_attributes_SetBlob,
|
|
bytestream_wrapper_attributes_SetUnknown,
|
|
bytestream_wrapper_attributes_LockStore,
|
|
bytestream_wrapper_attributes_UnlockStore,
|
|
bytestream_wrapper_attributes_GetCount,
|
|
bytestream_wrapper_attributes_GetItemByIndex,
|
|
bytestream_wrapper_attributes_CopyAllItems
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateMFByteStreamWrapper (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateMFByteStreamWrapper(IMFByteStream *stream, IMFByteStream **wrapper)
|
|
{
|
|
struct bytestream_wrapper *object;
|
|
|
|
TRACE("%p, %p.\n", stream, wrapper);
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IMFByteStreamCacheControl_iface.lpVtbl = &bytestream_wrapper_cache_control_vtbl;
|
|
object->IMFByteStreamBuffering_iface.lpVtbl = &bytestream_wrapper_buffering_vtbl;
|
|
object->IMFMediaEventGenerator_iface.lpVtbl = &bytestream_wrapper_events_vtbl;
|
|
object->IMFByteStreamTimeSeek_iface.lpVtbl = &bytestream_wrapper_timeseek_vtbl;
|
|
object->IMFSampleOutputStream_iface.lpVtbl = &bytestream_wrapper_sample_output_vtbl;
|
|
object->IMFByteStream_iface.lpVtbl = &bytestream_wrapper_vtbl;
|
|
object->IPropertyStore_iface.lpVtbl = &bytestream_wrapper_propstore_vtbl;
|
|
object->IMFAttributes_iface.lpVtbl = &bytestream_wrapper_attributes_vtbl;
|
|
|
|
IMFByteStream_QueryInterface(stream, &IID_IMFByteStreamCacheControl, (void **)&object->cache_control);
|
|
IMFByteStream_QueryInterface(stream, &IID_IMFByteStreamBuffering, (void **)&object->stream_buffering);
|
|
IMFByteStream_QueryInterface(stream, &IID_IMFMediaEventGenerator, (void **)&object->event_generator);
|
|
IMFByteStream_QueryInterface(stream, &IID_IMFByteStreamTimeSeek, (void **)&object->time_seek);
|
|
IMFByteStream_QueryInterface(stream, &IID_IMFSampleOutputStream, (void **)&object->sample_output);
|
|
IMFByteStream_QueryInterface(stream, &IID_IPropertyStore, (void **)&object->propstore);
|
|
IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&object->attributes);
|
|
|
|
object->stream = stream;
|
|
IMFByteStream_AddRef(object->stream);
|
|
|
|
object->refcount = 1;
|
|
|
|
*wrapper = &object->IMFByteStream_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_QueryInterface(IMFPluginControl *iface, REFIID riid, void **ppv)
|
|
{
|
|
if(IsEqualGUID(riid, &IID_IUnknown)) {
|
|
TRACE("(IID_IUnknown %p)\n", ppv);
|
|
*ppv = iface;
|
|
}else if(IsEqualGUID(riid, &IID_IMFPluginControl)) {
|
|
TRACE("(IID_IMFPluginControl %p)\n", ppv);
|
|
*ppv = iface;
|
|
}else {
|
|
FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown*)*ppv);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI MFPluginControl_AddRef(IMFPluginControl *iface)
|
|
{
|
|
TRACE("\n");
|
|
return 2;
|
|
}
|
|
|
|
static ULONG WINAPI MFPluginControl_Release(IMFPluginControl *iface)
|
|
{
|
|
TRACE("\n");
|
|
return 1;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_GetPreferredClsid(IMFPluginControl *iface, DWORD plugin_type,
|
|
const WCHAR *selector, CLSID *clsid)
|
|
{
|
|
FIXME("(%d %s %p)\n", plugin_type, debugstr_w(selector), clsid);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_GetPreferredClsidByIndex(IMFPluginControl *iface, DWORD plugin_type,
|
|
DWORD index, WCHAR **selector, CLSID *clsid)
|
|
{
|
|
FIXME("(%d %d %p %p)\n", plugin_type, index, selector, clsid);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_SetPreferredClsid(IMFPluginControl *iface, DWORD plugin_type,
|
|
const WCHAR *selector, const CLSID *clsid)
|
|
{
|
|
FIXME("(%d %s %s)\n", plugin_type, debugstr_w(selector), debugstr_guid(clsid));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_IsDisabled(IMFPluginControl *iface, DWORD plugin_type, REFCLSID clsid)
|
|
{
|
|
FIXME("(%d %s)\n", plugin_type, debugstr_guid(clsid));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_GetDisabledByIndex(IMFPluginControl *iface, DWORD plugin_type, DWORD index, CLSID *clsid)
|
|
{
|
|
FIXME("(%d %d %p)\n", plugin_type, index, clsid);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MFPluginControl_SetDisabled(IMFPluginControl *iface, DWORD plugin_type, REFCLSID clsid, BOOL disabled)
|
|
{
|
|
FIXME("(%d %s %x)\n", plugin_type, debugstr_guid(clsid), disabled);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMFPluginControlVtbl MFPluginControlVtbl = {
|
|
MFPluginControl_QueryInterface,
|
|
MFPluginControl_AddRef,
|
|
MFPluginControl_Release,
|
|
MFPluginControl_GetPreferredClsid,
|
|
MFPluginControl_GetPreferredClsidByIndex,
|
|
MFPluginControl_SetPreferredClsid,
|
|
MFPluginControl_IsDisabled,
|
|
MFPluginControl_GetDisabledByIndex,
|
|
MFPluginControl_SetDisabled
|
|
};
|
|
|
|
static IMFPluginControl plugin_control = { &MFPluginControlVtbl };
|
|
|
|
/***********************************************************************
|
|
* MFGetPluginControl (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFGetPluginControl(IMFPluginControl **ret)
|
|
{
|
|
TRACE("(%p)\n", ret);
|
|
|
|
*ret = &plugin_control;
|
|
return S_OK;
|
|
}
|
|
|
|
typedef struct _mfsource
|
|
{
|
|
IMFMediaSource IMFMediaSource_iface;
|
|
LONG ref;
|
|
} mfsource;
|
|
|
|
static inline mfsource *impl_from_IMFMediaSource(IMFMediaSource *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, mfsource, IMFMediaSource_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFMediaSource) ||
|
|
IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*out = &This->IMFMediaSource_iface;
|
|
}
|
|
else
|
|
{
|
|
FIXME("(%s, %p)\n", debugstr_guid(riid), out);
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown*)*out);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI mfsource_AddRef(IMFMediaSource *iface)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
ULONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%u\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI mfsource_Release(IMFMediaSource *iface)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%u\n", This, ref);
|
|
|
|
if (!ref)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p)->(%#x, %p)\n", This, flags, event);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p)->(%p, %p)\n", This, callback, state);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p)->(%p, %p)\n", This, result, event);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
|
|
HRESULT hr, const PROPVARIANT *value)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p)->(%d, %s, %#x, %p)\n", This, event_type, debugstr_guid(ext_type), hr, value);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p)->(%p): stub\n", This, characteristics);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
IMFStreamDescriptor *sd;
|
|
IMFMediaType *mediatype;
|
|
HRESULT hr;
|
|
|
|
FIXME("(%p)->(%p): stub\n", This, descriptor);
|
|
|
|
if (FAILED(hr = MFCreateMediaType(&mediatype)))
|
|
return hr;
|
|
|
|
hr = MFCreateStreamDescriptor(0, 1, &mediatype, &sd);
|
|
IMFMediaType_Release(mediatype);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = MFCreatePresentationDescriptor(1, &sd, descriptor);
|
|
IMFStreamDescriptor_Release(sd);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
|
|
const GUID *time_format, const PROPVARIANT *start_position)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p)->(%p, %p, %p): stub\n", This, descriptor, time_format, start_position);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_Stop(IMFMediaSource *iface)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p): stub\n", This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_Pause(IMFMediaSource *iface)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p): stub\n", This);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI mfsource_Shutdown(IMFMediaSource *iface)
|
|
{
|
|
mfsource *This = impl_from_IMFMediaSource(iface);
|
|
|
|
FIXME("(%p): stub\n", This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFMediaSourceVtbl mfsourcevtbl =
|
|
{
|
|
mfsource_QueryInterface,
|
|
mfsource_AddRef,
|
|
mfsource_Release,
|
|
mfsource_GetEvent,
|
|
mfsource_BeginGetEvent,
|
|
mfsource_EndGetEvent,
|
|
mfsource_QueueEvent,
|
|
mfsource_GetCharacteristics,
|
|
mfsource_CreatePresentationDescriptor,
|
|
mfsource_Start,
|
|
mfsource_Stop,
|
|
mfsource_Pause,
|
|
mfsource_Shutdown,
|
|
};
|
|
|
|
enum resolved_object_origin
|
|
{
|
|
OBJECT_FROM_BYTESTREAM,
|
|
OBJECT_FROM_URL,
|
|
};
|
|
|
|
struct resolver_queued_result
|
|
{
|
|
struct list entry;
|
|
IUnknown *object;
|
|
MF_OBJECT_TYPE obj_type;
|
|
HRESULT hr;
|
|
IMFAsyncResult *inner_result;
|
|
enum resolved_object_origin origin;
|
|
};
|
|
|
|
struct resolver_cancel_object
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG refcount;
|
|
union
|
|
{
|
|
IUnknown *handler;
|
|
IMFByteStreamHandler *stream_handler;
|
|
IMFSchemeHandler *scheme_handler;
|
|
} u;
|
|
IUnknown *cancel_cookie;
|
|
enum resolved_object_origin origin;
|
|
};
|
|
|
|
typedef struct source_resolver
|
|
{
|
|
IMFSourceResolver IMFSourceResolver_iface;
|
|
LONG refcount;
|
|
IMFAsyncCallback stream_callback;
|
|
IMFAsyncCallback url_callback;
|
|
CRITICAL_SECTION cs;
|
|
struct list pending;
|
|
} mfsourceresolver;
|
|
|
|
static struct source_resolver *impl_from_IMFSourceResolver(IMFSourceResolver *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct source_resolver, IMFSourceResolver_iface);
|
|
}
|
|
|
|
static struct source_resolver *impl_from_stream_IMFAsyncCallback(IMFAsyncCallback *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct source_resolver, stream_callback);
|
|
}
|
|
|
|
static struct source_resolver *impl_from_url_IMFAsyncCallback(IMFAsyncCallback *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct source_resolver, url_callback);
|
|
}
|
|
|
|
static HRESULT resolver_handler_end_create(struct source_resolver *resolver, enum resolved_object_origin origin,
|
|
IMFAsyncResult *result)
|
|
{
|
|
IMFAsyncResult *inner_result = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
|
|
struct resolver_queued_result *queued_result;
|
|
union
|
|
{
|
|
IUnknown *handler;
|
|
IMFByteStreamHandler *stream_handler;
|
|
IMFSchemeHandler *scheme_handler;
|
|
} handler;
|
|
|
|
queued_result = heap_alloc_zero(sizeof(*queued_result));
|
|
|
|
IMFAsyncResult_GetObject(inner_result, &handler.handler);
|
|
|
|
switch (origin)
|
|
{
|
|
case OBJECT_FROM_BYTESTREAM:
|
|
queued_result->hr = IMFByteStreamHandler_EndCreateObject(handler.stream_handler, result,
|
|
&queued_result->obj_type, &queued_result->object);
|
|
break;
|
|
case OBJECT_FROM_URL:
|
|
queued_result->hr = IMFSchemeHandler_EndCreateObject(handler.scheme_handler, result,
|
|
&queued_result->obj_type, &queued_result->object);
|
|
break;
|
|
default:
|
|
queued_result->hr = E_FAIL;
|
|
}
|
|
|
|
IUnknown_Release(handler.handler);
|
|
|
|
if (SUCCEEDED(queued_result->hr))
|
|
{
|
|
MFASYNCRESULT *data = (MFASYNCRESULT *)inner_result;
|
|
|
|
if (data->hEvent)
|
|
{
|
|
queued_result->inner_result = inner_result;
|
|
IMFAsyncResult_AddRef(queued_result->inner_result);
|
|
}
|
|
|
|
/* Push resolved object type and created object, so we don't have to guess on End*() call. */
|
|
EnterCriticalSection(&resolver->cs);
|
|
list_add_tail(&resolver->pending, &queued_result->entry);
|
|
LeaveCriticalSection(&resolver->cs);
|
|
|
|
if (data->hEvent)
|
|
SetEvent(data->hEvent);
|
|
else
|
|
{
|
|
IUnknown *caller_state = IMFAsyncResult_GetStateNoAddRef(inner_result);
|
|
IMFAsyncResult *caller_result;
|
|
|
|
if (SUCCEEDED(MFCreateAsyncResult(queued_result->object, data->pCallback, caller_state, &caller_result)))
|
|
{
|
|
MFInvokeCallback(caller_result);
|
|
IMFAsyncResult_Release(caller_result);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
heap_free(queued_result);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static struct resolver_cancel_object *impl_cancel_obj_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct resolver_cancel_object, IUnknown_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI resolver_cancel_object_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
IUnknown_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI resolver_cancel_object_AddRef(IUnknown *iface)
|
|
{
|
|
struct resolver_cancel_object *object = impl_cancel_obj_from_IUnknown(iface);
|
|
return InterlockedIncrement(&object->refcount);
|
|
}
|
|
|
|
static ULONG WINAPI resolver_cancel_object_Release(IUnknown *iface)
|
|
{
|
|
struct resolver_cancel_object *object = impl_cancel_obj_from_IUnknown(iface);
|
|
ULONG refcount = InterlockedDecrement(&object->refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
if (object->cancel_cookie)
|
|
IUnknown_Release(object->cancel_cookie);
|
|
IUnknown_Release(object->u.handler);
|
|
heap_free(object);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static const IUnknownVtbl resolver_cancel_object_vtbl =
|
|
{
|
|
resolver_cancel_object_QueryInterface,
|
|
resolver_cancel_object_AddRef,
|
|
resolver_cancel_object_Release,
|
|
};
|
|
|
|
static struct resolver_cancel_object *unsafe_impl_cancel_obj_from_IUnknown(IUnknown *iface)
|
|
{
|
|
if (!iface)
|
|
return NULL;
|
|
|
|
return (iface->lpVtbl == &resolver_cancel_object_vtbl) ?
|
|
CONTAINING_RECORD(iface, struct resolver_cancel_object, IUnknown_iface) : NULL;
|
|
}
|
|
|
|
static HRESULT resolver_create_cancel_object(IUnknown *handler, enum resolved_object_origin origin,
|
|
IUnknown *cancel_cookie, IUnknown **cancel_object)
|
|
{
|
|
struct resolver_cancel_object *object;
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IUnknown_iface.lpVtbl = &resolver_cancel_object_vtbl;
|
|
object->refcount = 1;
|
|
object->u.handler = handler;
|
|
IUnknown_AddRef(object->u.handler);
|
|
object->cancel_cookie = cancel_cookie;
|
|
IUnknown_AddRef(object->cancel_cookie);
|
|
object->origin = origin;
|
|
|
|
*cancel_object = &object->IUnknown_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
IMFAsyncCallback_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI source_resolver_callback_stream_AddRef(IMFAsyncCallback *iface)
|
|
{
|
|
struct source_resolver *resolver = impl_from_stream_IMFAsyncCallback(iface);
|
|
return IMFSourceResolver_AddRef(&resolver->IMFSourceResolver_iface);
|
|
}
|
|
|
|
static ULONG WINAPI source_resolver_callback_stream_Release(IMFAsyncCallback *iface)
|
|
{
|
|
struct source_resolver *resolver = impl_from_stream_IMFAsyncCallback(iface);
|
|
return IMFSourceResolver_Release(&resolver->IMFSourceResolver_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_callback_stream_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
|
{
|
|
struct source_resolver *resolver = impl_from_stream_IMFAsyncCallback(iface);
|
|
|
|
return resolver_handler_end_create(resolver, OBJECT_FROM_BYTESTREAM, result);
|
|
}
|
|
|
|
static const IMFAsyncCallbackVtbl source_resolver_callback_stream_vtbl =
|
|
{
|
|
source_resolver_callback_QueryInterface,
|
|
source_resolver_callback_stream_AddRef,
|
|
source_resolver_callback_stream_Release,
|
|
source_resolver_callback_GetParameters,
|
|
source_resolver_callback_stream_Invoke,
|
|
};
|
|
|
|
static ULONG WINAPI source_resolver_callback_url_AddRef(IMFAsyncCallback *iface)
|
|
{
|
|
struct source_resolver *resolver = impl_from_url_IMFAsyncCallback(iface);
|
|
return IMFSourceResolver_AddRef(&resolver->IMFSourceResolver_iface);
|
|
}
|
|
|
|
static ULONG WINAPI source_resolver_callback_url_Release(IMFAsyncCallback *iface)
|
|
{
|
|
struct source_resolver *resolver = impl_from_url_IMFAsyncCallback(iface);
|
|
return IMFSourceResolver_Release(&resolver->IMFSourceResolver_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_callback_url_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
|
{
|
|
struct source_resolver *resolver = impl_from_url_IMFAsyncCallback(iface);
|
|
|
|
return resolver_handler_end_create(resolver, OBJECT_FROM_URL, result);
|
|
}
|
|
|
|
static const IMFAsyncCallbackVtbl source_resolver_callback_url_vtbl =
|
|
{
|
|
source_resolver_callback_QueryInterface,
|
|
source_resolver_callback_url_AddRef,
|
|
source_resolver_callback_url_Release,
|
|
source_resolver_callback_GetParameters,
|
|
source_resolver_callback_url_Invoke,
|
|
};
|
|
|
|
static HRESULT resolver_create_registered_handler(HKEY hkey, REFIID riid, void **handler)
|
|
{
|
|
unsigned int j = 0, name_length, type;
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR clsidW[39];
|
|
CLSID clsid;
|
|
|
|
name_length = ARRAY_SIZE(clsidW);
|
|
while (!RegEnumValueW(hkey, j++, clsidW, &name_length, NULL, &type, NULL, NULL))
|
|
{
|
|
if (type == REG_SZ)
|
|
{
|
|
if (SUCCEEDED(CLSIDFromString(clsidW, &clsid)))
|
|
{
|
|
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, riid, handler);
|
|
if (SUCCEEDED(hr))
|
|
break;
|
|
}
|
|
}
|
|
|
|
name_length = ARRAY_SIZE(clsidW);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags,
|
|
IMFByteStreamHandler **handler)
|
|
{
|
|
static const char streamhandlerspath[] = "Software\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers";
|
|
static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
|
|
IMFAttributes *attributes;
|
|
const WCHAR *url_ext;
|
|
WCHAR *mimeW = NULL;
|
|
unsigned int i, j;
|
|
UINT32 length;
|
|
HRESULT hr;
|
|
|
|
*handler = NULL;
|
|
|
|
/* MIME type */
|
|
if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
|
|
{
|
|
IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length);
|
|
IMFAttributes_Release(attributes);
|
|
}
|
|
|
|
/* Extension */
|
|
url_ext = url ? strrchrW(url, '.') : NULL;
|
|
|
|
if (!url_ext && !mimeW)
|
|
{
|
|
CoTaskMemFree(mimeW);
|
|
return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
|
|
}
|
|
|
|
/* FIXME: check local handlers first */
|
|
|
|
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i)
|
|
{
|
|
const WCHAR *namesW[2] = { mimeW, url_ext };
|
|
HKEY hkey, hkey_handler;
|
|
|
|
if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
|
|
continue;
|
|
|
|
for (j = 0; j < ARRAY_SIZE(namesW); ++j)
|
|
{
|
|
if (!namesW[j])
|
|
continue;
|
|
|
|
if (!RegOpenKeyW(hkey, namesW[j], &hkey_handler))
|
|
{
|
|
hr = resolver_create_registered_handler(hkey_handler, &IID_IMFByteStreamHandler, (void **)handler);
|
|
RegCloseKey(hkey_handler);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
break;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
if (SUCCEEDED(hr))
|
|
break;
|
|
}
|
|
|
|
CoTaskMemFree(mimeW);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSchemeHandler **handler)
|
|
{
|
|
static const char schemehandlerspath[] = "Software\\Microsoft\\Windows Media Foundation\\SchemeHandlers";
|
|
static const HKEY hkey_roots[2] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE };
|
|
const WCHAR *ptr = url;
|
|
unsigned int len, i;
|
|
WCHAR *scheme;
|
|
HRESULT hr;
|
|
|
|
/* RFC 3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
|
|
while (*ptr)
|
|
{
|
|
WCHAR ch = tolowerW(*ptr);
|
|
|
|
if (*ptr == '*' && ptr == url)
|
|
{
|
|
ptr++;
|
|
break;
|
|
}
|
|
else if (!(*ptr >= '0' && *ptr <= '9') &&
|
|
!(ch >= 'a' && ch <= 'z') &&
|
|
*ptr != '+' && *ptr != '-' && *ptr != '.')
|
|
{
|
|
break;
|
|
}
|
|
|
|
ptr++;
|
|
}
|
|
|
|
/* Schemes must end with a ':' */
|
|
if (ptr == url || *ptr != ':')
|
|
return MF_E_UNSUPPORTED_SCHEME;
|
|
|
|
len = ptr - url;
|
|
scheme = heap_alloc((len + 1) * sizeof(WCHAR));
|
|
if (!scheme)
|
|
return E_OUTOFMEMORY;
|
|
|
|
memcpy(scheme, url, len * sizeof(WCHAR));
|
|
scheme[len] = 0;
|
|
|
|
/* FIXME: check local handlers first */
|
|
|
|
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i)
|
|
{
|
|
HKEY hkey, hkey_handler;
|
|
|
|
if (RegOpenKeyA(hkey_roots[i], schemehandlerspath, &hkey))
|
|
continue;
|
|
|
|
if (!RegOpenKeyW(hkey, scheme, &hkey_handler))
|
|
{
|
|
hr = resolver_create_registered_handler(hkey_handler, &IID_IMFSchemeHandler, (void **)handler);
|
|
RegCloseKey(hkey_handler);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
if (SUCCEEDED(hr))
|
|
break;
|
|
}
|
|
|
|
heap_free(scheme);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT resolver_end_create_object(struct source_resolver *resolver, enum resolved_object_origin origin,
|
|
IMFAsyncResult *result, MF_OBJECT_TYPE *obj_type, IUnknown **out)
|
|
{
|
|
struct resolver_queued_result *queued_result = NULL, *iter;
|
|
IUnknown *object;
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
|
|
return hr;
|
|
|
|
EnterCriticalSection(&resolver->cs);
|
|
|
|
LIST_FOR_EACH_ENTRY(iter, &resolver->pending, struct resolver_queued_result, entry)
|
|
{
|
|
if (iter->inner_result == result || (iter->object == object && iter->origin == origin))
|
|
{
|
|
list_remove(&iter->entry);
|
|
queued_result = iter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&resolver->cs);
|
|
|
|
IUnknown_Release(object);
|
|
|
|
if (queued_result)
|
|
{
|
|
*out = queued_result->object;
|
|
*obj_type = queued_result->obj_type;
|
|
hr = queued_result->hr;
|
|
if (queued_result->inner_result)
|
|
IMFAsyncResult_Release(queued_result->inner_result);
|
|
heap_free(queued_result);
|
|
}
|
|
else
|
|
hr = E_UNEXPECTED;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_QueryInterface(IMFSourceResolver *iface, REFIID riid, void **obj)
|
|
{
|
|
mfsourceresolver *This = impl_from_IMFSourceResolver(iface);
|
|
|
|
TRACE("(%p->(%s, %p)\n", This, debugstr_guid(riid), obj);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFSourceResolver) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = &This->IMFSourceResolver_iface;
|
|
}
|
|
else
|
|
{
|
|
*obj = NULL;
|
|
FIXME("unsupported interface %s\n", debugstr_guid(riid));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown *)*obj);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI source_resolver_AddRef(IMFSourceResolver *iface)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
ULONG refcount = InterlockedIncrement(&resolver->refcount);
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI source_resolver_Release(IMFSourceResolver *iface)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
ULONG refcount = InterlockedDecrement(&resolver->refcount);
|
|
struct resolver_queued_result *result, *result2;
|
|
|
|
TRACE("%p, refcount %d.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
LIST_FOR_EACH_ENTRY_SAFE(result, result2, &resolver->pending, struct resolver_queued_result, entry)
|
|
{
|
|
if (result->object)
|
|
IUnknown_Release(result->object);
|
|
list_remove(&result->entry);
|
|
heap_free(result);
|
|
}
|
|
DeleteCriticalSection(&resolver->cs);
|
|
heap_free(resolver);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_CreateObjectFromURL(IMFSourceResolver *iface, const WCHAR *url,
|
|
DWORD flags, IPropertyStore *props, MF_OBJECT_TYPE *obj_type, IUnknown **object)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
IMFSchemeHandler *handler;
|
|
IMFAsyncResult *result;
|
|
MFASYNCRESULT *data;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s, %#x, %p, %p, %p\n", iface, debugstr_w(url), flags, props, obj_type, object);
|
|
|
|
if (!url || !obj_type || !object)
|
|
return E_POINTER;
|
|
|
|
if (FAILED(hr = resolver_get_scheme_handler(url, flags, &handler)))
|
|
return hr;
|
|
|
|
hr = MFCreateAsyncResult((IUnknown *)handler, NULL, NULL, &result);
|
|
IMFSchemeHandler_Release(handler);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
data = (MFASYNCRESULT *)result;
|
|
data->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
|
|
hr = IMFSchemeHandler_BeginCreateObject(handler, url, flags, props, NULL, &resolver->url_callback,
|
|
(IUnknown *)result);
|
|
if (FAILED(hr))
|
|
{
|
|
IMFAsyncResult_Release(result);
|
|
return hr;
|
|
}
|
|
|
|
WaitForSingleObject(data->hEvent, INFINITE);
|
|
|
|
hr = resolver_end_create_object(resolver, OBJECT_FROM_URL, result, obj_type, object);
|
|
IMFAsyncResult_Release(result);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_CreateObjectFromByteStream(IMFSourceResolver *iface, IMFByteStream *stream,
|
|
const WCHAR *url, DWORD flags, IPropertyStore *props, MF_OBJECT_TYPE *obj_type, IUnknown **object)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
IMFByteStreamHandler *handler;
|
|
IMFAsyncResult *result;
|
|
MFASYNCRESULT *data;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %s, %#x, %p, %p, %p.\n", iface, stream, debugstr_w(url), flags, props, obj_type, object);
|
|
|
|
if (!stream || !obj_type || !object)
|
|
return E_POINTER;
|
|
|
|
if (FAILED(hr = resolver_get_bytestream_handler(stream, url, flags, &handler)))
|
|
goto fallback;
|
|
|
|
hr = MFCreateAsyncResult((IUnknown *)handler, NULL, NULL, &result);
|
|
IMFByteStreamHandler_Release(handler);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
data = (MFASYNCRESULT *)result;
|
|
data->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
|
|
hr = IMFByteStreamHandler_BeginCreateObject(handler, stream, url, flags, props, NULL, &resolver->stream_callback,
|
|
(IUnknown *)result);
|
|
if (FAILED(hr))
|
|
{
|
|
IMFAsyncResult_Release(result);
|
|
return hr;
|
|
}
|
|
|
|
WaitForSingleObject(data->hEvent, INFINITE);
|
|
|
|
hr = resolver_end_create_object(resolver, OBJECT_FROM_BYTESTREAM, result, obj_type, object);
|
|
IMFAsyncResult_Release(result);
|
|
|
|
/* TODO: following stub is left intentionally until real source plugins are implemented. */
|
|
if (SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
fallback:
|
|
if (flags & MF_RESOLUTION_MEDIASOURCE)
|
|
{
|
|
mfsource *new_object;
|
|
|
|
new_object = HeapAlloc( GetProcessHeap(), 0, sizeof(*new_object) );
|
|
if (!new_object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
new_object->IMFMediaSource_iface.lpVtbl = &mfsourcevtbl;
|
|
new_object->ref = 1;
|
|
|
|
*object = (IUnknown *)&new_object->IMFMediaSource_iface;
|
|
*obj_type = MF_OBJECT_MEDIASOURCE;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_BeginCreateObjectFromURL(IMFSourceResolver *iface, const WCHAR *url,
|
|
DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
IMFSchemeHandler *handler;
|
|
IUnknown *inner_cookie = NULL;
|
|
IMFAsyncResult *result;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
|
|
|
|
if (FAILED(hr = resolver_get_scheme_handler(url, flags, &handler)))
|
|
return hr;
|
|
|
|
if (cancel_cookie)
|
|
*cancel_cookie = NULL;
|
|
|
|
hr = MFCreateAsyncResult((IUnknown *)handler, callback, state, &result);
|
|
IMFSchemeHandler_Release(handler);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = IMFSchemeHandler_BeginCreateObject(handler, url, flags, props, cancel_cookie ? &inner_cookie : NULL,
|
|
&resolver->url_callback, (IUnknown *)result);
|
|
|
|
if (SUCCEEDED(hr) && inner_cookie)
|
|
resolver_create_cancel_object((IUnknown *)handler, OBJECT_FROM_URL, inner_cookie, cancel_cookie);
|
|
|
|
IMFAsyncResult_Release(result);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_EndCreateObjectFromURL(IMFSourceResolver *iface, IMFAsyncResult *result,
|
|
MF_OBJECT_TYPE *obj_type, IUnknown **object)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
|
|
TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
|
|
|
|
return resolver_end_create_object(resolver, OBJECT_FROM_URL, result, obj_type, object);
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_BeginCreateObjectFromByteStream(IMFSourceResolver *iface, IMFByteStream *stream,
|
|
const WCHAR *url, DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback,
|
|
IUnknown *state)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
IMFByteStreamHandler *handler;
|
|
IUnknown *inner_cookie = NULL;
|
|
IMFAsyncResult *result;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %s, %#x, %p, %p, %p, %p.\n", iface, stream, debugstr_w(url), flags, props, cancel_cookie,
|
|
callback, state);
|
|
|
|
if (FAILED(hr = resolver_get_bytestream_handler(stream, url, flags, &handler)))
|
|
return hr;
|
|
|
|
if (cancel_cookie)
|
|
*cancel_cookie = NULL;
|
|
|
|
hr = MFCreateAsyncResult((IUnknown *)handler, callback, state, &result);
|
|
IMFByteStreamHandler_Release(handler);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = IMFByteStreamHandler_BeginCreateObject(handler, stream, url, flags, props,
|
|
cancel_cookie ? &inner_cookie : NULL, &resolver->stream_callback, (IUnknown *)result);
|
|
|
|
/* Cancel object wraps underlying handler cancel cookie with context necessary to call CancelObjectCreate(). */
|
|
if (SUCCEEDED(hr) && inner_cookie)
|
|
resolver_create_cancel_object((IUnknown *)handler, OBJECT_FROM_BYTESTREAM, inner_cookie, cancel_cookie);
|
|
|
|
IMFAsyncResult_Release(result);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_EndCreateObjectFromByteStream(IMFSourceResolver *iface, IMFAsyncResult *result,
|
|
MF_OBJECT_TYPE *obj_type, IUnknown **object)
|
|
{
|
|
struct source_resolver *resolver = impl_from_IMFSourceResolver(iface);
|
|
|
|
TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
|
|
|
|
return resolver_end_create_object(resolver, OBJECT_FROM_BYTESTREAM, result, obj_type, object);
|
|
}
|
|
|
|
static HRESULT WINAPI source_resolver_CancelObjectCreation(IMFSourceResolver *iface, IUnknown *cancel_cookie)
|
|
{
|
|
struct resolver_cancel_object *object;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p.\n", iface, cancel_cookie);
|
|
|
|
if (!(object = unsafe_impl_cancel_obj_from_IUnknown(cancel_cookie)))
|
|
return E_UNEXPECTED;
|
|
|
|
switch (object->origin)
|
|
{
|
|
case OBJECT_FROM_BYTESTREAM:
|
|
hr = IMFByteStreamHandler_CancelObjectCreation(object->u.stream_handler, object->cancel_cookie);
|
|
break;
|
|
case OBJECT_FROM_URL:
|
|
hr = IMFSchemeHandler_CancelObjectCreation(object->u.scheme_handler, object->cancel_cookie);
|
|
break;
|
|
default:
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static const IMFSourceResolverVtbl mfsourceresolvervtbl =
|
|
{
|
|
source_resolver_QueryInterface,
|
|
source_resolver_AddRef,
|
|
source_resolver_Release,
|
|
source_resolver_CreateObjectFromURL,
|
|
source_resolver_CreateObjectFromByteStream,
|
|
source_resolver_BeginCreateObjectFromURL,
|
|
source_resolver_EndCreateObjectFromURL,
|
|
source_resolver_BeginCreateObjectFromByteStream,
|
|
source_resolver_EndCreateObjectFromByteStream,
|
|
source_resolver_CancelObjectCreation,
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateSourceResolver (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateSourceResolver(IMFSourceResolver **resolver)
|
|
{
|
|
struct source_resolver *object;
|
|
|
|
TRACE("%p\n", resolver);
|
|
|
|
if (!resolver)
|
|
return E_POINTER;
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IMFSourceResolver_iface.lpVtbl = &mfsourceresolvervtbl;
|
|
object->stream_callback.lpVtbl = &source_resolver_callback_stream_vtbl;
|
|
object->url_callback.lpVtbl = &source_resolver_callback_url_vtbl;
|
|
object->refcount = 1;
|
|
list_init(&object->pending);
|
|
InitializeCriticalSection(&object->cs);
|
|
|
|
*resolver = &object->IMFSourceResolver_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
typedef struct media_event
|
|
{
|
|
struct attributes attributes;
|
|
IMFMediaEvent IMFMediaEvent_iface;
|
|
|
|
MediaEventType type;
|
|
GUID extended_type;
|
|
HRESULT status;
|
|
PROPVARIANT value;
|
|
} mfmediaevent;
|
|
|
|
static inline mfmediaevent *impl_from_IMFMediaEvent(IMFMediaEvent *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, mfmediaevent, IMFMediaEvent_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_QueryInterface(IMFMediaEvent *iface, REFIID riid, void **out)
|
|
{
|
|
mfmediaevent *This = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
|
|
|
|
if(IsEqualGUID(riid, &IID_IUnknown) ||
|
|
IsEqualGUID(riid, &IID_IMFAttributes) ||
|
|
IsEqualGUID(riid, &IID_IMFMediaEvent))
|
|
{
|
|
*out = &This->IMFMediaEvent_iface;
|
|
}
|
|
else
|
|
{
|
|
FIXME("(%s, %p)\n", debugstr_guid(riid), out);
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown*)*out);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI mfmediaevent_AddRef(IMFMediaEvent *iface)
|
|
{
|
|
mfmediaevent *This = impl_from_IMFMediaEvent(iface);
|
|
ULONG ref = InterlockedIncrement(&This->attributes.ref);
|
|
|
|
TRACE("(%p) ref=%u\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI mfmediaevent_Release(IMFMediaEvent *iface)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
ULONG ref = InterlockedDecrement(&event->attributes.ref);
|
|
|
|
TRACE("(%p) ref=%u\n", iface, ref);
|
|
|
|
if (!ref)
|
|
{
|
|
clear_attributes_object(&event->attributes);
|
|
PropVariantClear(&event->value);
|
|
heap_free(event);
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetItem(IMFMediaEvent *iface, REFGUID key, PROPVARIANT *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetItem(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetItemType(IMFMediaEvent *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
|
|
|
|
return attributes_GetItemType(&event->attributes, key, type);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_CompareItem(IMFMediaEvent *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, result);
|
|
|
|
return attributes_CompareItem(&event->attributes, key, value, result);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_Compare(IMFMediaEvent *iface, IMFAttributes *attrs, MF_ATTRIBUTES_MATCH_TYPE type,
|
|
BOOL *result)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %p, %d, %p.\n", iface, attrs, type, result);
|
|
|
|
return attributes_Compare(&event->attributes, attrs, type, result);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetUINT32(IMFMediaEvent *iface, REFGUID key, UINT32 *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetUINT32(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetUINT64(IMFMediaEvent *iface, REFGUID key, UINT64 *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetUINT64(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetDouble(IMFMediaEvent *iface, REFGUID key, double *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetDouble(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetGUID(IMFMediaEvent *iface, REFGUID key, GUID *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_GetGUID(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetStringLength(IMFMediaEvent *iface, REFGUID key, UINT32 *length)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
|
|
|
|
return attributes_GetStringLength(&event->attributes, key, length);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetString(IMFMediaEvent *iface, REFGUID key, WCHAR *value,
|
|
UINT32 size, UINT32 *length)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
|
|
|
|
return attributes_GetString(&event->attributes, key, value, size, length);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetAllocatedString(IMFMediaEvent *iface, REFGUID key,
|
|
WCHAR **value, UINT32 *length)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
|
|
|
|
return attributes_GetAllocatedString(&event->attributes, key, value, length);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetBlobSize(IMFMediaEvent *iface, REFGUID key, UINT32 *size)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
|
|
|
|
return attributes_GetBlobSize(&event->attributes, key, size);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetBlob(IMFMediaEvent *iface, REFGUID key, UINT8 *buf,
|
|
UINT32 bufsize, UINT32 *blobsize)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
|
|
|
|
return attributes_GetBlob(&event->attributes, key, buf, bufsize, blobsize);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetAllocatedBlob(IMFMediaEvent *iface, REFGUID key, UINT8 **buf, UINT32 *size)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
|
|
|
|
return attributes_GetAllocatedBlob(&event->attributes, key, buf, size);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetUnknown(IMFMediaEvent *iface, REFGUID key, REFIID riid, void **out)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
|
|
|
|
return attributes_GetUnknown(&event->attributes, key, riid, out);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetItem(IMFMediaEvent *iface, REFGUID key, REFPROPVARIANT value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_SetItem(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_DeleteItem(IMFMediaEvent *iface, REFGUID key)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s.\n", iface, debugstr_attr(key));
|
|
|
|
return attributes_DeleteItem(&event->attributes, key);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_DeleteAllItems(IMFMediaEvent *iface)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return attributes_DeleteAllItems(&event->attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetUINT32(IMFMediaEvent *iface, REFGUID key, UINT32 value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_SetUINT32(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetUINT64(IMFMediaEvent *iface, REFGUID key, UINT64 value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
|
|
|
|
return attributes_SetUINT64(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetDouble(IMFMediaEvent *iface, REFGUID key, double value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
|
|
|
|
return attributes_SetDouble(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetGUID(IMFMediaEvent *iface, REFGUID key, REFGUID value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_guid(value));
|
|
|
|
return attributes_SetGUID(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetString(IMFMediaEvent *iface, REFGUID key, const WCHAR *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
|
|
|
|
return attributes_SetString(&event->attributes, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetBlob(IMFMediaEvent *iface, REFGUID key, const UINT8 *buf, UINT32 size)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
|
|
|
|
return attributes_SetBlob(&event->attributes, key, buf, size);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_SetUnknown(IMFMediaEvent *iface, REFGUID key, IUnknown *unknown)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
|
|
|
|
return attributes_SetUnknown(&event->attributes, key, unknown);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_LockStore(IMFMediaEvent *iface)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return attributes_LockStore(&event->attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_UnlockStore(IMFMediaEvent *iface)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return attributes_UnlockStore(&event->attributes);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetCount(IMFMediaEvent *iface, UINT32 *count)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, count);
|
|
|
|
return attributes_GetCount(&event->attributes, count);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetItemByIndex(IMFMediaEvent *iface, UINT32 index, GUID *key, PROPVARIANT *value)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
|
|
|
|
return attributes_GetItemByIndex(&event->attributes, index, key, value);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_CopyAllItems(IMFMediaEvent *iface, IMFAttributes *dest)
|
|
{
|
|
struct media_event *event = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, dest);
|
|
|
|
return attributes_CopyAllItems(&event->attributes, dest);
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetType(IMFMediaEvent *iface, MediaEventType *type)
|
|
{
|
|
mfmediaevent *This = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %p\n", This, type);
|
|
|
|
*type = This->type;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetExtendedType(IMFMediaEvent *iface, GUID *extended_type)
|
|
{
|
|
mfmediaevent *This = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %p\n", This, extended_type);
|
|
|
|
*extended_type = This->extended_type;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetStatus(IMFMediaEvent *iface, HRESULT *status)
|
|
{
|
|
mfmediaevent *This = impl_from_IMFMediaEvent(iface);
|
|
|
|
TRACE("%p, %p\n", This, status);
|
|
|
|
*status = This->status;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI mfmediaevent_GetValue(IMFMediaEvent *iface, PROPVARIANT *value)
|
|
{
|
|
mfmediaevent *This = impl_from_IMFMediaEvent(iface);
|
|
|
|
PropVariantCopy(value, &This->value);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFMediaEventVtbl mfmediaevent_vtbl =
|
|
{
|
|
mfmediaevent_QueryInterface,
|
|
mfmediaevent_AddRef,
|
|
mfmediaevent_Release,
|
|
mfmediaevent_GetItem,
|
|
mfmediaevent_GetItemType,
|
|
mfmediaevent_CompareItem,
|
|
mfmediaevent_Compare,
|
|
mfmediaevent_GetUINT32,
|
|
mfmediaevent_GetUINT64,
|
|
mfmediaevent_GetDouble,
|
|
mfmediaevent_GetGUID,
|
|
mfmediaevent_GetStringLength,
|
|
mfmediaevent_GetString,
|
|
mfmediaevent_GetAllocatedString,
|
|
mfmediaevent_GetBlobSize,
|
|
mfmediaevent_GetBlob,
|
|
mfmediaevent_GetAllocatedBlob,
|
|
mfmediaevent_GetUnknown,
|
|
mfmediaevent_SetItem,
|
|
mfmediaevent_DeleteItem,
|
|
mfmediaevent_DeleteAllItems,
|
|
mfmediaevent_SetUINT32,
|
|
mfmediaevent_SetUINT64,
|
|
mfmediaevent_SetDouble,
|
|
mfmediaevent_SetGUID,
|
|
mfmediaevent_SetString,
|
|
mfmediaevent_SetBlob,
|
|
mfmediaevent_SetUnknown,
|
|
mfmediaevent_LockStore,
|
|
mfmediaevent_UnlockStore,
|
|
mfmediaevent_GetCount,
|
|
mfmediaevent_GetItemByIndex,
|
|
mfmediaevent_CopyAllItems,
|
|
mfmediaevent_GetType,
|
|
mfmediaevent_GetExtendedType,
|
|
mfmediaevent_GetStatus,
|
|
mfmediaevent_GetValue,
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateMediaEvent (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HRESULT status,
|
|
const PROPVARIANT *value, IMFMediaEvent **event)
|
|
{
|
|
mfmediaevent *object;
|
|
HRESULT hr;
|
|
|
|
TRACE("%s, %s, %08x, %p, %p\n", debugstr_eventid(type), debugstr_guid(extended_type), status, value, event);
|
|
|
|
object = HeapAlloc( GetProcessHeap(), 0, sizeof(*object) );
|
|
if(!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
|
|
{
|
|
heap_free(object);
|
|
return hr;
|
|
}
|
|
object->IMFMediaEvent_iface.lpVtbl = &mfmediaevent_vtbl;
|
|
|
|
object->type = type;
|
|
object->extended_type = *extended_type;
|
|
object->status = status;
|
|
|
|
PropVariantInit(&object->value);
|
|
if (value)
|
|
PropVariantCopy(&object->value, value);
|
|
|
|
*event = &object->IMFMediaEvent_iface;
|
|
|
|
TRACE("Created event %p.\n", *event);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
struct event_queue
|
|
{
|
|
IMFMediaEventQueue IMFMediaEventQueue_iface;
|
|
LONG refcount;
|
|
|
|
CRITICAL_SECTION cs;
|
|
CONDITION_VARIABLE update_event;
|
|
struct list events;
|
|
BOOL is_shut_down;
|
|
IMFAsyncResult *subscriber;
|
|
};
|
|
|
|
struct queued_event
|
|
{
|
|
struct list entry;
|
|
IMFMediaEvent *event;
|
|
};
|
|
|
|
static inline struct event_queue *impl_from_IMFMediaEventQueue(IMFMediaEventQueue *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct event_queue, IMFMediaEventQueue_iface);
|
|
}
|
|
|
|
static IMFMediaEvent *queue_pop_event(struct event_queue *queue)
|
|
{
|
|
struct list *head = list_head(&queue->events);
|
|
struct queued_event *queued_event;
|
|
IMFMediaEvent *event;
|
|
|
|
if (!head)
|
|
return NULL;
|
|
|
|
queued_event = LIST_ENTRY(head, struct queued_event, entry);
|
|
event = queued_event->event;
|
|
list_remove(&queued_event->entry);
|
|
heap_free(queued_event);
|
|
return event;
|
|
}
|
|
|
|
static void event_queue_cleanup(struct event_queue *queue)
|
|
{
|
|
IMFMediaEvent *event;
|
|
|
|
while ((event = queue_pop_event(queue)))
|
|
IMFMediaEvent_Release(event);
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_QueryInterface(IMFMediaEventQueue *iface, REFIID riid, void **out)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFMediaEventQueue) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*out = &queue->IMFMediaEventQueue_iface;
|
|
IMFMediaEventQueue_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI eventqueue_AddRef(IMFMediaEventQueue *iface)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
ULONG refcount = InterlockedIncrement(&queue->refcount);
|
|
|
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI eventqueue_Release(IMFMediaEventQueue *iface)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
ULONG refcount = InterlockedDecrement(&queue->refcount);
|
|
|
|
TRACE("%p, refcount %u.\n", queue, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
event_queue_cleanup(queue);
|
|
DeleteCriticalSection(&queue->cs);
|
|
heap_free(queue);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_GetEvent(IMFMediaEventQueue *iface, DWORD flags, IMFMediaEvent **event)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("%p, %p.\n", iface, event);
|
|
|
|
EnterCriticalSection(&queue->cs);
|
|
|
|
if (queue->is_shut_down)
|
|
hr = MF_E_SHUTDOWN;
|
|
else if (queue->subscriber)
|
|
hr = MF_E_MULTIPLE_SUBSCRIBERS;
|
|
else
|
|
{
|
|
if (flags & MF_EVENT_FLAG_NO_WAIT)
|
|
{
|
|
if (!(*event = queue_pop_event(queue)))
|
|
hr = MF_E_NO_EVENTS_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
while (list_empty(&queue->events) && !queue->is_shut_down)
|
|
{
|
|
SleepConditionVariableCS(&queue->update_event, &queue->cs, INFINITE);
|
|
}
|
|
*event = queue_pop_event(queue);
|
|
if (queue->is_shut_down)
|
|
hr = MF_E_SHUTDOWN;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&queue->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void queue_notify_subscriber(struct event_queue *queue)
|
|
{
|
|
if (list_empty(&queue->events) || !queue->subscriber)
|
|
return;
|
|
|
|
MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, queue->subscriber);
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_BeginGetEvent(IMFMediaEventQueue *iface, IMFAsyncCallback *callback, IUnknown *state)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
MFASYNCRESULT *result_data = (MFASYNCRESULT *)queue->subscriber;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p, %p.\n", iface, callback, state);
|
|
|
|
if (!callback)
|
|
return E_INVALIDARG;
|
|
|
|
EnterCriticalSection(&queue->cs);
|
|
|
|
if (queue->is_shut_down)
|
|
hr = MF_E_SHUTDOWN;
|
|
else if (result_data)
|
|
{
|
|
if (result_data->pCallback == callback)
|
|
hr = IMFAsyncResult_GetStateNoAddRef(queue->subscriber) == state ?
|
|
MF_S_MULTIPLE_BEGIN : MF_E_MULTIPLE_BEGIN;
|
|
else
|
|
hr = MF_E_MULTIPLE_SUBSCRIBERS;
|
|
}
|
|
else
|
|
{
|
|
hr = MFCreateAsyncResult(NULL, callback, state, &queue->subscriber);
|
|
if (SUCCEEDED(hr))
|
|
queue_notify_subscriber(queue);
|
|
}
|
|
|
|
LeaveCriticalSection(&queue->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_EndGetEvent(IMFMediaEventQueue *iface, IMFAsyncResult *result, IMFMediaEvent **event)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
HRESULT hr = E_FAIL;
|
|
|
|
TRACE("%p, %p, %p.\n", iface, result, event);
|
|
|
|
EnterCriticalSection(&queue->cs);
|
|
|
|
if (queue->is_shut_down)
|
|
hr = MF_E_SHUTDOWN;
|
|
else if (queue->subscriber == result)
|
|
{
|
|
*event = queue_pop_event(queue);
|
|
if (queue->subscriber)
|
|
IMFAsyncResult_Release(queue->subscriber);
|
|
queue->subscriber = NULL;
|
|
hr = *event ? S_OK : E_FAIL;
|
|
}
|
|
|
|
LeaveCriticalSection(&queue->cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT eventqueue_queue_event(struct event_queue *queue, IMFMediaEvent *event)
|
|
{
|
|
struct queued_event *queued_event;
|
|
HRESULT hr = S_OK;
|
|
|
|
queued_event = heap_alloc(sizeof(*queued_event));
|
|
if (!queued_event)
|
|
return E_OUTOFMEMORY;
|
|
|
|
queued_event->event = event;
|
|
|
|
EnterCriticalSection(&queue->cs);
|
|
|
|
if (queue->is_shut_down)
|
|
hr = MF_E_SHUTDOWN;
|
|
else
|
|
{
|
|
IMFMediaEvent_AddRef(queued_event->event);
|
|
list_add_tail(&queue->events, &queued_event->entry);
|
|
queue_notify_subscriber(queue);
|
|
}
|
|
|
|
LeaveCriticalSection(&queue->cs);
|
|
|
|
if (FAILED(hr))
|
|
heap_free(queued_event);
|
|
|
|
WakeAllConditionVariable(&queue->update_event);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_QueueEvent(IMFMediaEventQueue *iface, IMFMediaEvent *event)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, event);
|
|
|
|
return eventqueue_queue_event(queue, event);
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_QueueEventParamVar(IMFMediaEventQueue *iface, MediaEventType event_type,
|
|
REFGUID extended_type, HRESULT status, const PROPVARIANT *value)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
IMFMediaEvent *event;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s, %s, %#x, %p\n", iface, debugstr_eventid(event_type), debugstr_guid(extended_type), status, value);
|
|
|
|
if (FAILED(hr = MFCreateMediaEvent(event_type, extended_type, status, value, &event)))
|
|
return hr;
|
|
|
|
hr = eventqueue_queue_event(queue, event);
|
|
IMFMediaEvent_Release(event);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_QueueEventParamUnk(IMFMediaEventQueue *iface, MediaEventType event_type,
|
|
REFGUID extended_type, HRESULT status, IUnknown *unk)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
IMFMediaEvent *event;
|
|
PROPVARIANT value;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s, %s, %#x, %p.\n", iface, debugstr_eventid(event_type), debugstr_guid(extended_type), status, unk);
|
|
|
|
value.vt = VT_UNKNOWN;
|
|
value.u.punkVal = unk;
|
|
|
|
if (FAILED(hr = MFCreateMediaEvent(event_type, extended_type, status, &value, &event)))
|
|
return hr;
|
|
|
|
hr = eventqueue_queue_event(queue, event);
|
|
IMFMediaEvent_Release(event);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI eventqueue_Shutdown(IMFMediaEventQueue *iface)
|
|
{
|
|
struct event_queue *queue = impl_from_IMFMediaEventQueue(iface);
|
|
|
|
TRACE("%p\n", queue);
|
|
|
|
EnterCriticalSection(&queue->cs);
|
|
|
|
if (!queue->is_shut_down)
|
|
{
|
|
event_queue_cleanup(queue);
|
|
queue->is_shut_down = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&queue->cs);
|
|
|
|
WakeAllConditionVariable(&queue->update_event);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFMediaEventQueueVtbl eventqueuevtbl =
|
|
{
|
|
eventqueue_QueryInterface,
|
|
eventqueue_AddRef,
|
|
eventqueue_Release,
|
|
eventqueue_GetEvent,
|
|
eventqueue_BeginGetEvent,
|
|
eventqueue_EndGetEvent,
|
|
eventqueue_QueueEvent,
|
|
eventqueue_QueueEventParamVar,
|
|
eventqueue_QueueEventParamUnk,
|
|
eventqueue_Shutdown
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateEventQueue (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue)
|
|
{
|
|
struct event_queue *object;
|
|
|
|
TRACE("%p\n", queue);
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IMFMediaEventQueue_iface.lpVtbl = &eventqueuevtbl;
|
|
object->refcount = 1;
|
|
list_init(&object->events);
|
|
InitializeCriticalSection(&object->cs);
|
|
InitializeConditionVariable(&object->update_event);
|
|
|
|
*queue = &object->IMFMediaEventQueue_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
struct collection
|
|
{
|
|
IMFCollection IMFCollection_iface;
|
|
LONG refcount;
|
|
IUnknown **elements;
|
|
size_t capacity;
|
|
size_t count;
|
|
};
|
|
|
|
static struct collection *impl_from_IMFCollection(IMFCollection *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct collection, IMFCollection_iface);
|
|
}
|
|
|
|
static void collection_clear(struct collection *collection)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < collection->count; ++i)
|
|
{
|
|
if (collection->elements[i])
|
|
IUnknown_Release(collection->elements[i]);
|
|
}
|
|
|
|
heap_free(collection->elements);
|
|
collection->elements = NULL;
|
|
collection->count = 0;
|
|
collection->capacity = 0;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_QueryInterface(IMFCollection *iface, REFIID riid, void **out)
|
|
{
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFCollection) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*out = iface;
|
|
IMFCollection_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("Unsupported interface %s.\n", debugstr_guid(riid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI collection_AddRef(IMFCollection *iface)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
ULONG refcount = InterlockedIncrement(&collection->refcount);
|
|
|
|
TRACE("%p, %d.\n", collection, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI collection_Release(IMFCollection *iface)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
ULONG refcount = InterlockedDecrement(&collection->refcount);
|
|
|
|
TRACE("%p, %d.\n", collection, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
collection_clear(collection);
|
|
heap_free(collection->elements);
|
|
heap_free(collection);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_GetElementCount(IMFCollection *iface, DWORD *count)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, count);
|
|
|
|
if (!count)
|
|
return E_POINTER;
|
|
|
|
*count = collection->count;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_GetElement(IMFCollection *iface, DWORD idx, IUnknown **element)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
|
|
TRACE("%p, %u, %p.\n", iface, idx, element);
|
|
|
|
if (!element)
|
|
return E_POINTER;
|
|
|
|
if (idx >= collection->count)
|
|
return E_INVALIDARG;
|
|
|
|
*element = collection->elements[idx];
|
|
if (*element)
|
|
IUnknown_AddRef(*element);
|
|
|
|
return *element ? S_OK : E_UNEXPECTED;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_AddElement(IMFCollection *iface, IUnknown *element)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, element);
|
|
|
|
if (!mf_array_reserve((void **)&collection->elements, &collection->capacity, collection->count + 1,
|
|
sizeof(*collection->elements)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
collection->elements[collection->count++] = element;
|
|
if (element)
|
|
IUnknown_AddRef(element);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_RemoveElement(IMFCollection *iface, DWORD idx, IUnknown **element)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
size_t count;
|
|
|
|
TRACE("%p, %u, %p.\n", iface, idx, element);
|
|
|
|
if (!element)
|
|
return E_POINTER;
|
|
|
|
if (idx >= collection->count)
|
|
return E_INVALIDARG;
|
|
|
|
*element = collection->elements[idx];
|
|
|
|
count = collection->count - idx - 1;
|
|
if (count)
|
|
memmove(&collection->elements[idx], &collection->elements[idx + 1], count * sizeof(*collection->elements));
|
|
collection->count--;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_InsertElementAt(IMFCollection *iface, DWORD idx, IUnknown *element)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
size_t i;
|
|
|
|
TRACE("%p, %u, %p.\n", iface, idx, element);
|
|
|
|
if (!mf_array_reserve((void **)&collection->elements, &collection->capacity, idx + 1,
|
|
sizeof(*collection->elements)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (idx < collection->count)
|
|
{
|
|
memmove(&collection->elements[idx + 1], &collection->elements[idx],
|
|
(collection->count - idx) * sizeof(*collection->elements));
|
|
collection->count++;
|
|
}
|
|
else
|
|
{
|
|
for (i = collection->count; i < idx; ++i)
|
|
collection->elements[i] = NULL;
|
|
collection->count = idx + 1;
|
|
}
|
|
|
|
collection->elements[idx] = element;
|
|
if (collection->elements[idx])
|
|
IUnknown_AddRef(collection->elements[idx]);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI collection_RemoveAllElements(IMFCollection *iface)
|
|
{
|
|
struct collection *collection = impl_from_IMFCollection(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
collection_clear(collection);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMFCollectionVtbl mfcollectionvtbl =
|
|
{
|
|
collection_QueryInterface,
|
|
collection_AddRef,
|
|
collection_Release,
|
|
collection_GetElementCount,
|
|
collection_GetElement,
|
|
collection_AddElement,
|
|
collection_RemoveElement,
|
|
collection_InsertElementAt,
|
|
collection_RemoveAllElements,
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateCollection (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateCollection(IMFCollection **collection)
|
|
{
|
|
struct collection *object;
|
|
|
|
TRACE("%p\n", collection);
|
|
|
|
if (!collection)
|
|
return E_POINTER;
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IMFCollection_iface.lpVtbl = &mfcollectionvtbl;
|
|
object->refcount = 1;
|
|
|
|
*collection = &object->IMFCollection_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFHeapAlloc (mfplat.@)
|
|
*/
|
|
void *WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type)
|
|
{
|
|
TRACE("%lu, %#x, %s, %d, %#x.\n", size, flags, debugstr_a(file), line, type);
|
|
return HeapAlloc(GetProcessHeap(), flags, size);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFHeapFree (mfplat.@)
|
|
*/
|
|
void WINAPI MFHeapFree(void *p)
|
|
{
|
|
TRACE("%p\n", p);
|
|
HeapFree(GetProcessHeap(), 0, p);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MFCreateMFByteStreamOnStreamEx (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream)
|
|
{
|
|
FIXME("(%p, %p): stub\n", stream, bytestream);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_QueryInterface(IMFPresentationTimeSource *iface, REFIID riid, void **obj)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
|
|
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
|
|
|
|
if (IsEqualIID(riid, &IID_IMFPresentationTimeSource) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = &source->IMFPresentationTimeSource_iface;
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IMFClockStateSink))
|
|
{
|
|
*obj = &source->IMFClockStateSink_iface;
|
|
}
|
|
else
|
|
{
|
|
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown *)*obj);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI system_time_source_AddRef(IMFPresentationTimeSource *iface)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
|
|
ULONG refcount = InterlockedIncrement(&source->refcount);
|
|
|
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI system_time_source_Release(IMFPresentationTimeSource *iface)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
|
|
ULONG refcount = InterlockedDecrement(&source->refcount);
|
|
|
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
DeleteCriticalSection(&source->cs);
|
|
heap_free(source);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_GetClockCharacteristics(IMFPresentationTimeSource *iface, DWORD *flags)
|
|
{
|
|
TRACE("%p, %p.\n", iface, flags);
|
|
|
|
*flags = MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ | MFCLOCK_CHARACTERISTICS_FLAG_IS_SYSTEM_CLOCK;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_GetCorrelatedTime(IMFPresentationTimeSource *iface, DWORD reserved,
|
|
LONGLONG *clock_time, MFTIME *system_time)
|
|
{
|
|
FIXME("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI system_time_source_GetContinuityKey(IMFPresentationTimeSource *iface, DWORD *key)
|
|
{
|
|
TRACE("%p, %p.\n", iface, key);
|
|
|
|
*key = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_GetState(IMFPresentationTimeSource *iface, DWORD reserved,
|
|
MFCLOCK_STATE *state)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
|
|
|
|
TRACE("%p, %#x, %p.\n", iface, reserved, state);
|
|
|
|
EnterCriticalSection(&source->cs);
|
|
*state = source->state;
|
|
LeaveCriticalSection(&source->cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_GetProperties(IMFPresentationTimeSource *iface, MFCLOCK_PROPERTIES *props)
|
|
{
|
|
FIXME("%p, %p.\n", iface, props);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_GetUnderlyingClock(IMFPresentationTimeSource *iface, IMFClock **clock)
|
|
{
|
|
FIXME("%p, %p.\n", iface, clock);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMFPresentationTimeSourceVtbl systemtimesourcevtbl =
|
|
{
|
|
system_time_source_QueryInterface,
|
|
system_time_source_AddRef,
|
|
system_time_source_Release,
|
|
system_time_source_GetClockCharacteristics,
|
|
system_time_source_GetCorrelatedTime,
|
|
system_time_source_GetContinuityKey,
|
|
system_time_source_GetState,
|
|
system_time_source_GetProperties,
|
|
system_time_source_GetUnderlyingClock,
|
|
};
|
|
|
|
static HRESULT WINAPI system_time_source_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **out)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
return IMFPresentationTimeSource_QueryInterface(&source->IMFPresentationTimeSource_iface, riid, out);
|
|
}
|
|
|
|
static ULONG WINAPI system_time_source_sink_AddRef(IMFClockStateSink *iface)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
return IMFPresentationTimeSource_AddRef(&source->IMFPresentationTimeSource_iface);
|
|
}
|
|
|
|
static ULONG WINAPI system_time_source_sink_Release(IMFClockStateSink *iface)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
return IMFPresentationTimeSource_Release(&source->IMFPresentationTimeSource_iface);
|
|
}
|
|
|
|
enum clock_command
|
|
{
|
|
CLOCK_CMD_START = 0,
|
|
CLOCK_CMD_STOP,
|
|
CLOCK_CMD_PAUSE,
|
|
CLOCK_CMD_RESTART,
|
|
CLOCK_CMD_MAX,
|
|
};
|
|
|
|
static HRESULT system_time_source_change_state(struct system_time_source *source, enum clock_command command)
|
|
{
|
|
static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
|
|
{ /* S S* P R */
|
|
/* INVALID */ { 1, 0, 1, 0 },
|
|
/* RUNNING */ { 1, 1, 1, 0 },
|
|
/* STOPPED */ { 1, 1, 0, 0 },
|
|
/* PAUSED */ { 1, 1, 0, 1 },
|
|
};
|
|
static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
|
|
{
|
|
/* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
|
|
/* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
|
|
/* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
|
|
/* CLOCK_CMD_RESTART */ MFCLOCK_STATE_RUNNING,
|
|
};
|
|
|
|
/* Special case that go against usual state change vs return value behavior. */
|
|
if (source->state == MFCLOCK_STATE_INVALID && command == CLOCK_CMD_STOP)
|
|
return S_OK;
|
|
|
|
if (!state_change_is_allowed[source->state][command])
|
|
return MF_E_INVALIDREQUEST;
|
|
|
|
source->state = states[command];
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time,
|
|
LONGLONG start_offset)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(system_time), wine_dbgstr_longlong(start_offset));
|
|
|
|
EnterCriticalSection(&source->cs);
|
|
hr = system_time_source_change_state(source, CLOCK_CMD_START);
|
|
LeaveCriticalSection(&source->cs);
|
|
|
|
/* FIXME: update timestamps */
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
|
|
|
EnterCriticalSection(&source->cs);
|
|
hr = system_time_source_change_state(source, CLOCK_CMD_STOP);
|
|
LeaveCriticalSection(&source->cs);
|
|
|
|
/* FIXME: update timestamps */
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
|
|
|
EnterCriticalSection(&source->cs);
|
|
hr = system_time_source_change_state(source, CLOCK_CMD_PAUSE);
|
|
LeaveCriticalSection(&source->cs);
|
|
|
|
/* FIXME: update timestamps */
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time)
|
|
{
|
|
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
|
|
|
EnterCriticalSection(&source->cs);
|
|
hr = system_time_source_change_state(source, CLOCK_CMD_RESTART);
|
|
LeaveCriticalSection(&source->cs);
|
|
|
|
/* FIXME: update timestamps */
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI system_time_source_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate)
|
|
{
|
|
FIXME("%p, %s, %f.\n", iface, wine_dbgstr_longlong(system_time), rate);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMFClockStateSinkVtbl systemtimesourcesinkvtbl =
|
|
{
|
|
system_time_source_sink_QueryInterface,
|
|
system_time_source_sink_AddRef,
|
|
system_time_source_sink_Release,
|
|
system_time_source_sink_OnClockStart,
|
|
system_time_source_sink_OnClockStop,
|
|
system_time_source_sink_OnClockPause,
|
|
system_time_source_sink_OnClockRestart,
|
|
system_time_source_sink_OnClockSetRate,
|
|
};
|
|
|
|
/***********************************************************************
|
|
* MFCreateSystemTimeSource (mfplat.@)
|
|
*/
|
|
HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source)
|
|
{
|
|
struct system_time_source *object;
|
|
|
|
TRACE("%p.\n", time_source);
|
|
|
|
object = heap_alloc_zero(sizeof(*object));
|
|
if (!object)
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IMFPresentationTimeSource_iface.lpVtbl = &systemtimesourcevtbl;
|
|
object->IMFClockStateSink_iface.lpVtbl = &systemtimesourcesinkvtbl;
|
|
object->refcount = 1;
|
|
InitializeCriticalSection(&object->cs);
|
|
|
|
*time_source = &object->IMFPresentationTimeSource_iface;
|
|
|
|
return S_OK;
|
|
}
|