|
|
//==========================================================================;
//
// dsextend.h : additional infrastructure to extend the dshow stuff so that it
// works nicely from c++
// Copyright (c) Microsoft Corporation 1995-1999.
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef DSEXTEND_H
#define DSEXTEND_H
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>
#include <list>
#include <map>
#include <trace.h>
#include <throw.h>
#include <stextend.h>
#include <w32extend.h>
#include <ksextend.h>
#include <fwdseq.h>
#include <control.h>
#include <mpconfig.h>
#include <vptype.h>
#include <vpnotify.h>
#include <il21dec.h>
#include <mtype.h>
#include <tuner.h>
#include <bdaiface.h>
#include <errors.h>
#include <winerror.h>
#include <evcode.h>
struct DECLSPEC_NOVTABLE DECLSPEC_UUID("6E8D4A21-310C-11d0-B79A-00AA003767A7") IAMLine21Decoder;
#define LINE21_BY_MAGIC
#define FILTERDATA
// #define ATTEMPT_DIRECT_CONNECT
// we'd like to check to see if two filters can be connected by just trying to connect them
// this is less work and techinically more accurate since pins aren't required to enumerate all
// of the media types they potentiall could support.
// however, this exposes bugs in the filters and causes random hangs and crashes. instead
// we manually check mediums and media types and only attempt the connection when we find a match.
// this turns out to be much more stable.
//#define FORWARD_TRACE
const PIN_DIRECTION DOWNSTREAM = PINDIR_OUTPUT; const PIN_DIRECTION UPSTREAM = PINDIR_INPUT;
typedef CComQIPtr<IFileSourceFilter, &IID_IFileSourceFilter> PQFileSourceFilter; #ifndef POLYMORPHIC_TUNERS
typedef CComQIPtr<IAMTVTuner, &IID_IAMTVTuner> PQTVTuner; //typedef CComQIPtr<ISatelliteTuner, &IID_ISatelliteTuner> PQSatelliteTuner;
#else
typedef CComQIPtr<IAMTuner, &IID_IAMTuner> PQTuner; typedef CComQIPtr<IAMTVTuner, &IID_IAMTVTuner> PQTVTuner; typedef CComQIPtr<IBPCSatelliteTuner, &IID_IBPCSatelliteTuner> PQSatelliteTuner; #endif
#if 0
typedef CComQIPtr<IVideoWindow, &IID_IVideoWindow> PQVideoWindow; typedef CComQIPtr<IBasicVideo, &IID_IBasicVideo> PQBasicVideo; #else
typedef CComQIPtr<IVMRWindowlessControl, &IID_IVMRWindowlessControl> PQVMRWindowlessControl; #endif
typedef CComQIPtr<IPin, &IID_IPin> PQPin; typedef CComQIPtr<IBaseFilter, &IID_IBaseFilter> PQFilter; typedef CComQIPtr<IFilterInfo, &IID_IFilterInfo> PQFilterInfo; typedef CComQIPtr<IEnumPins, &IID_IEnumPins> PQEnumPins; typedef CComQIPtr<IEnumFilters, &IID_IEnumFilters> PQEnumFilters; typedef CComQIPtr<IBasicAudio, &IID_IBasicAudio> PQBasicAudio; typedef CComQIPtr<IAMCrossbar, &IID_IAMCrossbar> PQCrossbarSwitch; typedef CComQIPtr<IMediaEventEx, &IID_IMediaEventEx> PQMediaEventEx; typedef CComQIPtr<IMediaControl, &IID_IMediaControl> PQMediaControl; typedef CComQIPtr<IMediaPosition, &IID_IMediaPosition> PQMediaPosition; typedef CComQIPtr<IMediaSeeking, &IID_IMediaSeeking> PQMediaSeeking; typedef CComQIPtr<IGraphBuilder, &IID_IGraphBuilder> PQGraphBuilder; typedef CComQIPtr<ICreateDevEnum, &IID_ICreateDevEnum> PQCreateDevEnum; typedef CComQIPtr<IEnumMoniker, &IID_IEnumMoniker> PQEnumMoniker; typedef CComQIPtr<IFilterMapper2, &IID_IFilterMapper2> PQFilterMapper; typedef CComQIPtr<IEnumMediaTypes, &IID_IEnumMediaTypes> PQEnumMediaTypes; typedef CComQIPtr<IAMAnalogVideoDecoder, &IID_IAMAnalogVideoDecoder> PQAnalogVideoDecoder; typedef CComQIPtr<IMixerPinConfig, &IID_IMixerPinConfig> PQMixerPinConfig; typedef CComQIPtr<IAMAudioInputMixer, &IID_IAMAudioInputMixer> PQAudioInputMixer; typedef CComQIPtr<IAMLine21Decoder, &IID_IAMLine21Decoder> PQLine21Decoder; typedef CComQIPtr<IVPNotify2, &IID_IVPNotify2> PQVPNotify2; typedef CComQIPtr<ITuner> PQBDATuner; typedef CComQIPtr<IBDA_IPSinkControl> PQBDA_IPSinkControl; typedef CComQIPtr<IDvdControl, &IID_IDvdControl> PQDVDNavigator; typedef CComQIPtr<IVideoFrameStep> PQVideoFrameStep; typedef CComQIPtr<IMediaEventSink> PQMediaEventSink; typedef CComQIPtr<IVMRMonitorConfig> PQVMRMonitorConfig; typedef CComQIPtr<IDirectDraw7, &IID_IDirectDraw7> PQDirectDraw7; typedef CComQIPtr<IRegisterServiceProvider, &IID_IRegisterServiceProvider> PQRegisterServiceProvider; typedef std::vector<GUID2> MediaMajorTypeList;
#if 0
typedef std::pair<PQCrossbarSwitch, long> PQBasePoint;
inline void clear(PQBasePoint &p) {p.first.Release(); p.second = 0;} class PQPoint : public PQBasePoint { public: //PQBasePoint p;
inline PQPoint() : PQBasePoint(PQCrossbarSwitch(), 0) {} inline PQPoint(const PQBasePoint &p2) : PQBasePoint(p2) {} inline PQPoint(const PQPoint &p2) : PQBasePoint(p2) {} inline PQPoint(const PQCrossbarSwitch &s, long i) : PQBasePoint(s, i) {} virtual ~PQPoint() { ::clear(*this); } inline void clear(void) { ::clear(*this); } }; #else
typedef std::pair<PQCrossbarSwitch, long> PQPoint; #endif
class CDevices; class DSFilter; class DSPin; typedef std::vector< DSFilter, stl_smart_ptr_allocator<DSFilter> > DSFilterList; typedef std::vector< DSPin, stl_smart_ptr_allocator<DSPin> > DSPinList;
typedef std::pair< DSFilter, CString> DSFilterID; typedef std::vector< DSFilterID > DSFilterIDList;
typedef PQPoint XBarInputPoint, PQInputPoint; typedef PQPoint XBarOutputPoint, PQOutputPoint; typedef PQPoint XBarPoint;
typedef std::pair<XBarInputPoint, XBarOutputPoint> CIOPoint; typedef std::list<CIOPoint> VWGraphPath;
class VWStream : public VWGraphPath { public: //PQBasePoint p;
VWStream() {} VWStream(const VWGraphPath &p2) : VWGraphPath(p2) {} VWStream(const VWStream &p2) : VWGraphPath(p2) {} virtual ~VWStream() {} void Route(void); };
typedef std::list<VWStream> VWStreamList;
#ifdef _DEBUG
class DSREGPINMEDIUM; class DSMediaType; inline tostream &operator<<(tostream &dc, const DSREGPINMEDIUM &g); inline tostream& operator<<(tostream &d, const PQPin &pin); inline tostream &operator<<(tostream &dc, const DSREGPINMEDIUM &g); inline tostream& operator<<(tostream &d, const PQPin &pin); inline tostream& operator<<(tostream &d, const _AMMediaType *pmt); #endif
// AM_MEDIA_TYPE:
// GUID majortype;
// GUID subtype;
// BOOL bFixedSizeSamples;
// BOOL bTemporalCompression;
// ULONG lSampleSize;
// GUID formattype;
// IUnknown *pUnk;
// ULONG cbFormat;
#define GUID0 0L, 0, 0, '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
const AM_MEDIA_TYPE NULL_AMMEDIATYPE = { GUID0, GUID0, 0, 0, 0L, GUID0, NULL, 0L };
// this is basically a CComQIPtr with allocate/copy semantics instead of
// refcount semantics and without the QI stuff.
// i don't know why they didn't just implement media types as an
// com object with an IMediaType interface instead of this weird alloc stuff
// REV2: investigate inheriting from CMediaType class in mtype.h. but, i'm not using anything
// from the filter implementation class hierarchy. and, i'd like to keep this interface division
// clean. right now we only use dshow sdk \include which is the external interface stuff.
class DSMediaType { public: AM_MEDIA_TYPE *p;
inline DSMediaType() : p(NULL) {} DSMediaType(GUID majortype, GUID subtype = GUID_NULL, GUID formattype = GUID_NULL) : p(NULL) { try { p = CreateMediaType(&NULL_AMMEDIATYPE); if (p) { p->majortype = majortype; p->subtype = subtype; p->formattype = formattype; } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::DSMediaType(const DSMediaType) Exception"); } } DSMediaType(const DSMediaType &d) : p(NULL) { try { if (d.p) { p = CreateMediaType(d.p); } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::DSMediaType(const DSMediaType) Exception"); } } DSMediaType(int a) : p(NULL) {} ~DSMediaType() { try { if (p) { DeleteMediaType(p); p = NULL; } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::~DSMediaType() Exception"); } }
inline operator AM_MEDIA_TYPE*() const {return p;} inline AM_MEDIA_TYPE& operator*() const {_ASSERTE(p!=NULL); return *p; } inline AM_MEDIA_TYPE ** operator&() {ASSERT(p == NULL); return &p; } inline AM_MEDIA_TYPE * operator->() const {_ASSERTE(p!=NULL); return p; } inline DSMediaType * address(void) { return this; } inline const DSMediaType * const_address(void) const { return this; } typedef stl_smart_ptr_allocator<DSMediaType> stl_allocator; DSMediaType& operator=(const AM_MEDIA_TYPE &d) { if (&d != p) { try { if (p) { DeleteMediaType(p); p = NULL; } if (&d) { p = CreateMediaType(&d); } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::operator=(const AM_MEDIA_TYPE &) Exception"); } } return *this; } DSMediaType& operator=(const AM_MEDIA_TYPE *pd) { try { if (pd != p) { if (p) { DeleteMediaType(p); p = NULL; } if (pd) { p = CreateMediaType(pd); } } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::operator=(const AM_MEDIA_TYPE *) Exception"); } return *this; } DSMediaType& operator=(const DSMediaType &d) { try { if (d.const_address() != this) { if (p) { DeleteMediaType(p); p = NULL; } if (d.p) { p = CreateMediaType(d.p); } } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::operator=(DSMediaType &)Exception"); } return *this; } DSMediaType& operator=(int d) { ASSERT(d == 0); try { if (p) { DeleteMediaType(p); p = NULL; } } catch(...) { TRACELM(TRACE_ERROR, "DSMediaType::operator=(int) Exception"); } return *this; }
inline bool operator==(const DSMediaType &d) const { if (!p && !d.p) { // both null then they're the same
return true; } if (!p || !d.p) { // if either one null but not both then they aren't the same
return false; } TRACELSM(TRACE_DETAIL, (dbgDump << "DSMediaType::operator==() this = " << *this << " d = " << d), ""); return p->majortype == d.p->majortype && (p->subtype == GUID_NULL || d.p->subtype == GUID_NULL || p->subtype == d.p->subtype); } inline bool operator==(const AM_MEDIA_TYPE &d) const { if (!p && !&d) { return true; } return p && (&d) && p->majortype == d.majortype && (p->subtype == GUID_NULL || d.subtype == GUID_NULL || p->subtype == d.subtype); } inline bool operator==(const AM_MEDIA_TYPE *d) const { if (!p && !d) { return true; } return p && d && p->majortype == d->majortype && (p->subtype == GUID_NULL || d->subtype == GUID_NULL || p->subtype == d->subtype); } inline bool operator!=(const DSMediaType &d) const { return !(*this == d); } inline bool operator!() const { return (p == NULL); } inline bool MatchingMajor(const AM_MEDIA_TYPE *prhs) const { if (!p && !prhs) { return true; } TRACELSM(TRACE_DETAIL, (dbgDump << "DSMediaType::MatchingMajor() this = " << *this << "\rprhs = " << prhs), ""); return p && prhs && p->majortype == prhs->majortype; } inline bool MatchingMajor(const DSMediaType &rhs) const { return MatchingMajor(rhs.p); }
#ifdef _DEBUG
inline tostream& operator<<(tostream &d) { d << p; if (p) { d << _T(" major = ") << GUID2(p->majortype) << _T(" sub = ") << GUID2(p->subtype); } return d; } #endif
};
class DSFilterMoniker : public W32Moniker { public: inline DSFilterMoniker() {} inline DSFilterMoniker(const PQMoniker &a) : W32Moniker(a) {} inline DSFilterMoniker(const W32Moniker &a) : W32Moniker(a) {} inline DSFilterMoniker(IMoniker *p) : W32Moniker(p) {} inline DSFilterMoniker(IUnknown *p) : W32Moniker(p) {} inline DSFilterMoniker(const DSFilterMoniker &a) : W32Moniker(a) {}
CComBSTR GetName() const { CComVariant vName; vName.vt = VT_BSTR; HRESULT hr = (GetPropertyBag())->Read(OLESTR("FriendlyName"), &vName, NULL); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "DSFilterMoniker::GetName() can't read friendly name"); return CComBSTR(); } USES_CONVERSION; ASSERT(vName.vt == VT_BSTR); CComBSTR Name(vName.bstrVal); return Name; } DSFilter GetFilter() const; };
typedef Forward_Sequence< PQCreateDevEnum, PQEnumMoniker, DSFilterMoniker, ICreateDevEnum, IEnumMoniker, IMoniker*> DSDeviceSequence;
typedef Forward_Sequence< PQFilterMapper, PQEnumMoniker, DSFilterMoniker, IFilterMapper2, IEnumMoniker, IMoniker*> DSFilterMapperSequence;
typedef Forward_Sequence< PQPin, PQEnumMediaTypes, DSMediaType, IPin, IEnumMediaTypes, AM_MEDIA_TYPE*> DSPinSequence;
class DSGraph;
class DSPin : public DSPinSequence { public: DSPin() {} DSPin(const PQPin &a) : DSPinSequence(a) {} DSPin(IPin *p) : DSPinSequence(p) {} DSPin(IUnknown *p) : DSPinSequence(p) {} DSPin(const DSPin &a) : DSPinSequence(a) {}
CString GetName() const { CString csPinName; PIN_INFO pinfo; HRESULT hr = (*this)->QueryPinInfo(&pinfo); if (SUCCEEDED(hr)) { csPinName = pinfo.achName; if (pinfo.pFilter) pinfo.pFilter->Release(); } return csPinName; }
PIN_DIRECTION GetDirection() const { PIN_DIRECTION pin1dir; HRESULT hr = (*this)->QueryDirection(&pin1dir); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "DSPin::GetDirection() can't call QueryDirection"); THROWCOM(E_UNEXPECTED); } return pin1dir; }
bool IsConnected() const { return GetConnection() != DSPin(); }
bool IsRenderable() { CString csName(GetName()); if (!csName.IsEmpty() && csName.GetAt(0) == '~') { return false; } return true; } bool IsInput() const { return GetDirection() == PINDIR_INPUT; } static inline bool IsInput(const DSPin pin) { PIN_DIRECTION pin1dir = pin.GetDirection(); return pin1dir == PINDIR_INPUT; } bool IsKsProxied() const; HRESULT GetMediums(KSMediumList &MediumList) const { TRACELSM(TRACE_DETAIL, (dbgDump << "DSPin::GetMediums() " << this), ""); PQKSPin pin(*this); if (!pin) { TRACELM(TRACE_DETAIL, "DSPin::GetMedium() can't get IKsPin"); return E_FAIL; } HRESULT hr = pin->KsQueryMediums(&MediumList); // undone: in win64 mediumlist.size is really __int64. fix output operator for
// that type and remove cast
TRACELSM(TRACE_DETAIL, (dbgDump << "DSPin::GetMediums() hr = " << hr << " size = " << (long) MediumList.size()), ""); return hr; }
static inline bool HasCategory(DSPin& pin, const GUID2 &clsCategory, const PIN_DIRECTION pd) { return pin.HasCategory(clsCategory, pd); }
static inline bool HasCategory(DSPin& pin, const GUID2 &clsCategory) { return pin.HasCategory(clsCategory); }
void GetCategory(CLSID &clsCategory) const { ULONG outcount;
PQKSPropertySet ps(*this); if (!ps) { TRACELM(TRACE_ERROR, "DSPin::GetCategory() can't get IKsPropertySet"); clsCategory = GUID_NULL; return; }
HRESULT hr = ps->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, &clsCategory, sizeof(clsCategory), &outcount); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "DSPin::GetCategory() can't get pin category hr = " << hr), ""); clsCategory = GUID_NULL; } return; } DSPin GetConnection(void) const { DSPin pConn; HRESULT hr = (*this)->ConnectedTo(&pConn); if (FAILED(hr) || !pConn) { return DSPin(); } #ifdef _DEBUG
DSPin pConn2; hr = pConn->ConnectedTo(&pConn2); if (FAILED(hr) || pConn2.IsEqualObject(*this)) { TRACELSM(TRACE_DETAIL, (dbgDump << "DSPin::GetConnection() " << *this << " is Connected to " << pConn << " but not vice versa"), ""); } #endif
return pConn; } DSMediaType GetConnectionMediaType(void) const { DSMediaType amt(GUID_NULL); HRESULT hr = (*this)->ConnectionMediaType(amt); if (SUCCEEDED(hr)) { return amt; } else { return DSMediaType(); } } DSGraph GetGraph(void) const; DSFilter GetFilter(void) const;
bool HasCategory(const GUID2 &clsCategory, const PIN_DIRECTION pd) const; bool HasCategory(const GUID2 &clsCategory) const; HRESULT Connect(DSPin ConnectTo, const AM_MEDIA_TYPE *pMediaType = NULL); HRESULT IntelligentConnect(DSPin ConnectTo, const AM_MEDIA_TYPE *pMediaType = NULL) { // undone: implement this via igb2, currently we're just connecting directly via graph mgr.
return Connect(ConnectTo, pMediaType); } HRESULT IntelligentConnect(DSFilter& Filter1, DSFilterList &intermediates, const DWORD dwFlags = 0, const PIN_DIRECTION pd = DOWNSTREAM); HRESULT Disconnect(void); bool CanRoute(const DSPin pin2) const;
protected: bool Routable(const DSPin pin2) const; };
typedef Forward_Sequence< PQFilter, PQEnumPins, DSPin, IBaseFilter , IEnumPins, IPin*> DSFilterSequence;
inline bool _cdecl operator==(const CString &cs, const DSFilterSequence& pF); inline bool _cdecl operator==(const CLSID &cls, const DSFilterSequence& pF);
class DSFilter : public DSFilterSequence { public: DSFilter() {} DSFilter(const PQFilter &a) : DSFilterSequence(a) {} DSFilter(const DSFilterSequence &a) : DSFilterSequence(a) {} DSFilter(IBaseFilter *p) : DSFilterSequence(p) {} DSFilter(IUnknown *p) : DSFilterSequence(p) {} DSFilter(const DSFilter &a) : DSFilterSequence(a) {} DSFilter(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) : DSFilterSequence(rclsid, pUnkOuter, dwClsContext) {} DSGraph GetGraph(void); void GetPinCounts(ULONG &ulIn, ULONG &ulOut) const; ULONG PinCount(PIN_DIRECTION pd) { ULONG in, out; GetPinCounts(in, out); if (pd == PINDIR_INPUT) { return in; } else { return out; } } ULONG OutputPinCount() const { ULONG in, out; GetPinCounts(in, out); return out; } ULONG InputPinCount() const { ULONG in, out; GetPinCounts(in, out); return in; } bool HasFreePins(PIN_DIRECTION pd) const { int count = 0; for (iterator i = begin(); i != end(); ++i) { DSPin p(*i); if (p.GetDirection() != pd) { continue; } if (p.IsConnected()) { continue; } ++count; } return !!count; } bool IsKsProxied() const { CLSID cls; HRESULT hr = (*this)->GetClassID(&cls); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "DSFilter::IsKsProxied() can't get class id"); return false; // if it doesn't have a clsid it can't be the proxy
} #pragma warning(disable: 4800)
return (cls == CLSID_Proxy); #pragma warning(default: 4800)
} #if 0
DSFilter *operator&() { // using vector instead of list so don't need this
return this; } #endif
bool IsXBar() const; CString GetName(void) const; DSPin FirstPin(PIN_DIRECTION pd = PINDIR_INPUT) const { for (DSFilter::iterator i = begin(); i != end(); ++i) { if ((*i).GetDirection() == pd) { return *i; } } return DSPin(); } GUID2 ClassID() const { PQPersist p(*this); GUID2 g; p->GetClassID(&g); return g; } };
typedef Forward_Sequence< PQGraphBuilder, PQEnumFilters, DSFilter, IGraphBuilder, IEnumFilters, IBaseFilter*> DSGraphContainer;
typedef std_arity3pmf< ICreateDevEnum, REFCLSID, IEnumMoniker **, ULONG, HRESULT > DSDevicesMFType;
typedef std_bndr_mf_1_3<DSDevicesMFType> DSDevicesFetchType;
class DSDevices : public DSDeviceSequence { public: DSDevicesFetchType * Fetch; DSDevices(DSDeviceSequence &p, REFCLSID clsid) : Fetch(NULL), DSDeviceSequence(p) { SetFetch(clsid); } DSDevices(PQCreateDevEnum &p, REFCLSID clsid) : Fetch(NULL), DSDeviceSequence(p) { SetFetch(clsid); } DSDevices(DSDevices &d) : DSDeviceSequence(d) { SetFetch((d.Fetch)->arg1val); } virtual DSDeviceSequence::FetchType * GetFetch() const { return Fetch; } ~DSDevices() { if (Fetch) delete Fetch; } protected: // NOTE: this invalidates all currently outstanding iterators
// don't use outside of construction
void SetFetch(REFCLSID clsid) { if (Fetch) { delete Fetch; } Fetch = new DSDevicesFetchType(std_arity3_member(&ICreateDevEnum::CreateClassEnumerator), clsid, 0); }
};
typedef std_arity15pmf< IFilterMapper2, IEnumMoniker **, // enumerator returned
DWORD, // 0 flags
BOOL, // don't match wildcards
DWORD, // at least this merit needed
BOOL, // need at least one input pin
DWORD, // input media type count
const GUID *, // input major+sub pair array
const REGPINMEDIUM *, // input medium
const CLSID*, // input pin category
BOOL, // must the input be rendered?
BOOL, // need at least one output pin
DWORD, // output media type count
const GUID *, // output major type
const REGPINMEDIUM *, // output medium
const CLSID*, // output pin category
HRESULT > DSFilterMapperMFType;
typedef std_bndr_mf_2_3_4_5_6_7_8_9_10_11_12_13_14_15<DSFilterMapperMFType> DSFilterMapperFetchType;
class DSFilterMapper : public DSFilterMapperSequence { public: DSFilterMapperFetchType *Fetch;
protected: // NOTE: this invalidates all currently outstanding iterators
// don't use outside of construction
void SetFetch( DWORD dwFlags, // 0
BOOL bExactMatch, // don't match wildcards
DWORD dwMerit, // at least this merit needed
BOOL bInputNeeded, // need at least one input pin
DWORD cInputTypes, // Number of input types to match
// Any match is OK
const GUID *pInputTypes, // input major+subtype pair array
const REGPINMEDIUM *pMedIn, // input medium
const CLSID *pPinCategoryIn, // input pin category
BOOL bRender, // must the input be rendered?
BOOL bOutputNeeded, // need at least one output pin
DWORD cOutputTypes, // Number of output types to match
// Any match is OK
const GUID *pOutputTypes, // output major+subtype pair array
const REGPINMEDIUM *pMedOut, // output medium
const CLSID *pPinCategoryOut // output pin category
) { if (Fetch) { delete Fetch; } Fetch = new DSFilterMapperFetchType(std_arity15_member(&IFilterMapper2::EnumMatchingFilters), dwFlags, // 0
bExactMatch, dwMerit, bInputNeeded, cInputTypes, // Number of input types to match
pInputTypes, // input major+subtype pair array
// Any match is OK
pMedIn, pPinCategoryIn, bRender, bOutputNeeded, cOutputTypes, // Number of output types to match
// Any match is OK
pOutputTypes, // output major+subtype pair array
pMedOut, pPinCategoryOut ); }
public: DSFilterMapper(PQFilterMapper &p, DWORD dwFlags, // 0
BOOL bExactMatch, // don't match wildcards
DWORD dwMerit, // at least this merit needed
BOOL bInputNeeded, // need at least one input pin
DWORD cInputTypes, // Number of input types to match
// Any match is OK
const GUID *pInputTypes, // input major+subtype pair array
const REGPINMEDIUM *pMedIn, // input medium
const CLSID* pInCat, // input pin category
BOOL bRender, // must the input be rendered?
BOOL bOutputNeeded, // need at least one output pin
DWORD cOutputTypes, // Number of output types to match
// Any match is OK
const GUID *pOutputTypes, // output major+subtype pair array
const REGPINMEDIUM *pMedOut, // output medium
const CLSID* pOutCat // output pin category
) : Fetch(NULL), DSFilterMapperSequence(p) { SetFetch( dwFlags, // 0
bExactMatch, dwMerit, bInputNeeded, cInputTypes, // Number of input types to match
// Any match is OK
pInputTypes, // input major+subtype pair array
pMedIn, pInCat, bRender, bOutputNeeded, cOutputTypes, // Number of output types to match
// Any match is OK
pOutputTypes, // output major+subtype pair array
pMedOut, pOutCat ); }
DSFilterMapper(DSFilterMapperSequence &p, DWORD dwFlags, // 0
BOOL bExactMatch, // don't match wildcards
DWORD dwMerit, // at least this merit needed
BOOL bInputNeeded, // need at least one input pin
DWORD cInputTypes, // Number of input types to match
// Any match is OK
const GUID *pInputTypes, // input major+subtype pair array
const REGPINMEDIUM *pMedIn, // input medium
const CLSID* pInCat, // input pin category
BOOL bRender, // must the input be rendered?
BOOL bOutputNeeded, // need at least one output pin
DWORD cOutputTypes, // Number of output types to match
// Any match is OK
const GUID *pOutputTypes, // output major+subtype pair array
const REGPINMEDIUM *pMedOut, // output medium
const CLSID* pOutCat // output pin category
) : Fetch(NULL), DSFilterMapperSequence(p) { SetFetch( dwFlags, // 0
bExactMatch, dwMerit, bInputNeeded, cInputTypes, // Number of input types to match
// Any match is OK
pInputTypes, // input major+subtype pair array
pMedIn, pInCat, bRender, bOutputNeeded, cOutputTypes, // Number of output types to match
// Any match is OK
pOutputTypes, // output major+subtype pair array
pMedOut, pOutCat ); }
DSFilterMapper(DSFilterMapper &d) : DSFilterMapperSequence(d) { SetFetch((d.Fetch)->arg2val, (d.Fetch)->arg3val, (d.Fetch)->arg4val, (d.Fetch)->arg5val, (d.Fetch)->arg6val, (d.Fetch)->arg7val, (d.Fetch)->arg8val, (d.Fetch)->arg9val, (d.Fetch)->arg10val, (d.Fetch)->arg11val, (d.Fetch)->arg12val, (d.Fetch)->arg13val, (d.Fetch)->arg14val, (d.Fetch)->arg15val ); } virtual DSFilterMapperSequence::FetchType *GetFetch() const { return Fetch; } ~DSFilterMapper() { if (Fetch) delete Fetch; } };
class DSREGPINMEDIUM : public REGPINMEDIUM { public: DSREGPINMEDIUM() { memset(this, 0, sizeof(*this)); } DSREGPINMEDIUM(REFGUID SetInit, ULONG IdInit, ULONG FlagsInit) { clsMedium = SetInit; dw1 = IdInit; dw2 = FlagsInit; } DSREGPINMEDIUM(DSREGPINMEDIUM &rhs) { clsMedium = rhs.clsMedium; dw1 = rhs.dw1; dw2 = rhs.dw2; } DSREGPINMEDIUM(KSPinMedium &rhs) { clsMedium = rhs.Set; dw1 = rhs.Id; dw2 = rhs.Flags; }
DSREGPINMEDIUM& operator=(const KSPinMedium &rhs) { if (reinterpret_cast<const REGPINMEDIUM *>(&rhs) != this) { clsMedium = rhs.Set; dw1 = rhs.Id; dw2 = rhs.Flags; } return *this; } DSREGPINMEDIUM& operator=(const DSREGPINMEDIUM &rhs) { if (&rhs != this) { clsMedium = rhs.clsMedium; dw1 = rhs.dw1; dw2 = rhs.dw2; } return *this; } bool operator==(const DSREGPINMEDIUM &rhs) const { // NOTE: at some point there will be a flag in Flags to
// indicate whether or not Id is significant for this object
// at that point this method will need to change
return (dw1 == rhs.dw1 && clsMedium == rhs.clsMedium); } bool operator!=(const DSREGPINMEDIUM &rhs) const { // NOTE: at some point there will be a flag in Flags to
// indicate whether or not Id is significant for this object
// at that point this method will need to change
return !(*this == rhs); } };
const long DEFAULT_GRAPH_STATE_TIMEOUT = 5000;
class DSGraph : public DSGraphContainer { public: DSGraph() {} DSGraph(const DSGraph &a) : DSGraphContainer(a) {} DSGraph(const PQGraphBuilder &a) : DSGraphContainer(a) {} DSGraph(const DSGraphContainer &a) : DSGraphContainer(a) {} DSGraph(IGraphBuilder *p) : DSGraphContainer(p) {} DSGraph(IUnknown *p) : DSGraphContainer(p) {}
HRESULT AddToROT(DWORD *pdwObjectRegistration); void RemoveFromROT(DWORD dwObjectRegistration);
// graph operation
inline OAFilterState GetState(long timeout = DEFAULT_GRAPH_STATE_TIMEOUT) { PQMediaControl pMC(*this); if(!pMC) { THROWCOM(E_UNEXPECTED); } OAFilterState state; HRESULT hr = pMC->GetState(timeout, &state); if (hr == VFW_S_CANT_CUE) { state = State_Paused; } else if (hr == VFW_S_STATE_INTERMEDIATE) { THROWCOM(HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } else if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "DSGraph::GetState() can't get graph state hr = " << hr), ""); THROWCOM(hr); } return state; } inline bool IsPlaying() { try { return GetState() == State_Running; } catch(...) { return false; } } inline bool IsPaused() { try { return GetState() == State_Paused; } catch(...) { return false; } } inline bool IsStopped() { try { return GetState() == State_Stopped; } catch(...) { return false; } }
// graph building helpers
HRESULT Connect(DSFilter &pStart, DSFilter &pStop, DSFilterList &Added, const DWORD dwFlags = 0, PIN_DIRECTION pFilter1Direction = DOWNSTREAM); bool Connect(DSFilter &pFilter1, DSFilterMoniker &pMoniker, DSFilter &pAdded, DSFilterList &NewIntermediateFilters, const DWORD dwFlags = 0, PIN_DIRECTION pFilter1Direction = DOWNSTREAM);
typedef bool (DSGraph::*ConnectPred_t)(DSPin&, DSFilter&, DWORD dwFlags); typedef arity5pmf<DSGraph, DSPin&, DSFilterMoniker&, DSFilter&, DSFilterIDList &, ConnectPred_t, bool> LoadCheck_t; typedef arity5pmf<DSGraph, DSPin&, DSFilter&, DSFilter&, DSFilterIDList &, ConnectPred_t, bool> ConnectCheck_t;
bool DisconnectPin(DSPin &pPin, const bool fRecurseInputs, const bool fRecurseOutputs); bool DisconnectFilter(DSFilter &pFilter, const bool fRecurseInputs, const bool fRecurseOutputs); bool RemoveFilter(DSFilter &pFilter);
bool IsConnectable(DSPin &pPin1, DSFilter &Mapper, DSFilter &Destination, DSFilterIDList &NewFilters, const DWORD dwFlags, ConnectPred_t ConnPred); bool IsLoadable(DSPin &pPin1, DSFilterMoniker &Mapper, DSFilter &Destination, DSFilterIDList &IntermediateFilters, const DWORD dwFlags, ConnectPred_t ConnPred); bool IsPinConnected(const DSPin &pPin1, const DSFilter &pFDestination, DSFilterIDList &IntermediateFilters, const PIN_DIRECTION destdir) const;
// generic recursive build functions
#ifdef ATTEMPT_DIRECT_CONNECT
bool ConnectPinDirect(DSPin &pPin, DSFilter &pFilter2, DWORD dwFlags); #else
bool HasMediaType(const DSMediaType &LeftMedia, const DSPin &pPinRight) const; bool HasMedium(const KSPinMedium &Medium1, const DSPin &pPin2) const; bool HasUnconnectedMedium(const DSPin &pPinLeft, const DSPin &pPin2, int& cUseable) const; bool HasUnconnectedMediaType(const DSPin &pPinLeft, const DSPin &pPin2, DWORD dwFlags) const; bool ConnectPinByMedium(DSPin &pPin, DSFilter &pFilter2, DWORD dwFlags); bool ConnectPinByMediaType(DSPin &pPin1, DSFilter &pFilter1, DWORD dwFlags); #endif
bool FindPinByMedium(DSPin &pPin, DSFilter &pFilter2, DSFilterIDList &InterediateFilters, const DWORD dwFlags); bool LoadPinByMedium(KSPinMedium &medium, DSPin &pPinLeft, DSFilter &pFilter2, DSFilterIDList &IntermediateFilters, const DWORD dwFlags); bool LoadPinByAnyMedium(DSPin &pPin, DSFilter &pFilter2, DSFilterIDList &IntermediateFilters, const DWORD dwFlags); bool FindPinByMediaType(DSPin &pPin, DSFilter &pFilter2, DSFilterIDList &InterediateFilters, const DWORD dwFlags); bool LoadPinByMediaType(DSPin &pPin1, DSFilter &pFilter1, DSFilterIDList &IntermediatesAdded, const DWORD dwFlags, const DWORD dwMerit); bool LoadPinByAnyMediaType(DSPin &pPin, DSFilter &pFilter2, DSFilterIDList &IntermediateFilters, const DWORD dwFlags);
enum { RENDER_ALL_PINS = 0x01, IGNORE_EXISTING_CONNECTIONS = 0x02, DO_NOT_LOAD = 0x04, ATTEMPT_MERIT_DO_NOT_USE = 0x08, ATTEMPT_MERIT_UNLIKELY = 0x10, ALLOW_WILDCARDS = 0x20, IGNORE_MEDIATYPE_ERRORS = 0x40, DONT_TERMINATE_ON_RENDERER= 0x80, BIDIRECTIONAL_MEDIATYPE_MATCHING = 0x100, }; // render flags
bool ConnectPin(DSPin &pPin1, DSFilter &pFilter2, DSFilterIDList &NewFilters, const DWORD dwFlags, PIN_DIRECTION pin1dir); bool ConnectPin(DSPin &pPin1, DSFilter &pFilter2, DSFilterList &NewFilters, const DWORD dwFlags, PIN_DIRECTION pin1dir) { DSFilterIDList AddedIDs; bool rc = ConnectPin(pPin1, pFilter2, AddedIDs, dwFlags, pin1dir); if (rc) { for (DSFilterIDList::iterator i = AddedIDs.begin(); i != AddedIDs.end(); ++i) { NewFilters.push_back((*i).first); } } return rc; } DSFilter LoadFilter(const DSFilterMoniker &pM, CString &csName); DSFilter AddMoniker(const DSFilterMoniker &pM); HRESULT AddFilter(DSFilter &pFilter, CString &csName); DSFilter AddFilter(const CLSID &cls, CString &csName); bool ConnectFilters(DSFilter &pFilter1, DSFilter &pFilter2, DSFilterIDList &NewIntermediateFilters, const DWORD dwFlags = 0, PIN_DIRECTION pFilter1Direction = DOWNSTREAM); int BuildGraphPath(const DSFilter& pStart, const DSFilter& pStop, VWStream &path, MediaMajorTypeList& MediaList, PIN_DIRECTION direction, const DSPin &InitialInput);
HRESULT SetMediaEventNotificationWindow(HWND h, UINT msg, long lInstance) { // If windowless, WM_MEDIAEVENT is processed by the timer in OnTimer
PQMediaEventEx pme(*this); if (!pme) { return E_UNEXPECTED; } HRESULT hr = pme->CancelDefaultHandling(EC_STATE_CHANGE); ASSERT(SUCCEEDED(hr));
return pme->SetNotifyWindow((OAHWND) h, msg, lInstance);
} };
class DSXBarPin : public DSPin { public: DSXBarPin() {} DSXBarPin(const DSPin &p) : DSPin(p) { PQCrossbarSwitch px1(GetFilter()); if (!px1) { THROWCOM(E_FAIL); } } DSXBarPin(const PQPin &p) : DSPin(p) { PQCrossbarSwitch px1(GetFilter()); if (!px1) { THROWCOM(E_FAIL); } } DSXBarPin(const DSXBarPin &p) : DSPin(p) { PQCrossbarSwitch px1(GetFilter()); if (!px1) { THROWCOM(E_FAIL); } } DSXBarPin(IUnknown *p) : DSPin(p) { PQCrossbarSwitch px1(GetFilter()); if (!px1) { THROWCOM(E_FAIL); } } DSXBarPin(IAMCrossbar *p) : DSPin(p) { PQCrossbarSwitch px1(GetFilter()); if (!px1) { THROWCOM(E_FAIL); } }
#if 0
static const DSXBarPin Find(const CPinPoints &pinpoints, const PQPoint &point, PIN_DIRECTION pindir); #endif
// static DSPin DSPinFromIndex(const DSFilter XBar, const ULONG index);
const PQPoint GetPoint() const; bool CanRoute(const DSXBarPin pin2) const; #if 0
void GetRelations(const CPinPoints &pinpoint, CString &csName, CString &csType, CString &csRelName) const; #endif
};
inline DSFilter DSFilterMoniker::GetFilter() const { DSFilter pFilter; HRESULT hr = (*this)->BindToObject(0, 0, __uuidof(IBaseFilter), reinterpret_cast<LPVOID *>(&pFilter)); if (FAILED(hr)) { // undone: it would be useful to dump the mkr display name here....
TRACELSM(TRACE_ERROR, (dbgDump << "DSFilterMoniker::GetFilter() can't bind to object. hr = " << hexdump(hr)), ""); return DSFilter(); } return pFilter; }
#ifdef _DEBUG
//void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel);
inline tostream &operator<<(tostream &dc, const DSREGPINMEDIUM &g) { //TRACELM(TRACE_DETAIL, "operator<<(tostream, DSREGPINMEDIUM)");
const GUID2 g2(g.clsMedium); dc << _T("DSREGPINMEDIUM( ") << g2 << _T(", ") << hexdump(g.dw1) << _T(", ") << hexdump(g.dw2) << _T(")"); return dc; } inline tostream& operator<<(tostream &d, const PQPin &pin) { const CString csPinName(const DSPin(pin).GetName());
d << (csPinName.IsEmpty() ? CString(_T("**** UNKNOWN PIN NAME ****")) : csPinName) << " " << reinterpret_cast<void *>(pin.p); return d; }
inline tostream& operator<<(tostream &d, const DSFilter &filt) { d << filt.GetName() << _T(" ") << reinterpret_cast<void *>(filt.p); return d; }
inline tostream& operator<<(tostream &d, const _AMMediaType *pamt) { d << reinterpret_cast<const void *>(pamt); if (pamt) { d << _T(" major = ") << GUID2(pamt->majortype) << _T(" sub = ") << GUID2(pamt->subtype); } return d; } inline tostream& operator<<(tostream &d, const PQPoint &p) { const DSFilter pF(p.first); d << _T("PQPoint( ") << pF << _T(", ") << p.second << _T(")"); return d; }
inline tostream& operator<<(tostream &d, const CIOPoint &p) { d << _T("CIOPoint( ") << p.first << _T(", ") << p.second << _T(")"); return d; }
void DumpMediaTypes(DSPin &p1, DSPin &p2); #endif
inline bool _cdecl operator==(const CString &cs, const DSFilterSequence& pF) { // filter name
FILTER_INFO fi; HRESULT hr = pF->QueryFilterInfo(&fi); if (SUCCEEDED(hr)) { USES_CONVERSION; if (fi.pGraph) fi.pGraph->Release(); return (cs == OLE2T(fi.achName)); } return false; } inline bool _cdecl operator!=(const CString &cs, const DSFilterSequence& pF) { return !(cs == pF); } inline bool _cdecl operator==(const DSFilterSequence& pF, const CString &cs) { return (cs == pF); } inline bool _cdecl operator!=(const DSFilterSequence& pF, const CString &cs) { return !(cs == pF); }
inline bool _cdecl operator==(const CLSID &cls, const DSFilterSequence& pF) { // filter name
CLSID cid; HRESULT hr = pF->GetClassID(&cid); if (SUCCEEDED(hr)) { #pragma warning(disable: 4800)
return (cid == cls); #pragma warning(default: 4800)
} return false; }
inline bool _cdecl operator!=(const CLSID &cls, const DSFilterSequence& pF) { return !(cls == pF); } inline bool _cdecl operator==(const DSFilterSequence& pF, const CLSID &cls) { return (cls == pF); }
inline bool _cdecl operator!=(const DSFilterSequence& pF, const CLSID &cls) { return !(cls == pF); }
typedef enum { tempAMPROPERTY_OvMixerOwner = 0x01 //use AMOVMIXEROWNER
} tempAMPROPERTY_NOTIFYOWNER;
typedef enum { tempAM_OvMixerOwner_Unknown = 0x01, tempAM_OvMixerOwner_BPC = 0x02 } tempAMOVMIXEROWNER;
inline bool DSPin::IsKsProxied() const { return GetFilter().IsKsProxied(); } inline bool DSFilter::IsXBar() const { PQCrossbarSwitch px(*this); TRACELSM(TRACE_PAINT, (dbgDump << "DSFilter::IsXBar() " << *this << " is " << ((!px) ? " not " : "")), "crossbar"); return !!px; }
void CtorStaticDSExtendFwdSeqPMFs(void); void DtorStaticDSExtendFwdSeqPMFs(void);
bool IsVideoFilter(const DSFilter& f); bool IsVideoPin(const DSPin& p);
inline PIN_DIRECTION OppositeDirection(PIN_DIRECTION pd) { if (pd == PINDIR_INPUT) { return PINDIR_OUTPUT; } else { return PINDIR_INPUT; } }
inline bool IsVideoMediaType(const DSMediaType& mt) { GUID2 g(mt.p->majortype); if ((g == MEDIATYPE_Video) || (g == MEDIATYPE_AnalogVideo)) { return true; } return false; }
inline bool IsAnalogVideoCapture(const DSFilter &f) { return !!PQAnalogVideoDecoder(f); }
inline bool IsIPSink(const DSFilter &f) { return !!PQBDA_IPSinkControl(f); }
inline bool IsVPM(const DSFilter &f) { return f.ClassID() == CLSID_VideoPortManager; }
inline bool IsVideoRenderer(const DSFilter &f) { return f.ClassID() == CLSID_VideoMixingRenderer; }
inline bool IsDigitalAudioRenderer(const DSFilter &f) { return f.ClassID() == CLSID_DSoundRender; }
inline bool IsAnalogVideoCaptureViewingPin(const DSPin &p) { GUID2 pincat; p.GetCategory(pincat); return (pincat == PIN_CATEGORY_VIDEOPORT || pincat == PIN_CATEGORY_CAPTURE); }
inline bool IsAnalogVideoCapturePreviewPin(const DSPin &p) { GUID2 pincat; p.GetCategory(pincat); return (pincat == PIN_CATEGORY_PREVIEW); }
inline bool IsDVDNavigator(const DSFilter &f) { return !!PQDVDNavigator(f); }
inline bool IsL21Decoder(const DSFilter &f) { return !!PQLine21Decoder(f); }
inline bool IsDVDNavigatorVideoOutPin(const DSPin &p) { DSPin::iterator iMediaType; for (iMediaType = p.begin(); iMediaType != p.end(); ++iMediaType) { DSMediaType mt(*iMediaType); if ((mt.p->majortype == MEDIATYPE_MPEG2_PES || mt.p->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK ) && mt.p->subtype == MEDIASUBTYPE_MPEG2_VIDEO) return true; // elementary stream
if ((mt.p->majortype == MEDIATYPE_Video) && (mt.p->subtype == MEDIASUBTYPE_MPEG2_VIDEO || mt.p->subtype == MEDIASUBTYPE_RGB8 || mt.p->subtype == MEDIASUBTYPE_RGB565 || mt.p->subtype == MEDIASUBTYPE_RGB555 || mt.p->subtype == MEDIASUBTYPE_RGB24 || mt.p->subtype == MEDIASUBTYPE_RGB32)) return true; }
return false; }
inline bool IsDVDNavigatorSubpictureOutPin(const DSPin &p) { DSPin::iterator iMediaType; for (iMediaType = p.begin(); iMediaType != p.end(); ++iMediaType) { DSMediaType mt(*iMediaType); if ((mt.p->majortype == MEDIATYPE_MPEG2_PES || mt.p->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK ) && mt.p->subtype == MEDIASUBTYPE_DVD_SUBPICTURE) return true;
// elementary stream
if ((mt.p->majortype == MEDIATYPE_Video) && mt.p->subtype == MEDIASUBTYPE_DVD_SUBPICTURE) return true; }
return false; }
///////// DSPin
inline HRESULT DSPin::IntelligentConnect(DSFilter& Filter1, DSFilterList &intermediates, const DWORD dwFlags, const PIN_DIRECTION pd) { bool rc = GetGraph().ConnectPin(*this, Filter1, intermediates, dwFlags, pd); if (rc) { return NOERROR; } return E_FAIL; }
inline DSFilter DSPin::GetFilter(void) const { PIN_INFO pinfo;
HRESULT hr = (*this)->QueryPinInfo(&pinfo); if (FAILED(hr)) { return DSFilter(); } DSFilter pRet; pRet.p = pinfo.pFilter; // directly transfer ownership of ref count
return pRet; }
inline DSGraph DSPin::GetGraph(void) const { DSFilter f = GetFilter(); return f.GetGraph(); }
inline bool DSPin::HasCategory(const GUID2 &clsCategory) const { TRACELSM(TRACE_DETAIL, (dbgDump << "DSPin::IsPinCategory() pin = " << this), ""); GUID2 pincat2; GetCategory(pincat2); return clsCategory == pincat2; }
#endif
// end of file - dsextend.h
|