/* This file is part of the KDE project. Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 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 or 3 of the License. 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, see . */ #include "qbasefilter.h" #include "qpin.h" #include QT_BEGIN_NAMESPACE namespace Phonon { namespace DS9 { class QEnumPins : public IEnumPins { public: QEnumPins(QBaseFilter *filter) : m_refCount(1), m_filter(filter), m_pins(filter->pins()), m_index(0) { m_filter->AddRef(); } virtual ~QEnumPins() { m_filter->Release(); } STDMETHODIMP QueryInterface(const IID &iid,void **out) { if (!out) { return E_POINTER; } HRESULT hr = S_OK; if (iid == IID_IEnumPins) { *out = static_cast(this); } else if (iid == IID_IUnknown) { *out = static_cast(this); } else { *out = 0; hr = E_NOINTERFACE; } if (S_OK) AddRef(); return hr; } STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_refCount); } STDMETHODIMP_(ULONG) Release() { ULONG refCount = InterlockedDecrement(&m_refCount); if (refCount == 0) { delete this; } return refCount; } STDMETHODIMP Next(ULONG count,IPin **ret,ULONG *fetched) { QMutexLocker locker(&m_mutex); if (m_filter->pins() != m_pins) { return VFW_E_ENUM_OUT_OF_SYNC; } if (fetched == 0 && count > 1) { return E_INVALIDARG; } if (!ret) { return E_POINTER; } uint nbfetched = 0; while (nbfetched < count && m_index < m_pins.count()) { IPin *current = m_pins[m_index]; current->AddRef(); ret[nbfetched] = current; nbfetched++; m_index++; } if (fetched) { *fetched = nbfetched; } return nbfetched == count ? S_OK : S_FALSE; } STDMETHODIMP Skip(ULONG count) { QMutexLocker locker(&m_mutex); if (m_filter->pins() != m_pins) { return VFW_E_ENUM_OUT_OF_SYNC; } m_index = qMin(m_index + int(count), m_pins.count()); return m_index == m_pins.count() ? S_FALSE : S_OK; } STDMETHODIMP Reset() { QMutexLocker locker(&m_mutex); m_index = 0; return S_OK; } STDMETHODIMP Clone(IEnumPins **out) { QMutexLocker locker(&m_mutex); if (m_filter->pins() != m_pins) { return VFW_E_ENUM_OUT_OF_SYNC; } if (!out) { return E_POINTER; } *out = new QEnumPins(m_filter); (*out)->Skip(m_index); return S_OK; } private: LONG m_refCount; QBaseFilter *m_filter; QList m_pins; int m_index; QMutex m_mutex; }; QBaseFilter::QBaseFilter(const CLSID &clsid): m_refCount(1), m_clsid(clsid), m_clock(0), m_graph(0), m_state(State_Stopped) { } QBaseFilter::~QBaseFilter() { while (!m_pins.isEmpty()) { delete m_pins.first(); } } const QList QBaseFilter::pins() const { QMutexLocker locker(&m_mutex); return m_pins; } void QBaseFilter::addPin(QPin *pin) { QMutexLocker locker(&m_mutex); m_pins.append(pin); } void QBaseFilter::removePin(QPin *pin) { QMutexLocker locker(&m_mutex); m_pins.removeAll(pin); } FILTER_STATE QBaseFilter::state() const { return m_state; } IFilterGraph *QBaseFilter::graph() const { return m_graph; } STDMETHODIMP QBaseFilter::QueryInterface(REFIID iid, void **out) { if (!out) { return E_POINTER; } HRESULT hr = S_OK; if (iid == IID_IBaseFilter) { *out = static_cast(this); } else if (iid == IID_IMediaFilter) { *out = static_cast(this); } else if (iid == IID_IPersist) { *out = static_cast(this); } else if (iid == IID_IUnknown) { *out = static_cast(static_cast(this)); } else if (iid == IID_IMediaPosition || iid == IID_IMediaSeeking) { if (inputPins().isEmpty()) { *out = getUpStreamInterface(iid); if (*out) { return S_OK; //we return here to avoid adding a reference } else { hr = E_NOINTERFACE; } } else if (iid == IID_IMediaSeeking) { *out = static_cast(this); } else if (iid == IID_IMediaPosition ||iid == IID_IDispatch) { *out = static_cast(this); } } else { *out = 0; hr = E_NOINTERFACE; } if (hr == S_OK) { AddRef(); } return hr; } STDMETHODIMP_(ULONG) QBaseFilter::AddRef() { return InterlockedIncrement(&m_refCount); } STDMETHODIMP_(ULONG) QBaseFilter::Release() { ULONG refCount = InterlockedDecrement(&m_refCount); if (refCount == 0) { delete this; } return refCount; } STDMETHODIMP QBaseFilter::GetClassID(CLSID *clsid) { QMutexLocker locker(&m_mutex); *clsid = m_clsid; return S_OK; } STDMETHODIMP QBaseFilter::Stop() { QMutexLocker locker(&m_mutex); m_state = State_Stopped; return S_OK; } STDMETHODIMP QBaseFilter::Pause() { QMutexLocker locker(&m_mutex); m_state = State_Paused; return S_OK; } STDMETHODIMP QBaseFilter::Run(REFERENCE_TIME) { QMutexLocker locker(&m_mutex); m_state = State_Running; return S_OK; } STDMETHODIMP QBaseFilter::GetState(DWORD, FILTER_STATE *state) { QMutexLocker locker(&m_mutex); if (!state) { return E_POINTER; } *state = m_state; return S_OK; } STDMETHODIMP QBaseFilter::SetSyncSource(IReferenceClock *clock) { QMutexLocker locker(&m_mutex); if (clock) { clock->AddRef(); } if (m_clock) { m_clock->Release(); } m_clock = clock; return S_OK; } STDMETHODIMP QBaseFilter::GetSyncSource(IReferenceClock **clock) { QMutexLocker locker(&m_mutex); if (!clock) { return E_POINTER; } if (m_clock) { m_clock->AddRef(); } *clock = m_clock; return S_OK; } STDMETHODIMP QBaseFilter::FindPin(LPCWSTR name, IPin**pin) { if (!pin) { return E_POINTER; } for (int i = 0; i < m_pins.count(); ++i) { IPin * current = m_pins.at(i); PIN_INFO info; current->QueryPinInfo(&info); if (info.pFilter) { info.pFilter->Release(); } if ( wcscmp(info.achName, name) == 0) { *pin = current; current->AddRef(); return S_OK; } } *pin = 0; return VFW_E_NOT_FOUND; } STDMETHODIMP QBaseFilter::QueryFilterInfo(FILTER_INFO *info ) { QMutexLocker locker(&m_mutex); if (!info) { return E_POINTER; } info->pGraph = m_graph; if (m_graph) { m_graph->AddRef(); } qMemCopy(info->achName, m_name.utf16(), qMin(MAX_FILTER_NAME, m_name.length()+1) *2); return S_OK; } STDMETHODIMP QBaseFilter::JoinFilterGraph(IFilterGraph *graph, LPCWSTR name) { QMutexLocker locker(&m_mutex); m_graph = graph; m_name = QString::fromWCharArray(name); return S_OK; } STDMETHODIMP QBaseFilter::EnumPins( IEnumPins **ep) { if (!ep) { return E_POINTER; } *ep = new QEnumPins(this); return S_OK; } STDMETHODIMP QBaseFilter::QueryVendorInfo(LPWSTR *) { //we give no information on that return E_NOTIMPL; } //implementation from IMediaSeeking STDMETHODIMP QBaseFilter::GetCapabilities(DWORD *pCapabilities) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetCapabilities(pCapabilities); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::CheckCapabilities(DWORD *pCapabilities) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->CheckCapabilities(pCapabilities); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::IsFormatSupported(const GUID *pFormat) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->IsFormatSupported(pFormat); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::QueryPreferredFormat(GUID *pFormat) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->QueryPreferredFormat(pFormat); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetTimeFormat(GUID *pFormat) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetTimeFormat(pFormat); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::IsUsingTimeFormat(const GUID *pFormat) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->IsUsingTimeFormat(pFormat); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::SetTimeFormat(const GUID *pFormat) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->SetTimeFormat(pFormat); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetDuration(LONGLONG *pDuration) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetDuration(pDuration); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetStopPosition(LONGLONG *pStop) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetStopPosition(pStop); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetCurrentPosition(LONGLONG *pCurrent) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetCurrentPosition(pCurrent); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetPositions(pCurrent, pStop); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetAvailable(pEarliest, pLatest); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::SetRate(double dRate) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->SetRate(dRate); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetRate(double *dRate) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetRate(dRate); ms->Release(); return hr; } STDMETHODIMP QBaseFilter::GetPreroll(LONGLONG *pllPreroll) { IMediaSeeking *ms = getUpstreamMediaSeeking(); if (!ms) { return E_NOTIMPL; } HRESULT hr = ms->GetPreroll(pllPreroll); ms->Release(); return hr; } //implementation from IMediaPosition STDMETHODIMP QBaseFilter::get_Duration(REFTIME *plength) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->get_Duration(plength); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::put_CurrentPosition(REFTIME llTime) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->put_CurrentPosition(llTime); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::get_CurrentPosition(REFTIME *pllTime) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->get_CurrentPosition(pllTime); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::get_StopTime(REFTIME *pllTime) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->get_StopTime(pllTime); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::put_StopTime(REFTIME llTime) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->put_StopTime(llTime); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::get_PrerollTime(REFTIME *pllTime) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->get_PrerollTime(pllTime); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::put_PrerollTime(REFTIME llTime) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->put_PrerollTime(llTime); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::put_Rate(double dRate) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->put_Rate(dRate); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::get_Rate(double *pdRate) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->get_Rate(pdRate); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::CanSeekForward(LONG *pCanSeekForward) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->CanSeekForward(pCanSeekForward); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::CanSeekBackward(LONG *pCanSeekBackward) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->CanSeekBackward(pCanSeekBackward); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::GetTypeInfoCount(UINT *pctinfo) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->GetTypeInfoCount(pctinfo); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->GetTypeInfo(iTInfo, lcid, ppTInfo); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId); mp->Release(); return hr; } STDMETHODIMP QBaseFilter::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { IMediaPosition *mp = getUpstreamMediaPosition(); if (!mp) { return E_NOTIMPL; } HRESULT hr = mp->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); mp->Release(); return hr; } IMediaSeeking *QBaseFilter::getUpstreamMediaSeeking() { return static_cast(getUpStreamInterface(IID_IMediaSeeking)); } IMediaPosition *QBaseFilter::getUpstreamMediaPosition() { return static_cast(getUpStreamInterface(IID_IMediaPosition)); } QList QBaseFilter::inputPins() const { QList ret; for(int i = 0; i < m_pins.count(); ++i) { QPin * pin = m_pins.at(i); if (pin->direction() == PINDIR_INPUT) { ret += pin; } } return ret; } QList QBaseFilter::outputPins() const { QList ret; for(int i = 0; i < m_pins.count(); ++i) { QPin * pin = m_pins.at(i); if (pin->direction() == PINDIR_OUTPUT) { ret += pin; } } return ret; } void *QBaseFilter::getUpStreamInterface(const IID &iid) const { const QList inputs = inputPins(); for (int i = 0; i < inputs.count(); ++i) { IPin *out = inputs.at(i)->connected(); if (out) { void *ms = 0; out->QueryInterface(iid, &ms); if (ms) { return ms; } } } //none was found return 0; } //addition HRESULT QBaseFilter::processSample(IMediaSample *) { return S_OK; } } } QT_END_NAMESPACE