qcap: Reimplement COM registration and vending locally.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Zebediah Figura 2020-03-08 14:05:08 -05:00 committed by Alexandre Julliard
parent cf376c96e8
commit 7bcb8e74ce
10 changed files with 343 additions and 210 deletions

View File

@ -8,7 +8,6 @@ C_SRCS = \
avico.c \
avimux.c \
capturegraph.c \
dllfunc.c \
filter.c \
mediatype.c \
pin.c \
@ -18,3 +17,6 @@ C_SRCS = \
vfwcapture.c
RC_SRCS = version.rc
IDL_SRCS = \
qcap_classes.idl

View File

@ -154,22 +154,18 @@ static const IPersistPropertyBagVtbl PersistPropertyBagVtbl =
PPB_Save
};
IUnknown* WINAPI QCAP_createAudioCaptureFilter(IUnknown *outer, HRESULT *phr)
HRESULT audio_record_create(IUnknown *outer, IUnknown **out)
{
AudioRecord *This = NULL;
AudioRecord *object;
FIXME("(%p, %p): the entire CLSID_AudioRecord implementation is just stubs\n", outer, phr);
if (!(object = CoTaskMemAlloc(sizeof(*object))))
return E_OUTOFMEMORY;
memset(object, 0, sizeof(*object));
This = CoTaskMemAlloc(sizeof(*This));
if (This == NULL) {
*phr = E_OUTOFMEMORY;
return NULL;
}
memset(This, 0, sizeof(*This));
This->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl;
object->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl;
strmbase_filter_init(&object->filter, outer, &CLSID_AudioRecord, &filter_ops);
strmbase_filter_init(&This->filter, outer, &CLSID_AudioRecord, &filter_ops);
*phr = S_OK;
return &This->filter.IUnknown_inner;
TRACE("Created audio recorder %p.\n", object);
*out = &object->filter.IUnknown_inner;
return S_OK;
}

View File

@ -480,25 +480,22 @@ static const struct strmbase_source_ops source_ops =
.pfnDecideAllocator = AVICompressorOut_DecideAllocator,
};
IUnknown* WINAPI QCAP_createAVICompressor(IUnknown *outer, HRESULT *phr)
HRESULT avi_compressor_create(IUnknown *outer, IUnknown **out)
{
static const WCHAR source_name[] = {'O','u','t',0};
static const WCHAR sink_name[] = {'I','n',0};
AVICompressor *compressor;
AVICompressor *object;
compressor = heap_alloc_zero(sizeof(*compressor));
if(!compressor) {
*phr = E_NOINTERFACE;
return NULL;
}
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
strmbase_filter_init(&compressor->filter, outer, &CLSID_AVICo, &filter_ops);
strmbase_filter_init(&object->filter, outer, &CLSID_AVICo, &filter_ops);
object->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl;
compressor->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl;
strmbase_sink_init(&object->sink, &object->filter, sink_name, &sink_ops, NULL);
strmbase_source_init(&object->source, &object->filter, source_name, &source_ops);
strmbase_sink_init(&compressor->sink, &compressor->filter, sink_name, &sink_ops, NULL);
strmbase_source_init(&compressor->source, &compressor->filter, source_name, &source_ops);
*phr = S_OK;
return &compressor->filter.IUnknown_inner;
TRACE("Created AVI compressor %p.\n", object);
*out = &object->filter.IUnknown_inner;
return S_OK;
}

View File

