view loader/dshow/inputpin.c @ 33263:5f527a9a9521

Add an exit function. This function will allow performing clean-up operations. (MPlayer calls guiDone() before exiting, but only if the GUI has been initialized, i.e. if guiInit() has been called successfully. Any exit_player()/exit_player_with_rc() after GUI's cfg_read() until guiInit(), or any exit_player() during guiInit() itself will end the GUI without calling guiDone(). This exit function will at least handle abortions during guiInit() itself. It will be called twice in case of an guiExit() after GUI initialization - first directly, next by guiDone() via MPlayer's exit_player_with_rc().)
author ib
date Tue, 03 May 2011 12:19:22 +0000
parents 8fa2f43cb760
children
line wrap: on
line source

/*
 * Modified for use with MPlayer, detailed changelog at
 * http://svn.mplayerhq.hu/mplayer/trunk/
 */

#include "inputpin.h"
#include "mediatype.h"
#include "loader/wine/winerror.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

static inline int unimplemented(const char* s, void* p)
{
    Debug printf("%s(%p) called (UNIMPLEMENTED)", s, p);
    return E_NOTIMPL;
}

/***********
 * EnumPins
 ***********/

typedef struct
{
    IEnumPins_vt* vt;
    DECLARE_IUNKNOWN();
    IPin* pin1;
    IPin* pin2;
    int counter;
    GUID interfaces[2];
} CEnumPins;

/**
 * \brief IEnumPins:Next (retrives a specified number of pins )
 *
 * \param[in]  This pointer to CEnumPins object
 * \param[in]  cMediaTypes number of pins to retrive
 * \param[out] ppMediaTypes array of IPin interface pointers of size cMediaTypes
 * \param[out] pcFetched address of variables that receives number of returned pins
 *
 * \return S_OK - success
 * \return S_FALSE - did not return as meny pins as requested
 * \return E_INVALIDARG Invalid argument
 * \return E_POINTER Null pointer
 * \return VFW_E_ENUM_OUT_OF_SYNC - filter's state has changed and is now inconsistent with enumerator
 *
 */
static long STDCALL CEnumPins_Next(IEnumPins* This,
				   /* [in] */ unsigned long cMediaTypes,
				   /* [size_is][out] */ IPin** ppMediaTypes,
				   /* [out] */ unsigned long* pcFetched)
{
    CEnumPins* pin = (CEnumPins*)This;

    Debug printf("CEnumPins_Next(%p) called\n", This);
    if (!ppMediaTypes)
	return E_INVALIDARG;
    if (!pcFetched && (cMediaTypes!=1))
	return E_INVALIDARG;
    if (cMediaTypes<=0)
	return 0;

    //lcounter = ((CEnumPins*)This)->counter;
    //lpin1 = ((CEnumPins*)This)->pin1;
    //lpin2 = ((CEnumPins*)This)->pin2;
    if (((pin->counter == 2) && pin->pin2)
	|| ((pin->counter == 1) && !pin->pin2))
    {
	if (pcFetched)
	    *pcFetched=0;
	return 1;
    }

    if (pcFetched)
	*pcFetched=1;
    if (pin->counter==0)
    {
	*ppMediaTypes = pin->pin1;
	pin->pin1->vt->AddRef((IUnknown*)pin->pin1);
    }
    else
    {
	*ppMediaTypes = pin->pin2;
	pin->pin2->vt->AddRef((IUnknown*)pin->pin2);
    }
    pin->counter++;
    if (cMediaTypes == 1)
	return 0;
    return 1;
}

/**
 * \brief IEnumPins::Skip (skips over a specified number of pins)
 *
 * \param[in]  This pointer to CEnumPinss object
 * \param[in]  cMediaTypes number of pins to skip
 *
 * \return S_OK - success
 * \return S_FALSE - skipped past the end of the sequence
 * \return VFW_E_ENUM_OUT_OF_SYNC - filter's state has changed and is now inconsistent with enumerator
 *
 */
static long STDCALL CEnumPins_Skip(IEnumPins* This,
				   /* [in] */ unsigned long cMediaTypes)
{
    Debug unimplemented("CEnumPins_Skip", This);
    return E_NOTIMPL;
}

/**
 * \brief IEnumPins::Reset (resets enumeration sequence to beginning)
 *
 * \param[in]  This pointer to CEnumPins object
 *
 * \return S_OK - success
 *
 */
static long STDCALL CEnumPins_Reset(IEnumPins* This)
{
    Debug printf("CEnumPins_Reset(%p) called\n", This);
    ((CEnumPins*)This)->counter = 0;
    return 0;
}

/**
 * \brief IEnumPins::Clone (makes a copy of enumerator, returned object
 *        starts at the same position as original)
 *
 * \param[in]  This pointer to CEnumPins object
 * \param[out] ppEnum address of variable that receives pointer to IEnumPins interface
 *
 * \return S_OK - success
 * \return E_OUTOFMEMRY - Insufficient memory
 * \return E_POINTER - Null pointer
 * \return VFW_E_ENUM_OUT_OF_SYNC - filter's state has changed and is now inconsistent with enumerator
 *
 */
static long STDCALL CEnumPins_Clone(IEnumPins* This,
				    /* [out] */ IEnumPins** ppEnum)
{
    Debug unimplemented("CEnumPins_Clone", This);
    return E_NOTIMPL;
}

/**
 * \brief CEnumPins destructor
 *
 * \param[in]  This pointer to CEnumPins object
 *
 */
static void CEnumPins_Destroy(CEnumPins* This)
{
    free(This->vt);
    free(This);
}

IMPLEMENT_IUNKNOWN(CEnumPins)

