1463 lines
31 KiB
C
1463 lines
31 KiB
C
/*
|
|
* Implements IPin and IMemInputPin. (internal)
|
|
*
|
|
* Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
#include "winerror.h"
|
|
#include "strmif.h"
|
|
#include "vfwmsgs.h"
|
|
|
|
#include "wine/debug.h"
|
|
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
|
|
|
|
#include "quartz_private.h"
|
|
#include "basefilt.h"
|
|
#include "memalloc.h"
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CPinBaseImpl
|
|
*
|
|
*/
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnQueryInterface(IPin* iface,REFIID riid,void** ppobj)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CPinBaseImpl_fnAddRef(IPin* iface)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CPinBaseImpl_fnRelease(IPin* iface)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->punkControl);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnConnect(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
ULONG i;
|
|
FILTER_STATE fs;
|
|
|
|
TRACE("(%p)->(%p,%p)\n",This,pPin,pmt);
|
|
|
|
if ( !This->bOutput )
|
|
{
|
|
TRACE("Connect() should not be sent to input pins\n");
|
|
return E_UNEXPECTED;
|
|
}
|
|
if ( pPin == NULL )
|
|
return E_POINTER;
|
|
|
|
TRACE("try to connect to %p\n",pPin);
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
|
|
if ( This->pPinConnectedTo != NULL )
|
|
{
|
|
hr = VFW_E_ALREADY_CONNECTED;
|
|
goto err;
|
|
}
|
|
|
|
/* return fail if running */
|
|
hr = IBaseFilter_GetState((IBaseFilter*)(This->pFilter),0,&fs);
|
|
if ( hr != S_OK || fs != State_Stopped )
|
|
{
|
|
TRACE("not stopped\n");
|
|
hr = VFW_E_NOT_STOPPED;
|
|
goto err;
|
|
}
|
|
|
|
if ( This->pHandlers->pOnPreConnect != NULL )
|
|
{
|
|
hr = This->pHandlers->pOnPreConnect(This,pPin);
|
|
if ( FAILED(hr) )
|
|
{
|
|
TRACE("OnPreconnect() failed hr = %08lx\n",hr);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
if ( pmt != NULL )
|
|
{
|
|
hr = IPin_QueryAccept(iface,pmt);
|
|
if ( FAILED(hr) )
|
|
goto err;
|
|
This->pPinConnectedTo = pPin;
|
|
hr = IPin_ReceiveConnection(pPin,iface,pmt);
|
|
This->pPinConnectedTo = NULL;
|
|
if ( FAILED(hr) )
|
|
goto err;
|
|
}
|
|
else
|
|
{
|
|
for ( i = 0; i < This->cAcceptTypes; i++ )
|
|
{
|
|
pmt = &This->pmtAcceptTypes[i];
|
|
hr = IPin_QueryAccept(iface,pmt);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
This->pPinConnectedTo = pPin;
|
|
hr = IPin_ReceiveConnection(pPin,iface,pmt);
|
|
This->pPinConnectedTo = NULL;
|
|
|
|
TRACE("ReceiveConnection - %08lx\n",hr);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
goto connected;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = VFW_E_TYPE_NOT_ACCEPTED;
|
|
goto err;
|
|
}
|
|
|
|
connected:;
|
|
This->pmtConn = QUARTZ_MediaType_Duplicate( pmt );
|
|
if ( This->pmtConn == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
IPin_Disconnect(pPin);
|
|
goto err;
|
|
}
|
|
|
|
This->pPinConnectedTo = pPin; IPin_AddRef(pPin);
|
|
hr = IPin_QueryInterface(pPin,&IID_IMemInputPin,(void**)&This->pMemInputPinConnectedTo);
|
|
if ( FAILED(hr) )
|
|
{
|
|
TRACE("no IMemInputPin\n");
|
|
IPin_Disconnect(pPin);
|
|
goto err;
|
|
}
|
|
|
|
if ( This->pHandlers->pOnPostConnect != NULL )
|
|
{
|
|
hr = This->pHandlers->pOnPostConnect(This,pPin);
|
|
if ( FAILED(hr) )
|
|
{
|
|
TRACE("OnPostConnect() failed hr = %08lx\n",hr);
|
|
IPin_Disconnect(pPin);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
err:
|
|
if ( FAILED(hr) )
|
|
{
|
|
IPin_Disconnect(iface);
|
|
}
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
TRACE("return %08lx\n",hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnReceiveConnection(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
FILTER_STATE fs;
|
|
|
|
TRACE("(%p)->(%p,%p)\n",This,pPin,pmt);
|
|
|
|
if ( This->bOutput )
|
|
{
|
|
TRACE("ReceiveConnection() should not be sent to output pins\n");
|
|
return E_UNEXPECTED;
|
|
}
|
|
if ( pPin == NULL || pmt == NULL )
|
|
return E_POINTER;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
|
|
if ( This->pPinConnectedTo != NULL )
|
|
{
|
|
hr = VFW_E_ALREADY_CONNECTED;
|
|
goto err;
|
|
}
|
|
|
|
/* return fail if running */
|
|
hr = IBaseFilter_GetState((IBaseFilter*)(This->pFilter),0,&fs);
|
|
if ( hr != S_OK || fs != State_Stopped )
|
|
{
|
|
TRACE("not stopped\n");
|
|
hr = VFW_E_NOT_STOPPED;
|
|
goto err;
|
|
}
|
|
|
|
if ( This->pHandlers->pOnPreConnect != NULL )
|
|
{
|
|
hr = This->pHandlers->pOnPreConnect(This,pPin);
|
|
if ( FAILED(hr) )
|
|
{
|
|
TRACE("OnPreConnect() failed hr = %08lx\n",hr);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
hr = IPin_QueryAccept(iface,pmt);
|
|
if ( FAILED(hr) )
|
|
goto err;
|
|
|
|
This->pmtConn = QUARTZ_MediaType_Duplicate( pmt );
|
|
if ( This->pmtConn == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto err;
|
|
}
|
|
|
|
if ( This->pHandlers->pOnPostConnect != NULL )
|
|
{
|
|
hr = This->pHandlers->pOnPostConnect(This,pPin);
|
|
if ( FAILED(hr) )
|
|
{
|
|
TRACE("OnPostConnect() failed hr = %08lx\n",hr);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
This->pPinConnectedTo = pPin; IPin_AddRef(pPin);
|
|
|
|
err:
|
|
if ( FAILED(hr) )
|
|
IPin_Disconnect(iface);
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnDisconnect(IPin* iface)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = NOERROR;
|
|
FILTER_STATE fs;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
|
|
/* return fail if running */
|
|
hr = IBaseFilter_GetState((IBaseFilter*)(This->pFilter),0,&fs);
|
|
if ( hr != S_OK || fs != State_Stopped )
|
|
{
|
|
TRACE("not stopped\n");
|
|
hr = VFW_E_NOT_STOPPED;
|
|
goto err;
|
|
}
|
|
|
|
if ( This->pHandlers->pOnDisconnect != NULL )
|
|
hr = This->pHandlers->pOnDisconnect(This);
|
|
|
|
if ( This->pmtConn != NULL )
|
|
{
|
|
QUARTZ_MediaType_Destroy( This->pmtConn );
|
|
This->pmtConn = NULL;
|
|
}
|
|
if ( This->pMemInputPinConnectedTo != NULL )
|
|
{
|
|
IMemInputPin_Release(This->pMemInputPinConnectedTo);
|
|
This->pMemInputPinConnectedTo = NULL;
|
|
}
|
|
if ( This->pPinConnectedTo != NULL )
|
|
{
|
|
/* FIXME - cleanup */
|
|
|
|
IPin_Release(This->pPinConnectedTo);
|
|
This->pPinConnectedTo = NULL;
|
|
hr = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE; /* FIXME - is this correct??? */
|
|
}
|
|
|
|
err:
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnConnectedTo(IPin* iface,IPin** ppPin)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = VFW_E_NOT_CONNECTED;
|
|
|
|
TRACE("(%p)->(%p)\n",This,ppPin);
|
|
|
|
if ( ppPin == NULL )
|
|
return E_POINTER;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
|
|
*ppPin = This->pPinConnectedTo;
|
|
if ( This->pPinConnectedTo != NULL )
|
|
{
|
|
IPin_AddRef(This->pPinConnectedTo);
|
|
hr = NOERROR;
|
|
}
|
|
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnConnectionMediaType(IPin* iface,AM_MEDIA_TYPE* pmt)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_FAIL;
|
|
|
|
TRACE("(%p)->(%p)\n",This,pmt);
|
|
|
|
if ( pmt == NULL )
|
|
return E_POINTER;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
|
|
if ( This->pmtConn != NULL )
|
|
{
|
|
hr = QUARTZ_MediaType_Copy( pmt, This->pmtConn );
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
|
|
pmt->bFixedSizeSamples = TRUE;
|
|
pmt->lSampleSize = 1;
|
|
hr = VFW_E_NOT_CONNECTED;
|
|
}
|
|
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnQueryPinInfo(IPin* iface,PIN_INFO* pinfo)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->(%p)\n",This,pinfo);
|
|
|
|
if ( pinfo == NULL )
|
|
return E_POINTER;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
|
|
ZeroMemory( pinfo, sizeof(PIN_INFO) );
|
|
pinfo->pFilter = (IBaseFilter*)(This->pFilter);
|
|
if ( pinfo->pFilter != NULL )
|
|
IBaseFilter_AddRef( pinfo->pFilter );
|
|
pinfo->dir = This->bOutput ? PINDIR_OUTPUT : PINDIR_INPUT;
|
|
if ( This->cbIdLen <= sizeof(pinfo->achName) )
|
|
memcpy( pinfo->achName, This->pwszId, This->cbIdLen );
|
|
else
|
|
{
|
|
memcpy( pinfo->achName, This->pwszId, sizeof(pinfo->achName) );
|
|
pinfo->achName[sizeof(pinfo->achName)/sizeof(pinfo->achName[0])-1] = 0;
|
|
}
|
|
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnQueryDirection(IPin* iface,PIN_DIRECTION* pdir)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->(%p)\n",This,pdir);
|
|
|
|
if ( pdir == NULL )
|
|
return E_POINTER;
|
|
|
|
*pdir = This->bOutput ? PINDIR_OUTPUT : PINDIR_INPUT;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnQueryId(IPin* iface,LPWSTR* lpwszId)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->(%p)\n",This,lpwszId);
|
|
|
|
if ( lpwszId == NULL )
|
|
return E_POINTER;
|
|
|
|
*lpwszId = (WCHAR*)CoTaskMemAlloc( This->cbIdLen );
|
|
if ( *lpwszId == NULL )
|
|
return E_OUTOFMEMORY;
|
|
memcpy( *lpwszId, This->pwszId, This->cbIdLen );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnQueryAccept(IPin* iface,const AM_MEDIA_TYPE* pmt)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p)\n",This,pmt);
|
|
|
|
if ( pmt == NULL )
|
|
return E_POINTER;
|
|
|
|
hr = NOERROR;
|
|
EnterCriticalSection( This->pcsPin );
|
|
if ( This->pHandlers->pCheckMediaType != NULL )
|
|
hr = This->pHandlers->pCheckMediaType(This,pmt);
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnEnumMediaTypes(IPin* iface,IEnumMediaTypes** ppenum)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p)\n",This,ppenum);
|
|
|
|
if ( ppenum == NULL )
|
|
return E_POINTER;
|
|
|
|
hr = E_NOTIMPL;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
if ( This->cAcceptTypes > 0 )
|
|
hr = QUARTZ_CreateEnumMediaTypes(
|
|
ppenum, This->pmtAcceptTypes, This->cAcceptTypes );
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnQueryInternalConnections(IPin* iface,IPin** ppPin,ULONG* pul)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->(%p,%p)\n",This,ppPin,pul);
|
|
|
|
/* E_NOTIMPL means 'no internal connections'. */
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnEndOfStream(IPin* iface)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( This->bOutput )
|
|
return E_UNEXPECTED;
|
|
|
|
EnterCriticalSection( This->pcsPinReceive );
|
|
if ( This->pHandlers->pEndOfStream != NULL )
|
|
hr = This->pHandlers->pEndOfStream(This);
|
|
LeaveCriticalSection( This->pcsPinReceive );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnBeginFlush(IPin* iface)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( This->bOutput )
|
|
return E_UNEXPECTED;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
if ( This->pHandlers->pBeginFlush != NULL )
|
|
hr = This->pHandlers->pBeginFlush(This);
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
EnterCriticalSection( This->pcsPinReceive );
|
|
LeaveCriticalSection( This->pcsPinReceive );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnEndFlush(IPin* iface)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( This->bOutput )
|
|
return E_UNEXPECTED;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
if ( This->pHandlers->pEndFlush != NULL )
|
|
hr = This->pHandlers->pEndFlush(This);
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CPinBaseImpl_fnNewSegment(IPin* iface,REFERENCE_TIME rtStart,REFERENCE_TIME rtStop,double rate)
|
|
{
|
|
ICOM_THIS(CPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( This->bOutput )
|
|
return E_UNEXPECTED;
|
|
|
|
EnterCriticalSection( This->pcsPin );
|
|
if ( This->pHandlers->pNewSegment != NULL )
|
|
hr = This->pHandlers->pNewSegment(This,rtStart,rtStop,rate);
|
|
LeaveCriticalSection( This->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
static ICOM_VTABLE(IPin) ipin =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
CPinBaseImpl_fnQueryInterface,
|
|
CPinBaseImpl_fnAddRef,
|
|
CPinBaseImpl_fnRelease,
|
|
/* IPin fields */
|
|
CPinBaseImpl_fnConnect,
|
|
CPinBaseImpl_fnReceiveConnection,
|
|
CPinBaseImpl_fnDisconnect,
|
|
CPinBaseImpl_fnConnectedTo,
|
|
CPinBaseImpl_fnConnectionMediaType,
|
|
CPinBaseImpl_fnQueryPinInfo,
|
|
CPinBaseImpl_fnQueryDirection,
|
|
CPinBaseImpl_fnQueryId,
|
|
CPinBaseImpl_fnQueryAccept,
|
|
CPinBaseImpl_fnEnumMediaTypes,
|
|
CPinBaseImpl_fnQueryInternalConnections,
|
|
CPinBaseImpl_fnEndOfStream,
|
|
CPinBaseImpl_fnBeginFlush,
|
|
CPinBaseImpl_fnEndFlush,
|
|
CPinBaseImpl_fnNewSegment,
|
|
};
|
|
|
|
|
|
HRESULT CPinBaseImpl_InitIPin(
|
|
CPinBaseImpl* This, IUnknown* punkControl,
|
|
CRITICAL_SECTION* pcsPin,
|
|
CRITICAL_SECTION* pcsPinReceive,
|
|
CBaseFilterImpl* pFilter, LPCWSTR pwszId,
|
|
BOOL bOutput,
|
|
const CBasePinHandlers* pHandlers )
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
TRACE("(%p,%p,%p)\n",This,punkControl,pFilter);
|
|
|
|
if ( punkControl == NULL )
|
|
{
|
|
ERR( "punkControl must not be NULL\n" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ICOM_VTBL(This) = &ipin;
|
|
This->punkControl = punkControl;
|
|
This->pHandlers = pHandlers;
|
|
This->cbIdLen = sizeof(WCHAR)*(lstrlenW(pwszId)+1);
|
|
This->pwszId = NULL;
|
|
This->bOutput = bOutput;
|
|
This->pmtAcceptTypes = NULL;
|
|
This->cAcceptTypes = 0;
|
|
This->pcsPin = pcsPin;
|
|
This->pcsPinReceive = pcsPinReceive;
|
|
This->pFilter = pFilter;
|
|
This->pPinConnectedTo = NULL;
|
|
This->pMemInputPinConnectedTo = NULL;
|
|
This->pmtConn = NULL;
|
|
This->pAsyncOut = NULL;
|
|
|
|
This->pwszId = (WCHAR*)QUARTZ_AllocMem( This->cbIdLen );
|
|
if ( This->pwszId == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto err;
|
|
}
|
|
memcpy( This->pwszId, pwszId, This->cbIdLen );
|
|
|
|
return NOERROR;
|
|
|
|
err:;
|
|
CPinBaseImpl_UninitIPin( This );
|
|
return hr;
|
|
}
|
|
|
|
void CPinBaseImpl_UninitIPin( CPinBaseImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
|
|
IPin_Disconnect( (IPin*)(This) );
|
|
|
|
if ( This->pwszId != NULL )
|
|
{
|
|
QUARTZ_FreeMem( This->pwszId );
|
|
This->pwszId = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CMemInputPinBaseImpl
|
|
*
|
|
*/
|
|
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnQueryInterface(IMemInputPin* iface,REFIID riid,void** ppobj)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CMemInputPinBaseImpl_fnAddRef(IMemInputPin* iface)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CMemInputPinBaseImpl_fnRelease(IMemInputPin* iface)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->punkControl);
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnGetAllocator(IMemInputPin* iface,IMemAllocator** ppAllocator)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
HRESULT hr = NOERROR;
|
|
IUnknown* punk;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( ppAllocator == NULL )
|
|
return E_POINTER;
|
|
|
|
EnterCriticalSection( This->pPin->pcsPin );
|
|
|
|
if ( This->pAllocator == NULL )
|
|
{
|
|
hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
|
|
if ( hr == NOERROR )
|
|
{
|
|
hr = IUnknown_QueryInterface(punk,
|
|
&IID_IMemAllocator,(void**)&This->pAllocator);
|
|
IUnknown_Release(punk);
|
|
}
|
|
}
|
|
|
|
if ( hr == NOERROR )
|
|
{
|
|
*ppAllocator = This->pAllocator;
|
|
IMemAllocator_AddRef(This->pAllocator);
|
|
}
|
|
|
|
LeaveCriticalSection( This->pPin->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnNotifyAllocator(IMemInputPin* iface,IMemAllocator* pAllocator,BOOL bReadonly)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( pAllocator == NULL )
|
|
return E_POINTER;
|
|
|
|
EnterCriticalSection( This->pPin->pcsPin );
|
|
|
|
if ( This->pAllocator != NULL )
|
|
{
|
|
IMemAllocator_Release(This->pAllocator);
|
|
This->pAllocator = NULL;
|
|
}
|
|
This->pAllocator = pAllocator;
|
|
IMemAllocator_AddRef(This->pAllocator);
|
|
|
|
This->bReadonly = bReadonly;
|
|
|
|
LeaveCriticalSection( This->pPin->pcsPin );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnGetAllocatorRequirements(IMemInputPin* iface,ALLOCATOR_PROPERTIES* pProp)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
|
|
TRACE("(%p)->(%p)\n",This,pProp);
|
|
|
|
if ( pProp == NULL )
|
|
return E_POINTER;
|
|
|
|
/* E_MOTIMPL means 'no requirements' */
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnReceive(IMemInputPin* iface,IMediaSample* pSample)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->(%p)\n",This,pSample);
|
|
|
|
EnterCriticalSection( This->pPin->pcsPinReceive );
|
|
if ( This->pPin->pHandlers->pReceive != NULL )
|
|
hr = This->pPin->pHandlers->pReceive(This->pPin,pSample);
|
|
LeaveCriticalSection( This->pPin->pcsPinReceive );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnReceiveMultiple(IMemInputPin* iface,IMediaSample** ppSample,long nSample,long* pnSampleProcessed)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
long n;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( ppSample == NULL || pnSampleProcessed == NULL )
|
|
return E_POINTER;
|
|
|
|
hr = NOERROR;
|
|
for ( n = 0; n < nSample; n++ )
|
|
{
|
|
hr = IMemInputPin_Receive(iface,ppSample[n]);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
}
|
|
|
|
*pnSampleProcessed = n;
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CMemInputPinBaseImpl_fnReceiveCanBlock(IMemInputPin* iface)
|
|
{
|
|
ICOM_THIS(CMemInputPinBaseImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
EnterCriticalSection( This->pPin->pcsPin );
|
|
if ( This->pPin->pHandlers->pReceiveCanBlock != NULL )
|
|
hr = This->pPin->pHandlers->pReceiveCanBlock(This->pPin);
|
|
LeaveCriticalSection( This->pPin->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
static ICOM_VTABLE(IMemInputPin) imeminputpin =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
CMemInputPinBaseImpl_fnQueryInterface,
|
|
CMemInputPinBaseImpl_fnAddRef,
|
|
CMemInputPinBaseImpl_fnRelease,
|
|
/* IMemInputPin fields */
|
|
CMemInputPinBaseImpl_fnGetAllocator,
|
|
CMemInputPinBaseImpl_fnNotifyAllocator,
|
|
CMemInputPinBaseImpl_fnGetAllocatorRequirements,
|
|
CMemInputPinBaseImpl_fnReceive,
|
|
CMemInputPinBaseImpl_fnReceiveMultiple,
|
|
CMemInputPinBaseImpl_fnReceiveCanBlock,
|
|
};
|
|
|
|
HRESULT CMemInputPinBaseImpl_InitIMemInputPin(
|
|
CMemInputPinBaseImpl* This, IUnknown* punkControl,
|
|
CPinBaseImpl* pPin )
|
|
{
|
|
TRACE("(%p,%p)\n",This,punkControl);
|
|
|
|
if ( punkControl == NULL )
|
|
{
|
|
ERR( "punkControl must not be NULL\n" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ICOM_VTBL(This) = &imeminputpin;
|
|
This->punkControl = punkControl;
|
|
This->pPin = pPin;
|
|
This->pAllocator = NULL;
|
|
This->bReadonly = FALSE;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CMemInputPinBaseImpl_UninitIMemInputPin(
|
|
CMemInputPinBaseImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
|
|
if ( This->pAllocator != NULL )
|
|
{
|
|
IMemAllocator_Release(This->pAllocator);
|
|
This->pAllocator = NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CQualityControlPassThruImpl
|
|
*
|
|
*/
|
|
|
|
static HRESULT WINAPI
|
|
CQualityControlPassThruImpl_fnQueryInterface(IQualityControl* iface,REFIID riid,void** ppobj)
|
|
{
|
|
ICOM_THIS(CQualityControlPassThruImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CQualityControlPassThruImpl_fnAddRef(IQualityControl* iface)
|
|
{
|
|
ICOM_THIS(CQualityControlPassThruImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CQualityControlPassThruImpl_fnRelease(IQualityControl* iface)
|
|
{
|
|
ICOM_THIS(CQualityControlPassThruImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->punkControl);
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI
|
|
CQualityControlPassThruImpl_fnNotify(IQualityControl* iface,IBaseFilter* pFilter,Quality q)
|
|
{
|
|
ICOM_THIS(CQualityControlPassThruImpl,iface);
|
|
HRESULT hr = S_FALSE;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
if ( This->pControl != NULL )
|
|
return IQualityControl_Notify( This->pControl, pFilter, q );
|
|
|
|
EnterCriticalSection( This->pPin->pcsPin );
|
|
if ( This->pPin->pHandlers->pQualityNotify != NULL )
|
|
hr = This->pPin->pHandlers->pQualityNotify(This->pPin,pFilter,q);
|
|
LeaveCriticalSection( This->pPin->pcsPin );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CQualityControlPassThruImpl_fnSetSink(IQualityControl* iface,IQualityControl* pControl)
|
|
{
|
|
ICOM_THIS(CQualityControlPassThruImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
This->pControl = pControl; /* AddRef() must not be called */
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static ICOM_VTABLE(IQualityControl) iqualitycontrol =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
CQualityControlPassThruImpl_fnQueryInterface,
|
|
CQualityControlPassThruImpl_fnAddRef,
|
|
CQualityControlPassThruImpl_fnRelease,
|
|
/* IQualityControl fields */
|
|
CQualityControlPassThruImpl_fnNotify,
|
|
CQualityControlPassThruImpl_fnSetSink,
|
|
};
|
|
|
|
HRESULT CQualityControlPassThruImpl_InitIQualityControl(
|
|
CQualityControlPassThruImpl* This, IUnknown* punkControl,
|
|
CPinBaseImpl* pPin )
|
|
{
|
|
TRACE("(%p,%p)\n",This,punkControl);
|
|
|
|
if ( punkControl == NULL )
|
|
{
|
|
ERR( "punkControl must not be NULL\n" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ICOM_VTBL(This) = &iqualitycontrol;
|
|
This->punkControl = punkControl;
|
|
This->pPin = pPin;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CQualityControlPassThruImpl_UninitIQualityControl(
|
|
CQualityControlPassThruImpl* This )
|
|
{
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* helper methods for output pins.
|
|
*
|
|
*/
|
|
|
|
HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample )
|
|
{
|
|
if ( This->pHandlers->pReceive == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
return This->pHandlers->pReceive( This, pSample );
|
|
}
|
|
|
|
HRESULT CPinBaseImpl_SendReceiveCanBlock( CPinBaseImpl* This )
|
|
{
|
|
if ( This->pHandlers->pReceiveCanBlock == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
return This->pHandlers->pReceiveCanBlock( This );
|
|
}
|
|
|
|
HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This )
|
|
{
|
|
if ( This->pHandlers->pEndOfStream == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
return This->pHandlers->pEndOfStream( This );
|
|
}
|
|
|
|
HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This )
|
|
{
|
|
if ( This->pHandlers->pBeginFlush == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
return This->pHandlers->pBeginFlush( This );
|
|
}
|
|
|
|
HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This )
|
|
{
|
|
if ( This->pHandlers->pEndFlush == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
return This->pHandlers->pEndFlush( This );
|
|
}
|
|
|
|
HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
|
|
{
|
|
if ( This->pHandlers->pNewSegment == NULL )
|
|
return E_NOTIMPL;
|
|
|
|
return This->pHandlers->pNewSegment( This, rtStart, rtStop, rate );
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* handlers for output pins.
|
|
*
|
|
*/
|
|
|
|
HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
|
|
{
|
|
if ( pImpl->pMemInputPinConnectedTo == NULL )
|
|
return NOERROR;
|
|
|
|
return IMemInputPin_Receive(pImpl->pMemInputPinConnectedTo,pSample);
|
|
}
|
|
|
|
HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl )
|
|
{
|
|
if ( pImpl->pMemInputPinConnectedTo == NULL )
|
|
return S_FALSE;
|
|
|
|
return IMemInputPin_ReceiveCanBlock(pImpl->pMemInputPinConnectedTo);
|
|
}
|
|
|
|
HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl )
|
|
{
|
|
if ( pImpl->pPinConnectedTo == NULL )
|
|
return NOERROR;
|
|
|
|
return IPin_EndOfStream(pImpl->pPinConnectedTo);
|
|
}
|
|
|
|
HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl )
|
|
{
|
|
if ( pImpl->pPinConnectedTo == NULL )
|
|
return NOERROR;
|
|
|
|
return IPin_BeginFlush(pImpl->pPinConnectedTo);
|
|
}
|
|
|
|
HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl )
|
|
{
|
|
if ( pImpl->pPinConnectedTo == NULL )
|
|
return NOERROR;
|
|
|
|
return IPin_EndFlush(pImpl->pPinConnectedTo);
|
|
}
|
|
|
|
HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
|
|
{
|
|
if ( pImpl->pPinConnectedTo == NULL )
|
|
return NOERROR;
|
|
|
|
return IPin_NewSegment(pImpl->pPinConnectedTo,rtStart,rtStop,rate);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* handlers for output pins (async).
|
|
*
|
|
*/
|
|
|
|
typedef struct OutputPinTask OutputPinTask;
|
|
|
|
enum OutputPinTaskType
|
|
{
|
|
OutTask_ExitThread,
|
|
OutTask_Receive,
|
|
OutTask_EndOfStream,
|
|
OutTask_BeginFlush,
|
|
OutTask_EndFlush,
|
|
OutTask_NewSegment,
|
|
};
|
|
|
|
struct OutputPinTask
|
|
{
|
|
OutputPinTask* pNext;
|
|
enum OutputPinTaskType tasktype;
|
|
IMediaSample* pSample;
|
|
REFERENCE_TIME rtStart;
|
|
REFERENCE_TIME rtStop;
|
|
double rate;
|
|
};
|
|
|
|
struct OutputPinAsyncImpl
|
|
{
|
|
HANDLE m_hTaskThread;
|
|
HANDLE m_hTaskEvent;
|
|
IPin* m_pPin; /* connected pin */
|
|
IMemInputPin* m_pMemInputPin; /* connected pin */
|
|
CRITICAL_SECTION m_csTasks;
|
|
OutputPinTask* m_pFirst;
|
|
OutputPinTask* m_pLast;
|
|
OutputPinTask* m_pTaskExitThread;
|
|
};
|
|
|
|
static OutputPinTask* OutputPinAsync_AllocTask( enum OutputPinTaskType tasktype )
|
|
{
|
|
OutputPinTask* pTask;
|
|
|
|
pTask = (OutputPinTask*)QUARTZ_AllocMem( sizeof(OutputPinTask) );
|
|
pTask->pNext = NULL;
|
|
pTask->tasktype = tasktype;
|
|
pTask->pSample = NULL;
|
|
|
|
return pTask;
|
|
}
|
|
|
|
static void OutputPinAsync_FreeTask( OutputPinTask* pTask )
|
|
{
|
|
if ( pTask->pSample != NULL )
|
|
IMediaSample_Release( pTask->pSample );
|
|
QUARTZ_FreeMem( pTask );
|
|
}
|
|
|
|
static void OutputPinAsync_AddTask( OutputPinAsyncImpl* This, OutputPinTask* pTask, BOOL bFirst )
|
|
{
|
|
EnterCriticalSection( &This->m_csTasks );
|
|
|
|
if ( bFirst )
|
|
{
|
|
pTask->pNext = This->m_pFirst;
|
|
This->m_pFirst = pTask;
|
|
if ( This->m_pLast == NULL )
|
|
This->m_pLast = pTask;
|
|
}
|
|
else
|
|
{
|
|
if ( This->m_pLast != NULL )
|
|
This->m_pLast->pNext = pTask;
|
|
else
|
|
This->m_pFirst = pTask;
|
|
This->m_pLast = pTask;
|
|
}
|
|
|
|
LeaveCriticalSection( &This->m_csTasks );
|
|
|
|
SetEvent( This->m_hTaskEvent );
|
|
}
|
|
|
|
static OutputPinTask* OutputPinAsync_GetNextTask( OutputPinAsyncImpl* This )
|
|
{
|
|
OutputPinTask* pTask;
|
|
|
|
EnterCriticalSection( &This->m_csTasks );
|
|
pTask = This->m_pFirst;
|
|
if ( pTask != NULL )
|
|
{
|
|
This->m_pFirst = pTask->pNext;
|
|
if ( This->m_pFirst == NULL )
|
|
This->m_pLast = NULL;
|
|
else
|
|
SetEvent( This->m_hTaskEvent );
|
|
}
|
|
|
|
LeaveCriticalSection( &This->m_csTasks );
|
|
|
|
return pTask;
|
|
}
|
|
|
|
static DWORD WINAPI OutputPinAsync_ThreadEntry( LPVOID pv )
|
|
{
|
|
OutputPinAsyncImpl* This = ((CPinBaseImpl*)pv)->pAsyncOut;
|
|
OutputPinTask* pTask;
|
|
BOOL bLoop = TRUE;
|
|
BOOL bInFlush = FALSE;
|
|
HRESULT hr;
|
|
|
|
while ( bLoop )
|
|
{
|
|
WaitForSingleObject( This->m_hTaskEvent, INFINITE );
|
|
ResetEvent( This->m_hTaskEvent );
|
|
|
|
pTask = OutputPinAsync_GetNextTask( This );
|
|
if ( pTask == NULL )
|
|
continue;
|
|
|
|
hr = S_OK;
|
|
switch ( pTask->tasktype )
|
|
{
|
|
case OutTask_ExitThread:
|
|
bLoop = FALSE;
|
|
break;
|
|
case OutTask_Receive:
|
|
if ( !bInFlush )
|
|
hr = IMemInputPin_Receive( This->m_pMemInputPin, pTask->pSample );
|
|
break;
|
|
case OutTask_EndOfStream:
|
|
hr = IPin_EndOfStream( This->m_pPin );
|
|
break;
|
|
case OutTask_BeginFlush:
|
|
bInFlush = TRUE;
|
|
hr = IPin_BeginFlush( This->m_pPin );
|
|
break;
|
|
case OutTask_EndFlush:
|
|
bInFlush = FALSE;
|
|
hr = IPin_EndFlush( This->m_pPin );
|
|
break;
|
|
case OutTask_NewSegment:
|
|
hr = IPin_NewSegment( This->m_pPin, pTask->rtStart, pTask->rtStop, pTask->rate );
|
|
break;
|
|
default:
|
|
ERR( "unexpected task type %d.\n", pTask->tasktype );
|
|
bLoop = FALSE;
|
|
break;
|
|
}
|
|
|
|
OutputPinAsync_FreeTask( pTask );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
ERR( "hresult %08lx\n", hr );
|
|
bLoop = FALSE;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl )
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwThreadId;
|
|
|
|
FIXME("(%p)\n",pImpl);
|
|
|
|
if ( pImpl->pMemInputPinConnectedTo == NULL )
|
|
return NOERROR;
|
|
|
|
pImpl->pAsyncOut = (OutputPinAsyncImpl*)
|
|
QUARTZ_AllocMem( sizeof( OutputPinAsyncImpl ) );
|
|
if ( pImpl->pAsyncOut == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
InitializeCriticalSection( &pImpl->pAsyncOut->m_csTasks );
|
|
pImpl->pAsyncOut->m_hTaskThread = (HANDLE)NULL;
|
|
pImpl->pAsyncOut->m_hTaskEvent = (HANDLE)NULL;
|
|
pImpl->pAsyncOut->m_pFirst = NULL;
|
|
pImpl->pAsyncOut->m_pLast = NULL;
|
|
pImpl->pAsyncOut->m_pTaskExitThread = NULL;
|
|
pImpl->pAsyncOut->m_pPin = pImpl->pPinConnectedTo;
|
|
pImpl->pAsyncOut->m_pMemInputPin = pImpl->pMemInputPinConnectedTo;
|
|
|
|
pImpl->pAsyncOut->m_hTaskEvent =
|
|
CreateEventA( NULL, TRUE, FALSE, NULL );
|
|
if ( pImpl->pAsyncOut->m_hTaskEvent == (HANDLE)NULL )
|
|
{
|
|
hr = E_FAIL;
|
|
goto err;
|
|
}
|
|
|
|
pImpl->pAsyncOut->m_pTaskExitThread =
|
|
OutputPinAsync_AllocTask( OutTask_ExitThread );
|
|
if ( pImpl->pAsyncOut->m_pTaskExitThread == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto err;
|
|
}
|
|
|
|
pImpl->pAsyncOut->m_hTaskThread = CreateThread(
|
|
NULL, 0, OutputPinAsync_ThreadEntry, pImpl,
|
|
0, &dwThreadId );
|
|
if ( pImpl->pAsyncOut->m_hTaskThread == (HANDLE)NULL )
|
|
{
|
|
hr = E_FAIL;
|
|
goto err;
|
|
}
|
|
|
|
return NOERROR;
|
|
err:
|
|
OutputPinAsync_OnInactive( pImpl );
|
|
return hr;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl )
|
|
{
|
|
OutputPinTask* pTask;
|
|
|
|
FIXME("(%p)\n",pImpl);
|
|
|
|
if ( pImpl->pAsyncOut == NULL )
|
|
return NOERROR;
|
|
|
|
if ( pImpl->pAsyncOut->m_pTaskExitThread != NULL )
|
|
{
|
|
OutputPinAsync_AddTask( pImpl->pAsyncOut, pImpl->pAsyncOut->m_pTaskExitThread, TRUE );
|
|
pImpl->pAsyncOut->m_pTaskExitThread = NULL;
|
|
}
|
|
|
|
if ( pImpl->pAsyncOut->m_hTaskThread != (HANDLE)NULL )
|
|
{
|
|
WaitForSingleObject( pImpl->pAsyncOut->m_hTaskThread, INFINITE );
|
|
CloseHandle( pImpl->pAsyncOut->m_hTaskThread );
|
|
}
|
|
if ( pImpl->pAsyncOut->m_hTaskEvent != (HANDLE)NULL )
|
|
CloseHandle( pImpl->pAsyncOut->m_hTaskEvent );
|
|
|
|
/* release all tasks. */
|
|
while ( 1 )
|
|
{
|
|
pTask = OutputPinAsync_GetNextTask( pImpl->pAsyncOut );
|
|
if ( pTask == NULL )
|
|
break;
|
|
OutputPinAsync_FreeTask( pTask );
|
|
}
|
|
|
|
DeleteCriticalSection( &pImpl->pAsyncOut->m_csTasks );
|
|
|
|
QUARTZ_FreeMem( pImpl->pAsyncOut );
|
|
pImpl->pAsyncOut = NULL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
|
|
{
|
|
OutputPinAsyncImpl* This = pImpl->pAsyncOut;
|
|
OutputPinTask* pTask;
|
|
|
|
TRACE("(%p,%p)\n",pImpl,pSample);
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
pTask = OutputPinAsync_AllocTask( OutTask_Receive );
|
|
if ( pTask == NULL )
|
|
return E_OUTOFMEMORY;
|
|
pTask->pSample = pSample; IMediaSample_AddRef( pSample );
|
|
OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl )
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl )
|
|
{
|
|
OutputPinAsyncImpl* This = pImpl->pAsyncOut;
|
|
OutputPinTask* pTask;
|
|
|
|
TRACE("(%p)\n",pImpl);
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
pTask = OutputPinAsync_AllocTask( OutTask_EndOfStream );
|
|
if ( pTask == NULL )
|
|
return E_OUTOFMEMORY;
|
|
OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl )
|
|
{
|
|
OutputPinAsyncImpl* This = pImpl->pAsyncOut;
|
|
OutputPinTask* pTask;
|
|
|
|
TRACE("(%p)\n",pImpl);
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
pTask = OutputPinAsync_AllocTask( OutTask_BeginFlush );
|
|
if ( pTask == NULL )
|
|
return E_OUTOFMEMORY;
|
|
OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, TRUE );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl )
|
|
{
|
|
OutputPinAsyncImpl* This = pImpl->pAsyncOut;
|
|
OutputPinTask* pTask;
|
|
|
|
TRACE("(%p)\n",pImpl);
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
pTask = OutputPinAsync_AllocTask( OutTask_EndFlush );
|
|
if ( pTask == NULL )
|
|
return E_OUTOFMEMORY;
|
|
OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
|
|
{
|
|
OutputPinAsyncImpl* This = pImpl->pAsyncOut;
|
|
OutputPinTask* pTask;
|
|
|
|
TRACE("(%p)\n",pImpl);
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
pTask = OutputPinAsync_AllocTask( OutTask_NewSegment );
|
|
if ( pTask == NULL )
|
|
return E_OUTOFMEMORY;
|
|
pTask->rtStart = rtStart;
|
|
pTask->rtStop = rtStop;
|
|
pTask->rate = rate;
|
|
OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|