@ -1835,7 +1835,7 @@ static HRESULT create_input_pin(AviMux *avimux)
return S_OK;
}
IUnknown * WINAPI QCAP_createAVIMux(IUnknown *outer, HRESULT *phr)
HRESULT avi_mux_create(IUnknown *outer, IUnknown **out)
{
static const WCHAR output_name[] = {'A','V','I',' ','O','u','t',0};
@ -1843,11 +1843,8 @@ IUnknown * WINAPI QCAP_createAVIMux(IUnknown *outer, HRESULT *phr)
PIN_INFO info;
HRESULT hr;
avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux));
if(!avimux) {
*phr = E_OUTOFMEMORY;
return NULL;
}
if (!(avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux))))
return E_OUTOFMEMORY;
strmbase_filter_init(&avimux->filter, outer, &CLSID_AviDest, &filter_ops);
avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl;
@ -1870,13 +1867,13 @@ IUnknown * WINAPI QCAP_createAVIMux(IUnknown *outer, HRESULT *phr)
strmbase_source_cleanup(&avimux->source);
strmbase_filter_cleanup(&avimux->filter);
HeapFree(GetProcessHeap(), 0, avimux);
*phr = hr;
return NULL;
return hr;
}
avimux->interleave = 10000000;
TRACE("Created AVI mux %p.\n", avimux);
ObjectRefCount(TRUE);
*phr = S_OK;
return &avimux->filter.IUnknown_inner;
*out = &avimux->filter.IUnknown_inner;
return S_OK;
}

View File

@ -74,33 +74,27 @@ static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder2(ICaptureGraphBui
}
IUnknown * CALLBACK QCAP_createCaptureGraphBuilder2(IUnknown *pUnkOuter,
HRESULT *phr)
HRESULT capture_graph_create(IUnknown *outer, IUnknown **out)
{
CaptureGraphImpl * pCapture = NULL;
CaptureGraphImpl *object;
TRACE("(%p, %p)\n", pUnkOuter, phr);
if (outer)
return CLASS_E_NOAGGREGATION;
*phr = CLASS_E_NOAGGREGATION;
if (pUnkOuter)
{
return NULL;
}
*phr = E_OUTOFMEMORY;
if (!(object = CoTaskMemAlloc(sizeof(*object))))
return E_OUTOFMEMORY;
pCapture = CoTaskMemAlloc(sizeof(CaptureGraphImpl));
if (pCapture)
{
pCapture->ICaptureGraphBuilder2_iface.lpVtbl = &builder2_Vtbl;
pCapture->ICaptureGraphBuilder_iface.lpVtbl = &builder_Vtbl;
pCapture->ref = 1;
pCapture->mygraph = NULL;
InitializeCriticalSection(&pCapture->csFilter);
pCapture->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CaptureGraphImpl.csFilter");
*phr = S_OK;
ObjectRefCount(TRUE);
}
return (IUnknown *)&pCapture->ICaptureGraphBuilder_iface;
object->ICaptureGraphBuilder2_iface.lpVtbl = &builder2_Vtbl;
object->ICaptureGraphBuilder_iface.lpVtbl = &builder_Vtbl;
object->ref = 1;
object->mygraph = NULL;
InitializeCriticalSection(&object->csFilter);
object->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CaptureGraphImpl.csFilter");
TRACE("Created capture graph builder %p.\n", object);
ObjectRefCount(TRUE);
*out = (IUnknown *)&object->ICaptureGraphBuilder_iface;
return S_OK;
}
static HRESULT WINAPI

View File

@ -0,0 +1,70 @@
/*
* COM classes for qcap
*
* Copyright 2019 Zebediah Figura
*
* 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
*/
#pragma makedep register
[
helpstring("Audio Capture Filter"),
threading(both),
uuid(e30629d2-27e5-11ce-875d-00608cb78066)
]
coclass AudioRecord {}
[
helpstring("Audio Capture Filter"),
threading(both),
uuid(d76e2820-1563-11cf-ac98-00aa004c0fa9)
]
coclass AVICo {}
[
helpstring("AVI mux"),
threading(both),
uuid(e2510970-f137-11ce-8b67-00aa00a3f1a6)
]
coclass AviDest {}
[
helpstring("Capture Graph Builder"),
threading(both),
uuid(bf87b6e0-8c27-11d0-b3f0-00aa003761c5)
]
coclass CaptureGraphBuilder {}
[
helpstring("Capture Graph Builder 2"),
threading(both),
uuid(bf87b6e1-8c27-11d0-b3f0-00aa003761c5)
]
coclass CaptureGraphBuilder2 {}
[
helpstring("Smart Tee Filter"),
threading(both),
uuid(cc58e280-8aa1-11d1-b3f1-00aa003761c5)
]
coclass SmartTee {}
[
helpstring("VFW Capture Filter"),
threading(both),
uuid(1b544c22-fd0b-11ce-8c63-00aa0044b51e)
]
coclass VfwCapture {}