/**
 * \brief CEnumPins constructor
 *
 * \param[in]  p first pin for enumerator
 * \param[in]  pp second pin for enumerator
 *
 * \return pointer to CEnumPins object or NULL if error occured
 *
 */
static CEnumPins* CEnumPinsCreate(IPin* p, IPin* pp)
{
    CEnumPins* This = malloc(sizeof(CEnumPins));

    if (!This)
        return NULL;

    This->refcount = 1;
    This->pin1 = p;
    This->pin2 = pp;
    This->counter = 0;

    This->vt = malloc(sizeof(IEnumPins_vt));
    if (!This->vt)
    {
	free(This);
        return NULL;
    }
    This->vt->QueryInterface = CEnumPins_QueryInterface;
    This->vt->AddRef = CEnumPins_AddRef;
    This->vt->Release = CEnumPins_Release;
    This->vt->Next = CEnumPins_Next;
    This->vt->Skip = CEnumPins_Skip;
    This->vt->Reset = CEnumPins_Reset;
    This->vt->Clone = CEnumPins_Clone;

    This->interfaces[0] = IID_IUnknown;
    This->interfaces[1] = IID_IEnumPins;

    return This;
}



/***********
 * InputPin
 *
 * WARNING:
 * This is implementation of OUTPUT pin in DirectShow's terms
 *
 ***********/

/**
 * \brief IPin::Connect (connects pin to another pin)
 *
 * \param[in] This          pointer to IPin interface
 * \param[in] pReceivePin   pointer to IPin interface of remote pin
 * \param[in] pmt           suggested media type for link. Can be NULL (any media type)
 *
 * \return S_OK - success.
 * \return VFW_E_ALREADY_CONNECTED - pin already connected
 * \return VFW_E_NOT_STOPPED - filter is active
 * \return VFW_E_TYPE_NOT_ACCEPT - type is not acceptable
 * \return Apropriate error code otherwise.
 *
 */
