devenum: Register VFW codecs as codec devices.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2018-03-31 16:25:18 -05:00 committed by Alexandre Julliard
parent f4a98b8ce4
commit d63e560e6b
3 changed files with 164 additions and 63 deletions

View File

@ -106,28 +106,6 @@ static ULONG WINAPI DEVENUM_ICreateDevEnum_Release(ICreateDevEnum * iface)
return 1; /* non-heap based object */
}
static HKEY open_special_category_key(const CLSID *clsid, BOOL create)
{
WCHAR key_name[sizeof(wszActiveMovieKey)/sizeof(WCHAR) + CHARS_IN_GUID-1];
HKEY ret;
LONG res;
strcpyW(key_name, wszActiveMovieKey);
if (!StringFromGUID2(clsid, key_name + sizeof(wszActiveMovieKey)/sizeof(WCHAR)-1, CHARS_IN_GUID))
return NULL;
if(create)
res = RegCreateKeyW(HKEY_CURRENT_USER, key_name, &ret);
else
res = RegOpenKeyExW(HKEY_CURRENT_USER, key_name, 0, KEY_READ, &ret);
if (res != ERROR_SUCCESS) {
WARN("Could not open %s\n", debugstr_w(key_name));
return NULL;
}
return ret;
}
static HRESULT register_codec(const CLSID *class, const WCHAR *name, IMoniker **ret)
{
static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','c','m',':',0};
@ -817,6 +795,96 @@ cleanup:
}
}
static void register_vfw_codecs(void)
{
static const WCHAR fcchandlerW[] = {'F','c','c','H','a','n','d','l','e','r',0};
REGFILTERPINS2 rgpins[2] = {};
IPropertyBag *prop_bag = NULL;
REGPINTYPES rgtypes[2];
REGFILTER2 rgf;
WCHAR clsid[CHARS_IN_GUID];
IMoniker *mon = NULL;
GUID typeguid;
ICINFO info;
VARIANT var;
HRESULT hr;
int i = 0;
HIC hic;
hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
if (FAILED(hr)) return;
while (ICInfo(ICTYPE_VIDEO, i++, &info))
{
WCHAR name[5] = {LOBYTE(LOWORD(info.fccHandler)), HIBYTE(LOWORD(info.fccHandler)),
LOBYTE(HIWORD(info.fccHandler)), HIBYTE(HIWORD(info.fccHandler))};
hic = ICOpen(ICTYPE_VIDEO, info.fccHandler, ICMODE_QUERY);
ICGetInfo(hic, &info, sizeof(info));
ICClose(hic);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(name);
if (!(V_BSTR(&var)))
goto cleanup;
hr = register_codec(&CLSID_VideoCompressorCategory, V_BSTR(&var), &mon);
if (FAILED(hr)) goto cleanup;
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
if (FAILED(hr)) goto cleanup;
/* write WaveInId */
hr = IPropertyBag_Write(prop_bag, fcchandlerW, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
/* write friendly name */
V_VT(&var) = VT_BSTR;
if (!(V_BSTR(&var) = SysAllocString(info.szDescription)))
goto cleanup;
hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
/* write clsid */
V_VT(&var) = VT_BSTR;
StringFromGUID2(&CLSID_AVICo, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
/* write filter data */
rgf.dwVersion = 2;
rgf.dwMerit = MERIT_DO_NOT_USE;
rgf.u.s2.cPins2 = 2;
rgf.u.s2.rgPins2 = rgpins;
rgpins[0].dwFlags = 0;
rgpins[0].nMediaTypes = 1;
rgpins[0].lpMediaType = &rgtypes[0];
rgtypes[0].clsMajorType = &MEDIATYPE_Video;
typeguid = MEDIASUBTYPE_PCM;
typeguid.Data1 = info.fccHandler;
rgtypes[0].clsMinorType = &typeguid;
rgpins[1].dwFlags = REG_PINFLAG_B_OUTPUT;
rgpins[1].nMediaTypes = 1;
rgpins[1].lpMediaType = &rgtypes[1];
rgtypes[1].clsMajorType = &MEDIATYPE_Video;
rgtypes[1].clsMinorType = &GUID_NULL;
write_filter_data(prop_bag, &rgf);
cleanup:
VariantClear(&var);
if (prop_bag) IPropertyBag_Release(prop_bag);
if (mon) IMoniker_Release(mon);
}
}
/**********************************************************************
* DEVENUM_ICreateDevEnum_CreateClassEnumerator
*/
@ -842,6 +910,7 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
register_waveout_devices();
register_wavein_devices();
register_midiout_devices();
register_vfw_codecs();
return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker);
}
@ -894,44 +963,6 @@ static HRESULT DEVENUM_CreateAMCategoryKey(const CLSID * clsidCategory)
return res;
}
static void register_vfw_codecs(void)
{
WCHAR avico_clsid_str[CHARS_IN_GUID];
HKEY basekey, key;
ICINFO icinfo;
DWORD i, res;
static const WCHAR CLSIDW[] = {'C','L','S','I','D',0};
static const WCHAR FccHandlerW[] = {'F','c','c','H','a','n','d','l','e','r',0};
static const WCHAR FriendlyNameW[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
StringFromGUID2(&CLSID_AVICo, avico_clsid_str, sizeof(avico_clsid_str)/sizeof(WCHAR));
basekey = open_special_category_key(&CLSID_VideoCompressorCategory, TRUE);
if(!basekey) {
ERR("Could not create key\n");
return;
}
for(i=0; ICInfo(FCC('v','i','d','c'), i, &icinfo); i++) {
WCHAR fcc_str[5] = {LOBYTE(LOWORD(icinfo.fccHandler)), HIBYTE(LOWORD(icinfo.fccHandler)),
LOBYTE(HIWORD(icinfo.fccHandler)), HIBYTE(HIWORD(icinfo.fccHandler))};
res = RegCreateKeyW(basekey, fcc_str, &key);
if(res != ERROR_SUCCESS)
continue;
RegSetValueExW(key, CLSIDW, 0, REG_SZ, (const BYTE*)avico_clsid_str, sizeof(avico_clsid_str));
RegSetValueExW(key, FccHandlerW, 0, REG_SZ, (const BYTE*)fcc_str, sizeof(fcc_str));
RegSetValueExW(key, FriendlyNameW, 0, REG_SZ, (const BYTE*)icinfo.szName, (strlenW(icinfo.szName)+1)*sizeof(WCHAR));
/* FIXME: Set ClassManagerFlags and FilterData values */
RegCloseKey(key);
}
RegCloseKey(basekey);
}
static HRESULT register_codecs(void)
{
HRESULT res;
@ -1037,7 +1068,5 @@ static HRESULT register_codecs(void)
if (pMapper)
IFilterMapper2_Release(pMapper);
register_vfw_codecs();
return res;
}

View File

@ -1,5 +1,5 @@
TESTDLL = devenum.dll
IMPORTS = advapi32 dsound oleaut32 ole32 winmm
IMPORTS = advapi32 dsound msvfw32 oleaut32 ole32 winmm
C_SRCS = \
devenum.c

View File

@ -31,6 +31,7 @@
#include "mmsystem.h"
#include "dsound.h"
#include "mmddk.h"
#include "vfw.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
@ -879,6 +880,76 @@ static void test_midiout(void)
IParseDisplayName_Release(parser);
}
static void test_vfw(void)
{
static const WCHAR fcchandlerW[] = {'F','c','c','H','a','n','d','l','e','r',0};
IParseDisplayName *parser;
IPropertyBag *prop_bag;
IMoniker *mon;
WCHAR buffer[200];
ICINFO info;
VARIANT var;
HRESULT hr;
int i = 0;
HIC hic;
if (broken(sizeof(void *) == 8))
{
win_skip("VFW codecs are not enumerated on 64-bit Windows\n");
return;
}
hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
while (ICInfo(ICTYPE_VIDEO, i++, &info))
{
WCHAR name[5] = {LOBYTE(LOWORD(info.fccHandler)), HIBYTE(LOWORD(info.fccHandler)),
LOBYTE(HIWORD(info.fccHandler)), HIBYTE(HIWORD(info.fccHandler))};
hic = ICOpen(ICTYPE_VIDEO, info.fccHandler, ICMODE_QUERY);
ICGetInfo(hic, &info, sizeof(info));
ICClose(hic);
lstrcpyW(buffer, deviceW);
lstrcatW(buffer, cmW);
StringFromGUID2(&CLSID_VideoCompressorCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
lstrcatW(buffer, backslashW);
lstrcatW(buffer, name);
mon = check_display_name(parser, buffer);
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
VariantInit(&var);
hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
ok(hr == S_OK, "Read failed: %#x\n", hr);
ok(!lstrcmpW(info.szDescription, V_BSTR(&var)), "expected %s, got %s\n",
wine_dbgstr_w(info.szDescription), wine_dbgstr_w(V_BSTR(&var)));
VariantClear(&var);
hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
ok(hr == S_OK, "Read failed: %#x\n", hr);
StringFromGUID2(&CLSID_AVICo, buffer, CHARS_IN_GUID);
ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
VariantClear(&var);
hr = IPropertyBag_Read(prop_bag, fcchandlerW, &var, NULL);
ok(hr == S_OK, "Read failed: %#x\n", hr);
ok(!lstrcmpW(name, V_BSTR(&var)), "expected %s, got %s\n",
wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&var)));
IPropertyBag_Release(prop_bag);
IMoniker_Release(mon);
}
IParseDisplayName_Release(parser);
}
START_TEST(devenum)
{
IBindCtx *bind_ctx = NULL;
@ -907,6 +978,7 @@ START_TEST(devenum)
test_waveout();
test_wavein();
test_midiout();
test_vfw();
CoUninitialize();
}