reactos/dll/directx/ksproxy/proxy.cpp
Hermès Bélusca-Maïto 9393fc320e
[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
Excluded: 3rd-party code (incl. wine) and most of the win32ss.
2021-09-13 03:52:22 +02:00

3185 lines
83 KiB
C++

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS WDM Streaming ActiveMovie Proxy
* FILE: dll/directx/ksproxy/proxy.cpp
* PURPOSE: IKsProxy interface
*
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "precomp.h"
const GUID IID_IPersistPropertyBag = {0x37D84F60, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
const GUID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, {0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}};
const GUID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
const GUID IID_IKsAggregateControl = {0x7F40EAC0, 0x3947, 0x11D2, {0x87, 0x4E, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID IID_IKsClockPropertySet = {0x5C5CBD84, 0xE755, 0x11D0, {0xAC, 0x18, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID IID_IKsTopology = {0x28F54683, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID IID_IKsClock = {0x877E4351, 0x6FEA, 0x11D0, {0xB8, 0x63, 0x00, 0xAA, 0x00, 0xA2, 0x16, 0xA1}};
/*
Needs IKsClock, IKsNotifyEvent
*/
class CKsProxy : public IBaseFilter,
public IAMovieSetup,
public IPersistPropertyBag,
public IKsObject,
public IPersistStream,
public IAMDeviceRemoval,
public ISpecifyPropertyPages,
public IReferenceClock,
public IMediaSeeking,
public IKsPropertySet,
public IKsClock,
public IKsClockPropertySet,
public IAMFilterMiscFlags,
public IKsControl,
public IKsTopology,
public IKsAggregateControl
{
public:
typedef std::vector<IUnknown *>ProxyPluginVector;
typedef std::vector<IPin *> PinVector;
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
//delete this;
return 0;
}
return m_Ref;
}
// IBaseFilter methods
HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
HRESULT STDMETHODCALLTYPE Stop( void);
HRESULT STDMETHODCALLTYPE Pause( void);
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State);
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock);
HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
//IReferenceClock
HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTime);
HRESULT STDMETHODCALLTYPE AdviseTime(REFERENCE_TIME baseTime, REFERENCE_TIME streamTime, HEVENT hEvent, DWORD_PTR *pdwAdviseCookie);
HRESULT STDMETHODCALLTYPE AdvisePeriodic(REFERENCE_TIME startTime, REFERENCE_TIME periodTime, HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie);
HRESULT STDMETHODCALLTYPE Unadvise(DWORD_PTR dwAdviseCookie);
//IMediaSeeking
HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
HRESULT STDMETHODCALLTYPE SetRate(double dRate);
HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
//IKsPropertySet
HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData);
HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned);
HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);
//IAMFilterMiscFlags
ULONG STDMETHODCALLTYPE GetMiscFlags( void);
//IKsControl
HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned);
HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned);
HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned);
//IKsTopolology
HRESULT STDMETHODCALLTYPE CreateNodeInstance(ULONG NodeId, ULONG Flags, ACCESS_MASK DesiredAccess, IUnknown* UnkOuter, REFGUID InterfaceId, LPVOID* Interface);
//IKsAggregateControl
HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass);
HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass);
//IKsClockPropertySet
HRESULT STDMETHODCALLTYPE KsGetTime(LONGLONG* Time);
HRESULT STDMETHODCALLTYPE KsSetTime(LONGLONG Time);
HRESULT STDMETHODCALLTYPE KsGetPhysicalTime(LONGLONG* Time);
HRESULT STDMETHODCALLTYPE KsSetPhysicalTime(LONGLONG Time);
HRESULT STDMETHODCALLTYPE KsGetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
HRESULT STDMETHODCALLTYPE KsSetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
HRESULT STDMETHODCALLTYPE KsGetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
HRESULT STDMETHODCALLTYPE KsSetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
HRESULT STDMETHODCALLTYPE KsGetResolution(KSRESOLUTION* Resolution);
HRESULT STDMETHODCALLTYPE KsGetState(KSSTATE* State);
//IAMovieSetup methods
HRESULT STDMETHODCALLTYPE Register( void);
HRESULT STDMETHODCALLTYPE Unregister( void);
// IPersistPropertyBag methods
HRESULT STDMETHODCALLTYPE InitNew( void);
HRESULT STDMETHODCALLTYPE Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog);
HRESULT STDMETHODCALLTYPE Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
// IKsObject
HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
// IKsClock
HANDLE STDMETHODCALLTYPE KsGetClockHandle();
//IAMDeviceRemoval
HRESULT STDMETHODCALLTYPE DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink);
HRESULT STDMETHODCALLTYPE Reassociate(void);
HRESULT STDMETHODCALLTYPE Disassociate( void);
//IPersistStream
HRESULT STDMETHODCALLTYPE IsDirty( void);
HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
// ISpecifyPropertyPages
HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages);
CKsProxy();
~CKsProxy()
{
if (m_hDevice)
CloseHandle(m_hDevice);
};
HRESULT STDMETHODCALLTYPE GetSupportedSets(LPGUID * pOutGuid, PULONG NumGuids);
HRESULT STDMETHODCALLTYPE LoadProxyPlugins(LPGUID pGuids, ULONG NumGuids);
HRESULT STDMETHODCALLTYPE GetNumberOfPins(PULONG NumPins);
HRESULT STDMETHODCALLTYPE GetPinInstanceCount(ULONG PinId, PKSPIN_CINSTANCES Instances);
HRESULT STDMETHODCALLTYPE GetPinDataflow(ULONG PinId, KSPIN_DATAFLOW * DataFlow);
HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName);
HRESULT STDMETHODCALLTYPE GetPinCommunication(ULONG PinId, KSPIN_COMMUNICATION * Communication);
HRESULT STDMETHODCALLTYPE CreatePins();
HRESULT STDMETHODCALLTYPE GetMediaSeekingFormats(PKSMULTIPLE_ITEM *FormatList);
HRESULT STDMETHODCALLTYPE CreateClockInstance();
HRESULT STDMETHODCALLTYPE PerformClockProperty(ULONG PropertyId, ULONG PropertyFlags, PVOID OutputBuffer, ULONG OutputBufferSize);
HRESULT STDMETHODCALLTYPE SetPinState(KSSTATE State);
protected:
LONG m_Ref;
IFilterGraph *m_pGraph;
IReferenceClock * m_ReferenceClock;
FILTER_STATE m_FilterState;
HANDLE m_hDevice;
ProxyPluginVector m_Plugins;
PinVector m_Pins;
LPWSTR m_DevicePath;
CLSID m_DeviceInterfaceGUID;
HANDLE m_hClock;
CRITICAL_SECTION m_Lock;
};
CKsProxy::CKsProxy() : m_Ref(0),
m_pGraph(0),
m_FilterState(State_Stopped),
m_hDevice(0),
m_Plugins(),
m_Pins(),
m_DevicePath(0),
m_hClock(0)
{
m_ReferenceClock = this;
InitializeCriticalSection(&m_Lock);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
*Output = NULL;
if (IsEqualGUID(refiid, IID_IUnknown) ||
IsEqualGUID(refiid, IID_IBaseFilter))
{
*Output = PVOID(this);
reinterpret_cast<IUnknown*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IPersistPropertyBag))
{
*Output = (IPersistPropertyBag*)(this);
reinterpret_cast<IPersistPropertyBag*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IAMDeviceRemoval))
{
*Output = (IAMDeviceRemoval*)(this);
reinterpret_cast<IAMDeviceRemoval*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IPersistStream))
{
*Output = (IPersistStream*)(this);
reinterpret_cast<IPersistStream*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IPersist))
{
*Output = (IPersistStream*)(this);
reinterpret_cast<IPersist*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsObject))
{
*Output = (IKsObject*)(this);
reinterpret_cast<IKsObject*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsClock))
{
*Output = (IKsClock*)(this);
reinterpret_cast<IKsClock*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IReferenceClock))
{
if (!m_hClock)
{
HRESULT hr = CreateClockInstance();
if (FAILED(hr))
return hr;
}
*Output = (IReferenceClock*)(this);
reinterpret_cast<IReferenceClock*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IMediaSeeking))
{
*Output = (IMediaSeeking*)(this);
reinterpret_cast<IMediaSeeking*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IAMFilterMiscFlags))
{
*Output = (IAMFilterMiscFlags*)(this);
reinterpret_cast<IAMFilterMiscFlags*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsControl))
{
*Output = (IKsControl*)(this);
reinterpret_cast<IKsControl*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsPropertySet))
{
*Output = (IKsPropertySet*)(this);
reinterpret_cast<IKsPropertySet*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsTopology))
{
*Output = (IKsTopology*)(this);
reinterpret_cast<IKsTopology*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsAggregateControl))
{
*Output = (IKsAggregateControl*)(this);
reinterpret_cast<IKsAggregateControl*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_IKsClockPropertySet))
{
if (!m_hClock)
{
HRESULT hr = CreateClockInstance();
if (FAILED(hr))
return hr;
}
*Output = (IKsClockPropertySet*)(this);
reinterpret_cast<IKsClockPropertySet*>(*Output)->AddRef();
return NOERROR;
}
else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
{
*Output = (ISpecifyPropertyPages*)(this);
reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
return NOERROR;
}
for(ULONG Index = 0; Index < m_Plugins.size(); Index++)
{
if (m_Pins[Index])
{
HRESULT hr = m_Plugins[Index]->QueryInterface(refiid, Output);
if (SUCCEEDED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
LPOLESTR lpstr;
StringFromCLSID(refiid, &lpstr);
swprintf(Buffer, L"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index, lpstr);
OutputDebugStringW(Buffer);
CoTaskMemFree(lpstr);
#endif
return hr;
}
}
}
#ifdef KSPROXY_TRACE
WCHAR Buffer[MAX_PATH];
LPOLESTR lpstr;
StringFromCLSID(refiid, &lpstr);
swprintf(Buffer, L"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr);
OutputDebugStringW(Buffer);
CoTaskMemFree(lpstr);
#endif
return E_NOINTERFACE;
}
//-------------------------------------------------------------------
// ISpecifyPropertyPages
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPages(CAUUID *pPages)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetPages NotImplemented\n");
#endif
if (!pPages)
return E_POINTER;
pPages->cElems = 0;
pPages->pElems = NULL;
return S_OK;
}
//-------------------------------------------------------------------
// IKsClockPropertySet interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::CreateClockInstance()
{
HRESULT hr;
HANDLE hPin = INVALID_HANDLE_VALUE;
ULONG Index;
PIN_DIRECTION PinDir;
IKsObject *pObject;
KSCLOCK_CREATE ClockCreate;
// find output pin and handle
for(Index = 0; Index < m_Pins.size(); Index++)
{
//get pin
IPin * pin = m_Pins[Index];
if (!pin)
continue;
// get direction
hr = pin->QueryDirection(&PinDir);
if (FAILED(hr))
continue;
// query IKsObject interface
hr = pin->QueryInterface(IID_IKsObject, (void**)&pObject);
if (FAILED(hr))
continue;
// get pin handle
hPin = pObject->KsGetObjectHandle();
//release IKsObject
pObject->Release();
if (hPin != INVALID_HANDLE_VALUE)
break;
}
if (hPin == INVALID_HANDLE_VALUE)
{
// clock can only be instantiated on a pin handle
return E_NOTIMPL;
}
if (m_hClock)
{
// release clock handle
CloseHandle(m_hClock);
}
//setup clock create request
ClockCreate.CreateFlags = 0;
// setup clock create request
hr = KsCreateClock(hPin, &ClockCreate, &m_hClock); // FIXME KsCreateClock returns NTSTATUS
if (SUCCEEDED(hr))
{
// failed to create clock
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::PerformClockProperty(
ULONG PropertyId,
ULONG PropertyFlags,
PVOID OutputBuffer,
ULONG OutputBufferSize)
{
KSPROPERTY Property;
HRESULT hr;
ULONG BytesReturned;
if (!m_hClock)
{
// create clock
hr = CreateClockInstance();
if (FAILED(hr))
return hr;
}
// setup request
Property.Set = KSPROPSETID_Clock;
Property.Id = PropertyId;
Property.Flags = PropertyFlags;
hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)OutputBuffer, OutputBufferSize, &BytesReturned);
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsGetTime(
LONGLONG* Time)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsSetTime(
LONGLONG Time)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsSetTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsGetPhysicalTime(
LONGLONG* Time)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsSetPhysicalTime(
LONGLONG Time)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsSetPhysicalTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsGetCorrelatedTime(
KSCORRELATED_TIME* CorrelatedTime)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsSetCorrelatedTime(
KSCORRELATED_TIME* CorrelatedTime)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsGetCorrelatedPhysicalTime(
KSCORRELATED_TIME* CorrelatedTime)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsSetCorrelatedPhysicalTime(
KSCORRELATED_TIME* CorrelatedTime)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsGetResolution(
KSRESOLUTION* Resolution)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetResolution\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_TYPE_GET, (PVOID)Resolution, sizeof(KSRESOLUTION));
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsGetState(
KSSTATE* State)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetState\n");
#endif
return PerformClockProperty(KSPROPERTY_CLOCK_STATE, KSPROPERTY_TYPE_GET, (PVOID)State, sizeof(KSSTATE));
}
//-------------------------------------------------------------------
// IReferenceClock interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetTime(
REFERENCE_TIME *pTime)
{
HRESULT hr;
KSPROPERTY Property;
ULONG BytesReturned;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetTime\n");
#endif
if (!pTime)
return E_POINTER;
//
//FIXME locks
//
if (!m_hClock)
{
// create clock
hr = CreateClockInstance();
if (FAILED(hr))
return hr;
}
// setup request
Property.Set = KSPROPSETID_Clock;
Property.Id = KSPROPERTY_CLOCK_TIME;
Property.Flags = KSPROPERTY_TYPE_GET;
// perform request
hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pTime, sizeof(REFERENCE_TIME), &BytesReturned);
// TODO
// increment value
//
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::AdviseTime(
REFERENCE_TIME baseTime,
REFERENCE_TIME streamTime,
HEVENT hEvent,
DWORD_PTR *pdwAdviseCookie)
{
HRESULT hr;
KSEVENT Property;
ULONG BytesReturned;
PKSEVENT_TIME_MARK Event;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::AdviseTime\n");
#endif
//
//FIXME locks
//
if (!pdwAdviseCookie)
return E_POINTER;
if (!m_hClock)
{
// create clock
hr = CreateClockInstance();
if (FAILED(hr))
return hr;
}
// allocate event entry
Event = (PKSEVENT_TIME_MARK)CoTaskMemAlloc(sizeof(KSEVENT_TIME_MARK));
if (Event)
{
// setup request
Property.Set = KSEVENTSETID_Clock;
Property.Id = KSEVENT_CLOCK_POSITION_MARK;
Property.Flags = KSEVENT_TYPE_ENABLE;
Event->EventData.NotificationType = KSEVENTF_EVENT_HANDLE;
Event->EventData.EventHandle.Event = (HANDLE)hEvent;
Event->EventData.Alignment.Alignment[0] = 0;
Event->EventData.Alignment.Alignment[1] = 0;
Event->MarkTime = baseTime + streamTime;
// perform request
hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_MARK), &BytesReturned);
if (SUCCEEDED(hr))
{
// store event handle
*pdwAdviseCookie = (DWORD_PTR)Event;
}
else
{
// failed to enable event
CoTaskMemFree(Event);
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::AdvisePeriodic(
REFERENCE_TIME startTime,
REFERENCE_TIME periodTime,
HSEMAPHORE hSemaphore,
DWORD_PTR *pdwAdviseCookie)
{
HRESULT hr;
KSEVENT Property;
ULONG BytesReturned;
PKSEVENT_TIME_INTERVAL Event;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::AdvisePeriodic\n");
#endif
//
//FIXME locks
//
if (!pdwAdviseCookie)
return E_POINTER;
if (!m_hClock)
{
// create clock
hr = CreateClockInstance();
if (FAILED(hr))
return hr;
}
// allocate event entry
Event = (PKSEVENT_TIME_INTERVAL)CoTaskMemAlloc(sizeof(KSEVENT_TIME_INTERVAL));
if (Event)
{
// setup request
Property.Set = KSEVENTSETID_Clock;
Property.Id = KSEVENT_CLOCK_INTERVAL_MARK;
Property.Flags = KSEVENT_TYPE_ENABLE;
Event->EventData.NotificationType = KSEVENTF_SEMAPHORE_HANDLE;
Event->EventData.SemaphoreHandle.Semaphore = (HANDLE)hSemaphore;
Event->EventData.SemaphoreHandle.Reserved = 0;
Event->EventData.SemaphoreHandle.Adjustment = 1;
Event->TimeBase = startTime;
Event->Interval = periodTime;
// perform request
hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_INTERVAL), &BytesReturned);
if (SUCCEEDED(hr))
{
// store event handle
*pdwAdviseCookie = (DWORD_PTR)Event;
}
else
{
// failed to enable event
CoTaskMemFree(Event);
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Unadvise(
DWORD_PTR dwAdviseCookie)
{
HRESULT hr;
ULONG BytesReturned;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Unadvise\n");
#endif
if (m_hClock)
{
//lets disable the event
hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_DISABLE_EVENT, (PVOID)dwAdviseCookie, sizeof(KSEVENTDATA), 0, 0, &BytesReturned);
if (SUCCEEDED(hr))
{
// lets free event data
CoTaskMemFree((LPVOID)dwAdviseCookie);
}
}
else
{
// no clock available
hr = E_FAIL;
}
return hr;
}
//-------------------------------------------------------------------
// IMediaSeeking interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetCapabilities(
DWORD *pCapabilities)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr = S_OK;
DWORD TempCaps;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_CAPABILITIES;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetCapabilities\n");
#endif
if (!pCapabilities)
return E_POINTER;
*pCapabilities = (KS_SEEKING_CanSeekAbsolute | KS_SEEKING_CanSeekForwards | KS_SEEKING_CanSeekBackwards | KS_SEEKING_CanGetCurrentPos |
KS_SEEKING_CanGetStopPos | KS_SEEKING_CanGetDuration | KS_SEEKING_CanPlayBackwards);
KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pCapabilities, sizeof(KS_SEEKING_CAPABILITIES), &BytesReturned);
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (FAILED(hr))
{
*pCapabilities = 0;
return hr;
}
TempCaps = 0;
// set time format
hr = pSeek->GetCapabilities(&TempCaps);
if (SUCCEEDED(hr))
{
// and with supported flags
*pCapabilities = (*pCapabilities & TempCaps);
}
// release IMediaSeeking interface
pSeek->Release();
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::CheckCapabilities(
DWORD *pCapabilities)
{
DWORD Capabilities;
HRESULT hr;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::CheckCapabilities\n");
#endif
if (!pCapabilities)
return E_POINTER;
if (!*pCapabilities)
return E_FAIL;
hr = GetCapabilities(&Capabilities);
if (SUCCEEDED(hr))
{
if ((Capabilities | *pCapabilities) == Capabilities)
{
// all present
return S_OK;
}
Capabilities = (Capabilities & *pCapabilities);
if (Capabilities)
{
// not all present
*pCapabilities = Capabilities;
return S_FALSE;
}
// no capabilities are present
return E_FAIL;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetMediaSeekingFormats(
PKSMULTIPLE_ITEM *FormatList)
{
KSPROPERTY Property;
HRESULT hr;
ULONG BytesReturned;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_FORMATS;
Property.Flags = KSPROPERTY_TYPE_GET;
// query for format size list
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
{
// allocate format list
*FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned);
if (!*FormatList)
{
// not enough memory
return E_OUTOFMEMORY;
}
// get format list
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)*FormatList, BytesReturned, &BytesReturned);
if (FAILED(hr))
{
// failed to query format list
CoTaskMemFree(FormatList);
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::IsFormatSupported(
const GUID *pFormat)
{
PKSMULTIPLE_ITEM FormatList;
LPGUID pGuid;
ULONG Index;
HRESULT hr = S_FALSE;
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
LPOLESTR pstr;
StringFromCLSID(*pFormat, &pstr);
swprintf(Buffer, L"CKsProxy::IsFormatSupported %s\n",pstr);
OutputDebugStringW(Buffer);
#endif
if (!pFormat)
return E_POINTER;
// get media formats
hr = GetMediaSeekingFormats(&FormatList);
if (SUCCEEDED(hr))
{
#ifdef KSPROXY_TRACE
swprintf(Buffer, L"CKsProxy::IsFormatSupported NumFormat %lu\n",FormatList->Count);
OutputDebugStringW(Buffer);
#endif
//iterate through format list
pGuid = (LPGUID)(FormatList + 1);
for(Index = 0; Index < FormatList->Count; Index++)
{
if (IsEqualGUID(*pGuid, *pFormat))
{
CoTaskMemFree(FormatList);
return S_OK;
}
pGuid++;
}
// free format list
CoTaskMemFree(FormatList);
}
// check if all plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (FAILED(hr))
{
// plugin does not support interface
hr = S_FALSE;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::IsFormatSupported plugin does not support IMediaSeeking interface\n");
#endif
break;
}
// query if it is supported
hr = pSeek->IsFormatSupported(pFormat);
// release interface
pSeek->Release();
if (FAILED(hr) || hr == S_FALSE)
break;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::QueryPreferredFormat(
GUID *pFormat)
{
PKSMULTIPLE_ITEM FormatList;
HRESULT hr;
ULONG Index;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::QueryPreferredFormat\n");
#endif
if (!pFormat)
return E_POINTER;
hr = GetMediaSeekingFormats(&FormatList);
if (SUCCEEDED(hr))
{
if (FormatList->Count)
{
CopyMemory(pFormat, (FormatList + 1), sizeof(GUID));
CoTaskMemFree(FormatList);
return S_OK;
}
CoTaskMemFree(FormatList);
}
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// get preferred time format
hr = pSeek->QueryPreferredFormat(pFormat);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE)
return hr;
}
}
hr = S_FALSE;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetTimeFormat(
GUID *pFormat)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetTimeFormat\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
hr = E_NOTIMPL;
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// set time format
hr = pSeek->GetTimeFormat(pFormat);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE)
break;
}
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::IsUsingTimeFormat(
const GUID *pFormat)
{
GUID Format;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat\n");
#endif
if (FAILED(QueryPreferredFormat(&Format)))
return S_FALSE;
if (IsEqualGUID(Format, *pFormat))
return S_OK;
else
return S_FALSE;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::SetTimeFormat(
const GUID *pFormat)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
Property.Flags = KSPROPERTY_TYPE_SET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::SetTimeFormat\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
hr = E_NOTIMPL;
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (FAILED(hr))
{
//not supported
break;
}
// set time format
hr = pSeek->SetTimeFormat(pFormat);
// release IMediaSeeking interface
pSeek->Release();
if (FAILED(hr))
break;
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetDuration(
LONGLONG *pDuration)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_DURATION;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetDuration\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pDuration, sizeof(LONGLONG), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
hr = E_NOTIMPL;
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// get duration
hr = pSeek->GetStopPosition(pDuration);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE) // plugin implements it
break;
}
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetStopPosition(
LONGLONG *pStop)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_STOPPOSITION;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetStopPosition\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pStop, sizeof(LONGLONG), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
hr = E_NOTIMPL;
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// get stop position
hr = pSeek->GetStopPosition(pStop);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE) // plugin implements it
break;
}
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetCurrentPosition(
LONGLONG *pCurrent)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_POSITION;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetCurrentPosition\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pCurrent, sizeof(LONGLONG), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
hr = E_NOTIMPL;
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// get current position
hr = pSeek->GetCurrentPosition(pCurrent);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE) // plugin implements it
break;
}
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::ConvertTimeFormat(
LONGLONG *pTarget,
const GUID *pTargetFormat,
LONGLONG Source,
const GUID *pSourceFormat)
{
KSP_TIMEFORMAT Property;
ULONG BytesReturned, Index;
GUID SourceFormat, TargetFormat;
HRESULT hr;
Property.Property.Set = KSPROPSETID_MediaSeeking;
Property.Property.Id = KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::ConvertTimeFormat\n");
#endif
if (!pTargetFormat)
{
// get current format
hr = GetTimeFormat(&TargetFormat);
if (FAILED(hr))
return hr;
pTargetFormat = &TargetFormat;
}
if (!pSourceFormat)
{
// get current format
hr = GetTimeFormat(&SourceFormat);
if (FAILED(hr))
return hr;
pSourceFormat = &SourceFormat;
}
Property.SourceFormat = *pSourceFormat;
Property.TargetFormat = *pTargetFormat;
Property.Time = Source;
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_TIMEFORMAT), (PVOID)pTarget, sizeof(LONGLONG), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
//default error
hr = E_NOTIMPL;
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// convert time format
hr = pSeek->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE) // plugin implements it
break;
}
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::SetPositions(
LONGLONG *pCurrent,
DWORD dwCurrentFlags,
LONGLONG *pStop,
DWORD dwStopFlags)
{
KSPROPERTY Property;
KSPROPERTY_POSITIONS Positions;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_POSITIONS;
Property.Flags = KSPROPERTY_TYPE_SET;
Positions.Current = *pCurrent;
Positions.CurrentFlags = (KS_SEEKING_FLAGS)dwCurrentFlags;
Positions.Stop = *pStop;
Positions.StopFlags = (KS_SEEKING_FLAGS)dwStopFlags;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::SetPositions\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Positions, sizeof(KSPROPERTY_POSITIONS), &BytesReturned);
if (SUCCEEDED(hr))
{
if (dwCurrentFlags & AM_SEEKING_ReturnTime)
{
// retrieve current position
hr = GetCurrentPosition(pCurrent);
}
if (SUCCEEDED(hr))
{
if (dwStopFlags & AM_SEEKING_ReturnTime)
{
// retrieve current position
hr = GetStopPosition(pStop);
}
}
return hr;
}
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
hr = E_NOTIMPL;
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// set positions
hr = pSeek->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
// release IMediaSeeking interface
pSeek->Release();
if (FAILED(hr))
break;
}
}
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPositions(
LONGLONG *pCurrent,
LONGLONG *pStop)
{
HRESULT hr;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetPositions\n");
#endif
hr = GetCurrentPosition(pCurrent);
if (SUCCEEDED(hr))
hr = GetStopPosition(pStop);
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetAvailable(
LONGLONG *pEarliest,
LONGLONG *pLatest)
{
KSPROPERTY Property;
KSPROPERTY_MEDIAAVAILABLE Media;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_AVAILABLE;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetAvailable\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Media, sizeof(KSPROPERTY_MEDIAAVAILABLE), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
hr = E_NOTIMPL;
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// delegate call
hr = pSeek->GetAvailable(pEarliest, pLatest);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE) // plugin implements it
break;
}
}
}
else if (SUCCEEDED(hr))
{
*pEarliest = Media.Earliest;
*pLatest = Media.Latest;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::SetRate(
double dRate)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::SetRate\n");
#endif
return E_NOTIMPL;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetRate(
double *pdRate)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetRate\n");
#endif
return E_NOTIMPL;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPreroll(
LONGLONG *pllPreroll)
{
KSPROPERTY Property;
ULONG BytesReturned, Index;
HRESULT hr;
Property.Set = KSPROPSETID_MediaSeeking;
Property.Id = KSPROPERTY_MEDIASEEKING_PREROLL;
Property.Flags = KSPROPERTY_TYPE_GET;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetPreroll\n");
#endif
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pllPreroll, sizeof(LONGLONG), &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
{
// check if all plugins support it
for(Index = 0; Index < m_Plugins.size(); Index++)
{
// get plugin
IUnknown * Plugin = m_Plugins[Index];
if (!Plugin)
continue;
// query for IMediaSeeking interface
IMediaSeeking *pSeek = NULL;
hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
if (SUCCEEDED(hr))
{
// get preroll
hr = pSeek->GetPreroll(pllPreroll);
// release IMediaSeeking interface
pSeek->Release();
if (hr != S_FALSE) // plugin implements it
break;
}
}
hr = E_NOTIMPL;
}
return hr;
}
//-------------------------------------------------------------------
// IAMFilterMiscFlags interface
//
ULONG
STDMETHODCALLTYPE
CKsProxy::GetMiscFlags()
{
ULONG Index;
ULONG Flags = 0;
HRESULT hr;
PIN_DIRECTION PinDirection;
KSPIN_COMMUNICATION Communication;
for(Index = 0; Index < m_Pins.size(); Index++)
{
// get current pin
IPin * pin = m_Pins[Index];
// query direction
hr = pin->QueryDirection(&PinDirection);
if (SUCCEEDED(hr))
{
if (PinDirection == PINDIR_INPUT)
{
if (SUCCEEDED(GetPinCommunication(Index, //FIXME verify PinId
&Communication)))
{
if (Communication != KSPIN_COMMUNICATION_NONE && Communication != KSPIN_COMMUNICATION_BRIDGE)
{
Flags |= AM_FILTER_MISC_FLAGS_IS_SOURCE;
}
}
}
}
}
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::GetMiscFlags stub Flags %x\n", Flags);
OutputDebugStringW(Buffer);
#endif
return Flags;
}
//-------------------------------------------------------------------
// IKsControl
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsProperty(
PKSPROPERTY Property,
ULONG PropertyLength,
LPVOID PropertyData,
ULONG DataLength,
ULONG* BytesReturned)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsProperty\n");
#endif
assert(m_hDevice != 0);
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsMethod(
PKSMETHOD Method,
ULONG MethodLength,
LPVOID MethodData,
ULONG DataLength,
ULONG* BytesReturned)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsMethod\n");
#endif
assert(m_hDevice != 0);
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsEvent(
PKSEVENT Event,
ULONG EventLength,
LPVOID EventData,
ULONG DataLength,
ULONG* BytesReturned)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsEvent\n");
#endif
assert(m_hDevice != 0);
if (EventLength)
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned);
else
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned);
}
//-------------------------------------------------------------------
// IKsPropertySet
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::Set(
REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData)
{
ULONG BytesReturned;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Set\n");
#endif
if (cbInstanceData)
{
PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
if (!Property)
return E_OUTOFMEMORY;
Property->Set = guidPropSet;
Property->Id = dwPropID;
Property->Flags = KSPROPERTY_TYPE_SET;
CopyMemory((Property+1), pInstanceData, cbInstanceData);
HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
CoTaskMemFree(Property);
return hr;
}
else
{
KSPROPERTY Property;
Property.Set = guidPropSet;
Property.Id = dwPropID;
Property.Flags = KSPROPERTY_TYPE_SET;
HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
return hr;
}
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Get(
REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData,
DWORD *pcbReturned)
{
ULONG BytesReturned;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Get\n");
#endif
if (cbInstanceData)
{
PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
if (!Property)
return E_OUTOFMEMORY;
Property->Set = guidPropSet;
Property->Id = dwPropID;
Property->Flags = KSPROPERTY_TYPE_GET;
CopyMemory((Property+1), pInstanceData, cbInstanceData);
HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
CoTaskMemFree(Property);
return hr;
}
else
{
KSPROPERTY Property;
Property.Set = guidPropSet;
Property.Id = dwPropID;
Property.Flags = KSPROPERTY_TYPE_GET;
HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
return hr;
}
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::QuerySupported(
REFGUID guidPropSet,
DWORD dwPropID,
DWORD *pTypeSupport)
{
KSPROPERTY Property;
ULONG BytesReturned;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::QuerySupported\n");
#endif
Property.Set = guidPropSet;
Property.Id = dwPropID;
Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
return KsProperty(&Property, sizeof(KSPROPERTY), pTypeSupport, sizeof(DWORD), &BytesReturned);
}
//-------------------------------------------------------------------
// IKsTopology interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::CreateNodeInstance(
ULONG NodeId,
ULONG Flags,
ACCESS_MASK DesiredAccess,
IUnknown* UnkOuter,
REFGUID InterfaceId,
LPVOID* Interface)
{
HRESULT hr;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::CreateNodeInstance\n");
#endif
*Interface = NULL;
if (IsEqualIID(IID_IUnknown, InterfaceId) || !UnkOuter)
{
hr = CKsNode_Constructor(UnkOuter, m_hDevice, NodeId, DesiredAccess, InterfaceId, Interface);
}
else
{
// interface not supported
hr = E_NOINTERFACE;
}
return hr;
}
//-------------------------------------------------------------------
// IKsAggregateControl interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsAddAggregate(
IN REFGUID AggregateClass)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsAddAggregate NotImplemented\n");
#endif
return E_NOTIMPL;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::KsRemoveAggregate(
REFGUID AggregateClass)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsRemoveAggregate NotImplemented\n");
#endif
return E_NOTIMPL;
}
//-------------------------------------------------------------------
// IPersistStream interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::IsDirty()
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::IsDirty Notimplemented\n");
#endif
return E_NOTIMPL;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Load(
IStream *pStm)
{
HRESULT hr;
WCHAR Buffer[1000];
AM_MEDIA_TYPE MediaType;
ULONG BytesReturned;
LONG Length;
ULONG PinId;
LPOLESTR pMajor, pSub, pFormat;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Load\n");
#endif
#if 0
ULONG Version = ReadInt(pStm, hr);
if (Version != 1)
return E_FAIL;
#endif
hr = pStm->Read(&Length, sizeof(ULONG), &BytesReturned);
swprintf(Buffer, L"Length hr %x hr length %lu\n", hr, Length);
OutputDebugStringW(Buffer);
do
{
hr = pStm->Read(&PinId, sizeof(ULONG), &BytesReturned);
swprintf(Buffer, L"Read: hr %08x PinId %lx BytesReturned %lu\n", hr, PinId, BytesReturned);
OutputDebugStringW(Buffer);
if (FAILED(hr) || !BytesReturned)
break;
Length -= BytesReturned;
hr = pStm->Read(&MediaType, sizeof(AM_MEDIA_TYPE), &BytesReturned);
if (FAILED(hr) || BytesReturned != sizeof(AM_MEDIA_TYPE))
{
swprintf(Buffer, L"Read failed with %lx\n", hr);
OutputDebugStringW(Buffer);
break;
}
StringFromIID(MediaType.majortype, &pMajor);
StringFromIID(MediaType.subtype , &pSub);
StringFromIID(MediaType.formattype, &pFormat);
swprintf(Buffer, L"BytesReturned %lu majortype %s subtype %s bFixedSizeSamples %u bTemporalCompression %u lSampleSize %u formattype %s, pUnk %p cbFormat %u pbFormat %p\n", BytesReturned, pMajor, pSub, MediaType.bFixedSizeSamples, MediaType.bTemporalCompression, MediaType.lSampleSize, pFormat, MediaType.pUnk, MediaType.cbFormat, MediaType.pbFormat);
OutputDebugStringW(Buffer);
Length -= BytesReturned;
if (MediaType.cbFormat)
{
MediaType.pbFormat = (BYTE*)CoTaskMemAlloc(MediaType.cbFormat);
if (!MediaType.pbFormat)
return E_OUTOFMEMORY;
hr = pStm->Read(&MediaType.pbFormat, sizeof(MediaType.cbFormat), &BytesReturned);
if (FAILED(hr))
{
swprintf(Buffer, L"ReadFormat failed with %lx\n", hr);
OutputDebugStringW(Buffer);
break;
}
Length -= BytesReturned;
}
}while(Length > 0);
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Save(
IStream *pStm,
BOOL fClearDirty)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Save Notimplemented\n");
#endif
return E_NOTIMPL;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetSizeMax(
ULARGE_INTEGER *pcbSize)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetSizeMax Notimplemented\n");
#endif
return E_NOTIMPL;
}
//-------------------------------------------------------------------
// IAMDeviceRemoval interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::DeviceInfo\n");
#endif
if (!m_DevicePath)
{
// object not initialized
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
}
// copy device interface guid
CopyMemory(pclsidInterfaceClass, &m_DeviceInterfaceGUID, sizeof(GUID));
if (pwszSymbolicLink)
{
*pwszSymbolicLink = (LPWSTR)CoTaskMemAlloc((wcslen(m_DevicePath)+1) * sizeof(WCHAR));
if (!*pwszSymbolicLink)
return E_OUTOFMEMORY;
wcscpy(*pwszSymbolicLink, m_DevicePath);
}
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Reassociate(void)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Reassociate\n");
#endif
if (!m_DevicePath || m_hDevice)
{
// file path not available
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
}
m_hDevice = CreateFileW(m_DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (!m_hDevice)
{
// failed to open device
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
// success
return NOERROR;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Disassociate(void)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Disassociate\n");
#endif
if (!m_hDevice)
return E_HANDLE;
CloseHandle(m_hDevice);
m_hDevice = NULL;
return NOERROR;
}
//-------------------------------------------------------------------
// IKsClock interface
//
HANDLE
STDMETHODCALLTYPE
CKsProxy::KsGetClockHandle()
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetClockHandle\n");
#endif
return m_hClock;
}
//-------------------------------------------------------------------
// IKsObject interface
//
HANDLE
STDMETHODCALLTYPE
CKsProxy::KsGetObjectHandle()
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::KsGetObjectHandle\n");
#endif
return m_hDevice;
}
//-------------------------------------------------------------------
// IPersistPropertyBag interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::InitNew( void)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::InitNew\n");
#endif
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetSupportedSets(
LPGUID * pOutGuid,
PULONG NumGuids)
{
KSPROPERTY Property;
LPGUID pGuid;
ULONG NumProperty = 0;
ULONG NumMethods = 0;
ULONG NumEvents = 0;
ULONG Length;
ULONG BytesReturned;
HRESULT hr;
Property.Set = GUID_NULL;
Property.Id = 0;
Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumProperty);
KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumMethods);
KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumEvents);
Length = NumProperty + NumMethods + NumEvents;
// allocate guid buffer
pGuid = (LPGUID)CoTaskMemAlloc(Length);
if (!pGuid)
{
// failed
return E_OUTOFMEMORY;
}
NumProperty /= sizeof(GUID);
NumMethods /= sizeof(GUID);
NumEvents /= sizeof(GUID);
// get all properties
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pGuid, Length, &BytesReturned);
if (FAILED(hr))
{
CoTaskMemFree(pGuid);
return E_FAIL;
}
Length -= BytesReturned;
// get all methods
if (Length)
{
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty], Length, &BytesReturned);
if (FAILED(hr))
{
CoTaskMemFree(pGuid);
return E_FAIL;
}
Length -= BytesReturned;
}
// get all events
if (Length)
{
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty+NumMethods], Length, &BytesReturned);
if (FAILED(hr))
{
CoTaskMemFree(pGuid);
return E_FAIL;
}
Length -= BytesReturned;
}
#ifdef KSPROXY_TRACE
WCHAR Buffer[200];
swprintf(Buffer, L"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty, NumMethods, NumEvents);
OutputDebugStringW(Buffer);
#endif
*pOutGuid = pGuid;
*NumGuids = NumProperty+NumEvents+NumMethods;
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::LoadProxyPlugins(
LPGUID pGuids,
ULONG NumGuids)
{
ULONG Index;
LPOLESTR pStr;
HKEY hKey, hSubKey;
HRESULT hr;
IUnknown * pUnknown;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
{
OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
return E_FAIL;
}
// enumerate all sets
for(Index = 0; Index < NumGuids; Index++)
{
// convert to string
hr = StringFromCLSID(pGuids[Index], &pStr);
if (FAILED(hr))
return E_FAIL;
// now try open class key
if (RegOpenKeyExW(hKey, pStr, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
{
// no plugin for that set exists
CoTaskMemFree(pStr);
continue;
}
// try load plugin
hr = CoCreateInstance(pGuids[Index], (IBaseFilter*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
if (SUCCEEDED(hr))
{
// store plugin
m_Plugins.push_back(pUnknown);
}
// close key
RegCloseKey(hSubKey);
}
// close media interfaces key
RegCloseKey(hKey);
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetNumberOfPins(
PULONG NumPins)
{
KSPROPERTY Property;
ULONG BytesReturned;
// setup request
Property.Set = KSPROPSETID_Pin;
Property.Id = KSPROPERTY_PIN_CTYPES;
Property.Flags = KSPROPERTY_TYPE_GET;
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)NumPins, sizeof(ULONG), &BytesReturned);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPinInstanceCount(
ULONG PinId,
PKSPIN_CINSTANCES Instances)
{
KSP_PIN Property;
ULONG BytesReturned;
// setup request
Property.Property.Set = KSPROPSETID_Pin;
Property.Property.Id = KSPROPERTY_PIN_CINSTANCES;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
Property.PinId = PinId;
Property.Reserved = 0;
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Instances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPinCommunication(
ULONG PinId,
KSPIN_COMMUNICATION * Communication)
{
KSP_PIN Property;
ULONG BytesReturned;
// setup request
Property.Property.Set = KSPROPSETID_Pin;
Property.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
Property.PinId = PinId;
Property.Reserved = 0;
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPinDataflow(
ULONG PinId,
KSPIN_DATAFLOW * DataFlow)
{
KSP_PIN Property;
ULONG BytesReturned;
// setup request
Property.Property.Set = KSPROPSETID_Pin;
Property.Property.Id = KSPROPERTY_PIN_DATAFLOW;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
Property.PinId = PinId;
Property.Reserved = 0;
return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetPinName(
ULONG PinId,
KSPIN_DATAFLOW DataFlow,
ULONG PinCount,
LPWSTR * OutPinName)
{
KSP_PIN Property;
LPWSTR PinName;
ULONG BytesReturned;
HRESULT hr;
WCHAR Buffer[100];
// setup request
Property.Property.Set = KSPROPSETID_Pin;
Property.Property.Id = KSPROPERTY_PIN_NAME;
Property.Property.Flags = KSPROPERTY_TYPE_GET;
Property.PinId = PinId;
Property.Reserved = 0;
// #1 try get it from pin directly
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
{
// allocate pin name
PinName = (LPWSTR)CoTaskMemAlloc(BytesReturned);
if (!PinName)
return E_OUTOFMEMORY;
// retry with allocated buffer
hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), PinName, BytesReturned, &BytesReturned);
if (SUCCEEDED(hr))
{
*OutPinName = PinName;
return hr;
}
//free buffer
CoTaskMemFree(PinName);
}
//
// TODO: retrieve pin name from topology node
//
if (DataFlow == KSPIN_DATAFLOW_IN)
{
swprintf(Buffer, L"Input%lu", PinCount);
}
else
{
swprintf(Buffer, L"Output%lu", PinCount);
}
// allocate pin name
PinName = (LPWSTR)CoTaskMemAlloc((wcslen(Buffer)+1) * sizeof(WCHAR));
if (!PinName)
return E_OUTOFMEMORY;
// copy pin name
wcscpy(PinName, Buffer);
// store result
*OutPinName = PinName;
// done
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::CreatePins()
{
ULONG NumPins, Index;
KSPIN_CINSTANCES Instances;
KSPIN_DATAFLOW DataFlow;
KSPIN_COMMUNICATION Communication;
HRESULT hr;
LPWSTR PinName;
IPin * pPin;
ULONG InputPin = 0;
ULONG OutputPin = 0;
// get number of pins
hr = GetNumberOfPins(&NumPins);
if (FAILED(hr))
return hr;
for(Index = 0; Index < NumPins; Index++)
{
// query current instance count
hr = GetPinInstanceCount(Index, &Instances);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins GetPinInstanceCount failed with %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
continue;
}
// query pin communication;
hr = GetPinCommunication(Index, &Communication);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins GetPinCommunication failed with %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
continue;
}
if (Instances.CurrentCount == Instances.PossibleCount)
{
// already maximum reached for this pin
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins Instances.CurrentCount == Instances.PossibleCount\n");
OutputDebugStringW(Buffer);
#endif
continue;
}
// get direction of pin
hr = GetPinDataflow(Index, &DataFlow);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins GetPinDataflow failed with %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
continue;
}
if (DataFlow == KSPIN_DATAFLOW_IN)
hr = GetPinName(Index, DataFlow, InputPin, &PinName);
else
hr = GetPinName(Index, DataFlow, OutputPin, &PinName);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins GetPinName failed with %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
continue;
}
// construct the pins
if (DataFlow == KSPIN_DATAFLOW_IN)
{
hr = CInputPin_Constructor((IBaseFilter*)this, PinName, m_hDevice, Index, Communication, IID_IPin, (void**)&pPin);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins CInputPin_Constructor failed with %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
CoTaskMemFree(PinName);
continue;
}
InputPin++;
}
else
{
hr = COutputPin_Constructor((IBaseFilter*)this, PinName, Index, Communication, IID_IPin, (void**)&pPin);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::CreatePins COutputPin_Constructor failed with %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
CoTaskMemFree(PinName);
continue;
}
OutputPin++;
}
// store pins
m_Pins.push_back(pPin);
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"Index %lu DataFlow %lu Name %s\n", Index, DataFlow, PinName);
OutputDebugStringW(Buffer);
#endif
}
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
{
HRESULT hr;
VARIANT varName;
LPGUID pGuid;
ULONG NumGuids = 0;
HDEVINFO hList;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
OutputDebugStringW(L"CKsProxy::Load\n");
#endif
// read device path
varName.vt = VT_BSTR;
hr = pPropBag->Read(L"DevicePath", &varName, pErrorLog);
if (FAILED(hr))
{
#ifdef KSPROXY_TRACE
swprintf(Buffer, L"CKsProxy::Load Read %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"DevicePath: ");
OutputDebugStringW(varName.bstrVal);
OutputDebugStringW(L"\n");
#endif
// create device list
hList = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
if (hList == INVALID_HANDLE_VALUE)
{
// failed to create device list
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiOpenDeviceInterfaceW(hList, (PCWSTR)varName.bstrVal, 0, &DeviceInterfaceData))
{
// failed to open device interface
SetupDiDestroyDeviceInfoList(hList);
}
// FIXME handle device interface links(aliases)
CopyMemory(&m_DeviceInterfaceGUID, &DeviceInterfaceData.InterfaceClassGuid, sizeof(GUID));
// close device info list
SetupDiDestroyDeviceInfoList(hList);
// open device
m_hDevice = CreateFileW(varName.bstrVal, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (m_hDevice == INVALID_HANDLE_VALUE)
{
// failed to open device
#ifdef KSPROXY_TRACE
swprintf(Buffer, L"CKsProxy:: failed to open device with %lx\n", GetLastError());
OutputDebugStringW(Buffer);
#endif
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
// store device path
m_DevicePath = varName.bstrVal;
// get all supported sets
hr = GetSupportedSets(&pGuid, &NumGuids);
if (FAILED(hr))
{
CloseHandle(m_hDevice);
m_hDevice = NULL;
return hr;
}
// load all proxy plugins
hr = LoadProxyPlugins(pGuid, NumGuids);
if (FAILED(hr))
{
#if 0 //HACK
CloseHandle(m_hDevice);
m_hDevice = NULL;
return hr;
#endif
OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed!\n");
}
// free sets
CoTaskMemFree(pGuid);
// now create the input / output pins
hr = CreatePins();
#ifdef KSPROXY_TRACE
swprintf(Buffer, L"CKsProxy::Load CreatePins %lx\n", hr);
OutputDebugStringW(Buffer);
#endif
//HACK
hr = S_OK;
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Save\n");
#endif
return E_NOTIMPL;
}
//-------------------------------------------------------------------
// IBaseFilter interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetClassID(
CLSID *pClassID)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetClassID\n");
#endif
CopyMemory(pClassID, &CLSID_Proxy, sizeof(GUID));
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Stop()
{
HRESULT hr;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Stop\n");
#endif
EnterCriticalSection(&m_Lock);
hr = SetPinState(KSSTATE_STOP);
if (SUCCEEDED(hr))
m_FilterState = State_Stopped;
LeaveCriticalSection(&m_Lock);
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Pause()
{
HRESULT hr = S_OK;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Pause\n");
#endif
EnterCriticalSection(&m_Lock);
if (m_FilterState == State_Running)
{
hr = SetPinState(KSSTATE_STOP);
}
if (SUCCEEDED(hr))
{
if (m_FilterState == State_Stopped)
{
hr = SetPinState(KSSTATE_PAUSE);
}
}
if (SUCCEEDED(hr))
m_FilterState = State_Paused;
LeaveCriticalSection(&m_Lock);
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Run(
REFERENCE_TIME tStart)
{
HRESULT hr;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Run\n");
#endif
EnterCriticalSection(&m_Lock);
if (m_FilterState == State_Stopped)
{
LeaveCriticalSection(&m_Lock);
// setting filter state to pause
hr = Pause();
if (FAILED(hr))
return hr;
EnterCriticalSection(&m_Lock);
assert(m_FilterState == State_Paused);
}
hr = SetPinState(KSSTATE_RUN);
if (SUCCEEDED(hr))
{
m_FilterState = State_Running;
}
LeaveCriticalSection(&m_Lock);
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::SetPinState(
KSSTATE State)
{
HRESULT hr = S_OK;
ULONG Index;
IKsObject *pObject;
ULONG BytesReturned;
KSPROPERTY Property;
PIN_INFO PinInfo;
Property.Set = KSPROPSETID_Connection;
Property.Id = KSPROPERTY_CONNECTION_STATE;
Property.Flags = KSPROPERTY_TYPE_SET;
// set all pins to running state
for(Index = 0; Index < m_Pins.size(); Index++)
{
IPin * Pin = m_Pins[Index];
if (!Pin)
continue;
//check if the pin is connected
IPin * TempPin;
hr = Pin->ConnectedTo(&TempPin);
if (FAILED(hr))
{
// skip unconnected pins
continue;
}
// release connected pin
TempPin->Release();
// query for the pin info
hr = Pin->QueryPinInfo(&PinInfo);
if (SUCCEEDED(hr))
{
if (PinInfo.pFilter)
PinInfo.pFilter->Release();
if (PinInfo.dir == PINDIR_OUTPUT)
{
hr = COutputPin_SetState(Pin, State);
if (SUCCEEDED(hr))
continue;
}
}
//query IKsObject interface
hr = Pin->QueryInterface(IID_IKsObject, (void**)&pObject);
// get pin handle
HANDLE hPin = pObject->KsGetObjectHandle();
// sanity check
assert(hPin && hPin != INVALID_HANDLE_VALUE);
// now set state
hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::SetPinState Index %u State %u hr %lx\n", Index, State, hr);
OutputDebugStringW(Buffer);
#endif
if (FAILED(hr))
return hr;
}
return hr;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetState(
DWORD dwMilliSecsTimeout,
FILTER_STATE *State)
{
if (!State)
return E_POINTER;
*State = m_FilterState;
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::SetSyncSource(
IReferenceClock *pClock)
{
HRESULT hr;
IKsClock *pKsClock;
HANDLE hClock, hPin;
ULONG Index;
IPin * pin;
IKsObject * pObject;
KSPROPERTY Property;
ULONG BytesReturned;
PIN_DIRECTION PinDir;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::SetSyncSource\n");
#endif
// FIXME
// need locks
if (pClock)
{
hr = pClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
if (FAILED(hr))
{
hr = m_ReferenceClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
if (FAILED(hr))
return hr;
}
// get clock handle
hClock = pKsClock->KsGetClockHandle();
// release IKsClock interface
pKsClock->Release();
m_hClock = hClock;
}
else
{
// no clock handle
m_hClock = NULL;
}
// distribute clock to all pins
for(Index = 0; Index < m_Pins.size(); Index++)
{
// get current pin
pin = m_Pins[Index];
if (!pin)
continue;
// get IKsObject interface
hr = pin->QueryInterface(IID_IKsObject, (void **)&pObject);
if (SUCCEEDED(hr))
{
// get pin handle
hPin = pObject->KsGetObjectHandle();
if (hPin != INVALID_HANDLE_VALUE && hPin)
{
// set clock
Property.Set = KSPROPSETID_Stream;
Property.Id = KSPROPERTY_STREAM_MASTERCLOCK;
Property.Flags = KSPROPERTY_TYPE_SET;
// set master clock
hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&m_hClock, sizeof(HANDLE), &BytesReturned);
if (FAILED(hr))
{
if (hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND) &&
hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND))
{
// failed to set master clock
pObject->Release();
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::SetSyncSource KSPROPERTY_STREAM_MASTERCLOCK failed with %lx\n", hr);
OutputDebugStringW(Buffer);
return hr;
}
}
}
// release IKsObject
pObject->Release();
}
// now get the direction
hr = pin->QueryDirection(&PinDir);
if (SUCCEEDED(hr))
{
if (PinDir == PINDIR_OUTPUT)
{
// notify pin via
//CBaseStreamControl::SetSyncSource(pClock)
}
}
}
if (pClock)
{
pClock->AddRef();
}
if (m_ReferenceClock)
{
m_ReferenceClock->Release();
}
m_ReferenceClock = pClock;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::SetSyncSource done\n");
#endif
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::GetSyncSource(
IReferenceClock **pClock)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::GetSyncSource\n");
#endif
if (!pClock)
return E_POINTER;
if (m_ReferenceClock)
m_ReferenceClock->AddRef();
*pClock = m_ReferenceClock;
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::EnumPins(
IEnumPins **ppEnum)
{
return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum);
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::FindPin(
LPCWSTR Id, IPin **ppPin)
{
ULONG PinId;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::FindPin\n");
#endif
if (!ppPin)
return E_POINTER;
// convert to pin
int ret = swscanf(Id, L"%u", &PinId);
if (!ret || ret == EOF)
{
// invalid id
return VFW_E_NOT_FOUND;
}
if (PinId >= m_Pins.size() || m_Pins[PinId] == NULL)
{
// invalid id
return VFW_E_NOT_FOUND;
}
// found pin
*ppPin = m_Pins[PinId];
m_Pins[PinId]->AddRef();
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::QueryFilterInfo(
FILTER_INFO *pInfo)
{
if (!pInfo)
return E_POINTER;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::QueryFilterInfo\n");
#endif
pInfo->achName[0] = L'\0';
pInfo->pGraph = m_pGraph;
if (m_pGraph)
m_pGraph->AddRef();
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::JoinFilterGraph(
IFilterGraph *pGraph,
LPCWSTR pName)
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsProxy::JoinFilterGraph pName %s pGraph %p m_Ref %u\n", pName, pGraph, m_Ref);
OutputDebugStringW(Buffer);
#endif
if (pGraph)
{
// joining filter graph
m_pGraph = pGraph;
}
else
{
// leaving graph
m_pGraph = 0;
}
return S_OK;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::QueryVendorInfo(
LPWSTR *pVendorInfo)
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::QueryVendorInfo\n");
#endif
return StringFromCLSID(CLSID_Proxy, pVendorInfo);
}
//-------------------------------------------------------------------
// IAMovieSetup interface
//
HRESULT
STDMETHODCALLTYPE
CKsProxy::Register()
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Register : NotImplemented\n");
#endif
return E_NOTIMPL;
}
HRESULT
STDMETHODCALLTYPE
CKsProxy::Unregister()
{
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsProxy::Unregister : NotImplemented\n");
#endif
return E_NOTIMPL;
}
HRESULT
WINAPI
CKsProxy_Constructor(
IUnknown * pUnkOuter,
REFIID riid,
LPVOID * ppv)
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
LPOLESTR pstr;
StringFromCLSID(riid, &pstr);
swprintf(Buffer, L"CKsProxy_Constructor pUnkOuter %p riid %s\n", pUnkOuter, pstr);
OutputDebugStringW(Buffer);
#endif
CKsProxy * handler = new CKsProxy();
if (!handler)
return E_OUTOFMEMORY;
if (FAILED(handler->QueryInterface(riid, ppv)))
{
/* not supported */
delete handler;
return E_NOINTERFACE;
}
return S_OK;
}