static long STDCALL CInputPin_Connect(IPin* This,
				      /* [in] */ IPin* pReceivePin,
				      /* [in] */ AM_MEDIA_TYPE* pmt)
{
    Debug unimplemented("CInputPin_Connect", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::ReceiveConnection (accepts a connection from another pin)
 *
 * \param[in] This       pointer to IPin interface
 * \param[in] pConnector connecting pin's IPin interface
 * \param[in] pmt        suggested media type for connection
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 * \return VFW_E_ALREADY_CONNECTED - pin already connected
 * \return VFW_E_NOT_STOPPED - filter is active
 * \return VFW_E_TYPE_NOT_ACCEPT - type is not acceptable
 *
 * \note
 * When returning S_OK method should also do the following:
 *  - store media type and return the same type in IPin::ConnectionMediaType
 *  - store pConnector and return it in IPin::ConnectedTo
 *
 */
static long STDCALL CInputPin_ReceiveConnection(IPin* This,
						/* [in] */ IPin* pConnector,
						/* [in] */ const AM_MEDIA_TYPE *pmt)
{
    Debug unimplemented("CInputPin_ReceiveConnection", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::Disconnect (accepts a connection from another pin)
 *
 * \param[in] This pointer to IPin interface
 *
 * \return S_OK - success
 * \return S_FALSE - pin was not connected
 * \return VFW_E_NOT_STOPPED - filter is active
 *
 * \note
 *   To break connection you have to also call Disconnect on other pin
 */
static long STDCALL CInputPin_Disconnect(IPin* This)
{
    Debug unimplemented("CInputPin_Disconnect", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::ConnectedTo (retrieves pointer to the connected pin, if such exist)
 *
 * \param[in]  This pointer to IPin interface
 * \param[out] pPin pointer to remote pin's IPin interface
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 * \return VFW_E_NOT_CONNECTED - pin is not connected
 *
 * \note
 * Caller must call Release on received IPin, when done
 */
static long STDCALL CInputPin_ConnectedTo(IPin* This,
					  /* [out] */ IPin** pPin)
{
    Debug unimplemented("CInputPin_ConnectedTo", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::ConnectionMediaType (retrieves media type for connection, if such exist)
 *
 * \param[in]  This pointer to IPin interface
 * \param[out] pmt pointer to AM_MEDIA_TYPE,  that receives connection media type
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 * \return VFW_E_NOT_CONNECTED - pin is not connected
 *
 */
static long STDCALL CInputPin_ConnectionMediaType(IPin* This,
						  /* [out] */ AM_MEDIA_TYPE *pmt)
{
    Debug printf("CInputPin_ConnectionMediaType(%p) called\n", This);
    if (!pmt)
	return E_INVALIDARG;
    CopyMediaType(pmt,&(((CInputPin*)This)->type));
    return 0;
}

/**
 * \brief IPin::QueryPinInfo (retrieves information about the pin)
 *
 * \param[in]  This  pointer to IPin interface
 * \param[out] pInfo pointer to PIN_INFO structure, that receives pin info
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 *
 * \note
 * If pInfo->pFilter is not NULL, then caller must call Release on pInfo->pFilter when done
 *
 */
static long STDCALL CInputPin_QueryPinInfo(IPin* This,
					   /* [out] */ PIN_INFO *pInfo)
{
    CBaseFilter* lparent=((CInputPin*)This)->parent;
    Debug printf("CInputPin_QueryPinInfo(%p) called\n", This);
    pInfo->dir = PINDIR_OUTPUT;
    pInfo->pFilter = (IBaseFilter*) lparent;
    lparent->vt->AddRef((IUnknown*)lparent);
    pInfo->achName[0] = 0;
    return 0;
}

/**
 * \brief IPin::QueryDirection (retrieves pin direction)
 *
 * \param[in]  This    pointer to IPin interface
 * \param[out] pPinDir pointer to variable, that receives pin direction (PINDIR_INPUT,PINDIR_OUTPUT)
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 *
 */
static long STDCALL CInputPin_QueryDirection(IPin* This,
					      /* [out] */ PIN_DIRECTION *pPinDir)
{
    *pPinDir = PINDIR_OUTPUT;
    Debug printf("CInputPin_QueryDirection(%p) called\n", This);
    return 0;
}

/**
 * \brief IPin::QueryId (retrieves pin identificator)
 *
 * \param[in]  This pointer to IPin interface
 * \param[out] Id   adress of variable, that receives string with pin's Id.
 *
 * \return S_OK - success
 * \return E_OUTOFMEMORY - Insufficient memory
 * \return E_POINTER     - Null pointer
 *
 * \note
 * Pin's Id is not the same as pin's name
 *
 */
static long STDCALL CInputPin_QueryId(IPin* This,
				       /* [out] */ unsigned short* *Id)
{
    Debug unimplemented("CInputPin_QueryId", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::QueryAccept (determines can media type be accepted or not)
 *
 * \param[in] This  pointer to IPin interface
 * \param[in] pmt   Media type to check
 *
 * \return S_OK - success
 * \return S_FALSE - pin rejects media type
 *
 */
static long STDCALL CInputPin_QueryAccept(IPin* This,
					  /* [in] */ const AM_MEDIA_TYPE* pmt)
{
    Debug unimplemented("CInputPin_QueryAccept", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::EnumMediaTypes (enumerates the pin's preferred media types)
 *
 * \param[in] This  pointer to IPin interface
 * \param[out] ppEnum adress of variable that receives pointer to IEnumMEdiaTypes interface
 *
 * \return S_OK - success
 * \return E_OUTOFMEMORY - Insufficient memory
 * \return E_POINTER     - Null pointer
 *
 * \note
 * Caller must call Release on received interface when done
 *
 */
static long STDCALL CInputPin_EnumMediaTypes(IPin* This,
					     /* [out] */ IEnumMediaTypes** ppEnum)
{
    Debug unimplemented("CInputPin_EnumMediaTypes", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::QueryInternalConnections (retries pin's internal connections)
 *
 * \param[in]     This  pointer to IPin interface
 * \param[out]    apPin Array that receives pins, internally connected to this
 * \param[in,out] nPint Size of an array
 *
 * \return S_OK - success
 * \return S_FALSE - pin rejects media type
 * \return E_NOTIMPL - not implemented
 *
 */
static long STDCALL CInputPin_QueryInternalConnections(IPin* This,
						       /* [out] */ IPin** apPin,
						       /* [out][in] */ unsigned long *nPin)
{
    Debug unimplemented("CInputPin_QueryInternalConnections", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::EndOfStream (notifies pin, that no data is expected, until new run command)
 *
 * \param[in] This  pointer to IPin interface
 *
 * \return S_OK - success
 * \return E_UNEXPECTED - The pin is output pin
 *
 * \note
 * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream,
 * IMemAllocator::GetBuffer runs in different (streaming) thread then other
 * methods (application thread).
 * IMemoryInputPin::NewSegment runs either in streaming or application thread.
 * Developer must use critical sections for thread-safing work.
 *
 */
static long STDCALL CInputPin_EndOfStream(IPin * This)
{
    Debug unimplemented("CInputPin_EndOfStream", This);
    return E_NOTIMPL;
}


/**
 * \brief IPin::BeginFlush (begins a flush operation)
 *
 * \param[in] This  pointer to IPin interface
 *
 * \return S_OK - success
 * \return E_UNEXPECTED - The pin is output pin
 *
 */
static long STDCALL CInputPin_BeginFlush(IPin * This)
{
    Debug unimplemented("CInputPin_BeginFlush", This);
    return E_NOTIMPL;
}


/**
 * \brief IPin::EndFlush (ends a flush operation)
 *
 * \param[in] This  pointer to IPin interface
 *
 * \return S_OK - success
 * \return E_UNEXPECTED - The pin is output pin
 *
 */
static long STDCALL CInputPin_EndFlush(IPin* This)
{
    Debug unimplemented("CInputPin_EndFlush", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::NewSegment (media sample received after this call grouped as segment with common
 *        start,stop time and rate)
 *
 * \param[in] This   pointer to IPin interface
 * \param[in] tStart start time of new segment
 * \param[in] tStop  end time of new segment
 * \param[in] dRate  rate at wich segment should be processed
 *
 * \return S_OK - success
 * \return E_UNEXPECTED - The pin is output pin
 *
 */
static long STDCALL CInputPin_NewSegment(IPin* This,
					  /* [in] */ REFERENCE_TIME tStart,
					  /* [in] */ REFERENCE_TIME tStop,
					  /* [in] */ double dRate)
{
    Debug unimplemented("CInputPin_NewSegment", This);
    return E_NOTIMPL;
}

/**
 * \brief CInputPin destructor
 *
 * \param[in]  This pointer to CInputPin class
 *
 */
static void CInputPin_Destroy(CInputPin* This)
{
    free(This->vt);
    FreeMediaType(&(This->type));
    free(This);
}

IMPLEMENT_IUNKNOWN(CInputPin)

/**
 * \brief CInputPin constructor
 *
 * \param[in]  amt media type for pin
 *
 * \return pointer to CInputPin if success
 * \return NULL if error occured
 *
 */
CInputPin* CInputPinCreate(CBaseFilter* p, const AM_MEDIA_TYPE* amt)
{
    CInputPin* This = malloc(sizeof(CInputPin));

    if (!This)
        return NULL;

    This->refcount = 1;
    This->parent = p;
    CopyMediaType(&(This->type),amt);

    This->vt= malloc(sizeof(IPin_vt));

    if (!This->vt)
    {
	free(This);
	return NULL;
    }

    This->vt->QueryInterface = CInputPin_QueryInterface;
    This->vt->AddRef = CInputPin_AddRef;
    This->vt->Release = CInputPin_Release;
    This->vt->Connect = CInputPin_Connect;
    This->vt->ReceiveConnection = CInputPin_ReceiveConnection;
    This->vt->Disconnect = CInputPin_Disconnect;
    This->vt->ConnectedTo = CInputPin_ConnectedTo;
    This->vt->ConnectionMediaType = CInputPin_ConnectionMediaType;
    This->vt->QueryPinInfo = CInputPin_QueryPinInfo;
    This->vt->QueryDirection = CInputPin_QueryDirection;
    This->vt->QueryId = CInputPin_QueryId;
    This->vt->QueryAccept = CInputPin_QueryAccept;
    This->vt->EnumMediaTypes = CInputPin_EnumMediaTypes;
    This->vt->QueryInternalConnections = CInputPin_QueryInternalConnections;
    This->vt->EndOfStream = CInputPin_EndOfStream;
    This->vt->BeginFlush = CInputPin_BeginFlush;
    This->vt->EndFlush = CInputPin_EndFlush;
    This->vt->NewSegment = CInputPin_NewSegment;

    This->interfaces[0]=IID_IUnknown;

    return This;
}


/*************
 * BaseFilter
 *************/

static long STDCALL CBaseFilter_GetClassID(IBaseFilter * This,
					   /* [out] */ CLSID *pClassID)
{
    Debug unimplemented("CBaseFilter_GetClassID", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::Stop  (stops the filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 *
 * \return S_OK success
 * \return S_FALSE transition is not complete
 *
 * \remarks
 * When filter is stopped it does onot deliver or process any samples and rejects any samples
 * from upstream filter.
 * Transition may be asynchronous. In this case method should return S_FALSE.
 * Method always sets filter's state to State_Stopped even if error occured.
 *
 */
static long STDCALL CBaseFilter_Stop(IBaseFilter* This)
{
    Debug unimplemented("CBaseFilter_Stop", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::Pause (pauses filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 *
 * \return S_OK success
 * \return S_FALSE transition is not complete
 *
 * \remarks
 * When filter is paused it can receive, process and deliver samples.
 * Live source filters do not deliver any samples while paused.
 * Transition may be asynchronous. In this case method should return S_FALSE.
 * Method always sets filter's state to State_Stopped even if error occured.
 *
 */
static long STDCALL CBaseFilter_Pause(IBaseFilter* This)
{
    Debug unimplemented("CBaseFilter_Pause", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::Run (runs the filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] tStart Reference time corresponding to stream time 0.
 *
 * \return S_OK success
 * \return S_FALSE transition is not complete
 *
 * \remarks
 * When filter is running it can receive, process and deliver samples. Source filters
 * generatesnew  samples, and renderers renders them.
 * Stream time is calculated as the current reference time minus tStart.
 * Graph Manager sets tStart slightly in the future according to graph latency.
 *
 */
static long STDCALL CBaseFilter_Run(IBaseFilter* This, REFERENCE_TIME tStart)
{
    Debug unimplemented("CBaseFilter_Run", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::GetState (retrieves the filter's state (running, stopped or paused))
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] dwMilliSecsTimeout Timeout interval in milliseconds. To block indifinitely pass
 *            INFINITE.
 * \param[out] State pointer to variable that receives a member of FILTER_STATE enumeration.
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 * \return VFW_S_STATE_INTERMEDATE Intermediate state
 * \return VFW_S_CANT_CUE The filter is active, but cannot deliver data.
 *
 */
static long STDCALL CBaseFilter_GetState(IBaseFilter* This,
					 /* [in] */ unsigned long dwMilliSecsTimeout,
					 // /* [out] */ FILTER_STATE *State)
					 void* State)
{
    Debug unimplemented("CBaseFilter_GetState", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::SetSyncSource (sets the reference clock)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] pClock IReferenceClock interface of reference clock
 *
 * \return S_OK success
 * \return apripriate error otherwise
 *
 */
static long STDCALL CBaseFilter_SetSyncSource(IBaseFilter* This,
					      /* [in] */ IReferenceClock *pClock)
{
    Debug unimplemented("CBaseFilter_SetSyncSource", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediafilter::GetSyncSource (gets current reference clock)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] pClock address of variable that receives pointer to clock's
 *  IReferenceClock interface
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 *
 */
static long STDCALL CBaseFilter_GetSyncSource(IBaseFilter* This,
					      /* [out] */ IReferenceClock **pClock)
{
    Debug unimplemented("CBaseFilter_GetSyncSource", This);
    return E_NOTIMPL;
}


/**
 * \brief IBaseFilter::EnumPins (enumerates the pins of this filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] ppEnum address of variable that receives pointer to IEnumPins interface
 *
 * \return S_OK success
 * \return E_OUTOFMEMORY Insufficient memory
 * \return E_POINTER Null pointer
 *
 */
static long STDCALL CBaseFilter_EnumPins(IBaseFilter* This,
					 /* [out] */ IEnumPins **ppEnum)
{
    Debug printf("CBaseFilter_EnumPins(%p) called\n", This);
    *ppEnum = (IEnumPins*) CEnumPinsCreate(((CBaseFilter*)This)->pin, ((CBaseFilter*)This)->unused_pin);
    return 0;
}

/**
 * \brief IBaseFilter::FindPin (retrieves the pin with specified id)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] Id  constant wide string, containing pin id
 * \param[out] ppPin address of variable that receives pointer to pin's IPin interface
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 * \return VFW_E_NOT_FOUND Could not find a pin with specified id
 *
 * \note
 * Be sure to release the interface after use.
 *
 */
static long STDCALL CBaseFilter_FindPin(IBaseFilter* This,
					/* [string][in] */ const unsigned short* Id,
					/* [out] */ IPin **ppPin)
{
    Debug unimplemented("CBaseFilter_FindPin\n", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::QueryFilterInfo (retrieves information aboud the filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] pInfo pointer to FILTER_INFO structure
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 *
 * \note
 * If pGraph member of FILTER_INFO is not NULL, be sure to release IFilterGraph interface after use.
 *
 */
static long STDCALL CBaseFilter_QueryFilterInfo(IBaseFilter* This,
						// /* [out] */ FILTER_INFO *pInfo)
						void* pInfo)
{
    Debug unimplemented("CBaseFilter_QueryFilterInfo", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::JoinFilterGraph (notifies the filter that it has joined of left filter graph)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] pInfo pointer to graph's IFilterGraph interface or NULL if filter is leaving graph
 * \param[in] pName pointer to wide character string that specifies a name for the filter
 *
 * \return S_OK success
 * \return apropriate error code otherwise
 *
 * \remarks
 * Filter should not call to graph's AddRef method.
 * The IFilterGraph is guaranteed to be valid until graph manager calls this method again with
 * the value NULL.
 *
 */
static long STDCALL CBaseFilter_JoinFilterGraph(IBaseFilter* This,
						/* [in] */ IFilterGraph* pGraph,
						/* [string][in] */ const unsigned short* pName)
{
    Debug unimplemented("CBaseFilter_JoinFilterGraph", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::QueryVendorInfo (retrieves a string containing vendor info)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] address of variable that receives pointer to a string containing vendor info
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 * \return E_NOTIMPL Not implemented
 *
 * \remarks
 * Call to CoTaskMemFree to free memory allocated for string
 *
 */
static long STDCALL CBaseFilter_QueryVendorInfo(IBaseFilter* This,
						/* [string][out] */ unsigned short** pVendorInfo)
{
    Debug unimplemented("CBaseFilter_QueryVendorInfo", This);
    return E_NOTIMPL;
}

/**
 * \brief CBaseFilter::GetPin (gets used pin)
 *
 * \param[in] This pointer to CBaseFilter object
 *
 * \return pointer to used pin's IPin interface
 *
 */
static IPin* CBaseFilter_GetPin(CBaseFilter* This)
{
    return This->pin;
}

/**
 * \brief CBaseFilter::GetUnusedPin (gets used pin)
 *
 * \param[in] This pointer to CBaseFilter object
 *
 * \return pointer to unused pin's IPin interface
 *
 */
static IPin* CBaseFilter_GetUnusedPin(CBaseFilter* This)
{
    return This->unused_pin;
}

/**
 * \brief CBaseFilter destructor
 *
 * \param[in] This pointer to CBaseFilter object
 *
 */
static void CBaseFilter_Destroy(CBaseFilter* This)
{
    free(This->vt);
    if (This->pin)
	This->pin->vt->Release((IUnknown*)This->pin);
    if (This->unused_pin)
	This->unused_pin->vt->Release((IUnknown*)This->unused_pin);
    free(This);
}

IMPLEMENT_IUNKNOWN(CBaseFilter)

/**
 * \brief CBaseFilter constructor
 *
 * \param[in] type Pointer to media type for connection
 * \param[in] parent Pointer to parent CBaseFilter2 object
 *
 * \return pointer to CBaseFilter object or NULL if error occured
 *
 */
CBaseFilter* CBaseFilterCreate(const AM_MEDIA_TYPE* type, CBaseFilter2* parent)
{
    CBaseFilter* This = malloc(sizeof(CBaseFilter));
    if (!This)
	return NULL;

    This->refcount = 1;

    This->pin = (IPin*) CInputPinCreate(This, type);
    This->unused_pin = (IPin*) CRemotePinCreate(This, parent->GetPin(parent));

    This->vt = malloc(sizeof(IBaseFilter_vt));
    if (!This->vt || !This->pin || !This->unused_pin)
    {
        CBaseFilter_Destroy(This);
        return NULL;
    }

    This->vt->QueryInterface = CBaseFilter_QueryInterface;
    This->vt->AddRef = CBaseFilter_AddRef;
    This->vt->Release = CBaseFilter_Release;
    This->vt->GetClassID = CBaseFilter_GetClassID;
    This->vt->Stop = CBaseFilter_Stop;
    This->vt->Pause = CBaseFilter_Pause;
    This->vt->Run = CBaseFilter_Run;
    This->vt->GetState = CBaseFilter_GetState;
    This->vt->SetSyncSource = CBaseFilter_SetSyncSource;
    This->vt->GetSyncSource = CBaseFilter_GetSyncSource;
    This->vt->EnumPins = CBaseFilter_EnumPins;
    This->vt->FindPin = CBaseFilter_FindPin;
    This->vt->QueryFilterInfo = CBaseFilter_QueryFilterInfo;
    This->vt->JoinFilterGraph = CBaseFilter_JoinFilterGraph;
    This->vt->QueryVendorInfo = CBaseFilter_QueryVendorInfo;

    This->interfaces[0] = IID_IUnknown;
    This->interfaces[1] = IID_IBaseFilter;

    This->GetPin = CBaseFilter_GetPin;
    This->GetUnusedPin = CBaseFilter_GetUnusedPin;

    return This;
}


/**************
 * BaseFilter2
 **************/


static long STDCALL CBaseFilter2_GetClassID(IBaseFilter* This,
					     /* [out] */ CLSID* pClassID)
{
    Debug unimplemented("CBaseFilter2_GetClassID", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::Stop  (stops the filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 *
 * \return S_OK success
 * \return S_FALSE transition is not complete
 *
 * \remarks
 * When filter is stopped it does onot deliver or process any samples and rejects any samples
 * from upstream filter.
 * Transition may be asynchronous. In this case method should return S_FALSE.
 * Method always sets filter's state to State_Stopped even if error occured.
 *
 */
static long STDCALL CBaseFilter2_Stop(IBaseFilter* This)
{
    Debug unimplemented("CBaseFilter2_Stop", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::Pause (pauses filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 *
 * \return S_OK success
 * \return S_FALSE transition is not complete
 *
 * \remarks
 * When filter is paused it can receive, process and deliver samples.
 * Live source filters do not deliver any samples while paused.
 * Transition may be asynchronous. In this case method should return S_FALSE.
 * Method always sets filter's state to State_Stopped even if error occured.
 *
 */
static long STDCALL CBaseFilter2_Pause(IBaseFilter* This)
{
    Debug unimplemented("CBaseFilter2_Pause", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::Run (runs the filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] tStart Reference time corresponding to stream time 0.
 *
 * \return S_OK success
 * \return S_FALSE transition is not complete
 *
 * \remarks
 * When filter is running it can receive, process and deliver samples. Source filters
 * generatesnew  samples, and renderers renders them.
 * Stream time is calculated as the current reference time minus tStart.
 * Graph Manager sets tStart slightly in the future according to graph latency.
 *
 */
static long STDCALL CBaseFilter2_Run(IBaseFilter* This, REFERENCE_TIME tStart)
{
    Debug unimplemented("CBaseFilter2_Run", This);
    return E_NOTIMPL;
}


/**
 * \brief IMediaFilter::GetState (retrieves the filter's state (running, stopped or paused))
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] dwMilliSecsTimeout Timeout interval in milliseconds. To block indifinitely pass
 *            INFINITE.
 * \param[out] State pointer to variable that receives a member of FILTER_STATE enumeration.
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 * \return VFW_S_STATE_INTERMEDATE Intermediate state
 * \return VFW_S_CANT_CUE The filter is active, but cannot deliver data.
 *
 */
static long STDCALL CBaseFilter2_GetState(IBaseFilter* This,
					  /* [in] */ unsigned long dwMilliSecsTimeout,
					  // /* [out] */ FILTER_STATE *State)
					  void* State)
{
    Debug unimplemented("CBaseFilter2_GetState", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediaFilter::SetSyncSource (sets the reference clock)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] pClock IReferenceClock interface of reference clock
 *
 * \return S_OK success
 * \return apripriate error otherwise
 *
 */
static long STDCALL CBaseFilter2_SetSyncSource(IBaseFilter* This,
					       /* [in] */ IReferenceClock* pClock)
{
    Debug unimplemented("CBaseFilter2_SetSyncSource", This);
    return E_NOTIMPL;
}

/**
 * \brief IMediafilter::GetSyncSource (gets current reference clock)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] pClock address of variable that receives pointer to clock's
 *  IReferenceClock interface
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 *
 */
static long STDCALL CBaseFilter2_GetSyncSource(IBaseFilter* This,
					       /* [out] */ IReferenceClock** pClock)
{
    Debug unimplemented("CBaseFilter2_GetSyncSource", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::EnumPins (enumerates the pins of this filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] ppEnum address of variable that receives pointer to IEnumPins interface
 *
 * \return S_OK success
 * \return E_OUTOFMEMORY Insufficient memory
 * \return E_POINTER Null pointer
 *
 */
static long STDCALL CBaseFilter2_EnumPins(IBaseFilter* This,
					  /* [out] */ IEnumPins** ppEnum)
{
    Debug printf("CBaseFilter2_EnumPins(%p) called\n", This);
    *ppEnum = (IEnumPins*) CEnumPinsCreate(((CBaseFilter2*)This)->pin, 0);
    return 0;
}

/**
 * \brief IBaseFilter::FindPin (retrieves the pin with specified id)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] Id  constant wide string, containing pin id
 * \param[out] ppPin address of variable that receives pointer to pin's IPin interface
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 * \return VFW_E_NOT_FOUND Could not find a pin with specified id
 *
 * \note
 * Be sure to release the interface after use.
 *
 */
static long STDCALL CBaseFilter2_FindPin(IBaseFilter* This,
					 /* [string][in] */ const unsigned short* Id,
					 /* [out] */ IPin** ppPin)
{
    Debug unimplemented("CBaseFilter2_FindPin", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::QueryFilterInfo (retrieves information aboud the filter)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] pInfo pointer to FILTER_INFO structure
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 *
 * \note
 * If pGraph member of FILTER_INFO is not NULL, be sure to release IFilterGraph interface after use.
 *
 */
static long STDCALL CBaseFilter2_QueryFilterInfo(IBaseFilter* This,
						 // /* [out] */ FILTER_INFO *pInfo)
						 void* pInfo)
{
    Debug unimplemented("CBaseFilter2_QueryFilterInfo", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::JoinFilterGraph (notifies the filter that it has joined of left filter graph)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[in] pInfo pointer to graph's IFilterGraph interface or NULL if filter is leaving graph
 * \param[in] pName pointer to wide character string that specifies a name for the filter
 *
 * \return S_OK success
 * \return apropriate error code otherwise
 *
 * \remarks
 * Filter should not call to graph's AddRef method.
 * The IFilterGraph is guaranteed to be valid until graph manager calls this method again with
 * the value NULL.
 *
 */
static long STDCALL CBaseFilter2_JoinFilterGraph(IBaseFilter* This,
						 /* [in] */ IFilterGraph* pGraph,
						 /* [string][in] */
						  const unsigned short* pName)
{
    Debug unimplemented("CBaseFilter2_JoinFilterGraph", This);
    return E_NOTIMPL;
}

/**
 * \brief IBaseFilter::QueryVendorInfo (retrieves a string containing vendor info)
 *
 * \param[in] This pointer to IBaseFilter interface
 * \param[out] address of variable that receives pointer to a string containing vendor info
 *
 * \return S_OK success
 * \return E_POINTER Null pointer
 * \return E_NOTIMPL Not implemented
 *
 * \remarks
 * Call to CoTaskMemFree to free memory allocated for string
 *
 */
static long STDCALL CBaseFilter2_QueryVendorInfo(IBaseFilter* This,
						 /* [string][out] */
						 unsigned short** pVendorInfo)
{
    Debug unimplemented("CBaseFilter2_QueryVendorInfo", This);
    return E_NOTIMPL;
}

/**
 * \brief CBaseFilter2::GetPin (gets used pin)
 *
 * \param[in] This pointer to CBaseFilter2 object
 *
 * \return pointer to used pin's IPin interface
 *
 */
static IPin* CBaseFilter2_GetPin(CBaseFilter2* This)
{
    return This->pin;
}

/**
 * \brief CBaseFilter2 destructor
 *
 * \param[in] This pointer to CBaseFilter2 object
 *
 */
static void CBaseFilter2_Destroy(CBaseFilter2* This)
{
    Debug printf("CBaseFilter2_Destroy(%p) called\n", This);
    if (This->pin)
	This->pin->vt->Release((IUnknown*) This->pin);
    free(This->vt);
    free(This);
}

IMPLEMENT_IUNKNOWN(CBaseFilter2)

static GUID CBaseFilter2_interf1 =
{0x76c61a30, 0xebe1, 0x11cf, {0x89, 0xf9, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb}};
/// IID_IAMNetShowPreroll
static GUID CBaseFilter2_interf2 =
{0xaae7e4e2, 0x6388, 0x11d1, {0x8d, 0x93, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2}};
/// IID_IAMRebuild
static GUID CBaseFilter2_interf3 =
{0x02ef04dd, 0x7580, 0x11d1, {0xbe, 0xce, 0x00, 0xc0, 0x4f, 0xb6, 0xe9, 0x37}};

/**
 * \brief CBaseFilter2 constructor
 *
 * \return pointer to CBaseFilter2 object or NULL if error occured
 *
 */
CBaseFilter2* CBaseFilter2Create()
{
    CBaseFilter2* This = malloc(sizeof(CBaseFilter2));

    if (!This)
	return NULL;

    This->refcount = 1;
    This->pin = (IPin*) CRemotePin2Create(This);

    This->vt = malloc(sizeof(IBaseFilter_vt));

    if (!This->pin || !This->vt)
    {
	CBaseFilter2_Destroy(This);
        return NULL;
    }

    memset(This->vt, 0, sizeof(IBaseFilter_vt));
    This->vt->QueryInterface = CBaseFilter2_QueryInterface;
    This->vt->AddRef = CBaseFilter2_AddRef;
    This->vt->Release = CBaseFilter2_Release;
    This->vt->GetClassID = CBaseFilter2_GetClassID;
    This->vt->Stop = CBaseFilter2_Stop;
    This->vt->Pause = CBaseFilter2_Pause;
    This->vt->Run = CBaseFilter2_Run;
    This->vt->GetState = CBaseFilter2_GetState;
    This->vt->SetSyncSource = CBaseFilter2_SetSyncSource;
    This->vt->GetSyncSource = CBaseFilter2_GetSyncSource;
    This->vt->EnumPins = CBaseFilter2_EnumPins;
    This->vt->FindPin = CBaseFilter2_FindPin;
    This->vt->QueryFilterInfo = CBaseFilter2_QueryFilterInfo;
    This->vt->JoinFilterGraph = CBaseFilter2_JoinFilterGraph;
    This->vt->QueryVendorInfo = CBaseFilter2_QueryVendorInfo;

    This->GetPin = CBaseFilter2_GetPin;

    This->interfaces[0] = IID_IUnknown;
    This->interfaces[1] = IID_IBaseFilter;
    This->interfaces[2] = CBaseFilter2_interf1;
    This->interfaces[3] = CBaseFilter2_interf2;
    This->interfaces[4] = CBaseFilter2_interf3;

    return This;
}


/*************
 * CRemotePin
 *************/


/**
 * \brief IPin::ConnectedTo (retrieves pointer to the connected pin, if such exist)
 *
 * \param[in]  This pointer to IPin interface
 * \param[out] pPin pointer to remote pin's IPin interface
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 * \return VFW_E_NOT_CONNECTED - pin is not connected
 *
 * \note
 * Caller must call Release on received IPin, when done
 */
static long STDCALL CRemotePin_ConnectedTo(IPin* This, /* [out] */ IPin** pPin)
{
    Debug printf("CRemotePin_ConnectedTo(%p) called\n", This);
    if (!pPin)
	return E_INVALIDARG;
    *pPin = ((CRemotePin*)This)->remote_pin;
    (*pPin)->vt->AddRef((IUnknown*)(*pPin));
    return 0;
}

/**
 * \brief IPin::QueryDirection (retrieves pin direction)
 *
 * \param[in]  This    pointer to IPin interface
 * \param[out] pPinDir pointer to variable, that receives pin direction (PINDIR_INPUT,PINDIR_OUTPUT)
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 *
 */
static long STDCALL CRemotePin_QueryDirection(IPin* This,
					      /* [out] */ PIN_DIRECTION* pPinDir)
{
    Debug printf("CRemotePin_QueryDirection(%p) called\n", This);
    if (!pPinDir)
	return E_INVALIDARG;
    *pPinDir=PINDIR_INPUT;
    return 0;
}

/**
 * \brief IPin::ConnectionMediaType (retrieves media type for connection, if such exist)
 *
 * \param[in]  This pointer to IPin interface
 * \param[out] pmt pointer to AM_MEDIA_TYPE,  that receives connection media type
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 * \return VFW_E_NOT_CONNECTED - pin is not connected
 *
 */
static long STDCALL CRemotePin_ConnectionMediaType(IPin* This, /* [out] */ AM_MEDIA_TYPE* pmt)
{
    Debug unimplemented("CRemotePin_ConnectionMediaType", This);
    return E_NOTIMPL;
}

/**
 * \brief IPin::QueryPinInfo (retrieves information about the pin)
 *
 * \param[in]  This  pointer to IPin interface
 * \param[out] pInfo pointer to PIN_INFO structure, that receives pin info
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 *
 * \note
 * If pInfo->pFilter is not NULL, then caller must call Release on pInfo->pFilter when done
 *
 */
static long STDCALL CRemotePin_QueryPinInfo(IPin* This, /* [out] */ PIN_INFO* pInfo)
{
    CBaseFilter* lparent = ((CRemotePin*)This)->parent;
    Debug printf("CRemotePin_QueryPinInfo(%p) called\n", This);
    pInfo->dir= PINDIR_INPUT;
    pInfo->pFilter = (IBaseFilter*) lparent;
    lparent->vt->AddRef((IUnknown*)lparent);
    pInfo->achName[0]=0;
    return 0;
}

/**
 * \brief CRemotePin destructor
 *
 * \param[in] This pointer to CRemotePin object
 *
 */
static void CRemotePin_Destroy(CRemotePin* This)
{
    Debug printf("CRemotePin_Destroy(%p) called\n", This);
    free(This->vt);
    free(This);
}

IMPLEMENT_IUNKNOWN(CRemotePin)

/**
 * \brief CRemotePin constructor
 *
 * \param[in] pt parent filter
 * \param[in] rpin remote pin
 *
 * \return pointer to CRemotePin or NULL if error occured
 *
 */
CRemotePin* CRemotePinCreate(CBaseFilter* pt, IPin* rpin)
{
    CRemotePin* This = malloc(sizeof(CRemotePin));

    if (!This)
        return NULL;

    Debug printf("CRemotePinCreate() called -> %p\n", This);

    This->parent = pt;
    This->remote_pin = rpin;
    This->refcount = 1;

    This->vt = malloc(sizeof(IPin_vt));

    if (!This->vt)
    {
	free(This);
	return NULL;
    }

    memset(This->vt, 0, sizeof(IPin_vt));
    This->vt->QueryInterface = CRemotePin_QueryInterface;
    This->vt->AddRef = CRemotePin_AddRef;
    This->vt->Release = CRemotePin_Release;
    This->vt->QueryDirection = CRemotePin_QueryDirection;
    This->vt->ConnectedTo = CRemotePin_ConnectedTo;
    This->vt->ConnectionMediaType = CRemotePin_ConnectionMediaType;
    This->vt->QueryPinInfo = CRemotePin_QueryPinInfo;

    This->interfaces[0] = IID_IUnknown;

    return This;
}


/*************
 * CRemotePin2
 *************/


/**
 * \brief IPin::QueryPinInfo (retrieves information about the pin)
 *
 * \param[in]  This  pointer to IPin interface
 * \param[out] pInfo pointer to PIN_INFO structure, that receives pin info
 *
 * \return S_OK - success
 * \return E_POINTER - Null pointer
 *
 * \note
 * If pInfo->pFilter is not NULL, then caller must call Release on pInfo->pFilter when done
 *
 */
static long STDCALL CRemotePin2_QueryPinInfo(IPin* This,
					     /* [out] */ PIN_INFO* pInfo)
{
    CBaseFilter2* lparent=((CRemotePin2*)This)->parent;
    Debug printf("CRemotePin2_QueryPinInfo(%p) called\n", This);
    pInfo->pFilter=(IBaseFilter*)lparent;
    lparent->vt->AddRef((IUnknown*)lparent);
    pInfo->dir=PINDIR_OUTPUT;
    pInfo->achName[0]=0;
    return 0;
}

/**
 * \brief CremotePin2 destructor
 *
 * \param This pointer to CRemotePin2 object
 *
 *  FIXME - not being released!
 */
static void CRemotePin2_Destroy(CRemotePin2* This)
{
    Debug printf("CRemotePin2_Destroy(%p) called\n", This);
    free(This->vt);
    free(This);
}

IMPLEMENT_IUNKNOWN(CRemotePin2)

/**
 * \brief CRemotePin2 contructor
 *
 * \param[in] p pointer to parent CBaseFilter2 object
 *
 * \return pointer to CRemotePin2 object or NULL if error occured
 *
 */
CRemotePin2* CRemotePin2Create(CBaseFilter2* p)
{
    CRemotePin2* This = malloc(sizeof(CRemotePin2));

    if (!This)
        return NULL;

    Debug printf("CRemotePin2Create() called -> %p\n", This);

    This->parent = p;
    This->refcount = 1;

    This->vt = malloc(sizeof(IPin_vt));

    if (!This->vt)
    {
	free(This);
        return NULL;
    }

    memset(This->vt, 0, sizeof(IPin_vt));
    This->vt->QueryInterface = CRemotePin2_QueryInterface;
    This->vt->AddRef = CRemotePin2_AddRef;
    This->vt->Release = CRemotePin2_Release;
    This->vt->QueryPinInfo = CRemotePin2_QueryPinInfo;

    This->interfaces[0] = IID_IUnknown;

    return This;
}