View File

@ -1,8 +1,9 @@
/*
* Qcap implementation, dllentry points
* DirectShow capture
*
* Copyright (C) 2003 Dominik Strasser
* Copyright (C) 2005 Rolf Kalbermatter
* Copyright (C) 2019 Zebediah Figura
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -25,7 +26,8 @@
#include <stdarg.h>
#define COBJMACROS
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
@ -33,6 +35,7 @@
#include "objbase.h"
#include "uuids.h"
#include "strmif.h"
#include "rpcproxy.h"
#include "qcap_main.h"
@ -41,132 +44,207 @@
WINE_DEFAULT_DEBUG_CHANNEL(qcap);
static HINSTANCE qcap_instance;
static LONG objects_ref = 0;
static const WCHAR wAudioCaptureFilter[] =
{'A','u','d','i','o',' ','C','a','p','t','u','r','e',' ','F','i','l','t','e','r',0};
static const WCHAR wAVICompressor[] =
{'A','V','I',' ','C','o','m','p','r','e','s','s','o','r',0};
static const WCHAR wVFWCaptFilter[] =
{'V','F','W',' ','C','a','p','t','u','r','e',' ','F','i','l','t','e','r',0};
static const WCHAR wVFWCaptFilterProp[] =
{'V','F','W',' ','C','a','p','t','u','r','e',' ','F','i','l','t','e','r',' ',
'P','r','o','p','e','r','t','y',' ','P','a','g','e',0};
static const WCHAR wAVIMux[] =
{'A','V','I',' ','m','u','x',0};
static const WCHAR wAVIMuxPropPage[] =
{'A','V','I',' ','m','u','x',' ','P','r','o','p','e','r','t','y',' ','P','a','g','e',0};
static const WCHAR wAVIMuxPropPage1[] =
{'A','V','I',' ','m','u','x',' ','P','r','o','p','e','r','t','y',' ','P','a','g','e','1',0};
static const WCHAR wFileWriter[] =
{'F','i','l','e',' ','W','r','i','t','e','r',0};
static const WCHAR wCaptGraphBuilder[] =
{'C','a','p','t','u','r','e',' ','G','r','a','p','h',' ','B','u','i','l','d','e','r',0};
static const WCHAR wCaptGraphBuilder2[] =
{'C','a','p','t','u','r','e',' ','G','r','a','p','h',' ','B','u','i','l','d','e','r','2',0};
static const WCHAR wInfPinTeeFilter[] =
{'I','n','f','i','n','i','t','e',' ','P','i','n',' ','T','e','e',' ','F','i',
'l','t','e','r',0};
static const WCHAR wSmartTeeFilter[] =
{'S','m','a','r','t',' ','T','e','e',' ','F','i','l','t','e','r',0};
static const WCHAR wAudioInMixerProp[] =
{'A','u','d','i','o','I','n','p','u','t','M','i','x','e','r',' ','P','r','o',
'p','e','r','t','y',' ','P','a','g','e',0};
FactoryTemplate const g_Templates[] = {
{
wAudioCaptureFilter,
&CLSID_AudioRecord,
QCAP_createAudioCaptureFilter,
NULL
},{
wAVICompressor,
&CLSID_AVICo,
QCAP_createAVICompressor,
NULL
},{
wVFWCaptFilter,
&CLSID_VfwCapture,
QCAP_createVFWCaptureFilter,
NULL
},{
wVFWCaptFilterProp,
&CLSID_CaptureProperties,
NULL, /* FIXME: Implement QCAP_createVFWCaptureFilterPropertyPage */
NULL
},{
wAVIMux,
&CLSID_AviDest,
QCAP_createAVIMux,
NULL
},{
wAVIMuxPropPage,
&CLSID_AviMuxProptyPage,
NULL, /* FIXME: Implement QCAP_createAVIMuxPropertyPage */
NULL
},{
wAVIMuxPropPage1,
&CLSID_AviMuxProptyPage1,
NULL, /* FIXME: Implement QCAP_createAVIMuxPropertyPage1 */
NULL
},{
wFileWriter,
&CLSID_FileWriter,
NULL, /* FIXME: Implement QCAP_createFileWriter */
NULL
},{
wCaptGraphBuilder,
&CLSID_CaptureGraphBuilder,
QCAP_createCaptureGraphBuilder2,
NULL
},{
wCaptGraphBuilder2,
&CLSID_CaptureGraphBuilder2,
QCAP_createCaptureGraphBuilder2,
NULL
},{
wInfPinTeeFilter,
&CLSID_InfTee,
NULL, /* FIXME: Implement QCAP_createInfinitePinTeeFilter */
NULL
},{
wSmartTeeFilter,
&CLSID_SmartTee,
QCAP_createSmartTeeFilter,
NULL
},{
wAudioInMixerProp,
&CLSID_AudioInputMixerProperties,
NULL, /* FIXME: Implement QCAP_createAudioInputMixerPropertyPage */
NULL
}
struct class_factory
{
IClassFactory IClassFactory_iface;
HRESULT (*create_instance)(IUnknown *outer, IUnknown **out);
};
const int g_cTemplates = ARRAY_SIZE(g_Templates);
/***********************************************************************
* Dll EntryPoint (QCAP.@)
*/
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
static inline struct class_factory *impl_from_IClassFactory(IClassFactory *iface)
{
return STRMBASE_DllMain(hInstDLL,fdwReason,lpv);
return CONTAINING_RECORD(iface, struct class_factory, IClassFactory_iface);
}
/***********************************************************************
* DllGetClassObject
*/
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID iid, void **out)
{
return STRMBASE_DllGetClassObject( rclsid, riid, ppv );
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory))
{
*out = iface;
IClassFactory_AddRef(iface);
return S_OK;
}
*out = NULL;
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
return E_NOINTERFACE;
}
static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
{
return 2;
}
static ULONG WINAPI class_factory_Release(IClassFactory *iface)
{
return 1;
}
static HRESULT WINAPI class_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out)
{
struct class_factory *factory = impl_from_IClassFactory(iface);
IUnknown *unk;
HRESULT hr;
TRACE("iface %p, outer %p, iid %s, out %p.\n", iface, outer, debugstr_guid(iid), out);
if (outer && !IsEqualGUID(iid, &IID_IUnknown))
return E_NOINTERFACE;
*out = NULL;
if (SUCCEEDED(hr = factory->create_instance(outer, &unk)))
{
hr = IUnknown_QueryInterface(unk, iid, out);
IUnknown_Release(unk);
}
return hr;
}
static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL lock)
{
TRACE("iface %p, lock %d.\n", iface, lock);
if (lock)
InterlockedIncrement(&objects_ref);
else
InterlockedDecrement(&objects_ref);
return S_OK;
}
static const IClassFactoryVtbl class_factory_vtbl =
{
class_factory_QueryInterface,
class_factory_AddRef,
class_factory_Release,
class_factory_CreateInstance,
class_factory_LockServer,
};
static struct class_factory audio_record_cf = {{&class_factory_vtbl}, audio_record_create};
static struct class_factory avi_compressor_cf = {{&class_factory_vtbl}, avi_compressor_create};
static struct class_factory avi_mux_cf = {{&class_factory_vtbl}, avi_mux_create};
static struct class_factory capture_graph_cf = {{&class_factory_vtbl}, capture_graph_create};
static struct class_factory smart_tee_cf = {{&class_factory_vtbl}, smart_tee_create};
static struct class_factory vfw_capture_cf = {{&class_factory_vtbl}, vfw_capture_create};
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
qcap_instance = instance;
DisableThreadLibraryCalls(instance);
}
return TRUE;
}
HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
{
struct class_factory *factory;
TRACE("clsid %s, iid %s, out %p.\n", debugstr_guid(clsid), debugstr_guid(iid), out);
if (IsEqualGUID(clsid, &CLSID_AudioRecord))
factory = &audio_record_cf;
else if (IsEqualGUID(clsid, &CLSID_AVICo))
factory = &avi_compressor_cf;
else if (IsEqualGUID(clsid, &CLSID_AviDest))
factory = &avi_mux_cf;
else if (IsEqualGUID(clsid, &CLSID_CaptureGraphBuilder))
factory = &capture_graph_cf;
else if (IsEqualGUID(clsid, &CLSID_CaptureGraphBuilder2))
factory = &capture_graph_cf;
else if (IsEqualGUID(clsid, &CLSID_SmartTee))
factory = &smart_tee_cf;
else if (IsEqualGUID(clsid, &CLSID_VfwCapture))
factory = &vfw_capture_cf;
else
{
FIXME("%s not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid));
return CLASS_E_CLASSNOTAVAILABLE;
}
return IClassFactory_QueryInterface(&factory->IClassFactory_iface, iid, out);
}
static const REGPINTYPES reg_avi_mux_sink_mt = {&MEDIATYPE_Stream, &MEDIASUBTYPE_Avi};
static const REGFILTERPINS2 reg_avi_mux_pins[1] =
{
{
.cInstances = 1,
.nMediaTypes = 1,
.lpMediaType = &reg_avi_mux_sink_mt,
},
};
static const REGFILTER2 reg_avi_mux =
{
.dwVersion = 2,
.dwMerit = MERIT_DO_NOT_USE,
.u.s2.cPins2 = 1,
.u.s2.rgPins2 = reg_avi_mux_pins,
};
static const REGPINTYPES reg_video_mt = {&MEDIATYPE_Video, &GUID_NULL};
static const REGFILTERPINS2 reg_smart_tee_pins[3] =
{
{
.cInstances = 1,
.nMediaTypes = 1,
.lpMediaType = &reg_video_mt,
},
{
.dwFlags = REG_PINFLAG_B_OUTPUT,
.cInstances = 1,
.nMediaTypes = 1,
.lpMediaType = &reg_video_mt,
},
{
.dwFlags = REG_PINFLAG_B_OUTPUT,
.cInstances = 1,
.nMediaTypes = 1,
.lpMediaType = &reg_video_mt,
},
};
static const REGFILTER2 reg_smart_tee =
{
.dwVersion = 2,
.dwMerit = MERIT_DO_NOT_USE,
.u.s2.cPins2 = 3,
.u.s2.rgPins2 = reg_smart_tee_pins,
};
/***********************************************************************
* DllRegisterServer (QCAP.@)
*/
HRESULT WINAPI DllRegisterServer(void)
{
TRACE("()\n");
return AMovieDllRegisterServer2(TRUE);
static const WCHAR avi_muxW[] = {'A','V','I',' ','M','u','x',0};
static const WCHAR smart_teeW[] = {'S','m','a','r','t',' ','T','e','e',0};
IFilterMapper2 *mapper;
HRESULT hr;
if (FAILED(hr = __wine_register_resources( qcap_instance )))
return hr;
if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
&IID_IFilterMapper2, (void **)&mapper)))
return hr;
IFilterMapper2_RegisterFilter(mapper, &CLSID_AviDest, avi_muxW,
NULL, NULL, NULL, &reg_avi_mux);
IFilterMapper2_RegisterFilter(mapper, &CLSID_SmartTee, smart_teeW,
NULL, NULL, NULL, &reg_smart_tee);
IFilterMapper2_Release(mapper);
return S_OK;
}
/***********************************************************************
@ -174,8 +252,21 @@ HRESULT WINAPI DllRegisterServer(void)
*/
HRESULT WINAPI DllUnregisterServer(void)
{
TRACE("\n");
return AMovieDllRegisterServer2(FALSE);
IFilterMapper2 *mapper;
HRESULT hr;
if (FAILED(hr = __wine_unregister_resources( qcap_instance )))
return hr;
if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
&IID_IFilterMapper2, (void **)&mapper)))
return hr;
IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_AviDest);
IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_SmartTee);
IFilterMapper2_Release(mapper);
return S_OK;
}
/***********************************************************************
@ -183,11 +274,9 @@ HRESULT WINAPI DllUnregisterServer(void)
*/
HRESULT WINAPI DllCanUnloadNow(void)
{
TRACE("\n");
TRACE(".\n");
if (STRMBASE_DllCanUnloadNow() == S_OK && objects_ref == 0)
return S_OK;
return S_FALSE;
return objects_ref ? S_FALSE : S_OK;
}
DWORD ObjectRefCount(BOOL increment)

View File

@ -25,18 +25,11 @@
extern DWORD ObjectRefCount(BOOL increment) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAudioCaptureFilter(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAVICompressor(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createVFWCaptureFilterPropertyPage(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAVICompressor(IUnknown*,HRESULT*) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAVIMux(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAVIMuxPropertyPage(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAVIMuxPropertyPage1(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createFileWriter(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createCaptureGraphBuilder2(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createInfinitePinTeeFilter(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createSmartTeeFilter(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
extern IUnknown * WINAPI QCAP_createAudioInputMixerPropertyPage(IUnknown *pUnkOuter, HRESULT *phr) DECLSPEC_HIDDEN;
HRESULT audio_record_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT avi_compressor_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT avi_mux_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT capture_graph_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT smart_tee_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
#endif /* _QCAP_MAIN_H_DEFINED */

View File

@ -321,7 +321,7 @@ static const struct strmbase_source_ops preview_ops =
.pfnDecideAllocator = SmartTeeFilterPreview_DecideAllocator,
};
IUnknown* WINAPI QCAP_createSmartTeeFilter(IUnknown *outer, HRESULT *phr)
HRESULT smart_tee_create(IUnknown *outer, IUnknown **out)
{
static const WCHAR captureW[] = {'C','a','p','t','u','r','e',0};
static const WCHAR previewW[] = {'P','r','e','v','i','e','w',0};
@ -330,10 +330,7 @@ IUnknown* WINAPI QCAP_createSmartTeeFilter(IUnknown *outer, HRESULT *phr)
HRESULT hr;
if (!(object = CoTaskMemAlloc(sizeof(*object))))
{
*phr = E_OUTOFMEMORY;
return NULL;
}
return E_OUTOFMEMORY;
memset(object, 0, sizeof(*object));
strmbase_filter_init(&object->filter, outer, &CLSID_SmartTee, &filter_ops);
@ -342,14 +339,15 @@ IUnknown* WINAPI QCAP_createSmartTeeFilter(IUnknown *outer, HRESULT *phr)
&IID_IMemAllocator, (void **)&object->sink.pAllocator);
if (FAILED(hr))
{
*phr = hr;
strmbase_filter_cleanup(&object->filter);
return NULL;
CoTaskMemFree(object);
return hr;
}
strmbase_source_init(&object->capture, &object->filter, captureW, &capture_ops);
strmbase_source_init(&object->preview, &object->filter, previewW, &preview_ops);
*phr = S_OK;
return &object->filter.IUnknown_inner;
TRACE("Created smart tee %p.\n", object);
*out = &object->filter.IUnknown_inner;
return S_OK;
}

View File

@ -563,16 +563,13 @@ static const struct strmbase_source_ops source_ops =
.pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
};
IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *outer, HRESULT *phr)
HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
{
static const WCHAR source_name[] = {'O','u','t','p','u','t',0};
VfwCapture *object;
if (!(object = CoTaskMemAlloc(sizeof(*object))))
{
*phr = E_OUTOFMEMORY;
return NULL;
}
return E_OUTOFMEMORY;
strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
@ -587,6 +584,6 @@ IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *outer, HRESULT *phr)
TRACE("Created VFW capture filter %p.\n", object);
ObjectRefCount(TRUE);
*phr = S_OK;
return &object->filter.IUnknown_inner;
*out = &object->filter.IUnknown_inner;
return S_OK;
}